Include layouts & groups from Saved Games folder

Partial #244
This commit is contained in:
Raffson 2024-10-06 22:29:29 +02:00
parent 69c6f8f2f2
commit 4aacc68f4a
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
3 changed files with 54 additions and 11 deletions

View File

@ -9,6 +9,7 @@ from typing import Any, ClassVar, Iterator, Optional, TYPE_CHECKING, Type
import yaml import yaml
from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType, VehicleType from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType, VehicleType
from game import persistency
from game.data.groups import GroupTask from game.data.groups import GroupTask
from game.dcs.groundunittype import GroundUnitType from game.dcs.groundunittype import GroundUnitType
from game.dcs.helpers import static_type_from_name from game.dcs.helpers import static_type_from_name
@ -317,7 +318,18 @@ class ForceGroup:
@classmethod @classmethod
def _load_all(cls) -> None: def _load_all(cls) -> None:
for file in Path("resources/groups").glob("*.yaml"): locations = [
Path("resources/groups"),
persistency.groups_dir(),
]
for path in locations:
cls._process_path(path)
cls._loaded = True
@classmethod
def _process_path(cls, path: Path) -> None:
for file in path.glob("*.yaml"):
if not file.is_file(): if not file.is_file():
raise RuntimeError(f"{file.name} is not a valid ForceGroup") raise RuntimeError(f"{file.name} is not a valid ForceGroup")
@ -365,5 +377,3 @@ class ForceGroup:
) )
cls._by_name[force_group.name] = force_group cls._by_name[force_group.name] = force_group
cls._loaded = True

View File

@ -5,6 +5,7 @@ import logging
import pickle import pickle
from collections import defaultdict from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from copy import deepcopy
from pathlib import Path from pathlib import Path
from typing import Iterator from typing import Iterator
@ -41,6 +42,8 @@ LAYOUT_TYPES = {
GroupRole.DEFENSES: DefensesLayout, GroupRole.DEFENSES: DefensesLayout,
} }
LOCATIONS_TO_CHECK: list[Path] = []
class LayoutLoader: class LayoutLoader:
# Map of all available layouts indexed by name # Map of all available layouts indexed by name
@ -51,9 +54,19 @@ class LayoutLoader:
def initialize(self) -> None: def initialize(self) -> None:
if not self._layouts: if not self._layouts:
self.initialize_locations_to_check()
with logged_duration("Loading layouts"): with logged_duration("Loading layouts"):
self.load_templates() self.load_templates()
@staticmethod
def initialize_locations_to_check() -> None:
global LOCATIONS_TO_CHECK
if not LOCATIONS_TO_CHECK:
LOCATIONS_TO_CHECK = [
Path(LAYOUT_DIR),
persistency.layouts_dir(),
]
@property @property
def layouts(self) -> Iterator[TgoLayout]: def layouts(self) -> Iterator[TgoLayout]:
self.initialize() self.initialize()
@ -83,14 +96,9 @@ class LayoutLoader:
self._layouts = {} self._layouts = {}
mappings: dict[str, list[LayoutMapping]] = defaultdict(list) mappings: dict[str, list[LayoutMapping]] = defaultdict(list)
with logged_duration("Parsing mapping yamls"): with logged_duration("Parsing mapping yamls"):
for file in Path(LAYOUT_DIR).rglob("*.yaml"): for path_to_check in LOCATIONS_TO_CHECK:
if not file.is_file(): for file in path_to_check.rglob("*.yaml"):
raise RuntimeError(f"{file.name} is not a file") self._process_yaml(file, mappings)
with file.open("r", encoding="utf-8") as f:
mapping_dict = yaml.safe_load(f)
template_map = LayoutMapping.from_dict(mapping_dict, f.name)
mappings[template_map.layout_file].append(template_map)
with logged_duration(f"Parsing all layout miz multithreaded"): with logged_duration(f"Parsing all layout miz multithreaded"):
with ThreadPoolExecutor() as exe: with ThreadPoolExecutor() as exe:
@ -105,6 +113,15 @@ class LayoutLoader:
logging.info(f"Imported {len(self._layouts)} layouts") logging.info(f"Imported {len(self._layouts)} layouts")
self._dump_templates() self._dump_templates()
@staticmethod
def _process_yaml(file: Path, mappings: dict[str, list[LayoutMapping]]) -> None:
if not file.is_file():
raise RuntimeError(f"{file.name} is not a file")
with file.open("r", encoding="utf-8") as f:
mapping_dict = yaml.safe_load(f)
template_map = LayoutMapping.from_dict(mapping_dict, f.name)
mappings[template_map.layout_file].append(template_map)
def _dump_templates(self) -> None: def _dump_templates(self) -> None:
file = persistency.base_path() / LAYOUT_DUMP file = persistency.base_path() / LAYOUT_DUMP
dump = (VERSION, self._layouts) dump = (VERSION, self._layouts)
@ -112,6 +129,14 @@ class LayoutLoader:
pickle.dump(dump, fdata) pickle.dump(dump, fdata)
def _load_from_miz(self, miz: str, mappings: list[LayoutMapping]) -> None: def _load_from_miz(self, miz: str, mappings: list[LayoutMapping]) -> None:
path = Path(miz)
locations_to_check = deepcopy(LOCATIONS_TO_CHECK)
while not path.exists() and locations_to_check:
path = locations_to_check.pop() / miz
miz = path.absolute().as_posix()
if not path.exists():
logging.warning(f"Layout miz file not found: '{miz}'")
return
template_position: dict[str, Point] = {} template_position: dict[str, Point] = {}
temp_mis = dcs.Mission() temp_mis = dcs.Mission()
with logged_duration(f"Parsing {miz}"): with logged_duration(f"Parsing {miz}"):

View File

@ -125,6 +125,14 @@ def debug_dir() -> Path:
return base_path() / "Retribution" / "Debug" return base_path() / "Retribution" / "Debug"
def groups_dir() -> Path:
return base_path() / "Retribution" / "Groups"
def layouts_dir() -> Path:
return base_path() / "Retribution" / "Layouts"
def waypoint_debug_directory() -> Path: def waypoint_debug_directory() -> Path:
return debug_dir() / "Waypoints" return debug_dir() / "Waypoints"