from __future__ import annotations import inspect from dataclasses import dataclass from typing import Dict, Iterator, Set, Tuple, Type, Union, cast from dcs.unitgroup import FlyingGroup from dcs.unittype import FlyingType PydcsWeapon = Dict[str, Union[int, str]] PydcsWeaponAssignment = Tuple[int, PydcsWeapon] @dataclass(frozen=True) class Weapon: """Wraps a pydcs weapon dict in a hashable type.""" cls_id: str name: str weight: int @property def as_pydcs(self) -> PydcsWeapon: return { "clsid": self.cls_id, "name": self.name, "weight": self.weight, } @classmethod def from_pydcs(cls, weapon_data: PydcsWeapon) -> Weapon: return cls( cast(str, weapon_data["clsid"]), cast(str, weapon_data["name"]), cast(int, weapon_data["weight"]) ) @dataclass(frozen=True) class Pylon: number: int allowed: Set[Weapon] def can_equip(self, weapon: Weapon) -> bool: return weapon in self.allowed def equip(self, group: FlyingGroup, weapon: Weapon) -> None: if not self.can_equip(weapon): raise ValueError(f"Pylon {self.number} cannot equip {weapon.name}") group.load_pylon(self.make_pydcs_assignment(weapon), self.number) def make_pydcs_assignment(self, weapon: Weapon) -> PydcsWeaponAssignment: return self.number, weapon.as_pydcs @classmethod def for_aircraft(cls, aircraft: Type[FlyingType], number: int) -> Pylon: # In pydcs these are all arbitrary inner classes of the aircraft type. # The only way to identify them is by their name. pylons = [v for v in aircraft.__dict__.values() if inspect.isclass(v) and v.__name__.startswith("Pylon")] # And that Pylon class has members with irrelevant names that have # values of (pylon number, allowed weapon). allowed = set() for pylon in pylons: for key, value in pylon.__dict__.items(): if key.startswith("__"): continue pylon_number, weapon = value if pylon_number != number: continue allowed.add(Weapon.from_pydcs(weapon)) return cls(number, allowed) @classmethod def iter_pylons(cls, aircraft: Type[FlyingType]) -> Iterator[Pylon]: for pylon in sorted(list(aircraft.pylons)): yield cls.for_aircraft(aircraft, pylon)