mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
98 lines
2.8 KiB
Python
98 lines
2.8 KiB
Python
import json
|
|
from collections.abc import Iterator
|
|
from dataclasses import dataclass
|
|
from enum import IntEnum, auto
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from game.radio.radios import RadioFrequency
|
|
from game.radio.tacan import TacanBand, TacanChannel
|
|
from game.theater import ConflictTheater
|
|
|
|
BEACONS_RESOURCE_PATH = Path("resources/dcs/beacons")
|
|
|
|
|
|
class BeaconType(IntEnum):
|
|
BEACON_TYPE_NULL = auto()
|
|
BEACON_TYPE_VOR = auto()
|
|
BEACON_TYPE_DME = auto()
|
|
BEACON_TYPE_VOR_DME = auto()
|
|
BEACON_TYPE_TACAN = auto()
|
|
BEACON_TYPE_VORTAC = auto()
|
|
BEACON_TYPE_RSBN = auto()
|
|
BEACON_TYPE_BROADCAST_STATION = auto()
|
|
|
|
BEACON_TYPE_HOMER = auto()
|
|
BEACON_TYPE_AIRPORT_HOMER = auto()
|
|
BEACON_TYPE_AIRPORT_HOMER_WITH_MARKER = auto()
|
|
BEACON_TYPE_ILS_FAR_HOMER = auto()
|
|
BEACON_TYPE_ILS_NEAR_HOMER = auto()
|
|
|
|
BEACON_TYPE_ILS_LOCALIZER = auto()
|
|
BEACON_TYPE_ILS_GLIDESLOPE = auto()
|
|
|
|
BEACON_TYPE_PRMG_LOCALIZER = auto()
|
|
BEACON_TYPE_PRMG_GLIDESLOPE = auto()
|
|
|
|
BEACON_TYPE_ICLS_LOCALIZER = auto()
|
|
BEACON_TYPE_ICLS_GLIDESLOPE = auto()
|
|
|
|
BEACON_TYPE_NAUTICAL_HOMER = auto()
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Beacon:
|
|
name: str
|
|
callsign: str
|
|
beacon_type: BeaconType
|
|
hertz: int
|
|
channel: Optional[int]
|
|
|
|
@property
|
|
def frequency(self) -> RadioFrequency:
|
|
return RadioFrequency(self.hertz)
|
|
|
|
@property
|
|
def is_tacan(self) -> bool:
|
|
return self.beacon_type in (
|
|
BeaconType.BEACON_TYPE_VORTAC,
|
|
BeaconType.BEACON_TYPE_TACAN,
|
|
)
|
|
|
|
@property
|
|
def tacan_channel(self) -> TacanChannel:
|
|
assert self.is_tacan
|
|
assert self.channel is not None
|
|
return TacanChannel(self.channel, TacanBand.X)
|
|
|
|
|
|
class Beacons:
|
|
_by_terrain: dict[str, dict[str, Beacon]] = {}
|
|
|
|
@classmethod
|
|
def _load_for_theater_if_needed(cls, theater: ConflictTheater) -> None:
|
|
if theater.terrain.name in cls._by_terrain:
|
|
return
|
|
|
|
beacons_file = BEACONS_RESOURCE_PATH / f"{theater.terrain.name.lower()}.json"
|
|
if not beacons_file.exists():
|
|
raise RuntimeError(f"Beacon file {beacons_file.resolve()} is missing")
|
|
|
|
beacons = {}
|
|
for bid, beacon in json.loads(beacons_file.read_text()).items():
|
|
beacons[bid] = Beacon(**beacon)
|
|
cls._by_terrain[theater.terrain.name] = beacons
|
|
|
|
@classmethod
|
|
def _dict_for_theater(cls, theater: ConflictTheater) -> dict[str, Beacon]:
|
|
cls._load_for_theater_if_needed(theater)
|
|
return cls._by_terrain[theater.terrain.name]
|
|
|
|
@classmethod
|
|
def iter_theater(cls, theater: ConflictTheater) -> Iterator[Beacon]:
|
|
yield from cls._dict_for_theater(theater).values()
|
|
|
|
@classmethod
|
|
def with_id(cls, beacon_id: str, theater: ConflictTheater) -> Beacon:
|
|
return cls._dict_for_theater(theater)[beacon_id]
|