mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
198 lines
6.8 KiB
Python
198 lines
6.8 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from collections import defaultdict
|
|
from pathlib import Path
|
|
from typing import Any
|
|
from typing import Type
|
|
|
|
import yaml
|
|
from dcs.unittype import VehicleType
|
|
from dcs.vehicles import Infantry, Unarmed, Armor, AirDefence, Artillery, vehicle_map
|
|
|
|
from game.data.groundunitclass import GroundUnitClass
|
|
from game.db import PRICES, INFANTRY, MANPADS
|
|
from game.factions.faction import unit_loader
|
|
from pydcs_extensions.mod_units import MODDED_VEHICLES
|
|
|
|
THIS_DIR = Path(__file__).resolve().parent
|
|
SRC_ROOT = THIS_DIR.parent.parent
|
|
UNIT_DATA_DIR = SRC_ROOT / "resources/units"
|
|
FACTIONS_DIR = SRC_ROOT / "resources/factions"
|
|
|
|
|
|
class Converter:
|
|
def __init__(self) -> None:
|
|
self.all_variants: set[str] = set()
|
|
self.variant_map: dict[str, dict[str, str]] = {}
|
|
self.unconverted: set[Type[VehicleType]] = set(
|
|
k for k in PRICES if issubclass(k, VehicleType)
|
|
)
|
|
for infantry_type in set(INFANTRY + MANPADS):
|
|
self.unconverted.add(infantry_type)
|
|
PRICES[infantry_type] = 0
|
|
self.name_to_vehicle_map = {v.name: v for v in vehicle_map.values()}
|
|
|
|
@staticmethod
|
|
def find_unit_id_for_faction_name(name: str) -> str:
|
|
unit_type = unit_loader(
|
|
name, [Infantry, Unarmed, Armor, AirDefence, Artillery, MODDED_VEHICLES]
|
|
)
|
|
if unit_type is None:
|
|
raise KeyError(f"Found no unit named {name}")
|
|
return unit_type.id
|
|
|
|
def convert(self) -> None:
|
|
data_path = UNIT_DATA_DIR / "unit_info_text.json"
|
|
with data_path.open(encoding="utf-8") as unit_data_file:
|
|
unit_data = json.load(unit_data_file)
|
|
|
|
for unit_name, data in dict(unit_data).items():
|
|
if self.convert_unit(unit_name, data):
|
|
unit_data.pop(unit_name)
|
|
|
|
with data_path.open("w", encoding="utf-8") as unit_data_file:
|
|
json.dump(unit_data, unit_data_file, indent=2)
|
|
|
|
for unconverted in self.unconverted:
|
|
self.generate_basic_info(unconverted)
|
|
|
|
for faction_path in FACTIONS_DIR.glob("*.json"):
|
|
self.update_faction(faction_path)
|
|
|
|
def update_faction(self, faction_path: Path) -> None:
|
|
with faction_path.open() as faction_file:
|
|
data = json.load(faction_file)
|
|
|
|
self.update_vehicle_list(data, "frontline_units")
|
|
self.update_vehicle_list(data, "artillery_units")
|
|
self.update_vehicle_list(data, "infantry_units")
|
|
self.update_vehicle_list(data, "logistics_units")
|
|
|
|
with faction_path.open("w") as faction_file:
|
|
json.dump(data, faction_file, indent=2)
|
|
|
|
def new_name_for(self, old_name: str, country: str) -> str:
|
|
if old_name in self.all_variants:
|
|
return old_name
|
|
vehicle_id = self.find_unit_id_for_faction_name(old_name)
|
|
return self.variant_map[vehicle_id][country]
|
|
|
|
def update_vehicle_list(self, data: dict[str, Any], field: str) -> None:
|
|
if field not in data:
|
|
return
|
|
|
|
new_vehicles = []
|
|
for vehicle in data[field]:
|
|
new_vehicles.append(self.new_name_for(vehicle, data["country"]))
|
|
data[field] = sorted(new_vehicles)
|
|
|
|
def generate_basic_info(self, unit_type: Type[VehicleType]) -> None:
|
|
self.all_variants.add(unit_type.id)
|
|
output_path = UNIT_DATA_DIR / "ground_units" / f"{unit_type.id}.yaml"
|
|
if output_path.exists():
|
|
# Already have data for this, don't clobber it, but do register the
|
|
# variant names.
|
|
with output_path.open() as unit_info_file:
|
|
data = yaml.safe_load(unit_info_file)
|
|
self.all_variants.update(data["variants"].keys())
|
|
return
|
|
with output_path.open("w") as output_file:
|
|
yaml.safe_dump(
|
|
{
|
|
"price": PRICES[unit_type],
|
|
"variants": {unit_type.name: None},
|
|
},
|
|
output_file,
|
|
)
|
|
|
|
self.variant_map[unit_type.id] = defaultdict(lambda: unit_type.name)
|
|
|
|
def convert_unit(
|
|
self, pydcs_name: str, data: list[dict[str, dict[str, str]]]
|
|
) -> bool:
|
|
if len(data) != 1:
|
|
raise ValueError(f"Unexpected data format for {pydcs_name}")
|
|
|
|
try:
|
|
unit_type: Type[VehicleType] = vehicle_map[pydcs_name]
|
|
except KeyError:
|
|
# The data is probably using the name instead of the key. This has always
|
|
# been absent in the game but we can probably find a vehicle with a matching
|
|
# name.
|
|
unit_type = self.name_to_vehicle_map[pydcs_name]
|
|
|
|
try:
|
|
self.unconverted.remove(unit_type)
|
|
except KeyError as ex:
|
|
raise KeyError(
|
|
f"Could not find existing unconverted unit for {pydcs_name}"
|
|
) from ex
|
|
|
|
variants_dict = data[0]
|
|
default = variants_dict.pop("default")
|
|
|
|
default_name = default["name"]
|
|
self.all_variants.add(default_name)
|
|
country_to_variant = defaultdict(lambda: default_name)
|
|
|
|
variants = {default_name: {}}
|
|
for country, variant_dict in variants_dict.items():
|
|
variant_name = variant_dict["name"]
|
|
self.all_variants.add(variant_name)
|
|
country_to_variant[country] = variant_name
|
|
variants[variant_name] = self.get_variant_data(variant_dict)
|
|
|
|
output_dict: dict[str, Any] = {"variants": variants, "price": PRICES[unit_type]}
|
|
output_dict.update(self.get_variant_data(default))
|
|
|
|
for unit_class in GroundUnitClass:
|
|
if unit_type in unit_class:
|
|
output_dict["class"] = unit_class.class_name
|
|
|
|
output_path = UNIT_DATA_DIR / "ground_units" / f"{unit_type.id}.yaml"
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with output_path.open("w") as output_file:
|
|
yaml.safe_dump(output_dict, output_file)
|
|
|
|
self.variant_map[unit_type.id] = country_to_variant
|
|
return True
|
|
|
|
@staticmethod
|
|
def get_variant_data(variant: dict[str, Any]) -> dict[str, Any]:
|
|
result = {}
|
|
|
|
try:
|
|
result["manufacturer"] = variant["manufacturer"]
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
result["origin"] = variant["country-of-origin"]
|
|
except KeyError:
|
|
pass
|
|
try:
|
|
result["role"] = variant["role"]
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
as_str = variant["year-of-variant-introduction"]
|
|
if as_str == "N/A":
|
|
result["introduced"] = None
|
|
else:
|
|
result["introduced"] = int(as_str)
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
result["description"] = variant["text"]
|
|
except KeyError:
|
|
pass
|
|
|
|
return result
|
|
|
|
|
|
if __name__ == "__main__":
|
|
Converter().convert()
|