Skip to content

Commit

Permalink
Merge pull request #209 from felixvonsamson/fix-buffered-engine-data
Browse files Browse the repository at this point in the history
Fix buffered engine data
  • Loading branch information
yassir-akram authored Nov 25, 2024
2 parents 81ee89a + a90470e commit 05a95d8
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 182 deletions.
3 changes: 1 addition & 2 deletions website/api/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,11 @@ def get_player_data():
if current_user.tile is None:
return "", 404
levels = current_user.get_lvls()
config = g.engine.config[current_user.id]
capacities = current_user.capacities.get_all()
return jsonify(
{
"levels": levels,
"config": config,
"config": current_user.config,
"capacities": capacities,
"multipliers": get_current_technology_values(current_user),
}
Expand Down
21 changes: 12 additions & 9 deletions website/config/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

# TODO: it would be better to store the relevant data in a non-code file. Maybe a JSON

from __future__ import annotations

from datetime import timedelta
from typing import TYPE_CHECKING

from website.database.player import Player
if TYPE_CHECKING:
from website.database.player import Player

const_config = {
"assets": {
Expand Down Expand Up @@ -932,17 +936,16 @@ class Config(object):
def __init__(self):
self.for_player = {}

def update_config_for_user(self, player_id):
def update_config_for_user(self, player: Player):
"""This function updates the config values according to the players technology level"""
# TODO: deprecate this method eventually
self.for_player[player_id] = {
self.for_player[player.id] = {
"industry": {},
"carbon_capture": {},
"warehouse_capacities": {},
"transport": {},
}
assets = self.for_player[player_id]
player: Player = Player.query.get(player_id)
assets = self.for_player[player.id]

# calculating industry energy consumption and income
assets["industry"]["power_consumption"] = (
Expand Down Expand Up @@ -986,10 +989,10 @@ def update_config_for_user(self, player_id):
player.construction_workers = player_construction_workers_for_level(player.building_technology)
player.lab_workers = player_lab_workers_for_level(player.laboratory)

def __getitem__(self, player_id):
if player_id not in self.for_player:
self.update_config_for_user(player_id)
return self.for_player[player_id]
def __getitem__(self, player: Player):
if player.id not in self.for_player:
self.update_config_for_user(player)
return self.for_player[player.id]


config = Config()
203 changes: 130 additions & 73 deletions website/database/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
)
from website.database.messages import Chat, Message, Notification, player_chats
from website.database.player_assets import ActiveFacility, OngoingConstruction
from website.technology_effects import (
package_available_technologies,
package_extraction_facilities,
package_functional_facilities,
package_power_facilities,
package_storage_facilities,
)

if TYPE_CHECKING:
from website.game_engine import GameEngine
Expand Down Expand Up @@ -141,43 +148,45 @@ class Player(db.Model, UserMixin):
active_facilities = db.relationship("ActiveFacility", backref="player", lazy="dynamic")
climate_events = db.relationship("ClimateEventRecovery", backref="player")

_buffered_data_for_power_facilities_page = None
_buffered_data_for_storage_facilities_page = None
_buffered_data_for_extraction_facilities_page = None
_buffered_data_for_functional_facilities_page = None
_buffered_data_for_technologies_page = None
_buffered_data_for_resource_market_page = None

@property
def engine(self) -> "GameEngine":
return current_app.config["engine"]

@property
def config(self):
return current_app.config["engine"].config[self]

@property
def socketio_clients(self) -> List[int]:
return current_app.config["engine"].clients[self.id]

@property
def current_data(self) -> CircularBufferPlayer:
return current_app.config["engine"].data["players"][self.id]["current_data"]
return current_app.config["engine"].data[type(self).__name__][self.id]["current_data"]

@current_data.setter
def current_data(self, value):
current_app.config["engine"].data["players"][self.id]["current_data"] = value
current_app.config["engine"].data[type(self).__name__][self.id]["current_data"] = value

@property
def capacities(self) -> CapacityData:
return current_app.config["engine"].data["players"][self.id]["capacities"]
return current_app.config["engine"].data[type(self).__name__][self.id]["capacities"]

@capacities.setter
def capacities(self, value):
current_app.config["engine"].data["players"][self.id]["capacities"] = value
current_app.config["engine"].data[type(self).__name__][self.id]["capacities"] = value

@property
def cumul_emissions(self) -> CumulativeEmissionsData:
return current_app.config["engine"].data["players"][self.id]["cumul_emissions"]
return current_app.config["engine"].data[type(self).__name__][self.id]["cumul_emissions"]

@cumul_emissions.setter
def cumul_emissions(self, value):
current_app.config["engine"].data["players"][self.id]["cumul_emissions"] = value
current_app.config["engine"].data[type(self).__name__][self.id]["cumul_emissions"] = value

@property
def is_in_network(self):
"""Returns True if the player is in a network"""
return self.network_id is not None

def change_graph_view(self, view):
Expand Down Expand Up @@ -574,7 +583,7 @@ def package_constructions(self):
]
}
| {"display_name": current_app.config["engine"].const_config["assets"][construction.name]["name"]}
| ({"level": construction.level()} if construction.level() >= 0 else {})
| ({"level": construction.level} if construction.level >= 0 else {})
for construction in self.under_construction
}

Expand Down Expand Up @@ -629,90 +638,138 @@ def get_facility_data(facilities):
"extraction_facilities": get_facility_data(engine.extraction_facilities),
}

@property
def cached_power_facilities_data(self):
"""Cached data for the power facilities page"""
if "cached_power_facilities_data" not in current_app.config["engine"].buffered[type(self).__name__][self.id]:
self.cached_power_facilities_data = package_power_facilities(self)
return current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_power_facilities_data"]

@cached_power_facilities_data.setter
def cached_power_facilities_data(self, value):
"""Sets the cached data for the power facilities page"""
current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_power_facilities_data"] = value

@cached_power_facilities_data.deleter
def cached_power_facilities_data(self):
"""Deletes the cached data for the power facilities page"""
del current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_power_facilities_data"]

@property
def cached_storage_facilities_data(self):
"""Cached data for the storage facilities page"""
if "cached_storage_facilities_data" not in current_app.config["engine"].buffered[type(self).__name__][self.id]:
self.cached_storage_facilities_data = package_storage_facilities(self)
return current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_storage_facilities_data"]

@cached_storage_facilities_data.setter
def cached_storage_facilities_data(self, value):
"""Sets the cached data for the storage facilities page"""
current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_storage_facilities_data"] = value

@cached_storage_facilities_data.deleter
def cached_storage_facilities_data(self):
"""Deletes the cached data for the storage facilities page"""
del current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_storage_facilities_data"]

@property
def cached_extraction_facility_data(self):
"""Cached data for the extraction facilities page"""
if "cached_extraction_facility_data" not in current_app.config["engine"].buffered[type(self).__name__][self.id]:
self.cached_extraction_facility_data = package_extraction_facilities(self)
return current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_extraction_facility_data"]

@cached_extraction_facility_data.deleter
def cached_extraction_facility_data(self):
"""Deletes the cached data for the extraction facilities page"""
del current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_extraction_facility_data"]

@cached_extraction_facility_data.setter
def cached_extraction_facility_data(self, value):
"""Sets the cached data for the extraction facilities page"""
current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_extraction_facility_data"] = value

@property
def cached_functional_facilities_data(self):
"""Cached data for the functional facilities page"""
if (
"cached_functional_facilities_data"
not in current_app.config["engine"].buffered[type(self).__name__][self.id]
):
self.cached_functional_facilities_data = package_functional_facilities(self)
return current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_functional_facilities_data"]

@cached_functional_facilities_data.deleter
def cached_functional_facilities_data(self):
"""Deletes the cached data for the functional facilities page"""
del current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_functional_facilities_data"]

@cached_functional_facilities_data.setter
def cached_functional_facilities_data(self, value):
"""Sets the cached data for the functional facilities page"""
current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_functional_facilities_data"] = value

@property
def cached_technologies_data(self):
"""Cached data for the technologies page"""
if "cached_technologies_data" not in current_app.config["engine"].buffered[type(self).__name__][self.id]:
self.cached_technologies_data = package_available_technologies(self)
return current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_technologies_data"]

@cached_technologies_data.setter
def cached_technologies_data(self, value):
"""Sets the cached data for the technologies page"""
current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_technologies_data"] = value

@cached_technologies_data.deleter
def cached_technologies_data(self):
"""Deletes the cached data for the technologies page"""
del current_app.config["engine"].buffered[type(self).__name__][self.id]["cached_technologies_data"]

def invalidate_recompute_and_dispatch_data_for_pages(
self,
*,
power_facilities=False,
storage_facilities=False,
extraction_facilities=False,
functional_facilities=False,
technologies=False,
resource_market=False,
# resource_market=False,
):
"""
Signal to all instances of clients for this player that there is possibly new data for the specified page.
This function will invalidate the data for all corresponding arguments that are set to True.
"""
if power_facilities:
self._buffered_data_for_power_facilities_page = None
del self.cached_power_facilities_data
if storage_facilities:
self._buffered_data_for_storage_facilities_page = None
del self.cached_storage_facilities_data
if extraction_facilities:
self._buffered_data_for_extraction_facilities_page = None
del self.cached_extraction_facility_data
if functional_facilities:
self._buffered_data_for_functional_facilities_page = None
del self.cached_functional_facilities_data
if technologies:
self._buffered_data_for_technologies_page = None
if resource_market:
self._buffered_data_for_resource_market_page = None
engine = current_app.config["engine"]
if engine.clients[self.id]:
del self.cached_technologies_data
# if resource_market:
# self._buffered_data_for_resource_market_page = None
if self.socketio_clients:
# or engine.websocket_dict[self.id]:
pages_data = {}
if power_facilities:
pages_data |= {"power_facilities": self.get_packaged_data_for_power_facilities_page()}
pages_data |= {"power_facilities": self.cached_power_facilities_data}
if storage_facilities:
pages_data |= {"storage_facilities": self.get_packaged_data_for_storage_facilities_page()}
pages_data |= {"storage_facilities": self.cached_storage_facilities_data}
if extraction_facilities:
pages_data |= {"extraction_facilities": self.get_packaged_data_for_extraction_facilities_page()}
pages_data |= {"extraction_facilities": self.cached_extraction_facility_data}
if functional_facilities:
pages_data |= {"functional_facilities": self.get_packaged_data_for_functional_facilities_page()}
pages_data |= {"functional_facilities": self.cached_functional_facilities_data}
if technologies:
pages_data |= {"technologies": self.get_packaged_data_for_technologies_page()}
pages_data |= {"technologies": self.cached_technologies_data}
# if resource_market:
# pages_data |= {"power_facilities": self.get_packaged_data_for_power_facilities_page()}
self.emit("update_page_data", pages_data)
# TODO: update clients over websocket

def get_packaged_data_for_power_facilities_page(self):
"""Get buffered data or recompute"""
from website import technology_effects

if self._buffered_data_for_power_facilities_page is None:
self._buffered_data_for_power_facilities_page = technology_effects.package_power_facilities(self)
return self._buffered_data_for_power_facilities_page

def get_packaged_data_for_storage_facilities_page(self):
"""Get buffered data or recompute"""
from website import technology_effects

if self._buffered_data_for_storage_facilities_page is None:
self._buffered_data_for_storage_facilities_page = technology_effects.package_storage_facilities(self)
return self._buffered_data_for_storage_facilities_page

def get_packaged_data_for_extraction_facilities_page(self):
"""Get buffered data or recompute"""
from website import technology_effects

if self._buffered_data_for_extraction_facilities_page is None:
self._buffered_data_for_extraction_facilities_page = technology_effects.package_extraction_facilities(self)
return self._buffered_data_for_extraction_facilities_page

def get_packaged_data_for_functional_facilities_page(self):
"""Get buffered data or recompute"""
from website import technology_effects

if self._buffered_data_for_functional_facilities_page is None:
self._buffered_data_for_functional_facilities_page = technology_effects.package_functional_facilities(self)
return self._buffered_data_for_functional_facilities_page

def get_packaged_data_for_technologies_page(self):
"""Get buffered data or recompute"""
from website import technology_effects

if self._buffered_data_for_technologies_page is None:
self._buffered_data_for_technologies_page = technology_effects.package_available_technologies(self)
return self._buffered_data_for_technologies_page


class Network(db.Model):
"""class that stores the networks of players"""
Expand All @@ -723,19 +780,19 @@ class Network(db.Model):

@property
def current_data(self) -> CircularBufferNetwork:
return current_app.config["engine"].data["networks"][self.id]["current_data"]
return current_app.config["engine"].data[type(self).__name__][self.id]["current_data"]

@current_data.setter
def current_data(self, value):
current_app.config["engine"].data["networks"][self.id]["current_data"] = value
current_app.config["engine"].data[type(self).__name__][self.id]["current_data"] = value

@property
def capacities(self) -> CapacityData:
return current_app.config["engine"].data["networks"][self.id]["capacities"]
return current_app.config["engine"].data[type(self).__name__][self.id]["capacities"]

@capacities.setter
def capacities(self, value):
current_app.config["engine"].data["networks"][self.id]["capacities"] = value
current_app.config["engine"].data[type(self).__name__][self.id]["capacities"] = value


class PlayerUnreadMessages(db.Model):
Expand Down
Loading

0 comments on commit 05a95d8

Please sign in to comment.