Remove GroundPlanners from the save state.

These are only used during mission generation. Remove them from the save
state to reduce compatibility requirements. We also have at least one
report of this data being corrupted... somehow. I don't know how that
could have happened, but if there's no data to corrupt in the first
place that's not a problem. If the corruption _does_ recur, it'll be
much easier to repro if it corrupts during mission generation rather
than during turn initialization.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2729.
This commit is contained in:
Dan Albert 2023-04-15 14:16:26 -07:00
parent 4a0975b21b
commit 4e067eaaa8
3 changed files with 31 additions and 18 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,