mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
1039 lines
37 KiB
Python
1039 lines
37 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import math
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Optional, Any, Iterator
|
|
|
|
import yaml
|
|
from dcs.ships import ship_map
|
|
from dcs.unit import Unit
|
|
from dcs.vehicles import vehicle_map
|
|
from tabulate import tabulate
|
|
|
|
import dcs
|
|
from dcs import Point
|
|
|
|
from game import Game, db
|
|
from game.campaignloader import CampaignAirWingConfig
|
|
from game.data.groups import GroupRole, GroupTask, ROLE_TASKINGS
|
|
from game.data.units import UnitClass
|
|
from game.db import FACTIONS
|
|
from game.dcs.groundunittype import GroundUnitType
|
|
from game.dcs.shipunittype import ShipUnitType
|
|
from game.missiongenerator.tgogenerator import (
|
|
GroundObjectGenerator,
|
|
)
|
|
from game.point_with_heading import PointWithHeading
|
|
from game.settings import Settings
|
|
from game.theater import CaucasusTheater, OffMapSpawn
|
|
from game.theater.start_generator import GameGenerator, GeneratorSettings, ModSettings
|
|
from game.theater.theatergroundobject import AirDefenseRange, SamGroundObject
|
|
from game.unitmap import UnitMap
|
|
from game.utils import Heading
|
|
from gen.templates import (
|
|
GroundObjectTemplates,
|
|
GroupTemplate,
|
|
UnitTemplate,
|
|
BuildingTemplate,
|
|
DefensesTemplate,
|
|
NavalTemplate,
|
|
TemplateMapping,
|
|
GroupTemplateMapping,
|
|
AntiAirTemplate,
|
|
GroundForceTemplate,
|
|
)
|
|
from gen.naming import namegen
|
|
from qt_ui import liberation_install
|
|
from gen.to_remove.armored_group_generator import (
|
|
FixedSizeArmorGroupGenerator,
|
|
FixedSizeArmorGroupGeneratorWithAA,
|
|
)
|
|
from gen.to_remove.carrier_group import (
|
|
CarrierGroupGenerator,
|
|
CarrierStrikeGroup8Generator,
|
|
)
|
|
from gen.to_remove.lha_group import LHAGroupGenerator
|
|
from gen.to_remove.ship_group_generator import SHIP_MAP
|
|
from gen.to_remove.coastal_group_generator import COASTAL_MAP
|
|
from gen.to_remove.missiles_group_generator import MISSILES_MAP
|
|
from gen.to_remove.airdefensegroupgenerator import AirDefenseGroupGenerator
|
|
from gen.to_remove.ewr_group_generator import EWR_MAP
|
|
from gen.to_remove.ewrs import EwrGenerator
|
|
from gen.to_remove.sam_group_generator import SAM_MAP
|
|
|
|
|
|
TEMPLATES_MIZ = "resources/templates/legacy_templates.miz"
|
|
MIGRATE_MIZ = "resources/tools/groundobject_templates.miz"
|
|
TEMPLATES_FOLDER = "resources/templates/"
|
|
TABLE_FILE = "doc/templates/template_list.md"
|
|
|
|
|
|
def export_templates(
|
|
miz_file: str, mapping_folder: str, templates: GroundObjectTemplates
|
|
) -> None:
|
|
"""Exports the migrated templates to the templates.miz and the mapping"""
|
|
# Prepare game
|
|
theater = CaucasusTheater()
|
|
initial_ground_position = Point(-500000, 250000)
|
|
initial_water_position = Point(-350000, 250000)
|
|
control_point_ground = OffMapSpawn(1, "Spawn Ground", initial_ground_position, True)
|
|
control_point_water = OffMapSpawn(2, "Spawn Water", initial_water_position, True)
|
|
theater.add_controlpoint(control_point_ground)
|
|
theater.add_controlpoint(control_point_water)
|
|
|
|
generator = GameGenerator(
|
|
FACTIONS["Bluefor Modern"],
|
|
FACTIONS["Russia 2010"],
|
|
theater,
|
|
CampaignAirWingConfig({control_point_ground: [], control_point_water: []}),
|
|
Settings(),
|
|
GeneratorSettings(
|
|
start_date=datetime.today(),
|
|
player_budget=1000,
|
|
enemy_budget=1000,
|
|
inverted=False,
|
|
no_carrier=False,
|
|
no_lha=False,
|
|
no_player_navy=False,
|
|
no_enemy_navy=False,
|
|
),
|
|
ModSettings(),
|
|
)
|
|
game = generator.generate()
|
|
|
|
# TODO Define combined forces as country so that the missioneditor type is correct
|
|
|
|
m = dcs.Mission(game.theater.terrain)
|
|
country = m.country("USA")
|
|
unit_map = UnitMap()
|
|
|
|
offset_x = 0
|
|
offset_y = 0
|
|
|
|
for group_role in GroupRole:
|
|
temmplates_for_category = list(templates.for_role_and_task(group_role))
|
|
|
|
# Define the offset / separation
|
|
category_separation = 10000
|
|
group_separation = 5000
|
|
|
|
if group_role == GroupRole.Naval:
|
|
initial_position = initial_water_position
|
|
control_point = control_point_water
|
|
else:
|
|
initial_position = initial_ground_position
|
|
control_point = control_point_ground
|
|
|
|
current_separation = offset_y + category_separation
|
|
offset_x = 0
|
|
offset_y = current_separation
|
|
max_cols = int(math.sqrt(len(temmplates_for_category)))
|
|
for template in temmplates_for_category:
|
|
mapping = TemplateMapping(
|
|
template.name,
|
|
template.description,
|
|
template.category,
|
|
template.generic,
|
|
group_role,
|
|
template.tasks,
|
|
[],
|
|
miz_file,
|
|
)
|
|
position = Point(
|
|
initial_position.x + offset_x, initial_position.y + offset_y
|
|
)
|
|
|
|
# Initialize the group template so that a unit can be selected
|
|
for group in template.groups:
|
|
game.blue.faction.initialize_group_template(group, False)
|
|
|
|
ground_object = template.generate(
|
|
template.name,
|
|
PointWithHeading.from_point(position, Heading.from_degrees(0)),
|
|
control_point,
|
|
game,
|
|
merge_groups=False, # Do not merge groups for migration
|
|
)
|
|
|
|
for g_id, group in enumerate(ground_object.groups):
|
|
group.name = f"{template.name} {g_id}"
|
|
for u_id, unit in enumerate(group.units):
|
|
unit.name = f"{template.name} {g_id}-{u_id}"
|
|
group_template = template.groups[g_id]
|
|
group_mapping = GroupTemplateMapping(
|
|
group.name,
|
|
group_template.optional,
|
|
[unit.name for unit in group.units] if group.static_group else [],
|
|
group_template.group,
|
|
group_template.unit_count,
|
|
group_template.unit_types,
|
|
group_template.unit_classes,
|
|
)
|
|
mapping.groups.append(group_mapping)
|
|
|
|
generator = GroundObjectGenerator(ground_object, country, game, m, unit_map)
|
|
generator.generate(unique_name=False) # Prevent the ID prefix
|
|
|
|
if ((offset_y - current_separation) / group_separation) < max_cols:
|
|
offset_y += group_separation
|
|
else:
|
|
offset_y = current_separation
|
|
offset_x += group_separation
|
|
|
|
# Export the mapping as yaml
|
|
mapping.export(mapping_folder)
|
|
|
|
m.save(miz_file)
|
|
|
|
|
|
def update_factions(generator_names) -> None:
|
|
folder: Path = Path("./resources/factions/")
|
|
factions = [f for f in folder.glob("*.json") if f.is_file()]
|
|
for f in factions:
|
|
with open(f, "r", encoding="utf-8") as fdata:
|
|
data = fdata.read()
|
|
|
|
with open(f, "w", encoding="utf-8") as fdata:
|
|
for old_name, new_name in generator_names:
|
|
new_name = new_name.replace('"', '\\"')
|
|
data = data.replace(f'"{old_name}"', f'"{new_name}"')
|
|
data = data.replace(f'"ewrs"', f'"air_defense_units"')
|
|
fdata.write(data)
|
|
|
|
print("\n \n Faction Updates:")
|
|
print(
|
|
tabulate(
|
|
generator_names,
|
|
headers=["Previous Value", "New Value"],
|
|
tablefmt="github",
|
|
)
|
|
)
|
|
|
|
|
|
def migrate_generators_to_templates(
|
|
input_miz: str,
|
|
templates_miz: str,
|
|
mapping_folder: str,
|
|
) -> None:
|
|
|
|
templates = GroundObjectTemplates()
|
|
|
|
theater = CaucasusTheater()
|
|
|
|
initial_position = Point(0, 0)
|
|
control_point = OffMapSpawn(1, "Spawn", initial_position, True)
|
|
theater.add_controlpoint(control_point)
|
|
|
|
game = Game(
|
|
FACTIONS["Bluefor Modern"],
|
|
FACTIONS["Russia 2010"],
|
|
theater,
|
|
CampaignAirWingConfig({control_point: []}),
|
|
datetime.today(),
|
|
Settings(),
|
|
10000,
|
|
10000,
|
|
)
|
|
|
|
generators: dict[GroupRole, dict[str, Any]] = {
|
|
GroupRole.AntiAir: SAM_MAP,
|
|
GroupRole.Naval: SHIP_MAP,
|
|
GroupRole.Defenses: MISSILES_MAP | COASTAL_MAP,
|
|
GroupRole.GroundForce: {},
|
|
}
|
|
|
|
aa_range_taskings = {
|
|
AirDefenseRange.AAA: GroupTask.AAA,
|
|
AirDefenseRange.Short: GroupTask.SHORAD,
|
|
AirDefenseRange.Medium: GroupTask.MERAD,
|
|
AirDefenseRange.Long: GroupTask.LORAD,
|
|
}
|
|
|
|
# Only use one EWR generator. The differnt units will be placed as randomizer
|
|
generators[GroupRole.AntiAir]["EWRGenerator"] = EwrGenerator
|
|
|
|
generators[GroupRole.Naval]["CarrierGroupGenerator"] = CarrierGroupGenerator
|
|
generators[GroupRole.Naval][
|
|
"CarrierStrikeGroup8Generator"
|
|
] = CarrierStrikeGroup8Generator
|
|
generators[GroupRole.Naval]["LHAGroupGenerator"] = LHAGroupGenerator
|
|
generators[GroupRole.GroundForce]["RandomArmorGroup"] = FixedSizeArmorGroupGenerator
|
|
generators[GroupRole.GroundForce][
|
|
"RandomArmorGroupWithAA"
|
|
] = FixedSizeArmorGroupGeneratorWithAA
|
|
|
|
generator_names = []
|
|
|
|
for category, template_generators in generators.items():
|
|
for generator_name, generator_class in template_generators.items():
|
|
# Just reuse SamGroundObject to make it easy
|
|
ground_object = SamGroundObject(
|
|
namegen.random_objective_name(),
|
|
initial_position,
|
|
Heading.from_degrees(0),
|
|
control_point,
|
|
)
|
|
|
|
if category in (GroupRole.Naval, GroupRole.Defenses):
|
|
generator = generator_class(game, ground_object, game.blue.faction)
|
|
elif category == GroupRole.GroundForce:
|
|
unit_type = next(
|
|
GroundUnitType.for_dcs_type(dcs.vehicles.Armor.M_1_Abrams)
|
|
)
|
|
generator = generator_class(
|
|
game,
|
|
ground_object,
|
|
unit_type,
|
|
# Create a group of 8 Armored Vehicles
|
|
8,
|
|
)
|
|
else:
|
|
generator = generator_class(game, ground_object)
|
|
|
|
# Generate the DCS Groups
|
|
generator.generate()
|
|
|
|
if isinstance(generator, EwrGenerator):
|
|
template = AntiAirTemplate("Early-Warning Radar")
|
|
template.tasks = [GroupTask.EWR]
|
|
elif isinstance(generator, AirDefenseGroupGenerator):
|
|
template = AntiAirTemplate(generator.name)
|
|
template.tasks = [aa_range_taskings[generator.range()]]
|
|
elif generator_name in MISSILES_MAP:
|
|
template = DefensesTemplate(generator_name)
|
|
template.tasks = [GroupTask.Missile]
|
|
elif generator_name in COASTAL_MAP:
|
|
template = DefensesTemplate(generator_name)
|
|
template.tasks = [GroupTask.Coastal]
|
|
elif category == GroupRole.Naval:
|
|
if generator_name == "CarrierGroupGenerator":
|
|
template = NavalTemplate("Carrier Group")
|
|
template.tasks = [GroupTask.AircraftCarrier]
|
|
elif generator_name == "CarrierStrikeGroup8Generator":
|
|
template = NavalTemplate("Carrier Strike Group 8")
|
|
template.tasks = [GroupTask.AircraftCarrier]
|
|
elif generator_name == "LHAGroupGenerator":
|
|
template = NavalTemplate("LHA Group")
|
|
template.tasks = [GroupTask.HelicopterCarrier]
|
|
else:
|
|
template = NavalTemplate(generator_name)
|
|
template.tasks = [GroupTask.Navy]
|
|
elif category == GroupRole.GroundForce:
|
|
if generator_name == "RandomArmorGroup":
|
|
template = GroundForceTemplate("Armor Group")
|
|
template.tasks = ROLE_TASKINGS[GroupRole.GroundForce]
|
|
elif generator_name == "RandomArmorGroupWithAA":
|
|
template = GroundForceTemplate("Armor Group with Anti-Air")
|
|
template.tasks = ROLE_TASKINGS[GroupRole.GroundForce]
|
|
else:
|
|
raise RuntimeError("Generator handling missing")
|
|
|
|
# Split groups by the unit_type
|
|
units_of_type: dict[str, tuple[int, list[Unit]]] = {}
|
|
for g_id, group in enumerate(generator.groups):
|
|
for unit in group.units:
|
|
if unit.type in units_of_type:
|
|
units_of_type[unit.type][1].append(unit)
|
|
else:
|
|
units_of_type[unit.type] = (g_id + 1, [unit])
|
|
|
|
i = 0
|
|
for unit_type, data in units_of_type.items():
|
|
g_id, units = data
|
|
for j, unit in enumerate(units):
|
|
unit.name = f"{template.name} {i}-{j}"
|
|
|
|
group_template = GroupTemplate(
|
|
f"{template.name} #{str(i)}",
|
|
[UnitTemplate.from_unit(unit) for unit in units],
|
|
)
|
|
|
|
# Save the group_id
|
|
group_template.group = g_id
|
|
|
|
if generator_name in [
|
|
"CarrierGroupGenerator",
|
|
"CarrierStrikeGroup8Generator",
|
|
]:
|
|
if i == 0:
|
|
group_template.unit_classes = [UnitClass.AircraftCarrier]
|
|
group_template.unit_count = [1]
|
|
elif i == 1:
|
|
group_template.unit_count = [
|
|
5 if generator_name == "CarrierStrikeGroup8Generator" else 4
|
|
]
|
|
group_template.unit_classes = [UnitClass.Destroyer]
|
|
elif i == 2:
|
|
group_template.unit_count = [2]
|
|
group_template.unit_classes = [UnitClass.Cruiser]
|
|
elif generator_name == "LHAGroupGenerator":
|
|
if i == 0:
|
|
group_template.unit_classes = [UnitClass.HelicopterCarrier]
|
|
group_template.unit_count = [1]
|
|
elif i == 1:
|
|
group_template.unit_count = [2]
|
|
group_template.unit_classes = [UnitClass.Destroyer]
|
|
elif generator_name == "RandomArmorGroup" and i == 0:
|
|
group_template.unit_count = [2, 6]
|
|
group_template.unit_classes = [
|
|
UnitClass.Apc,
|
|
UnitClass.Atgm,
|
|
UnitClass.Ifv,
|
|
UnitClass.Tank,
|
|
]
|
|
elif generator_name == "RandomArmorGroupWithAA":
|
|
if i == 0:
|
|
group_template.unit_count = [2, 6]
|
|
group_template.unit_classes = [
|
|
UnitClass.Apc,
|
|
UnitClass.Atgm,
|
|
UnitClass.Ifv,
|
|
UnitClass.Tank,
|
|
]
|
|
elif i == 1:
|
|
group_template.unit_count = [1, 2]
|
|
group_template.unit_classes = [
|
|
UnitClass.AAA,
|
|
UnitClass.SHORAD,
|
|
UnitClass.Manpad,
|
|
]
|
|
group_template.optional = True
|
|
elif generator_name == "EWRGenerator" and i == 0:
|
|
for ewr_generator_name, ewr_generator in EWR_MAP.items():
|
|
unit_type = next(
|
|
GroundUnitType.for_dcs_type(ewr_generator.unit_type)
|
|
)
|
|
# Update all factions from generator to unit_type
|
|
generator_names.append(
|
|
[ewr_generator.unit_type.name, str(unit_type)]
|
|
)
|
|
# Update old generator names
|
|
generator_names.append([ewr_generator_name, str(unit_type)])
|
|
|
|
group_template.unit_classes = [UnitClass.EWR, UnitClass.SR]
|
|
group_template.unit_count = [1]
|
|
elif generator_name == "ChineseNavyGroupGenerator":
|
|
if i == 0:
|
|
group_template.unit_types = [unit_type]
|
|
group_template.unit_count = [0, 2]
|
|
if i == 1:
|
|
group_template.unit_count = [0, 2]
|
|
group_template.unit_types = ["Type_052C", "Type_052B"]
|
|
elif generator_name == "RussianNavyGroupGenerator":
|
|
if i == 0:
|
|
group_template.unit_count = [0, 2]
|
|
group_template.unit_types = ["ALBATROS", "MOLNIYA"]
|
|
if i == 1:
|
|
group_template.unit_count = [0, 2]
|
|
group_template.unit_types = ["NEUSTRASH", "REZKY"]
|
|
if i == 2:
|
|
group_template.unit_count = [1]
|
|
group_template.unit_types = ["MOSCOW"]
|
|
elif generator_name == "FlakGenerator" and i == 0:
|
|
group_template.unit_count = [4]
|
|
group_template.unit_types = [
|
|
"flak38",
|
|
"flak18",
|
|
"flak36",
|
|
"flak37",
|
|
"flak41",
|
|
"flak30",
|
|
]
|
|
elif generator_name == "V1GroupGenerator" and i == 2:
|
|
group_template.unit_types = ["flak38", "flak30"]
|
|
elif generator_name == "SchnellbootGroupGenerator" and i == 0:
|
|
group_template.unit_types = [unit_type]
|
|
group_template.unit_count = [2, 4]
|
|
elif generator_name == "UBoatGroupGenerator" and i == 0:
|
|
group_template.unit_types = [unit_type]
|
|
group_template.unit_count = [1, 4]
|
|
else:
|
|
group_template.unit_types = [unit_type]
|
|
group_template.unit_count = [len(units)]
|
|
|
|
template.groups.append(group_template)
|
|
i += 1
|
|
|
|
templates.add_template(category, template)
|
|
generator_names.append([generator_name, template.name])
|
|
|
|
# Load the basic templates
|
|
temp_mis = dcs.Mission()
|
|
temp_mis.load_file(input_miz)
|
|
|
|
position_for_template: dict[str, Point] = {}
|
|
group_for_template_and_type: dict[str, dict[str, GroupTemplate]] = {}
|
|
for static_group in (
|
|
temp_mis.country("USA").static_group
|
|
+ temp_mis.country("USAF Aggressors").static_group
|
|
):
|
|
# Naming is: fob1 #001 -> name: fob1, category fob, group_name: fob1 #001
|
|
template_name = str(static_group.name).split()[0]
|
|
category_name, idx = template_name[:-1], int(template_name[-1])
|
|
|
|
template = templates.by_name(template_name)
|
|
if not template:
|
|
template = BuildingTemplate(template_name)
|
|
template.category = category_name
|
|
# Store original position to make the template relative to TGO later
|
|
position_for_template[template_name] = static_group.position
|
|
templates.add_template(GroupRole.Building, template)
|
|
group_for_template_and_type[template_name] = {}
|
|
|
|
for unit in static_group.units:
|
|
if unit.type not in group_for_template_and_type[template_name]:
|
|
# Create Group Template for the satic group. Within Liberation we map
|
|
# static units in groups even if dcs can not handle this. The dcs specific
|
|
# handling will happpen later in miz generation again.
|
|
is_static = False if unit.type in vehicle_map else True
|
|
group_template = GroupTemplate(f"{template.name}", [], is_static)
|
|
group_template.unit_types = [unit.type]
|
|
group_template.unit_count = [0]
|
|
group_for_template_and_type[template_name][unit.type] = group_template
|
|
template.groups.append(group_template)
|
|
else:
|
|
group_template = group_for_template_and_type[template_name][unit.type]
|
|
|
|
unit_template = UnitTemplate.from_unit(unit)
|
|
unit_template.position = Point(
|
|
int(unit_template.position.x - position_for_template[template_name].x),
|
|
int(unit_template.position.y - position_for_template[template_name].y),
|
|
)
|
|
group_template.units.append(unit_template)
|
|
group_template.unit_count = [group_template.unit_count[0] + 1]
|
|
|
|
# Update Faction files
|
|
update_factions(generator_names)
|
|
|
|
# Export
|
|
export_templates(templates_miz, mapping_folder, templates)
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser()
|
|
|
|
my_group = parser.add_mutually_exclusive_group(required=True)
|
|
my_group.add_argument(
|
|
"-m",
|
|
"--migrate",
|
|
dest="Migrate",
|
|
help="Migrates generators and the current ground object templates to the new system",
|
|
action="store_true",
|
|
)
|
|
my_group.add_argument(
|
|
"-t",
|
|
"--table",
|
|
dest="Table",
|
|
help="Prints a table of all templates",
|
|
action="store_true",
|
|
)
|
|
my_group.add_argument(
|
|
"-f",
|
|
"--faction",
|
|
dest="Faction",
|
|
help="Updates all factions",
|
|
action="store_true",
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
liberation_install.init()
|
|
|
|
if args.Table:
|
|
export_template_list()
|
|
elif args.Faction:
|
|
migrate_factions()
|
|
elif args.Migrate:
|
|
migrate_generators_to_templates(MIGRATE_MIZ, TEMPLATES_MIZ, TEMPLATES_FOLDER)
|
|
|
|
|
|
def export_template_list() -> None:
|
|
# Extrac UnitMaps from all templates: Units with the GroundUnitType name!
|
|
templates = GroundObjectTemplates.from_folder(TEMPLATES_FOLDER)
|
|
template_maps: dict[str, list[Any]] = {}
|
|
missing_units = []
|
|
for role, template in templates.templates:
|
|
units = []
|
|
for group in template.groups:
|
|
group_units = []
|
|
for unit_type in group.unit_types:
|
|
try:
|
|
if unit_type in vehicle_map:
|
|
group_units.append(
|
|
next(
|
|
GroundUnitType.for_dcs_type(vehicle_map[unit_type])
|
|
).name
|
|
)
|
|
elif unit_type in ship_map:
|
|
group_units.append(
|
|
next(ShipUnitType.for_dcs_type(ship_map[unit_type])).name
|
|
)
|
|
elif db.static_type_from_name(unit_type):
|
|
group_units.append(unit_type)
|
|
continue
|
|
except StopIteration:
|
|
pass
|
|
missing_units.append(unit_type)
|
|
if group.unit_classes:
|
|
group_units.append(
|
|
f"Classes = [ {', '.join(c.value for c in group.unit_classes)}]"
|
|
)
|
|
units.append(f"<li>{', '.join(group_units)}</li>")
|
|
tasks = ", ".join(t.value for t in template.tasks)
|
|
category = role.value + tasks
|
|
|
|
if category not in template_maps:
|
|
template_maps[category] = []
|
|
|
|
template_maps[category].append(
|
|
[
|
|
role.value,
|
|
tasks,
|
|
template.name,
|
|
"<ul>" + "".join(units) + "</ul>",
|
|
]
|
|
)
|
|
|
|
templates = [
|
|
template for templates in template_maps.values() for template in templates
|
|
]
|
|
|
|
templates.append(["Missing Units", ", ".join(set(missing_units))])
|
|
|
|
table_str = tabulate(
|
|
templates,
|
|
headers=[
|
|
"Role",
|
|
"Tasks",
|
|
"Template Name",
|
|
"Units",
|
|
],
|
|
tablefmt="github",
|
|
)
|
|
|
|
with open(TABLE_FILE, "w", encoding="utf-8") as fdata:
|
|
fdata.write(table_str)
|
|
|
|
|
|
@dataclass
|
|
class MigratedTemplate:
|
|
original_key: str
|
|
new_key: str
|
|
original_value: str
|
|
new_value: str
|
|
|
|
|
|
def migrate_factions() -> None:
|
|
# List of all currently migrated templates
|
|
migrated_templates: list[MigratedTemplate] = [
|
|
MigratedTemplate("air_defenses", "preset_groups", "Hawk Site", "Hawk"),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-5/S-200 Site", "SA-5/S-200"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"preset_groups",
|
|
"SA-5/S-200 Site wit FlatFace SR",
|
|
"SA-5/S-200",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-2/S-75 Site", "SA-2/S-75"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-3/S-125 Site", "SA-3/S-125"
|
|
),
|
|
MigratedTemplate("air_defenses", "preset_groups", "SA-6 Kub Site", "SA-6"),
|
|
MigratedTemplate("air_defenses", "preset_groups", "SA-11 Buk Battery", "SA-11"),
|
|
MigratedTemplate("air_defenses", "preset_groups", "Rapier AA Site", "Rapier"),
|
|
MigratedTemplate("air_defenses", "preset_groups", "Roland Site", "Roland"),
|
|
MigratedTemplate("air_defenses", "preset_groups", "Patriot Battery", "Patriot"),
|
|
MigratedTemplate("air_defenses", "preset_groups", "HQ-7 Site", "HQ-7"),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"preset_groups",
|
|
"SA-10/S-300PS Battery - With ZSU-23",
|
|
"SA-10/S-300PS",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"preset_groups",
|
|
"SA-10/S-300PS Battery - With SA-15 PD",
|
|
"SA-10/S-300PS",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"preset_groups",
|
|
"SA-10/S-300PS Battery - With SA-15 PD & SA-19 SHORAD",
|
|
"SA-10/S-300PS",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-10B/S-300PS Battery", "SA-10B/S-300PS"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-17 Grizzly Battery", "SA-17"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-12/S-300V Battery", "SA-12/S-300V"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"preset_groups",
|
|
"SA-20/S-300PMU-1 Battery",
|
|
"SA-20/S-300PMU-1",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"preset_groups",
|
|
"SA-20B/S-300PMU-2 Battery",
|
|
"SA-20B/S-300PMU-2",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "SA-23/S-300VM Battery", "SA-23/S-300VM"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "NASAMS AIM-120B", "NASAMS AIM-120B"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "NASAMS AIM-120C", "NASAMS AIM-120C"
|
|
),
|
|
MigratedTemplate("air_defenses", "preset_groups", "KS-19 AAA Site", "KS-19"),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "Cold War Flak Site", "Cold-War-Flak"
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "Early Cold War Flak Site", "Cold-War-Flak"
|
|
),
|
|
MigratedTemplate("air_defenses", "preset_groups", "Flak Site", "Flak"),
|
|
MigratedTemplate(
|
|
"air_defenses", "preset_groups", "WW2 Ally Flak Site", "Ally Flak"
|
|
),
|
|
MigratedTemplate("air_defenses", "preset_groups", "Freya EWR Site", "Freya"),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Vulcan Group",
|
|
"M163 Vulcan Air Defense System",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Avenger Group",
|
|
"M1097 Heavy HMMWV Avenger",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Chaparral Group",
|
|
"M48 Chaparral",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Gepard Group",
|
|
"Flakpanzer Gepard",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Linebacker Group",
|
|
"M6 Linebacker",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"SA-8 OSA Site",
|
|
'SAM SA-8 Osa "Gecko" TEL',
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"SA-9 Group",
|
|
"SA-9 Strela",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"SA-13 Strela Group",
|
|
"SA-13 Gopher (9K35 Strela-10M3)",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"SA-15 Tor Group",
|
|
"SA-15 Tor",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"SA-19 Tunguska Group",
|
|
"SA-19 Grison (2K22 Tunguska)",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Bofors AAA",
|
|
"Bofors 40 mm Gun",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"ZU-23 Group",
|
|
"AAA ZU-23 Closed Emplacement",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"ZU-23 Ural Group",
|
|
"ZU-23 on Ural-375",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"ZU-23 Ural Insurgent Group",
|
|
"ZU-23 on Ural-375",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"Zu-23 Site",
|
|
"AAA ZU-23 Insurgent Closed Emplacement",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"ZSU-23 Group",
|
|
"ZSU-23-4 Shilka",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"WW2 Flak Site",
|
|
"8.8 cm Flak 18",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"ZSU-57-2 Group",
|
|
"ZSU-57-2 'Sparka'",
|
|
),
|
|
MigratedTemplate(
|
|
"air_defenses",
|
|
"air_defense_units",
|
|
"WW2 Flak Site",
|
|
"8.8 cm Flak 18",
|
|
),
|
|
MigratedTemplate(
|
|
"missiles",
|
|
"missiles",
|
|
"V1GroupGenerator",
|
|
"V-1 Launch Ramp",
|
|
),
|
|
MigratedTemplate(
|
|
"missiles",
|
|
"missiles",
|
|
"ScudGenerator",
|
|
"SSM SS-1C Scud-B",
|
|
),
|
|
MigratedTemplate(
|
|
"coastal_defenses",
|
|
"preset_groups",
|
|
"SilkwormGenerator",
|
|
"Silkworm",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"destroyers",
|
|
"Type54GroupGenerator",
|
|
"Type 054A Frigate",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"Type54GroupGenerator",
|
|
"Type 054A Frigate",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"SchnellbootGroupGenerator",
|
|
"Boat Schnellboot type S130",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"preset_groups",
|
|
"WW2LSTGroupGenerator",
|
|
"WW2LST",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"preset_groups",
|
|
"ChineseNavyGroupGenerator",
|
|
"Chinese Navy",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"UBoatGroupGenerator",
|
|
"U-boat VIIC U-flak",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"OliverHazardPerryGroupGenerator",
|
|
"FFG Oliver Hazard Perry",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"ArleighBurkeGroupGenerator",
|
|
"DDG Arleigh Burke IIa",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"GrishaGroupGenerator",
|
|
"Corvette 1124.4 Grish",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"MolniyaGroupGenerator",
|
|
"Corvette 1241.1 Molniya",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"KiloSubGroupGenerator",
|
|
"SSK 877V Kilo",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"naval_units",
|
|
"LaCombattanteIIGroupGenerator",
|
|
"FAC La Combattante IIa",
|
|
),
|
|
MigratedTemplate(
|
|
"navy_generators",
|
|
"preset_groups",
|
|
"RussianNavyGroupGenerator",
|
|
"Russian Navy",
|
|
),
|
|
MigratedTemplate(
|
|
"aircraft_carrier",
|
|
"naval_units",
|
|
"Forrestal",
|
|
"CV-59 Forrestal",
|
|
),
|
|
MigratedTemplate(
|
|
"aircraft_carrier",
|
|
"naval_units",
|
|
"KUZNECOW",
|
|
"CV 1143.5 Admiral Kuznetsov",
|
|
),
|
|
MigratedTemplate(
|
|
"helicopter_carrier",
|
|
"naval_units",
|
|
"LHA_Tarawa",
|
|
"LHA-1 Tarawa",
|
|
),
|
|
MigratedTemplate(
|
|
"aircraft_carrier",
|
|
"naval_units",
|
|
"Stennis",
|
|
"CVN-74 John C. Stennis",
|
|
),
|
|
MigratedTemplate(
|
|
"helicopter_carrier",
|
|
"naval_units",
|
|
"Type_071",
|
|
"Type 071 Amphibious Transport Dock",
|
|
),
|
|
]
|
|
# Find the "air_defenses" key remove the template name there
|
|
folder: Path = Path("./resources/factions/")
|
|
factions = [f for f in folder.glob("*.json") if f.is_file()]
|
|
for f in factions:
|
|
with open(f, "r", encoding="utf-8") as fdata:
|
|
data = json.load(fdata)
|
|
|
|
with open(f, "w", encoding="utf-8") as fdata:
|
|
for migrated_template in migrated_templates:
|
|
if migrated_template.new_key not in data:
|
|
new_faction = {}
|
|
for key, value in data.items():
|
|
new_faction[key] = value
|
|
if key == "preset_groups":
|
|
# Add New Key after air_defenses
|
|
new_faction[migrated_template.new_key] = []
|
|
data = new_faction
|
|
if (
|
|
migrated_template.original_key in data
|
|
and migrated_template.original_value
|
|
in data[migrated_template.original_key]
|
|
):
|
|
data[migrated_template.original_key].remove(
|
|
migrated_template.original_value
|
|
)
|
|
if (
|
|
migrated_template.new_value
|
|
not in data[migrated_template.new_key]
|
|
):
|
|
data[migrated_template.new_key].append(
|
|
migrated_template.new_value
|
|
)
|
|
# Remove air_defenses and coastal if empty
|
|
if "coastal_defenses" in data and len(data["coastal_defenses"]) == 0:
|
|
data.pop("coastal_defenses")
|
|
if "navy_generators" in data and len(data["navy_generators"]) == 0:
|
|
data.pop("navy_generators")
|
|
if "destroyers" in data:
|
|
for unit in data["destroyers"]:
|
|
data["naval_units"].append(unit)
|
|
data.pop("destroyers")
|
|
if "cruisers" in data:
|
|
for unit in data["cruisers"]:
|
|
data["naval_units"].append(unit)
|
|
data.pop("cruisers")
|
|
if "air_defenses" in data and len(data["air_defenses"]) == 0:
|
|
data.pop("air_defenses")
|
|
if "helicopter_carrier" in data and len(data["helicopter_carrier"]) == 0:
|
|
data.pop("helicopter_carrier")
|
|
if "aircraft_carrier" in data and len(data["aircraft_carrier"]) == 0:
|
|
data.pop("aircraft_carrier")
|
|
if "navy_group_count" in data:
|
|
data.pop("navy_group_count")
|
|
if "missiles_group_count" in data:
|
|
data.pop("missiles_group_count")
|
|
if "coastal_group_count" in data:
|
|
data.pop("coastal_group_count")
|
|
|
|
for key, value in data.items():
|
|
# Remove duplicates
|
|
if isinstance(value, list):
|
|
data[key] = []
|
|
[data[key].append(item) for item in value if item not in data[key]]
|
|
|
|
json.dump(data, fdata, indent=2)
|
|
|
|
|
|
def list_units_without_class() -> None:
|
|
folder: Path = Path("./resources/units/ground_units/")
|
|
unit_files = [f for f in folder.glob("*.yaml") if f.is_file()]
|
|
for f in unit_files:
|
|
with f.open(encoding="utf-8") as data_file:
|
|
data = yaml.safe_load(data_file)
|
|
|
|
if data.get("class") is None:
|
|
print(f)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|