mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
We've actually been pretty good at getting this right in most of the code base, but we've missed it in a few places. Python defaults to the encoding of the current locale unless otherwise specified, and for a US English Windows install that's cp1252, not UTF-8. I'm not brave enough to change the locale at startup because I don't know how that might affect CJK encoding users (or for that matter, non-Latin derived alphabet UTF-8 variants). Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2786.
183 lines
6.4 KiB
Python
183 lines
6.4 KiB
Python
from __future__ import annotations
|
|
|
|
import datetime
|
|
from collections.abc import Iterator
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
from dcs.terrain import (
|
|
Caucasus,
|
|
Falklands,
|
|
MarianaIslands,
|
|
Nevada,
|
|
Normandy,
|
|
PersianGulf,
|
|
Syria,
|
|
TheChannel,
|
|
)
|
|
|
|
from .conflicttheater import ConflictTheater
|
|
from .daytimemap import DaytimeMap
|
|
from .landmap import load_landmap
|
|
from .seasonalconditions import Season, SeasonalConditions, WeatherTypeChances
|
|
|
|
ALL_TERRAINS = [
|
|
Caucasus(),
|
|
Falklands(),
|
|
PersianGulf(),
|
|
Normandy(),
|
|
MarianaIslands(),
|
|
Nevada(),
|
|
TheChannel(),
|
|
Syria(),
|
|
]
|
|
|
|
TERRAINS_BY_NAME = {t.name: t for t in ALL_TERRAINS}
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SeasonData:
|
|
average_temperature: float | None
|
|
average_pressure: float | None
|
|
weather: WeatherTypeChances
|
|
|
|
@staticmethod
|
|
def from_yaml(data: dict[str, Any]) -> SeasonData:
|
|
return SeasonData(
|
|
data.get("average_temperature"),
|
|
data.get("average_pressure"),
|
|
WeatherTypeChances(
|
|
data["weather"]["thunderstorm"],
|
|
data["weather"]["raining"],
|
|
data["weather"]["cloudy"],
|
|
data["weather"]["clear"],
|
|
),
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TurbulenceData:
|
|
high_avg_yearly_turbulence_per_10cm: float | None
|
|
low_avg_yearly_turbulence_per_10cm: float | None
|
|
solar_noon_turbulence_per_10cm: float | None
|
|
midnight_turbulence_per_10cm: float | None
|
|
|
|
@staticmethod
|
|
def from_yaml(data: dict[str, Any]) -> TurbulenceData:
|
|
return TurbulenceData(
|
|
data.get("high_avg_yearly_turbulence_per_10cm"),
|
|
data.get("low_avg_yearly_turbulence_per_10cm"),
|
|
data.get("solar_noon_turbulence_per_10cm"),
|
|
data.get("midnight_turbulence_per_10cm"),
|
|
)
|
|
|
|
|
|
class TheaterLoader:
|
|
THEATER_RESOURCE_DIR = Path("resources/theaters")
|
|
|
|
def __init__(self, name: str) -> None:
|
|
self.name = name
|
|
self.descriptor_path = self.THEATER_RESOURCE_DIR / self.name / "info.yaml"
|
|
|
|
@classmethod
|
|
def each(cls) -> Iterator[ConflictTheater]:
|
|
for theater_dir in cls.THEATER_RESOURCE_DIR.iterdir():
|
|
yield TheaterLoader(theater_dir.name).load()
|
|
|
|
@property
|
|
def landmap_path(self) -> Path:
|
|
return self.descriptor_path.with_name("landmap.p")
|
|
|
|
@property
|
|
def menu_thumbnail_dcs_relative_path(self) -> Path:
|
|
with self.descriptor_path.open(encoding="utf-8") as descriptor_file:
|
|
data = yaml.safe_load(descriptor_file)
|
|
name = data.get("pydcs_name", data["name"])
|
|
return Path("Mods/terrains") / name / "Theme/icon.png"
|
|
|
|
def load(self) -> ConflictTheater:
|
|
with self.descriptor_path.open(encoding="utf-8") as descriptor_file:
|
|
data = yaml.safe_load(descriptor_file)
|
|
return ConflictTheater(
|
|
TERRAINS_BY_NAME[data.get("pydcs_name", data["name"])],
|
|
load_landmap(self.landmap_path),
|
|
datetime.timezone(datetime.timedelta(hours=data["timezone"])),
|
|
self._load_seasonal_conditions(data["climate"]),
|
|
self._load_daytime_map(data["daytime"]),
|
|
)
|
|
|
|
def _load_daytime_map(self, daytime_data: dict[str, list[int]]) -> DaytimeMap:
|
|
return DaytimeMap(
|
|
dawn=self._load_daytime_range(daytime_data["dawn"]),
|
|
day=self._load_daytime_range(daytime_data["day"]),
|
|
dusk=self._load_daytime_range(daytime_data["dusk"]),
|
|
night=self._load_daytime_range(daytime_data["night"]),
|
|
)
|
|
|
|
@staticmethod
|
|
def _load_daytime_range(
|
|
daytime_range: list[int],
|
|
) -> tuple[datetime.time, datetime.time]:
|
|
begin, end = daytime_range
|
|
return datetime.time(hour=begin), datetime.time(hour=end)
|
|
|
|
def _load_seasonal_conditions(
|
|
self, climate_data: dict[str, Any]
|
|
) -> SeasonalConditions:
|
|
winter = SeasonData.from_yaml(climate_data["seasons"]["winter"])
|
|
spring = SeasonData.from_yaml(climate_data["seasons"]["spring"])
|
|
summer = SeasonData.from_yaml(climate_data["seasons"]["summer"])
|
|
fall = SeasonData.from_yaml(climate_data["seasons"]["fall"])
|
|
turbulence = TurbulenceData.from_yaml(climate_data["turbulence"])
|
|
if summer.average_pressure is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a summer average pressure"
|
|
)
|
|
if summer.average_temperature is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a summer average temperature"
|
|
)
|
|
if winter.average_pressure is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a winter average pressure"
|
|
)
|
|
if winter.average_temperature is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a winter average temperature"
|
|
)
|
|
if turbulence.high_avg_yearly_turbulence_per_10cm is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a yearly average high turbulence"
|
|
)
|
|
if turbulence.low_avg_yearly_turbulence_per_10cm is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a yearly average low turbulence"
|
|
)
|
|
if turbulence.solar_noon_turbulence_per_10cm is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a solar noon turbulence"
|
|
)
|
|
if turbulence.midnight_turbulence_per_10cm is None:
|
|
raise RuntimeError(
|
|
f"{self.descriptor_path} does not define a midnight turbulence"
|
|
)
|
|
return SeasonalConditions(
|
|
summer.average_pressure,
|
|
winter.average_pressure,
|
|
summer.average_temperature,
|
|
winter.average_temperature,
|
|
climate_data["day_night_temperature_difference"],
|
|
turbulence.high_avg_yearly_turbulence_per_10cm,
|
|
turbulence.low_avg_yearly_turbulence_per_10cm,
|
|
turbulence.solar_noon_turbulence_per_10cm,
|
|
turbulence.midnight_turbulence_per_10cm,
|
|
{
|
|
Season.Winter: winter.weather,
|
|
Season.Spring: spring.weather,
|
|
Season.Summer: summer.weather,
|
|
Season.Fall: fall.weather,
|
|
},
|
|
)
|