From 42e9a6294b6ff48d963e385301fb0248aeab9d14 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Mon, 17 Apr 2023 21:47:34 -0700 Subject: [PATCH] Remove eager loading of factions. Eager loading meant that users would need to restart Liberation to pick up changes to faction files. That's annoying for modders, slows down start up, and uselessly sits in RAM when it's not needed after game creation. Also removes the __getitem__ and __iter__ methods in favor of named methods, since the dunder methods are more or less impenetrable for IDEs and grep. --- game/factions/__init__.py | 3 -- game/factions/factionloader.py | 55 ------------------------- game/factions/factions.py | 46 +++++++++++++++++++++ qt_ui/main.py | 7 ++-- qt_ui/windows/newgame/QNewGameWizard.py | 22 +++++----- 5 files changed, 62 insertions(+), 71 deletions(-) delete mode 100644 game/factions/factionloader.py create mode 100644 game/factions/factions.py diff --git a/game/factions/__init__.py b/game/factions/__init__.py index a4d7fa86..6b678491 100644 --- a/game/factions/__init__.py +++ b/game/factions/__init__.py @@ -1,4 +1 @@ from .faction import Faction -from .factionloader import FactionLoader - -FACTIONS = FactionLoader() diff --git a/game/factions/factionloader.py b/game/factions/factionloader.py deleted file mode 100644 index d6b91518..00000000 --- a/game/factions/factionloader.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -import json -import logging -from pathlib import Path -from typing import Dict, Iterator, List, Optional, Type - -from game import persistence -from game.factions.faction import Faction - -FACTION_DIRECTORY = Path("./resources/factions/") - - -class FactionLoader: - def __init__(self) -> None: - self._factions: Optional[Dict[str, Faction]] = None - - @property - def factions(self) -> Dict[str, Faction]: - self.initialize() - assert self._factions is not None - return self._factions - - def initialize(self) -> None: - if self._factions is None: - self._factions = self.load_factions() - - @staticmethod - def find_faction_files_in(path: Path) -> List[Path]: - return [f for f in path.glob("*.json") if f.is_file()] - - @classmethod - def load_factions(cls: Type[FactionLoader]) -> Dict[str, Faction]: - user_faction_path = Path(persistence.base_path()) / "Liberation/Factions" - files = cls.find_faction_files_in( - FACTION_DIRECTORY - ) + cls.find_faction_files_in(user_faction_path) - factions = {} - - for f in files: - try: - with f.open("r", encoding="utf-8") as fdata: - data = json.load(fdata) - factions[data["name"]] = Faction.from_json(data) - logging.info("Loaded faction : " + str(f)) - except Exception: - logging.exception(f"Unable to load faction : {f}") - - return factions - - def __getitem__(self, name: str) -> Faction: - return self.factions[name] - - def __iter__(self) -> Iterator[str]: - return iter(self.factions.keys()) diff --git a/game/factions/factions.py b/game/factions/factions.py new file mode 100644 index 00000000..c22a2cae --- /dev/null +++ b/game/factions/factions.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +import json +import logging +from collections.abc import Iterator +from pathlib import Path + +from game import persistence +from .faction import Faction + + +class Factions: + def __init__(self, factions: dict[str, Faction]) -> None: + self.factions = factions + + def get_by_name(self, name: str) -> Faction: + return self.factions[name] + + def iter_faction_names(self) -> Iterator[str]: + return iter(self.factions.keys()) + + @staticmethod + def iter_faction_files_in(path: Path) -> Iterator[Path]: + yield from path.glob("*.json") + + @classmethod + def iter_faction_files(cls) -> Iterator[Path]: + yield from cls.iter_faction_files_in(Path("resources/factions/")) + yield from cls.iter_faction_files_in( + Path(persistence.base_path()) / "Liberation/Factions" + ) + + @classmethod + def load(cls) -> Factions: + factions = {} + for path in cls.iter_faction_files(): + try: + with path.open("r", encoding="utf-8") as fdata: + data = json.load(fdata) + faction = Faction.from_json(data) + factions[faction.name] = faction + logging.info("Loaded faction from %s", path) + except Exception: + logging.exception(f"Unable to load faction from %s", path) + + return Factions(factions) diff --git a/qt_ui/main.py b/qt_ui/main.py index 33630cdd..7ea181a1 100644 --- a/qt_ui/main.py +++ b/qt_ui/main.py @@ -17,7 +17,7 @@ from game import Game, VERSION, logging_config, persistence from game.campaignloader.campaign import Campaign, DEFAULT_BUDGET from game.data.weapons import Pylon, Weapon, WeaponGroup from game.dcs.aircrafttype import AircraftType -from game.factions import FACTIONS +from game.factions.factions import Factions from game.profiling import logged_duration from game.server import EventStream, Server from game.settings import Settings @@ -275,9 +275,10 @@ def create_game( inject_custom_payloads(Path(persistence.base_path())) campaign = Campaign.from_file(campaign_path) theater = campaign.load_theater(advanced_iads) + faction_loader = Factions.load() generator = GameGenerator( - FACTIONS[blue], - FACTIONS[red], + faction_loader.get_by_name(blue), + faction_loader.get_by_name(red), theater, campaign.load_air_wing_config(theater), Settings( diff --git a/qt_ui/windows/newgame/QNewGameWizard.py b/qt_ui/windows/newgame/QNewGameWizard.py index 531a7a08..d6a17732 100644 --- a/qt_ui/windows/newgame/QNewGameWizard.py +++ b/qt_ui/windows/newgame/QNewGameWizard.py @@ -10,7 +10,8 @@ from PySide6.QtWidgets import QCheckBox, QLabel, QTextEdit, QVBoxLayout from jinja2 import Environment, FileSystemLoader, select_autoescape from game.campaignloader.campaign import Campaign, DEFAULT_BUDGET -from game.factions import FACTIONS, Faction +from game.factions import Faction +from game.factions.factions import Factions from game.settings import Settings from game.theater.start_generator import GameGenerator, GeneratorSettings, ModSettings from qt_ui.widgets.QLiberationCalendar import QLiberationCalendar @@ -224,6 +225,8 @@ class FactionSelection(QtWidgets.QWizardPage): def __init__(self, parent=None): super(FactionSelection, self).__init__(parent) + self.factions = Factions.load() + self.setTitle("Faction selection") self.setSubTitle( "\nChoose the two opposing factions and select the player side." @@ -243,7 +246,7 @@ class FactionSelection(QtWidgets.QWizardPage): blueFaction = QtWidgets.QLabel("Player Faction :") self.blueFactionSelect = QtWidgets.QComboBox() - for f in FACTIONS: + for f in self.factions.iter_faction_names(): self.blueFactionSelect.addItem(f) blueFaction.setBuddy(self.blueFactionSelect) @@ -259,7 +262,7 @@ class FactionSelection(QtWidgets.QWizardPage): self.redFactionDescription.setReadOnly(True) # Setup default selected factions - for i, r in enumerate(FACTIONS): + for i, r in enumerate(self.factions.iter_faction_names()): self.redFactionSelect.addItem(r) if r == "Russia 1990": self.redFactionSelect.setCurrentIndex(i) @@ -305,10 +308,10 @@ class FactionSelection(QtWidgets.QWizardPage): self.blueFactionSelect.clear() self.redFactionSelect.clear() - for f in FACTIONS: + for f in self.factions.iter_faction_names(): self.blueFactionSelect.addItem(f) - for i, r in enumerate(FACTIONS): + for i, r in enumerate(self.factions.iter_faction_names()): self.redFactionSelect.addItem(r) if r == campaign.recommended_enemy_faction: self.redFactionSelect.setCurrentIndex(i) @@ -318,9 +321,8 @@ class FactionSelection(QtWidgets.QWizardPage): self.updateUnitRecap() def updateUnitRecap(self): - - red_faction = FACTIONS[self.redFactionSelect.currentText()] - blue_faction = FACTIONS[self.blueFactionSelect.currentText()] + red_faction = self.factions.get_by_name(self.redFactionSelect.currentText()) + blue_faction = self.factions.get_by_name(self.blueFactionSelect.currentText()) template = jinja_env.get_template("factiontemplate_EN.j2") @@ -332,11 +334,11 @@ class FactionSelection(QtWidgets.QWizardPage): @property def selected_blue_faction(self) -> Faction: - return FACTIONS[self.blueFactionSelect.currentText()] + return self.factions.get_by_name(self.blueFactionSelect.currentText()) @property def selected_red_faction(self) -> Faction: - return FACTIONS[self.redFactionSelect.currentText()] + return self.factions.get_by_name(self.redFactionSelect.currentText()) class TheaterConfiguration(QtWidgets.QWizardPage):