Skip to content

Commit

Permalink
Fix save issues after aborting mission.
Browse files Browse the repository at this point in the history
When the mission is aborted the pending mission is still in the event
list, which is part of the game option. That event has a reference to
the operation, which in turn contains all the mission generator
objects. Two of these objects are the radio/TACAN allocators, which
use a generator to track the next free channel. Generators cannot be
picked, so because these are transitively part of the game object the
game cannot be saved.

Aside from the briefing generator, none of those objects are
actually needed outside the generation function itself, so just make
them locals instead.

This probably needs a larger refactor at some point. It doesn't look
like we need so many calls into the operation type (it has an
initialize, a prepare, and a generate, and it doesn't seem to need
anything but the last one). The only reason breifinggen needs to
remain a part of the class is because the briefing title and
description are filled in from the derived class, where title and
description should probably be overridden properties instead. I'm also
not sure if we need to make the event list a part of game at all, and
also don't think that the mission needs to be one of these events.
  • Loading branch information
DanAlbert authored and Khopa committed Oct 5, 2020
1 parent 7dd3367 commit a1886e3
Showing 1 changed file with 52 additions and 46 deletions.
98 changes: 52 additions & 46 deletions game/operation/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,26 +68,8 @@ def is_player_attack(self) -> bool:
def initialize(self, mission: Mission, conflict: Conflict):
self.current_mission = mission
self.conflict = conflict
self.radio_registry = RadioRegistry()
self.tacan_registry = TacanRegistry()
self.airgen = AircraftConflictGenerator(
mission, conflict, self.game.settings, self.game,
self.radio_registry)
self.airsupportgen = AirSupportConflictGenerator(
mission, conflict, self.game, self.radio_registry,
self.tacan_registry)
self.triggersgen = TriggersGenerator(mission, conflict, self.game)
self.visualgen = VisualGenerator(mission, conflict, self.game)
self.envgen = EnviromentGenerator(mission, conflict, self.game)
self.forcedoptionsgen = ForcedOptionsGenerator(mission, conflict, self.game)
self.groundobjectgen = GroundObjectsGenerator(
mission,
conflict,
self.game,
self.radio_registry,
self.tacan_registry
)
self.briefinggen = BriefingGenerator(mission, conflict, self.game)
self.briefinggen = BriefingGenerator(self.current_mission,
self.conflict, self.game)

def prepare(self, terrain: Terrain, is_quick: bool):
with open("resources/default_options.lua", "r") as f:
Expand Down Expand Up @@ -127,6 +109,9 @@ def prepare(self, terrain: Terrain, is_quick: bool):
self.defenders_starting_position = self.to_cp.at

def generate(self):
radio_registry = RadioRegistry()
tacan_registry = TacanRegistry()

# Dedup beacon/radio frequencies, since some maps have some frequencies
# used multiple times.
beacons = load_beacons_for_terrain(self.game.theater.terrain.name)
Expand All @@ -138,7 +123,7 @@ def generate(self):
logging.error(
f"TACAN beacon has no channel: {beacon.callsign}")
else:
self.tacan_registry.reserve(beacon.tacan_channel)
tacan_registry.reserve(beacon.tacan_channel)

for airfield, data in AIRFIELD_DATA.items():
if data.theater == self.game.theater.terrain.name:
Expand All @@ -150,16 +135,26 @@ def generate(self):
# beacon list.

for frequency in unique_map_frequencies:
self.radio_registry.reserve(frequency)
radio_registry.reserve(frequency)

# Generate meteo
envgen = EnviromentGenerator(self.current_mission, self.conflict,
self.game)
if self.environment_settings is None:
self.environment_settings = self.envgen.generate()
self.environment_settings = envgen.generate()
else:
self.envgen.load(self.environment_settings)
envgen.load(self.environment_settings)

# Generate ground object first
self.groundobjectgen.generate()

groundobjectgen = GroundObjectsGenerator(
self.current_mission,
self.conflict,
self.game,
radio_registry,
tacan_registry
)
groundobjectgen.generate()

# Generate destroyed units
for d in self.game.get_destroyed_units():
Expand All @@ -180,23 +175,28 @@ def generate(self):
dead=True,
)


# Air Support (Tanker & Awacs)
self.airsupportgen.generate(self.is_awacs_enabled)
airsupportgen = AirSupportConflictGenerator(
self.current_mission, self.conflict, self.game, radio_registry,
tacan_registry)
airsupportgen.generate(self.is_awacs_enabled)

# Generate Activity on the map
airgen = AircraftConflictGenerator(
self.current_mission, self.conflict, self.game.settings, self.game,
radio_registry)
for cp in self.game.theater.controlpoints:
side = cp.captured
if side:
country = self.current_mission.country(self.game.player_country)
else:
country = self.current_mission.country(self.game.enemy_country)
if cp.id in self.game.planners.keys():
self.airgen.generate_flights(
airgen.generate_flights(
cp,
country,
self.game.planners[cp.id],
self.groundobjectgen.runways
groundobjectgen.runways
)

# Generate ground units on frontline everywhere
Expand All @@ -221,18 +221,20 @@ def generate(self):
self.current_mission.groundControl.red_tactical_commander = self.ca_slots

# Triggers
if self.game.is_player_attack(self.conflict.attackers_country):
cp = self.conflict.from_cp
else:
cp = self.conflict.to_cp
self.triggersgen.generate()
triggersgen = TriggersGenerator(self.current_mission, self.conflict,
self.game)
triggersgen.generate()

# Options
self.forcedoptionsgen.generate()
forcedoptionsgen = ForcedOptionsGenerator(self.current_mission,
self.conflict, self.game)
forcedoptionsgen.generate()

# Generate Visuals Smoke Effects
visualgen = VisualGenerator(self.current_mission, self.conflict,
self.game)
if self.game.settings.perf_smoke_gen:
self.visualgen.generate()
visualgen.generate()

# Inject Plugins Lua Scripts
listOfPluginsScripts = []
Expand Down Expand Up @@ -327,41 +329,44 @@ def generate(self):
trigger.add_action(DoScript(String(lua)))
self.current_mission.triggerrules.triggers.append(trigger)

self.assign_channels_to_flights()
self.assign_channels_to_flights(airgen.flights,
airsupportgen.air_support)

kneeboard_generator = KneeboardGenerator(self.current_mission)

for dynamic_runway in self.groundobjectgen.runways.values():
for dynamic_runway in groundobjectgen.runways.values():
self.briefinggen.add_dynamic_runway(dynamic_runway)

for tanker in self.airsupportgen.air_support.tankers:
for tanker in airsupportgen.air_support.tankers:
self.briefinggen.add_tanker(tanker)
kneeboard_generator.add_tanker(tanker)

if self.is_awacs_enabled:
for awacs in self.airsupportgen.air_support.awacs:
for awacs in airsupportgen.air_support.awacs:
self.briefinggen.add_awacs(awacs)
kneeboard_generator.add_awacs(awacs)

for jtac in jtacs:
self.briefinggen.add_jtac(jtac)
kneeboard_generator.add_jtac(jtac)

for flight in self.airgen.flights:
for flight in airgen.flights:
self.briefinggen.add_flight(flight)
kneeboard_generator.add_flight(flight)

self.briefinggen.generate()
kneeboard_generator.generate()

def assign_channels_to_flights(self) -> None:
def assign_channels_to_flights(self, flights: List[FlightData],
air_support: AirSupport) -> None:
"""Assigns preset radio channels for client flights."""
for flight in self.airgen.flights:
for flight in flights:
if not flight.client_units:
continue
self.assign_channels_to_flight(flight)
self.assign_channels_to_flight(flight, air_support)

def assign_channels_to_flight(self, flight: FlightData) -> None:
def assign_channels_to_flight(self, flight: FlightData,
air_support: AirSupport) -> None:
"""Assigns preset radio channels for a client flight."""
airframe = flight.aircraft_type

Expand All @@ -372,4 +377,5 @@ def assign_channels_to_flight(self, flight: FlightData) -> None:
return

aircraft_data.channel_allocator.assign_channels_for_flight(
flight, self.airsupportgen.air_support)
flight, air_support
)

0 comments on commit a1886e3

Please sign in to comment.