mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Pre-allocate laser codes for FLOTs and flights.
This commit is contained in:
parent
723e191f10
commit
177f357492
@ -1,8 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from game.ato.loadouts import Loadout
|
||||
from game.lasercodes import LaserCode
|
||||
from game.savecompat import has_save_compat_for
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.squadrons import Pilot
|
||||
@ -13,8 +15,30 @@ class FlightMember:
|
||||
self.pilot = pilot
|
||||
self.loadout = loadout
|
||||
self.use_custom_loadout = False
|
||||
self.tgp_laser_code: LaserCode | None = None
|
||||
self.properties: dict[str, bool | float | int] = {}
|
||||
|
||||
@has_save_compat_for(9)
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
if "tgp_laser_code" not in state:
|
||||
state["tgp_laser_code"] = None
|
||||
self.__dict__.update(state)
|
||||
|
||||
def assign_tgp_laser_code(self, code: LaserCode) -> None:
|
||||
if self.tgp_laser_code is not None:
|
||||
raise RuntimeError(
|
||||
f"{self.pilot} already has already been assigned laser code "
|
||||
f"{self.tgp_laser_code}"
|
||||
)
|
||||
self.tgp_laser_code = code
|
||||
|
||||
def release_tgp_laser_code(self) -> None:
|
||||
if self.tgp_laser_code is None:
|
||||
raise RuntimeError(f"{self.pilot} has no assigned laser code")
|
||||
|
||||
self.tgp_laser_code.release()
|
||||
self.tgp_laser_code = None
|
||||
|
||||
@property
|
||||
def is_player(self) -> bool:
|
||||
if self.pilot is None:
|
||||
|
||||
@ -53,9 +53,11 @@ class FlightMembers(IFlightRoster):
|
||||
|
||||
def resize(self, new_size: int) -> None:
|
||||
if self.max_size > new_size:
|
||||
self.flight.squadron.return_pilots(
|
||||
[m.pilot for m in self.members[new_size:] if m.pilot is not None]
|
||||
)
|
||||
for member in self.members[new_size:]:
|
||||
if (pilot := member.pilot) is not None:
|
||||
self.flight.squadron.return_pilot(pilot)
|
||||
if (code := member.tgp_laser_code) is not None:
|
||||
code.release()
|
||||
self.members = self.members[:new_size]
|
||||
return
|
||||
if self.max_size:
|
||||
@ -80,6 +82,9 @@ class FlightMembers(IFlightRoster):
|
||||
self.flight.squadron.return_pilots(
|
||||
[p for p in self.iter_pilots() if p is not None]
|
||||
)
|
||||
for member in self.members:
|
||||
if (code := member.tgp_laser_code) is not None:
|
||||
code.release()
|
||||
|
||||
def use_same_loadout_for_all_members(self) -> None:
|
||||
if not self.members:
|
||||
|
||||
@ -25,6 +25,7 @@ if TYPE_CHECKING:
|
||||
from .data.doctrine import Doctrine
|
||||
from .factions.faction import Faction
|
||||
from .game import Game
|
||||
from .lasercodes import LaserCodeRegistry
|
||||
from .sim import GameUpdateEvents
|
||||
|
||||
|
||||
@ -85,6 +86,10 @@ class Coalition:
|
||||
assert self._navmesh is not None
|
||||
return self._navmesh
|
||||
|
||||
@property
|
||||
def laser_code_registry(self) -> LaserCodeRegistry:
|
||||
return self.game.laser_code_registry
|
||||
|
||||
def __getstate__(self) -> dict[str, Any]:
|
||||
state = self.__dict__.copy()
|
||||
# Avoid persisting any volatile types that can be deterministically
|
||||
|
||||
@ -10,9 +10,10 @@ from ..ato.starttype import StartType
|
||||
from ..db.database import Database
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.squadrons.airwing import AirWing
|
||||
from game.ato.closestairfields import ClosestAirfields
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.lasercodes import LaserCodeRegistry
|
||||
from game.squadrons.airwing import AirWing
|
||||
from .missionproposals import ProposedFlight
|
||||
|
||||
|
||||
@ -24,6 +25,7 @@ class PackageBuilder:
|
||||
location: MissionTarget,
|
||||
closest_airfields: ClosestAirfields,
|
||||
air_wing: AirWing,
|
||||
laser_code_registry: LaserCodeRegistry,
|
||||
flight_db: Database[Flight],
|
||||
is_player: bool,
|
||||
start_type: StartType,
|
||||
@ -33,6 +35,7 @@ class PackageBuilder:
|
||||
self.is_player = is_player
|
||||
self.package = Package(location, flight_db, auto_asap=asap)
|
||||
self.air_wing = air_wing
|
||||
self.laser_code_registry = laser_code_registry
|
||||
self.start_type = start_type
|
||||
|
||||
def plan_flight(self, plan: ProposedFlight) -> bool:
|
||||
@ -62,6 +65,11 @@ class PackageBuilder:
|
||||
start_type,
|
||||
divert=self.find_divert_field(squadron.aircraft, squadron.location),
|
||||
)
|
||||
for member in flight.iter_members():
|
||||
if member.is_player:
|
||||
member.assign_tgp_laser_code(
|
||||
self.laser_code_registry.alloc_laser_code()
|
||||
)
|
||||
self.package.add_flight(flight)
|
||||
return True
|
||||
|
||||
|
||||
@ -142,6 +142,7 @@ class PackageFulfiller:
|
||||
mission.location,
|
||||
ObjectiveDistanceCache.get_closest_airfields(mission.location),
|
||||
self.air_wing,
|
||||
self.coalition.laser_code_registry,
|
||||
self.flight_db,
|
||||
self.is_player,
|
||||
self.default_start_type,
|
||||
|
||||
10
game/game.py
10
game/game.py
@ -28,7 +28,9 @@ from .coalition import Coalition
|
||||
from .db.gamedb import GameDb
|
||||
from .dcs.countries import country_with_name
|
||||
from .infos.information import Information
|
||||
from .lasercodes.lasercoderegistry import LaserCodeRegistry
|
||||
from .profiling import logged_duration
|
||||
from .savecompat import has_save_compat_for
|
||||
from .settings import Settings
|
||||
from .theater import ConflictTheater
|
||||
from .theater.bullseye import Bullseye
|
||||
@ -121,6 +123,7 @@ class Game:
|
||||
self.current_unit_id = 0
|
||||
self.current_group_id = 0
|
||||
self.name_generator = naming.namegen
|
||||
self.laser_code_registry = LaserCodeRegistry()
|
||||
|
||||
self.db = GameDb()
|
||||
|
||||
@ -148,8 +151,13 @@ class Game:
|
||||
|
||||
self.on_load(game_still_initializing=True)
|
||||
|
||||
@has_save_compat_for(9)
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
self.__dict__.update(state)
|
||||
if not hasattr(self, "laser_code_registry"):
|
||||
self.laser_code_registry = LaserCodeRegistry()
|
||||
for front_line in self.theater.conflicts():
|
||||
front_line.laser_code = self.laser_code_registry.alloc_laser_code()
|
||||
# Regenerate any state that was not persisted.
|
||||
self.on_load()
|
||||
|
||||
@ -305,7 +313,7 @@ class Game:
|
||||
self.theater.iads_network.initialize_network(self.theater.ground_objects)
|
||||
|
||||
for control_point in self.theater.controlpoints:
|
||||
control_point.initialize_turn_0()
|
||||
control_point.initialize_turn_0(self.laser_code_registry)
|
||||
for tgo in control_point.connected_objectives:
|
||||
self.db.tgos.add(tgo.id, tgo)
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ from game.ato.flightstate import Completed, WaitingForStart
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.ato.package import Package
|
||||
from game.ato.starttype import StartType
|
||||
from game.lasercodes import LaserCodeRegistry
|
||||
from game.missiongenerator.missiondata import MissionData
|
||||
from game.radio.radios import RadioRegistry
|
||||
from game.radio.tacan import TacanRegistry
|
||||
@ -53,7 +52,6 @@ class AircraftGenerator:
|
||||
time: datetime,
|
||||
radio_registry: RadioRegistry,
|
||||
tacan_registry: TacanRegistry,
|
||||
laser_code_registry: LaserCodeRegistry,
|
||||
unit_map: UnitMap,
|
||||
mission_data: MissionData,
|
||||
helipads: dict[ControlPoint, list[StaticGroup]],
|
||||
@ -66,7 +64,6 @@ class AircraftGenerator:
|
||||
self.time = time
|
||||
self.radio_registry = radio_registry
|
||||
self.tacan_registy = tacan_registry
|
||||
self.laser_code_registry = laser_code_registry
|
||||
self.unit_map = unit_map
|
||||
self.flights: List[FlightData] = []
|
||||
self.mission_data = mission_data
|
||||
@ -254,7 +251,6 @@ class AircraftGenerator:
|
||||
self.time,
|
||||
self.radio_registry,
|
||||
self.tacan_registy,
|
||||
self.laser_code_registry,
|
||||
self.mission_data,
|
||||
dynamic_runways,
|
||||
self.use_client,
|
||||
|
||||
@ -15,8 +15,7 @@ from dcs.unitgroup import FlyingGroup
|
||||
|
||||
from game.ato import Flight, FlightType
|
||||
from game.callsigns import callsign_for_support_unit
|
||||
from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum
|
||||
from game.lasercodes import LaserCodeRegistry
|
||||
from game.data.weapons import Pylon
|
||||
from game.missiongenerator.logisticsgenerator import LogisticsGenerator
|
||||
from game.missiongenerator.missiondata import MissionData, AwacsInfo, TankerInfo
|
||||
from game.radio.radios import RadioFrequency, RadioRegistry
|
||||
@ -47,7 +46,6 @@ class FlightGroupConfigurator:
|
||||
time: datetime,
|
||||
radio_registry: RadioRegistry,
|
||||
tacan_registry: TacanRegistry,
|
||||
laser_code_registry: LaserCodeRegistry,
|
||||
mission_data: MissionData,
|
||||
dynamic_runways: dict[str, RunwayData],
|
||||
use_client: bool,
|
||||
@ -59,7 +57,6 @@ class FlightGroupConfigurator:
|
||||
self.time = time
|
||||
self.radio_registry = radio_registry
|
||||
self.tacan_registry = tacan_registry
|
||||
self.laser_code_registry = laser_code_registry
|
||||
self.mission_data = mission_data
|
||||
self.dynamic_runways = dynamic_runways
|
||||
self.use_client = use_client
|
||||
@ -147,8 +144,8 @@ class FlightGroupConfigurator:
|
||||
self, unit: FlyingUnit, member: FlightMember, laser_codes: list[Optional[int]]
|
||||
) -> None:
|
||||
self.set_skill(unit, member)
|
||||
if member.loadout.has_weapon_of_type(WeaponTypeEnum.TGP) and member.is_player:
|
||||
laser_codes.append(self.laser_code_registry.alloc_laser_code().code)
|
||||
if (code := member.tgp_laser_code) is not None:
|
||||
laser_codes.append(code.code)
|
||||
else:
|
||||
laser_codes.append(None)
|
||||
settings = self.flight.coalition.game.settings
|
||||
|
||||
@ -37,7 +37,6 @@ from game.ground_forces.ai_ground_planner import (
|
||||
DISTANCE_FROM_FRONTLINE,
|
||||
)
|
||||
from game.ground_forces.combat_stance import CombatStance
|
||||
from game.lasercodes import LaserCodeRegistry
|
||||
from game.naming import namegen
|
||||
from game.radio.radios import RadioRegistry
|
||||
from game.theater.controlpoint import ControlPoint
|
||||
@ -82,7 +81,6 @@ class FlotGenerator:
|
||||
unit_map: UnitMap,
|
||||
radio_registry: RadioRegistry,
|
||||
mission_data: MissionData,
|
||||
laser_code_registry: LaserCodeRegistry,
|
||||
) -> None:
|
||||
self.mission = mission
|
||||
self.conflict = conflict
|
||||
@ -94,7 +92,6 @@ class FlotGenerator:
|
||||
self.unit_map = unit_map
|
||||
self.radio_registry = radio_registry
|
||||
self.mission_data = mission_data
|
||||
self.laser_code_registry = laser_code_registry
|
||||
|
||||
def generate(self) -> None:
|
||||
position = FrontLineConflictDescription.frontline_position(
|
||||
@ -149,9 +146,9 @@ class FlotGenerator:
|
||||
# laser codes to 1113 to allow lasing for Su-25 Frogfoots and A-10A Warthogs.
|
||||
# Otherwise use 1688 for the first JTAC, 1687 for the second etc.
|
||||
if self.game.settings.plugins.get("ctld.fc3LaserCode"):
|
||||
code = self.laser_code_registry.fc3_code
|
||||
code = self.game.laser_code_registry.fc3_code
|
||||
else:
|
||||
code = self.laser_code_registry.alloc_laser_code()
|
||||
code = self.conflict.front_line.laser_code
|
||||
|
||||
utype = self.game.blue.faction.jtac_unit
|
||||
if utype is None:
|
||||
|
||||
@ -32,7 +32,6 @@ from .flotgenerator import FlotGenerator
|
||||
from .forcedoptionsgenerator import ForcedOptionsGenerator
|
||||
from .frontlineconflictdescription import FrontLineConflictDescription
|
||||
from .kneeboard import KneeboardGenerator
|
||||
from game.lasercodes import LaserCodeRegistry
|
||||
from .luagenerator import LuaGenerator
|
||||
from .missiondata import MissionData
|
||||
from .tgogenerator import TgoGenerator
|
||||
@ -53,7 +52,6 @@ class MissionGenerator:
|
||||
|
||||
self.mission_data = MissionData()
|
||||
|
||||
self.laser_code_registry = LaserCodeRegistry()
|
||||
self.radio_registry = RadioRegistry()
|
||||
self.tacan_registry = TacanRegistry()
|
||||
|
||||
@ -224,7 +222,6 @@ class MissionGenerator:
|
||||
self.unit_map,
|
||||
self.radio_registry,
|
||||
self.mission_data,
|
||||
self.laser_code_registry,
|
||||
)
|
||||
ground_conflict_gen.generate()
|
||||
|
||||
@ -239,7 +236,6 @@ class MissionGenerator:
|
||||
self.time,
|
||||
self.radio_registry,
|
||||
self.tacan_registry,
|
||||
self.laser_code_registry,
|
||||
self.unit_map,
|
||||
mission_data=self.mission_data,
|
||||
helipads=tgo_generator.helipads,
|
||||
|
||||
@ -87,6 +87,7 @@ if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.coalition import Coalition
|
||||
from game.lasercodes.lasercoderegistry import LaserCodeRegistry
|
||||
from game.sim import GameUpdateEvents
|
||||
from game.squadrons.squadron import Squadron
|
||||
from game.transfers import PendingTransfers
|
||||
@ -430,42 +431,50 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
assert self._front_line_db is None
|
||||
self._front_line_db = game.db.front_lines
|
||||
|
||||
def initialize_turn_0(self) -> None:
|
||||
def initialize_turn_0(self, laser_code_registry: LaserCodeRegistry) -> None:
|
||||
# We don't need to send events for turn 0. The UI isn't up yet, and it'll fetch
|
||||
# the entire game state when it comes up.
|
||||
from game.sim import GameUpdateEvents
|
||||
|
||||
self._create_missing_front_lines(GameUpdateEvents())
|
||||
self._create_missing_front_lines(laser_code_registry, GameUpdateEvents())
|
||||
|
||||
@property
|
||||
def front_line_db(self) -> Database[FrontLine]:
|
||||
assert self._front_line_db is not None
|
||||
return self._front_line_db
|
||||
|
||||
def _create_missing_front_lines(self, events: GameUpdateEvents) -> None:
|
||||
def _create_missing_front_lines(
|
||||
self, laser_code_registry: LaserCodeRegistry, events: GameUpdateEvents
|
||||
) -> None:
|
||||
for connection in self.convoy_routes.keys():
|
||||
if not connection.front_line_active_with(
|
||||
self
|
||||
) and not connection.is_friendly_to(self):
|
||||
self._create_front_line_with(connection, events)
|
||||
self._create_front_line_with(laser_code_registry, connection, events)
|
||||
|
||||
def _create_front_line_with(
|
||||
self, connection: ControlPoint, events: GameUpdateEvents
|
||||
self,
|
||||
laser_code_registry: LaserCodeRegistry,
|
||||
connection: ControlPoint,
|
||||
events: GameUpdateEvents,
|
||||
) -> None:
|
||||
blue, red = FrontLine.sort_control_points(self, connection)
|
||||
front = FrontLine(blue, red)
|
||||
front = FrontLine(blue, red, laser_code_registry.alloc_laser_code())
|
||||
self.front_lines[connection] = front
|
||||
connection.front_lines[self] = front
|
||||
self.front_line_db.add(front.id, front)
|
||||
events.update_front_line(front)
|
||||
|
||||
def _remove_front_line_with(
|
||||
self, connection: ControlPoint, events: GameUpdateEvents
|
||||
self,
|
||||
connection: ControlPoint,
|
||||
events: GameUpdateEvents,
|
||||
) -> None:
|
||||
front = self.front_lines[connection]
|
||||
del self.front_lines[connection]
|
||||
del connection.front_lines[self]
|
||||
self.front_line_db.remove(front.id)
|
||||
front.laser_code.release()
|
||||
events.delete_front_line(front)
|
||||
|
||||
def _clear_front_lines(self, events: GameUpdateEvents) -> None:
|
||||
@ -929,7 +938,7 @@ class ControlPoint(MissionTarget, SidcDescribable, ABC):
|
||||
self._coalition = new_coalition
|
||||
self.base.set_strength_to_minimum()
|
||||
self._clear_front_lines(events)
|
||||
self._create_missing_front_lines(events)
|
||||
self._create_missing_front_lines(game.laser_code_registry, events)
|
||||
events.update_control_point(self)
|
||||
|
||||
# All the attached TGOs have either been depopulated or captured. Tell the UI to
|
||||
|
||||
@ -8,6 +8,7 @@ from typing import Any, Iterator, List, TYPE_CHECKING, Tuple
|
||||
from dcs.mapping import Point
|
||||
|
||||
from .missiontarget import MissionTarget
|
||||
from ..lasercodes.lasercode import LaserCode
|
||||
from ..utils import Heading, pairwise
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -49,10 +50,12 @@ class FrontLine(MissionTarget):
|
||||
self,
|
||||
blue_point: ControlPoint,
|
||||
red_point: ControlPoint,
|
||||
laser_code: LaserCode,
|
||||
) -> None:
|
||||
self.id = uuid.uuid4()
|
||||
self.blue_cp = blue_point
|
||||
self.red_cp = red_point
|
||||
self.laser_code = laser_code
|
||||
try:
|
||||
route = list(blue_point.convoy_route_to(red_point))
|
||||
except KeyError:
|
||||
|
||||
@ -194,6 +194,12 @@ class QFlightCreator(QDialog):
|
||||
roster=roster,
|
||||
)
|
||||
|
||||
for member in flight.iter_members():
|
||||
if member.is_player:
|
||||
member.assign_tgp_laser_code(
|
||||
self.game.laser_code_registry.alloc_laser_code()
|
||||
)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.created.emit(flight)
|
||||
self.accept()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user