mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Refactor Templates to Layouts, Review and Cleanup
- Fix tgogenerator - Fix UI for ForceGroup and Layouts - Fix ammo depot handling - Split bigger files in smaller meaningful files (TGO, layouts, forces) - Renamed Template to Layout - Renamed GroundGroup to TheaterGroup and GroundUnit to TheaterUnit - Reorganize Layouts and UnitGroups to a ArmedForces class and ForceGroup similar to the AirWing and Squadron - Reworded the UnitClass, GroupRole, GroupTask (adopted to PEP8) and reworked the connection from Role and Task - added comments - added missing unit classes - added temp workaround for missing classes - add repariable property to TheaterUnit - Review and Cleanup Added serialization for loaded templates Loading the templates from the .miz files takes a lot of computation time and in the future there will be more templates added to the system. Therefore a local pickle serialization for the loaded templates was re-added: - The pickle will be created the first time the TemplateLoader will be accessed - Pickle is stored in Liberation SaveDir - Added UI option to (re-)import templates
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from typing import Any, ClassVar, Iterator, Optional, TYPE_CHECKING, Type
|
||||
from typing import Any, Iterator, Optional, TYPE_CHECKING, Type
|
||||
|
||||
import yaml
|
||||
from dcs.helicopters import helicopter_map
|
||||
@@ -397,5 +396,5 @@ class AircraftType(UnitType[Type[FlyingType]]):
|
||||
channel_namer=radio_config.channel_namer,
|
||||
kneeboard_units=units,
|
||||
utc_kneeboard=data.get("utc_kneeboard", False),
|
||||
unit_class=UnitClass.Plane,
|
||||
unit_class=UnitClass.PLANE,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Type, Optional, Iterator
|
||||
from typing import Type, Iterator
|
||||
|
||||
import yaml
|
||||
from dcs.unittype import VehicleType
|
||||
@@ -55,8 +55,11 @@ class GroundUnitType(UnitType[Type[VehicleType]]):
|
||||
introduction = "No data."
|
||||
|
||||
class_name = data.get("class")
|
||||
# TODO Exception handling for missing classes
|
||||
unit_class = UnitClass(class_name) if class_name else UnitClass.Unknown
|
||||
if class_name is None:
|
||||
logging.warning(f"{vehicle.id} has no class")
|
||||
unit_class = UnitClass.UNKNOWN
|
||||
else:
|
||||
unit_class = UnitClass(class_name)
|
||||
|
||||
for variant in data.get("variants", [vehicle.id]):
|
||||
yield GroundUnitType(
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Type, Optional, ClassVar, Iterator
|
||||
from typing import Type, Iterator
|
||||
|
||||
import yaml
|
||||
from dcs.ships import ship_map
|
||||
from dcs.unittype import VehicleType, ShipType
|
||||
from dcs.vehicles import vehicle_map
|
||||
from dcs.unittype import ShipType
|
||||
|
||||
from game.data.units import UnitClass
|
||||
from game.dcs.unittype import UnitType
|
||||
@@ -70,5 +68,5 @@ class ShipUnitType(UnitType[Type[ShipType]]):
|
||||
country_of_origin=data.get("origin", "No data."),
|
||||
manufacturer=data.get("manufacturer", "No data."),
|
||||
role=data.get("role", "No data."),
|
||||
price=data.get("price", 1),
|
||||
price=data.get("price"),
|
||||
)
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import itertools
|
||||
import random
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import ClassVar, TYPE_CHECKING, Any, Iterator
|
||||
|
||||
import yaml
|
||||
|
||||
from game.data.groups import GroupRole, GroupTask
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.dcs.shipunittype import ShipUnitType
|
||||
from game.dcs.unittype import UnitType
|
||||
from game.point_with_heading import PointWithHeading
|
||||
from gen.templates import GroundObjectTemplate
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.factions.faction import Faction
|
||||
from game.theater import TheaterGroundObject, ControlPoint
|
||||
|
||||
|
||||
@dataclass
|
||||
class UnitGroup:
|
||||
name: str
|
||||
ground_units: list[GroundUnitType]
|
||||
ship_units: list[ShipUnitType]
|
||||
statics: list[str]
|
||||
role: GroupRole
|
||||
tasks: list[GroupTask] = field(default_factory=list)
|
||||
template_names: list[str] = field(default_factory=list)
|
||||
|
||||
_by_name: ClassVar[dict[str, UnitGroup]] = {}
|
||||
_by_role: ClassVar[dict[GroupRole, list[UnitGroup]]] = {}
|
||||
_loaded: bool = False
|
||||
_templates: list[GroundObjectTemplate] = field(default_factory=list)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.name
|
||||
|
||||
def update_from_unit_group(self, unit_group: UnitGroup) -> None:
|
||||
# Update tasking and templates
|
||||
self.tasks.extend([task for task in unit_group.tasks if task not in self.tasks])
|
||||
self._templates.extend(
|
||||
[
|
||||
template
|
||||
for template in unit_group.templates
|
||||
if template not in self.templates
|
||||
]
|
||||
)
|
||||
|
||||
@property
|
||||
def templates(self) -> list[GroundObjectTemplate]:
|
||||
return self._templates
|
||||
|
||||
def add_template(self, faction_template: GroundObjectTemplate) -> None:
|
||||
template = copy.deepcopy(faction_template)
|
||||
updated_groups = []
|
||||
for group in template.groups:
|
||||
unit_types = list(
|
||||
itertools.chain(
|
||||
[u.dcs_id for u in self.ground_units if group.can_use_unit(u)],
|
||||
[s.dcs_id for s in self.ship_units if group.can_use_unit(s)],
|
||||
[s for s in self.statics if group.can_use_unit_type(s)],
|
||||
)
|
||||
)
|
||||
if unit_types:
|
||||
group.set_possible_types(unit_types)
|
||||
updated_groups.append(group)
|
||||
template.groups = updated_groups
|
||||
self._templates.append(template)
|
||||
|
||||
def load_templates(self, faction: Faction) -> None:
|
||||
self._templates = []
|
||||
if self.template_names:
|
||||
# Preferred templates
|
||||
for template_name in self.template_names:
|
||||
template = faction.templates.by_name(template_name)
|
||||
if template:
|
||||
self.add_template(template)
|
||||
|
||||
if not self._templates:
|
||||
# Find all matching templates if no preferred set or available
|
||||
for template in list(
|
||||
faction.templates.for_role_and_tasks(self.role, self.tasks)
|
||||
):
|
||||
if any(self.has_unit_type(unit) for unit in template.units):
|
||||
self.add_template(template)
|
||||
|
||||
def set_templates(self, templates: list[GroundObjectTemplate]) -> None:
|
||||
self._templates = templates
|
||||
|
||||
def has_unit_type(self, unit_type: UnitType[Any]) -> bool:
|
||||
return unit_type in self.ground_units or unit_type in self.ship_units
|
||||
|
||||
@property
|
||||
def unit_types(self) -> Iterator[str]:
|
||||
for unit in self.ground_units:
|
||||
yield unit.dcs_id
|
||||
for ship in self.ship_units:
|
||||
yield ship.dcs_id
|
||||
for static in self.statics:
|
||||
yield static
|
||||
|
||||
@classmethod
|
||||
def named(cls, name: str) -> UnitGroup:
|
||||
if not cls._loaded:
|
||||
cls._load_all()
|
||||
return cls._by_name[name]
|
||||
|
||||
def generate(
|
||||
self,
|
||||
name: str,
|
||||
position: PointWithHeading,
|
||||
control_point: ControlPoint,
|
||||
game: Game,
|
||||
) -> TheaterGroundObject:
|
||||
template = random.choice(self.templates)
|
||||
return template.generate(name, position, control_point, game)
|
||||
|
||||
@classmethod
|
||||
def _load_all(cls) -> None:
|
||||
for file in Path("resources/units/unit_groups").glob("*.yaml"):
|
||||
if not file.is_file():
|
||||
continue
|
||||
|
||||
with file.open(encoding="utf-8") as data_file:
|
||||
data = yaml.safe_load(data_file)
|
||||
|
||||
group_role = GroupRole(data.get("role"))
|
||||
|
||||
group_tasks = [GroupTask(n) for n in data.get("tasks", [])]
|
||||
|
||||
ground_units = [
|
||||
GroundUnitType.named(n) for n in data.get("ground_units", [])
|
||||
]
|
||||
ship_units = [ShipUnitType.named(n) for n in data.get("ship_units", [])]
|
||||
|
||||
unit_group = UnitGroup(
|
||||
name=data.get("name"),
|
||||
ground_units=ground_units,
|
||||
ship_units=ship_units,
|
||||
statics=data.get("statics", []),
|
||||
role=group_role,
|
||||
tasks=group_tasks,
|
||||
template_names=data.get("templates", []),
|
||||
)
|
||||
|
||||
cls._by_name[unit_group.name] = unit_group
|
||||
if group_role in cls._by_role:
|
||||
cls._by_role[group_role].append(unit_group)
|
||||
else:
|
||||
cls._by_role[group_role] = [unit_group]
|
||||
|
||||
cls._loaded = True
|
||||
@@ -4,7 +4,7 @@ from abc import ABC
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from typing import TypeVar, Generic, Type, ClassVar, Any, Iterator, Optional
|
||||
from typing import TypeVar, Generic, Type, ClassVar, Any, Iterator
|
||||
|
||||
from dcs.unittype import UnitType as DcsUnitType
|
||||
|
||||
@@ -26,7 +26,9 @@ class UnitType(ABC, Generic[DcsUnitTypeT]):
|
||||
unit_class: UnitClass
|
||||
|
||||
_by_name: ClassVar[dict[str, UnitType[Any]]] = {}
|
||||
_by_unit_type: ClassVar[dict[DcsUnitTypeT, list[UnitType[Any]]]] = defaultdict(list)
|
||||
_by_unit_type: ClassVar[dict[Type[DcsUnitType], list[UnitType[Any]]]] = defaultdict(
|
||||
list
|
||||
)
|
||||
_loaded: ClassVar[bool] = False
|
||||
|
||||
def __str__(self) -> str:
|
||||
@@ -43,7 +45,7 @@ class UnitType(ABC, Generic[DcsUnitTypeT]):
|
||||
|
||||
@classmethod
|
||||
def named(cls, name: str) -> UnitType[Any]:
|
||||
raise NotImplementedError
|
||||
return cls._by_name[name]
|
||||
|
||||
@classmethod
|
||||
def for_dcs_type(cls, dcs_unit_type: DcsUnitTypeT) -> Iterator[UnitType[Any]]:
|
||||
|
||||
Reference in New Issue
Block a user