Files
dcs-retribution/game/dcs/unittype.py
Dan Albert 0ec375ad89 Fix unit variants to actually allow variance.
This was always the intent, but apparently it wasn't implemented
correctly. All properties of the unit type can now be overridden per
variant.
2023-10-07 17:23:34 +02:00

101 lines
2.7 KiB
Python

from __future__ import annotations
import logging
from abc import ABC
from dataclasses import dataclass
from functools import cached_property
from pathlib import Path
from typing import ClassVar, Generic, Iterator, Type, TypeVar, Any
import yaml
from dcs.unittype import UnitType as DcsUnitType
from typing_extensions import Self
from game.data.units import UnitClass
DcsUnitTypeT = TypeVar("DcsUnitTypeT", bound=Type[DcsUnitType])
@dataclass(frozen=True)
class UnitType(ABC, Generic[DcsUnitTypeT]):
dcs_unit_type: DcsUnitTypeT
variant_id: str
description: str
year_introduced: str
country_of_origin: str
manufacturer: str
role: str
price: int
unit_class: UnitClass
_loaded: ClassVar[bool] = False
def __str__(self) -> str:
return self.variant_id
@property
def dcs_id(self) -> str:
return self.dcs_unit_type.id
@classmethod
def register(cls, unit_type: Self) -> None:
raise NotImplementedError
@classmethod
def named(cls, name: str) -> Self:
raise NotImplementedError
@classmethod
def for_dcs_type(cls, dcs_unit_type: DcsUnitTypeT) -> Iterator[Self]:
raise NotImplementedError
@staticmethod
def each_dcs_type() -> Iterator[DcsUnitTypeT]:
raise NotImplementedError
@classmethod
def _data_directory(cls) -> Path:
raise NotImplementedError
@classmethod
def _each_variant_of(cls, unit: DcsUnitTypeT) -> Iterator[Self]:
data_path = cls._data_directory() / f"{unit.id}.yaml"
if not data_path.exists():
logging.warning(f"No data for {unit.id}; it will not be available")
return
with data_path.open(encoding="utf-8") as data_file:
data = yaml.safe_load(data_file)
for variant_id, variant_data in data.get("variants", {unit.id: {}}).items():
if variant_data is None:
variant_data = {}
yield cls._variant_from_dict(unit, variant_id, data | variant_data)
@classmethod
def _variant_from_dict(
cls, dcs_unit_type: DcsUnitTypeT, variant_id: str, data: dict[str, Any]
) -> Self:
raise NotImplementedError
@classmethod
def _load_all(cls) -> None:
for unit_type in cls.each_dcs_type():
for data in cls._each_variant_of(unit_type):
cls.register(data)
cls._loaded = True
@cached_property
def eplrs_capable(self) -> bool:
return getattr(self.dcs_unit_type, "eplrs", False)
@classmethod
def exists(cls, name: str) -> bool:
if not cls._loaded:
cls._load_all()
try:
cls.named(name)
return True
except (KeyError, AssertionError):
return False