Use the actual Country type instead of the name.

We want other pieces of country information (in particular the short
names). This cleans up a lot of code anyway.

As an added bonus, this now catches squadrons that used invalid names
which would previously be passed through to pydcs and... then I don't
know what would happen.
This commit is contained in:
Dan Albert 2023-05-12 17:59:51 -07:00 committed by Raffson
parent b3e21498fd
commit 0608089eb0
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
22 changed files with 63 additions and 91 deletions

View File

@ -44,7 +44,6 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
def __init__( def __init__(
self, self,
package: Package, package: Package,
country: str,
squadron: Squadron, squadron: Squadron,
count: int, count: int,
flight_type: FlightType, flight_type: FlightType,
@ -60,7 +59,6 @@ class Flight(SidcDescribable, RadioFrequencyContainer, TacanContainer):
) -> None: ) -> None:
self.id = uuid.uuid4() self.id = uuid.uuid4()
self.package = package self.package = package
self.country = country
self.coalition = squadron.coalition self.coalition = squadron.coalition
self.squadron = squadron self.squadron = squadron
if claim_inv: if claim_inv:

View File

@ -70,14 +70,6 @@ class Coalition:
return 2 return 2
return 1 return 1
@property
def country_name(self) -> str:
return self.faction.country
@property
def country_shortname(self) -> str:
return self.faction.country_shortname
@property @property
def opponent(self) -> Coalition: def opponent(self) -> Coalition:
assert self._opponent is not None assert self._opponent is not None

View File

@ -26,13 +26,11 @@ class PackageBuilder:
air_wing: AirWing, air_wing: AirWing,
flight_db: Database[Flight], flight_db: Database[Flight],
is_player: bool, is_player: bool,
package_country: str,
start_type: StartType, start_type: StartType,
asap: bool, asap: bool,
) -> None: ) -> None:
self.closest_airfields = closest_airfields self.closest_airfields = closest_airfields
self.is_player = is_player self.is_player = is_player
self.package_country = package_country
self.package = Package(location, flight_db, auto_asap=asap) self.package = Package(location, flight_db, auto_asap=asap)
self.air_wing = air_wing self.air_wing = air_wing
self.start_type = start_type self.start_type = start_type
@ -56,7 +54,6 @@ class PackageBuilder:
flight = Flight( flight = Flight(
self.package, self.package,
self.package_country,
squadron, squadron,
plan.num_aircraft, plan.num_aircraft,
plan.task, plan.task,

View File

@ -141,7 +141,6 @@ class PackageFulfiller:
self.air_wing, self.air_wing,
self.flight_db, self.flight_db,
self.is_player, self.is_player,
self.coalition.country_name,
self.default_start_type, self.default_start_type,
mission.asap, mission.asap,
) )

9
game/dcs/countries.py Normal file
View File

@ -0,0 +1,9 @@
from dcs.countries import country_dict
from dcs.country import Country
def country_with_name(name: str) -> Country:
for country in country_dict.values():
if country.name == name:
return country()
raise KeyError(f"No country found named {name}")

View File

@ -157,8 +157,8 @@ class Debriefing:
self.game = game self.game = game
self.unit_map = unit_map self.unit_map = unit_map
self.player_country = game.blue.country_name self.player_country = game.blue.faction.country.name
self.enemy_country = game.red.country_name self.enemy_country = game.red.faction.country.name
self.air_losses = self.dead_aircraft() self.air_losses = self.dead_aircraft()
self.ground_losses = self.dead_ground_units() self.ground_losses = self.dead_ground_units()

View File

@ -7,9 +7,8 @@ from functools import cached_property
from typing import Optional, Dict, Type, List, Any, Iterator, TYPE_CHECKING from typing import Optional, Dict, Type, List, Any, Iterator, TYPE_CHECKING
import dcs import dcs
from dcs.countries import country_dict from dcs.country import Country
from dcs.unittype import ShipType, StaticType from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType
from dcs.unittype import UnitType as DcsUnitType
from game.armedforces.forcegroup import ForceGroup from game.armedforces.forcegroup import ForceGroup
from game.data.building_data import ( from game.data.building_data import (
@ -29,6 +28,7 @@ from game.data.doctrine import (
from game.data.groups import GroupRole from game.data.groups import GroupRole
from game.data.units import UnitClass from game.data.units import UnitClass
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from game.dcs.countries import country_with_name
from game.dcs.groundunittype import GroundUnitType from game.dcs.groundunittype import GroundUnitType
from game.dcs.shipunittype import ShipUnitType from game.dcs.shipunittype import ShipUnitType
from game.dcs.unittype import UnitType from game.dcs.unittype import UnitType
@ -45,7 +45,7 @@ class Faction:
locales: Optional[List[str]] locales: Optional[List[str]]
# Country used by this faction # Country used by this faction
country: str = field(default="") country: Country
# Country's short name used by this faction # Country's short name used by this faction
country_shortname: str = field(default="") country_shortname: str = field(default="")
@ -183,23 +183,16 @@ class Faction:
return list(self.aircraft + self.awacs + self.tankers) return list(self.aircraft + self.awacs + self.tankers)
@classmethod @classmethod
def from_json(cls: Type[Faction], json: Dict[str, Any]) -> Faction: def from_dict(cls: Type[Faction], json: Dict[str, Any]) -> Faction:
faction = Faction(locales=json.get("locales")) try:
country = country_with_name(json["country"])
except KeyError as ex:
raise KeyError(
f'Faction\'s country ("{json.get("country")}") is not a valid DCS '
"country ID"
) from ex
faction.country = json.get("country", "/") faction = Faction(locales=json.get("locales"), country=country)
country = None
for c in country_dict.values():
if c.name == faction.country:
country = c
break
if country is None:
raise AssertionError(
'Faction\'s country ("{}") is not a valid DCS country ID'.format(
faction.country
)
)
faction.country_shortname = country.shortname faction.country_shortname = country.shortname

View File

@ -26,6 +26,7 @@ from .ato.flighttype import FlightType
from .campaignloader import CampaignAirWingConfig from .campaignloader import CampaignAirWingConfig
from .coalition import Coalition from .coalition import Coalition
from .db.gamedb import GameDb from .db.gamedb import GameDb
from .dcs.countries import country_with_name
from .infos.information import Information from .infos.information import Information
from .profiling import logged_duration from .profiling import logged_duration
from .settings import Settings from .settings import Settings
@ -179,13 +180,15 @@ class Game:
Make sure the opposing factions are using different countries Make sure the opposing factions are using different countries
:return: :return:
""" """
# TODO: This should just be rejected and sent back to the user to fix.
# This isn't always something that the original faction can support.
if player_faction.country == enemy_faction.country: if player_faction.country == enemy_faction.country:
if player_faction.country == "USA": if player_faction.country.name == "USA":
enemy_faction.country = "USAF Aggressors" enemy_faction.country = country_with_name("USAF Aggressors")
elif player_faction.country == "Russia": elif player_faction.country.name == "Russia":
enemy_faction.country = "USSR" enemy_faction.country = country_with_name("USSR")
else: else:
enemy_faction.country = "Russia" enemy_faction.country = country_with_name("Russia")
def faction_for(self, player: bool) -> Faction: def faction_for(self, player: bool) -> Faction:
return self.coalition_for(player).faction return self.coalition_for(player).faction
@ -196,13 +199,10 @@ class Game:
def air_wing_for(self, player: bool) -> AirWing: def air_wing_for(self, player: bool) -> AirWing:
return self.coalition_for(player).air_wing return self.coalition_for(player).air_wing
def country_for(self, player: bool) -> str:
return self.coalition_for(player).country_name
@property @property
def neutral_country(self) -> Type[Country]: def neutral_country(self) -> Type[Country]:
"""Return the best fitting country that can be used as neutral faction in the generated mission""" """Return the best fitting country that can be used as neutral faction in the generated mission"""
countries_in_use = [self.red.country_name, self.blue.country_name] countries_in_use = {self.red.faction.country, self.blue.faction.country}
if UnitedNationsPeacekeepers not in countries_in_use: if UnitedNationsPeacekeepers not in countries_in_use:
return UnitedNationsPeacekeepers return UnitedNationsPeacekeepers
elif Switzerland.name not in countries_in_use: elif Switzerland.name not in countries_in_use:

View File

@ -174,7 +174,6 @@ class AircraftGenerator:
# TODO: Special flight type? # TODO: Special flight type?
flight = Flight( flight = Flight(
Package(squadron.location, self.game.db.flights), Package(squadron.location, self.game.db.flights),
faction.country,
squadron, squadron,
1, 1,
FlightType.BARCAP, FlightType.BARCAP,

View File

@ -29,12 +29,9 @@ class CargoShipGenerator:
self.generate_cargo_ship(ship) self.generate_cargo_ship(ship)
def generate_cargo_ship(self, ship: CargoShip) -> ShipGroup: def generate_cargo_ship(self, ship: CargoShip) -> ShipGroup:
country = self.mission.country(
self.game.coalition_for(ship.player_owned).country_name
)
waypoints = ship.route waypoints = ship.route
group = self.mission.ship_group( group = self.mission.ship_group(
country, self.game.coalition_for(ship.player_owned).faction.country,
ship.name, ship.name,
HandyWind, HandyWind,
position=waypoints[0], position=waypoints[0],

View File

@ -72,14 +72,11 @@ class ConvoyGenerator:
units: dict[GroundUnitType, int], units: dict[GroundUnitType, int],
for_player: bool, for_player: bool,
) -> VehicleGroup: ) -> VehicleGroup:
country = self.mission.country(self.game.coalition_for(for_player).country_name)
faction = self.game.faction_for(for_player)
unit_types = list(units.items()) unit_types = list(units.items())
main_unit_type, main_unit_count = unit_types[0] main_unit_type, main_unit_count = unit_types[0]
group = self.mission.vehicle_group( group = self.mission.vehicle_group(
country, self.game.coalition_for(for_player).faction.country,
name, name,
main_unit_type.dcs_unit_type, main_unit_type.dcs_unit_type,
position=position, position=position,

View File

@ -160,7 +160,7 @@ class FlotGenerator:
utype = AircraftType.named("MQ-9 Reaper") utype = AircraftType.named("MQ-9 Reaper")
jtac = self.mission.flight_group( jtac = self.mission.flight_group(
country=self.mission.country(self.game.blue.country_name), country=self.game.blue.faction.country,
name=namegen.next_jtac_name(), name=namegen.next_jtac_name(),
aircraft_type=utype.dcs_unit_type, aircraft_type=utype.dcs_unit_type,
position=position[0], position=position[0],
@ -752,7 +752,7 @@ class FlotGenerator:
spawn_heading = ( spawn_heading = (
self.conflict.heading.left if is_player else self.conflict.heading.right self.conflict.heading.left if is_player else self.conflict.heading.right
) )
country = self.game.coalition_for(is_player).country_name country = self.game.coalition_for(is_player).faction.country
for group in groups: for group in groups:
if group.role == CombatGroupRole.ARTILLERY: if group.role == CombatGroupRole.ARTILLERY:
distance_from_frontline = ( distance_from_frontline = (
@ -770,7 +770,7 @@ class FlotGenerator:
g = self._generate_group( g = self._generate_group(
is_player, is_player,
self.mission.country(country), country,
group.unit_type, group.unit_type,
group.size, group.size,
final_position, final_position,
@ -786,7 +786,7 @@ class FlotGenerator:
self.gen_infantry_group_for_group( self.gen_infantry_group_for_group(
g, g,
is_player, is_player,
self.mission.country(country), country,
spawn_heading.opposite, spawn_heading.opposite,
) )

View File

@ -93,9 +93,8 @@ class LogisticsGenerator:
"ctld.logisticunit" "ctld.logisticunit"
): ):
# Spawn logisticsunit at pickup zones # Spawn logisticsunit at pickup zones
country = self.mission.country(self.flight.country)
logistic_unit = self.mission.static_group( logistic_unit = self.mission.static_group(
country, self.flight.squadron.coalition.faction.country,
f"{self.group.name}logistic", f"{self.group.name}logistic",
Fortification.FARP_Ammo_Dump_Coating, Fortification.FARP_Ammo_Dump_Coating,
pickup_point, pickup_point,

View File

@ -133,19 +133,12 @@ class MissionGenerator:
"neutrals", bullseye=Bullseye(Point(0, 0, self.mission.terrain)).to_pydcs() "neutrals", bullseye=Bullseye(Point(0, 0, self.mission.terrain)).to_pydcs()
) )
p_country = self.game.blue.country_name p_country = self.game.blue.faction.country
e_country = self.game.red.country_name e_country = self.game.red.faction.country
self.mission.coalition["blue"].add_country( self.mission.coalition["blue"].add_country(p_country)
country_dict[country_id_from_name(p_country)]() self.mission.coalition["red"].add_country(e_country)
)
self.mission.coalition["red"].add_country(
country_dict[country_id_from_name(e_country)]()
)
belligerents = [ belligerents = {p_country, e_country}
country_id_from_name(p_country),
country_id_from_name(e_country),
]
for country in country_dict.keys(): for country in country_dict.keys():
if country not in belligerents: if country not in belligerents:
self.mission.coalition["neutrals"].add_country(country_dict[country]()) self.mission.coalition["neutrals"].add_country(country_dict[country]())
@ -243,19 +236,19 @@ class MissionGenerator:
aircraft_generator.clear_parking_slots() aircraft_generator.clear_parking_slots()
aircraft_generator.generate_flights( aircraft_generator.generate_flights(
self.mission.country(self.game.blue.country_name), self.game.blue.faction.country,
self.game.blue.ato, self.game.blue.ato,
tgo_generator.runways, tgo_generator.runways,
) )
aircraft_generator.generate_flights( aircraft_generator.generate_flights(
self.mission.country(self.game.red.country_name), self.game.red.faction.country,
self.game.red.ato, self.game.red.ato,
tgo_generator.runways, tgo_generator.runways,
) )
if not self.game.settings.perf_disable_idle_aircraft: if not self.game.settings.perf_disable_idle_aircraft:
aircraft_generator.spawn_unused_aircraft( aircraft_generator.spawn_unused_aircraft(
self.mission.country(self.game.blue.country_name), self.game.blue.faction.country,
self.mission.country(self.game.red.country_name), self.game.red.faction.country,
) )
self.mission_data.flights = aircraft_generator.flights self.mission_data.flights = aircraft_generator.flights
@ -285,7 +278,7 @@ class MissionGenerator:
pos = Point(cast(float, d["x"]), cast(float, d["z"]), self.mission.terrain) pos = Point(cast(float, d["x"]), cast(float, d["z"]), self.mission.terrain)
if utype is not None and not self.game.position_culled(pos): if utype is not None and not self.game.position_culled(pos):
self.mission.static_group( self.mission.static_group(
country=self.mission.country(self.game.blue.country_name), country=self.game.blue.faction.country,
name="", name="",
_type=utype, _type=utype,
hidden=True, hidden=True,

View File

@ -604,7 +604,7 @@ class HelipadGenerator:
return return
# Note: Helipad are generated as neutral object in order not to interfer with # Note: Helipad are generated as neutral object in order not to interfer with
# capture triggers # capture triggers
country = self.m.country(self.game.coalition_for(self.cp.captured).country_name) country = self.game.coalition_for(self.cp.captured).faction.country
for i, helipad in enumerate(self.cp.helipads): for i, helipad in enumerate(self.cp.helipads):
heading = helipad.heading.degrees heading = helipad.heading.degrees
@ -687,7 +687,7 @@ class TgoGenerator:
def generate(self) -> None: def generate(self) -> None:
for cp in self.game.theater.controlpoints: for cp in self.game.theater.controlpoints:
country = self.m.country(self.game.coalition_for(cp.captured).country_name) country = self.game.coalition_for(cp.captured).faction.country
# Generate helipads # Generate helipads
helipad_gen = HelipadGenerator( helipad_gen = HelipadGenerator(

View File

@ -99,7 +99,7 @@ class VisualsGenerator:
break break
self.mission.static_group( self.mission.static_group(
self.mission.country(self.game.red.country_name), self.game.red.faction.country,
"", "",
_type=v, _type=v,
position=pos, position=pos,

View File

@ -6,6 +6,7 @@ from collections.abc import Iterable
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Optional, Sequence, TYPE_CHECKING from typing import Optional, Sequence, TYPE_CHECKING
from dcs.country import Country
from faker import Faker from faker import Faker
from game.ato import Flight, FlightType, Package from game.ato import Flight, FlightType, Package
@ -27,7 +28,7 @@ if TYPE_CHECKING:
class Squadron: class Squadron:
name: str name: str
nickname: Optional[str] nickname: Optional[str]
country: str country: Country
role: str role: str
aircraft: AircraftType aircraft: AircraftType
max_size: int max_size: int
@ -70,7 +71,7 @@ class Squadron:
( (
self.name, self.name,
self.nickname, self.nickname,
self.country, self.country.id,
self.role, self.role,
self.aircraft, self.aircraft,
) )
@ -412,7 +413,6 @@ class Squadron:
flight = Flight( flight = Flight(
package, package,
self.coalition.country_name,
self, self,
size, size,
FlightType.FERRY, FlightType.FERRY,

View File

@ -5,8 +5,10 @@ from pathlib import Path
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING
import yaml import yaml
from dcs.country import Country
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from game.dcs.countries import country_with_name
from game.squadrons.operatingbases import OperatingBases from game.squadrons.operatingbases import OperatingBases
from game.squadrons.pilot import Pilot from game.squadrons.pilot import Pilot
@ -19,7 +21,7 @@ if TYPE_CHECKING:
class SquadronDef: class SquadronDef:
name: str name: str
nickname: Optional[str] nickname: Optional[str]
country: str country: Country
role: str role: str
aircraft: AircraftType aircraft: AircraftType
livery: Optional[str] livery: Optional[str]
@ -76,7 +78,7 @@ class SquadronDef:
return SquadronDef( return SquadronDef(
name=data["name"], name=data["name"],
nickname=data.get("nickname"), nickname=data.get("nickname"),
country=data["country"], country=country_with_name(data["country"]),
role=data["role"], role=data["role"],
aircraft=unit_type, aircraft=unit_type,
livery=data.get("livery"), livery=data.get("livery"),

View File

@ -29,13 +29,13 @@ class SquadronDefLoader:
squadrons: dict[AircraftType, list[SquadronDef]] = defaultdict(list) squadrons: dict[AircraftType, list[SquadronDef]] = defaultdict(list)
country = self.faction.country country = self.faction.country
faction = self.faction faction = self.faction
any_country = country.startswith("Combined Joint Task Forces ") any_country = country.name.startswith("Combined Joint Task Forces ")
for directory in self.squadron_directories(): for directory in self.squadron_directories():
for path, squadron_def in self.load_squadrons_from(directory): for path, squadron_def in self.load_squadrons_from(directory):
if not any_country and squadron_def.country != country: if not any_country and squadron_def.country != country:
logging.debug( logging.debug(
"Not using squadron for non-matching country (is " "Not using squadron for non-matching country (is "
f"{squadron_def.country}, need {country}: {path}" f"{squadron_def.country.name}, need {country.name}: {path}"
) )
continue continue
if squadron_def.aircraft not in faction.aircrafts: if squadron_def.aircraft not in faction.aircrafts:

View File

@ -350,7 +350,6 @@ class AirliftPlanner:
flight = Flight( flight = Flight(
self.package, self.package,
self.game.country_for(squadron.player),
squadron, squadron,
flight_size, flight_size,
FlightType.TRANSPORT, FlightType.TRANSPORT,

View File

@ -40,7 +40,6 @@ class QFlightCreator(QDialog):
self.game = game self.game = game
self.package = package self.package = package
self.custom_name_text = None self.custom_name_text = None
self.country = self.game.blue.country_name
# Make dialog modal to prevent background windows to close unexpectedly. # Make dialog modal to prevent background windows to close unexpectedly.
self.setModal(True) self.setModal(True)
@ -183,7 +182,6 @@ class QFlightCreator(QDialog):
flight = Flight( flight = Flight(
self.package, self.package,
self.country,
squadron, squadron,
# A bit of a hack to work around the old API. Not actually relevant because # A bit of a hack to work around the old API. Not actually relevant because
# the roster is passed explicitly. Needs a refactor. # the roster is passed explicitly. Needs a refactor.

View File

@ -48,7 +48,7 @@ class TestFactionLoader(unittest.TestCase):
with (RESOURCES_DIR / "valid_faction.json").open("r") as data: with (RESOURCES_DIR / "valid_faction.json").open("r") as data:
faction = Faction.from_json(json.load(data)) faction = Faction.from_json(json.load(data))
self.assertEqual(faction.country, "USA") self.assertEqual(faction.country.name, "USA")
self.assertEqual(faction.name, "USA 2005") self.assertEqual(faction.name, "USA 2005")
self.assertEqual(faction.authors, "Khopa") self.assertEqual(faction.authors, "Khopa")
self.assertEqual(faction.description, "This is a test description") self.assertEqual(faction.description, "This is a test description")