diff --git a/changelog.md b/changelog.md index 44fecc3b..55e745ba 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,7 @@ Saves from 6.x are not compatible with 7.0. * **[Modding]** Fixed an issue where Falklands campaigns created or edited with new versions of DCS could not be loaded. * **[Modding]** Fixed decoding of campaign yaml files to use UTF-8 rather than the system locale's default. It's now possible to use "Bf 109 K-4 Kurfürst" as a preferred aircraft type. * **[Mission Generation]** Planes will no longer spawn in helipads that are not also designated for fixed wing parking. +* **[Mission Generation]** Potentially an issue where ground war planning game state could become corrupted, preventing mission generation. # 6.1.1 diff --git a/game/game.py b/game/game.py index 71015ee9..bee156d6 100644 --- a/game/game.py +++ b/game/game.py @@ -7,7 +7,6 @@ from collections.abc import Iterator from datetime import date, datetime, time, timedelta from enum import Enum from typing import Any, List, TYPE_CHECKING, Type, Union, cast -from uuid import UUID from dcs.countries import Switzerland, USAFAggressors, UnitedNationsPeacekeepers from dcs.country import Country @@ -17,7 +16,6 @@ from dcs.vehicles import AirDefence from faker import Faker from game.ato.closestairfields import ObjectiveDistanceCache -from game.ground_forces.ai_ground_planner import GroundPlanner from game.models.game_stats import GameStats from game.plugins import LuaPluginManager from game.utils import Distance @@ -109,7 +107,6 @@ class Game: self.date = date(start_date.year, start_date.month, start_date.day) self.game_stats = GameStats() self.notes = "" - self.ground_planners: dict[UUID, GroundPlanner] = {} self.informations: list[Information] = [] self.message("Game Start", "-" * 40) # Culling Zones are for areas around points of interest that contain things we may not wish to cull. @@ -432,14 +429,6 @@ class Game: if for_red: self.red.initialize_turn() - # Plan GroundWar - self.ground_planners = {} - for cp in self.theater.controlpoints: - if cp.has_frontline: - gplanner = GroundPlanner(cp, self) - gplanner.plan_groundwar() - self.ground_planners[cp.id] = gplanner - # Update cull zones with logged_duration("Computing culling positions"): self.compute_unculled_zones(events) diff --git a/game/missiongenerator/missiongenerator.py b/game/missiongenerator/missiongenerator.py index 70873869..38deaaa8 100644 --- a/game/missiongenerator/missiongenerator.py +++ b/game/missiongenerator/missiongenerator.py @@ -13,6 +13,7 @@ from dcs.countries import country_dict from game.atcdata import AtcData from game.dcs.beacons import Beacons from game.dcs.helpers import unit_type_from_name +from game.ground_forces.ai_ground_planner import GroundPlanner from game.missiongenerator.aircraft.aircraftgenerator import ( AircraftGenerator, ) @@ -42,7 +43,8 @@ from .visualsgenerator import VisualsGenerator if TYPE_CHECKING: from game import Game - + from game.theater import ControlPoint + from game.ground_forces.ai_ground_planner import CombatGroup COMBINED_ARMS_SLOTS = 1 @@ -189,8 +191,33 @@ class MissionGenerator: # No need to reserve ILS or TACAN because those are in the # beacon list. + def _find_combat_groups_between( + self, + planners: dict[ControlPoint, GroundPlanner], + origin: ControlPoint, + target: ControlPoint, + ) -> list[CombatGroup]: + try: + planner = planners[origin] + except KeyError as ex: + raise KeyError(f"No ground planner found at {origin}") from ex + + try: + return planner.units_per_cp[target.id] + except KeyError as ex: + raise KeyError( + f"Ground planner at {origin} does not target {target}" + ) from ex + def generate_ground_conflicts(self) -> None: """Generate FLOTs and JTACs for each active front line.""" + planners: dict[ControlPoint, GroundPlanner] = {} + for control_point in self.game.theater.controlpoints: + if control_point.has_frontline: + planner = GroundPlanner(control_point, self.game) + planners[control_point] = planner + planner.plan_groundwar() + for front_line in self.game.theater.conflicts(): player_cp = front_line.blue_cp enemy_cp = front_line.red_cp @@ -198,16 +225,12 @@ class MissionGenerator: front_line, self.game.theater ) # Generate frontline ops - player_gp = self.game.ground_planners[player_cp.id].units_per_cp[ - enemy_cp.id - ] - enemy_gp = self.game.ground_planners[enemy_cp.id].units_per_cp[player_cp.id] ground_conflict_gen = FlotGenerator( self.mission, conflict, self.game, - player_gp, - enemy_gp, + self._find_combat_groups_between(planners, player_cp, enemy_cp), + self._find_combat_groups_between(planners, enemy_cp, player_cp), player_cp.stances[enemy_cp.id], enemy_cp.stances[player_cp.id], self.unit_map,