mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add a UUID -> Flight database to Game.
This will be expanded with other types as needed.
This commit is contained in:
parent
ab6f44cb6f
commit
cba68549d8
@ -4,10 +4,11 @@ import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import timedelta
|
||||
from typing import List, Optional, Dict, TYPE_CHECKING
|
||||
from typing import Dict, List, Optional, TYPE_CHECKING
|
||||
|
||||
from game.ato import Flight, FlightType
|
||||
from game.ato.packagewaypoints import PackageWaypoints
|
||||
from game.db import Database
|
||||
from game.utils import Speed
|
||||
from gen.flights.flightplan import FormationFlightPlan
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
@ -24,6 +25,8 @@ class Package:
|
||||
#: TheaterGroundObject (non-ControlPoint map objectives).
|
||||
target: MissionTarget
|
||||
|
||||
_db: Database[Flight]
|
||||
|
||||
#: The set of flights in the package.
|
||||
flights: List[Flight] = field(default_factory=list)
|
||||
|
||||
@ -119,10 +122,12 @@ class Package:
|
||||
def add_flight(self, flight: Flight) -> None:
|
||||
"""Adds a flight to the package."""
|
||||
self.flights.append(flight)
|
||||
self._db.add(flight.id, flight)
|
||||
|
||||
def remove_flight(self, flight: Flight) -> None:
|
||||
"""Removes a flight from the package."""
|
||||
self.flights.remove(flight)
|
||||
self._db.remove(flight.id)
|
||||
if not self.flights:
|
||||
self.waypoints = None
|
||||
|
||||
|
||||
@ -2,11 +2,12 @@ from __future__ import annotations
|
||||
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from game.theater import ControlPoint, MissionTarget, OffMapSpawn
|
||||
from game.utils import nautical_miles
|
||||
from ..ato.package import Package
|
||||
from game.theater import MissionTarget, OffMapSpawn, ControlPoint
|
||||
from ..ato.flight import Flight
|
||||
from ..ato.package import Package
|
||||
from ..ato.starttype import StartType
|
||||
from ..db.database import Database
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
@ -23,6 +24,7 @@ class PackageBuilder:
|
||||
location: MissionTarget,
|
||||
closest_airfields: ClosestAirfields,
|
||||
air_wing: AirWing,
|
||||
flight_db: Database[Flight],
|
||||
is_player: bool,
|
||||
package_country: str,
|
||||
start_type: StartType,
|
||||
@ -31,7 +33,7 @@ class PackageBuilder:
|
||||
self.closest_airfields = closest_airfields
|
||||
self.is_player = is_player
|
||||
self.package_country = package_country
|
||||
self.package = Package(location, auto_asap=asap)
|
||||
self.package = Package(location, flight_db, auto_asap=asap)
|
||||
self.air_wing = air_wing
|
||||
self.start_type = start_type
|
||||
|
||||
|
||||
@ -2,24 +2,26 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from typing import Set, Iterable, Dict, TYPE_CHECKING, Optional
|
||||
from typing import Dict, Iterable, Optional, Set, TYPE_CHECKING
|
||||
|
||||
from game.commander.missionproposals import ProposedMission, ProposedFlight, EscortType
|
||||
from game.ato.airtaaskingorder import AirTaskingOrder
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.ato.package import Package
|
||||
from game.commander.missionproposals import EscortType, ProposedFlight, ProposedMission
|
||||
from game.commander.packagebuilder import PackageBuilder
|
||||
from game.data.doctrine import Doctrine
|
||||
from game.db import Database
|
||||
from game.procurement import AircraftProcurementRequest
|
||||
from game.profiling import MultiEventTracer
|
||||
from game.settings import Settings
|
||||
from game.squadrons import AirWing
|
||||
from game.theater import ConflictTheater
|
||||
from game.threatzones import ThreatZones
|
||||
from game.ato.airtaaskingorder import AirTaskingOrder
|
||||
from game.ato.package import Package
|
||||
from gen.flights.closestairfields import ObjectiveDistanceCache
|
||||
from game.ato.flighttype import FlightType
|
||||
from gen.flights.flightplan import FlightPlanBuilder
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.ato import Flight
|
||||
from game.coalition import Coalition
|
||||
|
||||
|
||||
@ -27,10 +29,15 @@ class PackageFulfiller:
|
||||
"""Responsible for package aircraft allocation and flight plan layout."""
|
||||
|
||||
def __init__(
|
||||
self, coalition: Coalition, theater: ConflictTheater, settings: Settings
|
||||
self,
|
||||
coalition: Coalition,
|
||||
theater: ConflictTheater,
|
||||
flight_db: Database[Flight],
|
||||
settings: Settings,
|
||||
) -> None:
|
||||
self.coalition = coalition
|
||||
self.theater = theater
|
||||
self.flight_db = flight_db
|
||||
self.player_missions_asap = settings.auto_ato_player_missions_asap
|
||||
self.default_start_type = settings.default_start_type
|
||||
|
||||
@ -133,6 +140,7 @@ class PackageFulfiller:
|
||||
mission.location,
|
||||
ObjectiveDistanceCache.get_closest_airfields(mission.location),
|
||||
self.air_wing,
|
||||
self.flight_db,
|
||||
self.is_player,
|
||||
self.coalition.country_name,
|
||||
self.default_start_type,
|
||||
|
||||
@ -4,10 +4,12 @@ import itertools
|
||||
import operator
|
||||
from abc import abstractmethod
|
||||
from dataclasses import dataclass, field
|
||||
from enum import unique, IntEnum, auto
|
||||
from typing import TYPE_CHECKING, Optional, Generic, TypeVar, Iterator, Union
|
||||
from enum import IntEnum, auto, unique
|
||||
from typing import Generic, Iterator, Optional, TYPE_CHECKING, TypeVar, Union
|
||||
|
||||
from game.commander.missionproposals import ProposedFlight, EscortType, ProposedMission
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.ato.package import Package
|
||||
from game.commander.missionproposals import EscortType, ProposedFlight, ProposedMission
|
||||
from game.commander.packagefulfiller import PackageFulfiller
|
||||
from game.commander.tasks.theatercommandertask import TheaterCommanderTask
|
||||
from game.commander.theaterstate import TheaterState
|
||||
@ -15,8 +17,6 @@ from game.settings import AutoAtoBehavior
|
||||
from game.theater import MissionTarget
|
||||
from game.theater.theatergroundobject import IadsGroundObject, NavalGroundObject
|
||||
from game.utils import Distance, meters
|
||||
from game.ato.package import Package
|
||||
from game.ato.flighttype import FlightType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.coalition import Coalition
|
||||
@ -40,7 +40,6 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.flights = []
|
||||
self.package = Package(self.target)
|
||||
|
||||
def preconditions_met(self, state: TheaterState) -> bool:
|
||||
if (
|
||||
@ -97,6 +96,7 @@ class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]):
|
||||
fulfiller = PackageFulfiller(
|
||||
state.context.coalition,
|
||||
state.context.theater,
|
||||
state.context.game_db.flights,
|
||||
state.context.settings,
|
||||
)
|
||||
self.package = fulfiller.plan_mission(
|
||||
|
||||
@ -9,6 +9,7 @@ from typing import Any, Optional, TYPE_CHECKING, Union
|
||||
|
||||
from game.commander.garrisons import Garrisons
|
||||
from game.commander.objectivefinder import ObjectiveFinder
|
||||
from game.db import GameDb
|
||||
from game.htn import WorldState
|
||||
from game.profiling import MultiEventTracer
|
||||
from game.settings import Settings
|
||||
@ -31,6 +32,7 @@ if TYPE_CHECKING:
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PersistentContext:
|
||||
game_db: GameDb
|
||||
coalition: Coalition
|
||||
theater: ConflictTheater
|
||||
turn: int
|
||||
@ -140,7 +142,7 @@ class TheaterState(WorldState["TheaterState"]):
|
||||
ordered_capturable_points = finder.prioritized_unisolated_points()
|
||||
|
||||
context = PersistentContext(
|
||||
coalition, game.theater, game.turn, game.settings, tracer
|
||||
game.db, coalition, game.theater, game.turn, game.settings, tracer
|
||||
)
|
||||
|
||||
# Plan enough rounds of CAP that the target has coverage over the expected
|
||||
|
||||
2
game/db/__init__.py
Normal file
2
game/db/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
from .database import Database
|
||||
from .gamedb import GameDb
|
||||
20
game/db/database.py
Normal file
20
game/db/database.py
Normal file
@ -0,0 +1,20 @@
|
||||
from typing import Generic, TypeVar
|
||||
from uuid import UUID
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class Database(Generic[T]):
|
||||
def __init__(self) -> None:
|
||||
self.objects: dict[UUID, T] = {}
|
||||
|
||||
def add(self, uuid: UUID, obj: T) -> None:
|
||||
if uuid in self.objects:
|
||||
raise KeyError(f"Object with UUID {uuid} already exists")
|
||||
self.objects[uuid] = obj
|
||||
|
||||
def get(self, uuid: UUID) -> T:
|
||||
return self.objects[uuid]
|
||||
|
||||
def remove(self, uuid: UUID) -> None:
|
||||
del self.objects[uuid]
|
||||
11
game/db/gamedb.py
Normal file
11
game/db/gamedb.py
Normal file
@ -0,0 +1,11 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .database import Database
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.ato import Flight
|
||||
|
||||
|
||||
class GameDb:
|
||||
def __init__(self) -> None:
|
||||
self.flights: Database[Flight] = Database()
|
||||
@ -6,7 +6,7 @@ import math
|
||||
from collections.abc import Iterator
|
||||
from datetime import date, datetime, timedelta
|
||||
from enum import Enum
|
||||
from typing import Any, List, TYPE_CHECKING, Type, TypeVar, Union, cast
|
||||
from typing import Any, List, TYPE_CHECKING, Type, Union, cast
|
||||
|
||||
from dcs.countries import Switzerland, USAFAggressors, UnitedNationsPeacekeepers
|
||||
from dcs.country import Country
|
||||
@ -25,6 +25,7 @@ from . import persistency
|
||||
from .ato.flighttype import FlightType
|
||||
from .campaignloader import CampaignAirWingConfig
|
||||
from .coalition import Coalition
|
||||
from .db.gamedb import GameDb
|
||||
from .factions.faction import Faction
|
||||
from .infos.information import Information
|
||||
from .profiling import logged_duration
|
||||
@ -115,6 +116,8 @@ class Game:
|
||||
self.current_group_id = 0
|
||||
self.name_generator = naming.namegen
|
||||
|
||||
self.db = GameDb()
|
||||
|
||||
self.conditions = self.generate_conditions()
|
||||
|
||||
self.sanitize_sides(player_faction, enemy_faction)
|
||||
|
||||
@ -140,7 +140,7 @@ class AircraftGenerator:
|
||||
# reuse the existing debriefing code.
|
||||
# TODO: Special flight type?
|
||||
flight = Flight(
|
||||
Package(squadron.location),
|
||||
Package(squadron.location, self.game.db.flights),
|
||||
faction.country,
|
||||
squadron,
|
||||
1,
|
||||
|
||||
@ -3,36 +3,22 @@ from uuid import UUID
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from game import Game
|
||||
from game.ato import Flight
|
||||
from game.server import GameContext
|
||||
from .models import HoldZonesJs, IpZonesJs, JoinZonesJs
|
||||
|
||||
router: APIRouter = APIRouter(prefix="/debug/waypoint-geometries")
|
||||
|
||||
|
||||
# TODO: Maintain map of UUID -> Flight in Game.
|
||||
def find_flight(game: Game, flight_id: UUID) -> Flight:
|
||||
for coalition in game.coalitions:
|
||||
for package in coalition.ato.packages:
|
||||
for flight in package.flights:
|
||||
if flight.id == flight_id:
|
||||
return flight
|
||||
raise KeyError(f"No flight found with ID {flight_id}")
|
||||
|
||||
|
||||
@router.get("/hold/{flight_id}")
|
||||
def hold_zones(flight_id: UUID, game: Game = Depends(GameContext.get)) -> HoldZonesJs:
|
||||
flight = find_flight(game, flight_id)
|
||||
return HoldZonesJs.for_flight(flight, game)
|
||||
return HoldZonesJs.for_flight(game.db.flights.get(flight_id), game)
|
||||
|
||||
|
||||
@router.get("/ip/{flight_id}")
|
||||
def ip_zones(flight_id: UUID, game: Game = Depends(GameContext.get)) -> IpZonesJs:
|
||||
flight = find_flight(game, flight_id)
|
||||
return IpZonesJs.for_flight(flight, game)
|
||||
return IpZonesJs.for_flight(game.db.flights.get(flight_id), game)
|
||||
|
||||
|
||||
@router.get("/join/{flight_id}")
|
||||
def join_zones(flight_id: UUID, game: Game = Depends(GameContext.get)) -> JoinZonesJs:
|
||||
flight = find_flight(game, flight_id)
|
||||
return JoinZonesJs.for_flight(flight, game)
|
||||
return JoinZonesJs.for_flight(game.db.flights.get(flight_id), game)
|
||||
|
||||
@ -12,6 +12,7 @@ from game.ato import Flight, FlightType, Package
|
||||
from game.settings import AutoAtoBehavior, Settings
|
||||
from gen.flights.flightplan import FlightPlanBuilder
|
||||
from .pilot import Pilot, PilotStatus
|
||||
from ..db.database import Database
|
||||
from ..utils import meters
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -50,6 +51,7 @@ class Squadron:
|
||||
)
|
||||
|
||||
coalition: Coalition = field(hash=False, compare=False)
|
||||
flight_db: Database[Flight] = field(hash=False, compare=False)
|
||||
settings: Settings = field(hash=False, compare=False)
|
||||
|
||||
location: ControlPoint
|
||||
@ -388,7 +390,7 @@ class Squadron:
|
||||
if not remaining:
|
||||
return
|
||||
|
||||
package = Package(self.destination)
|
||||
package = Package(self.destination, self.flight_db)
|
||||
builder = FlightPlanBuilder(package, self.coalition, theater)
|
||||
while remaining:
|
||||
size = min(remaining, self.aircraft.max_group_size)
|
||||
@ -437,6 +439,7 @@ class Squadron:
|
||||
squadron_def.female_pilot_percentage,
|
||||
squadron_def.pilot_pool,
|
||||
coalition,
|
||||
game.db.flights,
|
||||
game.settings,
|
||||
base,
|
||||
)
|
||||
|
||||
@ -36,18 +36,13 @@ import math
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from functools import singledispatchmethod
|
||||
from typing import (
|
||||
Generic,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
TYPE_CHECKING,
|
||||
TypeVar,
|
||||
Sequence,
|
||||
)
|
||||
from typing import Generic, Iterator, List, Optional, Sequence, TYPE_CHECKING, TypeVar
|
||||
|
||||
from dcs.mapping import Point
|
||||
|
||||
from game.ato.flight import Flight
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.ato.package import Package
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.dcs.groundunittype import GroundUnitType
|
||||
from game.procurement import AircraftProcurementRequest
|
||||
@ -57,11 +52,8 @@ from game.theater.transitnetwork import (
|
||||
TransitNetwork,
|
||||
)
|
||||
from game.utils import meters, nautical_miles
|
||||
from game.ato.package import Package
|
||||
from gen.flights.ai_flight_planner_db import aircraft_for_task
|
||||
from gen.flights.closestairfields import ObjectiveDistanceCache
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.ato.flight import Flight
|
||||
from gen.flights.flightplan import FlightPlanBuilder
|
||||
from gen.naming import namegen
|
||||
|
||||
@ -271,7 +263,7 @@ class AirliftPlanner:
|
||||
self.transfer = transfer
|
||||
self.next_stop = next_stop
|
||||
self.for_player = transfer.destination.captured
|
||||
self.package = Package(target=next_stop, auto_asap=True)
|
||||
self.package = Package(next_stop, game.db.flights, auto_asap=True)
|
||||
|
||||
def compatible_with_mission(
|
||||
self, unit_type: AircraftType, airfield: ControlPoint
|
||||
|
||||
@ -15,10 +15,10 @@ from PySide2.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
from game.ato.flight import Flight
|
||||
from game.ato.package import Package
|
||||
from game.game import Game
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.ato.package import Package
|
||||
from game.ato.flight import Flight
|
||||
from gen.flights.flightplan import FlightPlanBuilder, PlanningError
|
||||
from qt_ui.models import AtoModel, GameModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
@ -215,7 +215,9 @@ class QNewPackageDialog(QPackageDialog):
|
||||
) -> None:
|
||||
super().__init__(
|
||||
game_model,
|
||||
PackageModel(Package(target, auto_asap=True), game_model),
|
||||
PackageModel(
|
||||
Package(target, game_model.game.db.flights, auto_asap=True), game_model
|
||||
),
|
||||
parent=parent,
|
||||
)
|
||||
self.ato_model = model
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user