mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Make theater properties moddable.
Only the Caucasus has been migrated so far. Will follow up with the others, and also will be adding beacon/airport data to this.
This commit is contained in:
parent
44166203ab
commit
401a0ae557
@ -10,9 +10,9 @@ from typing import Any, Dict, Tuple
|
|||||||
import yaml
|
import yaml
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
|
||||||
|
from game import persistency
|
||||||
from game.profiling import logged_duration
|
from game.profiling import logged_duration
|
||||||
from game.theater import (
|
from game.theater import (
|
||||||
CaucasusTheater,
|
|
||||||
ConflictTheater,
|
ConflictTheater,
|
||||||
FalklandsTheater,
|
FalklandsTheater,
|
||||||
MarianaIslandsTheater,
|
MarianaIslandsTheater,
|
||||||
@ -23,10 +23,10 @@ from game.theater import (
|
|||||||
TheChannelTheater,
|
TheChannelTheater,
|
||||||
)
|
)
|
||||||
from game.theater.iadsnetwork.iadsnetwork import IadsNetwork
|
from game.theater.iadsnetwork.iadsnetwork import IadsNetwork
|
||||||
|
from game.theater.theaterloader import TheaterLoader
|
||||||
from game.version import CAMPAIGN_FORMAT_VERSION
|
from game.version import CAMPAIGN_FORMAT_VERSION
|
||||||
from .campaignairwingconfig import CampaignAirWingConfig
|
from .campaignairwingconfig import CampaignAirWingConfig
|
||||||
from .mizcampaignloader import MizCampaignLoader
|
from .mizcampaignloader import MizCampaignLoader
|
||||||
from .. import persistency
|
|
||||||
|
|
||||||
PERF_FRIENDLY = 0
|
PERF_FRIENDLY = 0
|
||||||
PERF_MEDIUM = 1
|
PERF_MEDIUM = 1
|
||||||
@ -116,7 +116,6 @@ class Campaign:
|
|||||||
|
|
||||||
def load_theater(self, advanced_iads: bool) -> ConflictTheater:
|
def load_theater(self, advanced_iads: bool) -> ConflictTheater:
|
||||||
theaters = {
|
theaters = {
|
||||||
"Caucasus": CaucasusTheater,
|
|
||||||
"Nevada": NevadaTheater,
|
"Nevada": NevadaTheater,
|
||||||
"Persian Gulf": PersianGulfTheater,
|
"Persian Gulf": PersianGulfTheater,
|
||||||
"Normandy": NormandyTheater,
|
"Normandy": NormandyTheater,
|
||||||
@ -125,8 +124,11 @@ class Campaign:
|
|||||||
"MarianaIslands": MarianaIslandsTheater,
|
"MarianaIslands": MarianaIslandsTheater,
|
||||||
"Falklands": FalklandsTheater,
|
"Falklands": FalklandsTheater,
|
||||||
}
|
}
|
||||||
theater = theaters[self.data["theater"]]
|
try:
|
||||||
t = theater()
|
theater = theaters[self.data["theater"]]
|
||||||
|
t = theater()
|
||||||
|
except KeyError:
|
||||||
|
t = TheaterLoader(self.data["theater"].lower()).load()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
miz = self.data["miz"]
|
miz = self.data["miz"]
|
||||||
|
|||||||
@ -2,14 +2,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import math
|
import math
|
||||||
from dataclasses import dataclass
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple
|
from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from dcs.mapping import Point
|
from dcs.mapping import Point
|
||||||
from dcs.terrain import (
|
from dcs.terrain import (
|
||||||
caucasus,
|
|
||||||
falklands,
|
falklands,
|
||||||
marianaislands,
|
marianaislands,
|
||||||
nevada,
|
nevada,
|
||||||
@ -33,12 +31,6 @@ if TYPE_CHECKING:
|
|||||||
from .theatergroundobject import TheaterGroundObject
|
from .theatergroundobject import TheaterGroundObject
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ReferencePoint:
|
|
||||||
world_coordinates: Point
|
|
||||||
image_coordinates: Point
|
|
||||||
|
|
||||||
|
|
||||||
class ConflictTheater:
|
class ConflictTheater:
|
||||||
terrain: Terrain
|
terrain: Terrain
|
||||||
|
|
||||||
@ -254,28 +246,6 @@ class ConflictTheater:
|
|||||||
return Heading.from_degrees(position.heading_between_point(conflict_center))
|
return Heading.from_degrees(position.heading_between_point(conflict_center))
|
||||||
|
|
||||||
|
|
||||||
class CaucasusTheater(ConflictTheater):
|
|
||||||
terrain = caucasus.Caucasus()
|
|
||||||
|
|
||||||
landmap = load_landmap(Path("resources/caulandmap.p"))
|
|
||||||
daytime_map = DaytimeMap(
|
|
||||||
dawn=(datetime.time(hour=6), datetime.time(hour=9)),
|
|
||||||
day=(datetime.time(hour=9), datetime.time(hour=18)),
|
|
||||||
dusk=(datetime.time(hour=18), datetime.time(hour=20)),
|
|
||||||
night=(datetime.time(hour=0), datetime.time(hour=5)),
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def timezone(self) -> datetime.timezone:
|
|
||||||
return datetime.timezone(datetime.timedelta(hours=4))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def seasonal_conditions(self) -> SeasonalConditions:
|
|
||||||
from .seasonalconditions.caucasus import CONDITIONS
|
|
||||||
|
|
||||||
return CONDITIONS
|
|
||||||
|
|
||||||
|
|
||||||
class PersianGulfTheater(ConflictTheater):
|
class PersianGulfTheater(ConflictTheater):
|
||||||
terrain = persiangulf.PersianGulf()
|
terrain = persiangulf.PersianGulf()
|
||||||
landmap = load_landmap(Path("resources/gulflandmap.p"))
|
landmap = load_landmap(Path("resources/gulflandmap.p"))
|
||||||
|
|||||||
126
game/theater/theaterloader.py
Normal file
126
game/theater/theaterloader.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
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
|
||||||
|
from .yamltheater import YamlTheater
|
||||||
|
|
||||||
|
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"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TheaterLoader:
|
||||||
|
def __init__(self, name: str) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.descriptor_path = Path("resources/theaters") / self.name / "info.yaml"
|
||||||
|
|
||||||
|
def load(self) -> ConflictTheater:
|
||||||
|
with self.descriptor_path.open() as descriptor_file:
|
||||||
|
data = yaml.safe_load(descriptor_file)
|
||||||
|
return YamlTheater(
|
||||||
|
TERRAINS_BY_NAME[data["name"]],
|
||||||
|
load_landmap(self.descriptor_path.with_name("landmap.p")),
|
||||||
|
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"])
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
return SeasonalConditions(
|
||||||
|
summer.average_pressure,
|
||||||
|
winter.average_pressure,
|
||||||
|
summer.average_temperature,
|
||||||
|
winter.average_temperature,
|
||||||
|
climate_data["day_night_temperature_difference"],
|
||||||
|
{
|
||||||
|
Season.Winter: winter.weather,
|
||||||
|
Season.Spring: spring.weather,
|
||||||
|
Season.Summer: summer.weather,
|
||||||
|
Season.Fall: fall.weather,
|
||||||
|
},
|
||||||
|
)
|
||||||
35
game/theater/yamltheater.py
Normal file
35
game/theater/yamltheater.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import timezone
|
||||||
|
|
||||||
|
from dcs.terrain import Terrain
|
||||||
|
|
||||||
|
from .conflicttheater import ConflictTheater
|
||||||
|
from .daytimemap import DaytimeMap
|
||||||
|
from .landmap import Landmap
|
||||||
|
from .seasonalconditions import SeasonalConditions
|
||||||
|
|
||||||
|
|
||||||
|
class YamlTheater(ConflictTheater):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
terrain: Terrain,
|
||||||
|
landmap: Landmap | None,
|
||||||
|
time_zone: timezone,
|
||||||
|
seasonal_conditions: SeasonalConditions,
|
||||||
|
daytime_map: DaytimeMap,
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.terrain = terrain
|
||||||
|
self.landmap = landmap
|
||||||
|
self._timezone = time_zone
|
||||||
|
self._seasonal_conditions = seasonal_conditions
|
||||||
|
self.daytime_map = daytime_map
|
||||||
|
|
||||||
|
@property
|
||||||
|
def timezone(self) -> timezone:
|
||||||
|
return self._timezone
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seasonal_conditions(self) -> SeasonalConditions:
|
||||||
|
return self._seasonal_conditions
|
||||||
39
resources/theaters/caucasus/info.yaml
Normal file
39
resources/theaters/caucasus/info.yaml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
name: Caucasus
|
||||||
|
timezone: +4
|
||||||
|
daytime:
|
||||||
|
dawn: [6, 9]
|
||||||
|
day: [9, 18]
|
||||||
|
dusk: [18, 20]
|
||||||
|
night: [0, 5]
|
||||||
|
climate:
|
||||||
|
day_night_temperature_difference: 6.0
|
||||||
|
seasons:
|
||||||
|
winter:
|
||||||
|
average_pressure: 29.72 # TODO: Find real-world data
|
||||||
|
average_temperature: 3.0
|
||||||
|
weather:
|
||||||
|
thunderstorm: 1
|
||||||
|
raining: 20
|
||||||
|
cloudy: 60
|
||||||
|
clear: 20
|
||||||
|
spring:
|
||||||
|
weather:
|
||||||
|
thunderstorm: 1
|
||||||
|
raining: 20
|
||||||
|
cloudy: 40
|
||||||
|
clear: 40
|
||||||
|
summer:
|
||||||
|
average_pressure: 30.02 # TODO: Find real-world data
|
||||||
|
average_temperature: 22.5
|
||||||
|
weather:
|
||||||
|
thunderstorm: 1
|
||||||
|
raining: 10
|
||||||
|
cloudy: 35
|
||||||
|
clear: 55
|
||||||
|
fall:
|
||||||
|
weather:
|
||||||
|
thunderstorm: 1
|
||||||
|
raining: 30
|
||||||
|
cloudy: 50
|
||||||
|
clear: 20
|
||||||
Loading…
x
Reference in New Issue
Block a user