diff --git a/game/ato/loadouts.py b/game/ato/loadouts.py index 442be6b6..0038227a 100644 --- a/game/ato/loadouts.py +++ b/game/ato/loadouts.py @@ -1,8 +1,9 @@ from __future__ import annotations import datetime +import logging from collections.abc import Iterable -from typing import Iterator, Mapping, Optional, TYPE_CHECKING, Type +from typing import Iterator, Mapping, Optional, TYPE_CHECKING, Type, Dict, Any from dcs.unittype import FlyingType @@ -120,6 +121,10 @@ class Loadout: # } payloads = aircraft.dcs_unit_type.load_payloads() for payload in payloads.values(): + if not cls.valid_payload(payload["pylons"]): + msg = f'Incompatible loadout for {aircraft} skipped: {payload["name"]}' + logging.warning(msg) + continue name = payload["name"] pylons = payload["pylons"] yield Loadout( @@ -128,6 +133,13 @@ class Loadout: date=None, ) + @staticmethod + def valid_payload(pylons: Dict[int, Dict[str, str]]) -> bool: + for p in pylons.values(): + if Weapon.with_clsid(p["CLSID"]) is None: + return False + return True + @classmethod def default_loadout_names_for(cls, task: FlightType) -> Iterator[str]: # This is a list of mappings from the FlightType of a Flight to the type of @@ -189,6 +201,12 @@ class Loadout: dcs_unit_type.load_payloads() payload = dcs_unit_type.loadout_by_name(name) if payload is not None: + pylons = {i: {"CLSID": d["clsid"]} for i, d in payload} + if not cls.valid_payload(pylons): + aircraft = dcs_unit_type.id + msg = f"Incompatible loadout for {aircraft} skipped: {name}" + logging.warning(msg) + continue return Loadout( name, {i: Weapon.with_clsid(d["clsid"]) for i, d in payload}, diff --git a/game/data/weapons.py b/game/data/weapons.py index 23db497d..5333a66e 100644 --- a/game/data/weapons.py +++ b/game/data/weapons.py @@ -53,8 +53,9 @@ class Weapon: def __setstate__(self, state: dict[str, Any]) -> None: # Update any existing models with new data on load. updated = Weapon.with_clsid(state["clsid"]) - state.update(updated.__dict__) - self.__dict__.update(state) + if updated is not None: + state.update(updated.__dict__) + self.__dict__.update(state) @classmethod def register(cls, weapon: Weapon) -> None: @@ -67,10 +68,10 @@ class Weapon: cls._by_clsid[weapon.clsid] = weapon @classmethod - def with_clsid(cls, clsid: str) -> Weapon: + def with_clsid(cls, clsid: str) -> Optional[Weapon]: if not cls._loaded: cls._load_all() - return cls._by_clsid[clsid] + return cls._by_clsid.get(clsid) @classmethod def _load_all(cls) -> None: @@ -267,7 +268,9 @@ class Pylon: pylon_number, weapon = value if pylon_number != number: continue - allowed.add(Weapon.with_clsid(weapon["clsid"])) + allowed_weapon = Weapon.with_clsid(weapon["clsid"]) + if allowed_weapon is not None: + allowed.add(allowed_weapon) return cls(number, allowed)