mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Move frozen combat handling out of MapModel.
This commit is contained in:
@@ -4,6 +4,7 @@ import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, List, Optional, TYPE_CHECKING
|
||||
|
||||
from dcs import Point
|
||||
from dcs.planes import C_101CC, C_101EB, Su_33
|
||||
|
||||
from gen.flights.loadouts import Loadout
|
||||
@@ -125,6 +126,9 @@ class Flight:
|
||||
def points(self) -> List[FlightWaypoint]:
|
||||
return self.flight_plan.waypoints[1:]
|
||||
|
||||
def position(self) -> Point:
|
||||
return self.state.estimate_position()
|
||||
|
||||
def resize(self, new_size: int) -> None:
|
||||
self.squadron.claim_inventory(new_size - self.count)
|
||||
self.roster.resize(new_size)
|
||||
|
||||
10
game/ato/flightstate/atdeparture.py
Normal file
10
game/ato/flightstate/atdeparture.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from abc import ABC
|
||||
|
||||
from dcs import Point
|
||||
|
||||
from game.ato.flightstate import FlightState
|
||||
|
||||
|
||||
class AtDeparture(FlightState, ABC):
|
||||
def estimate_position(self) -> Point:
|
||||
return self.flight.departure.position
|
||||
@@ -3,6 +3,8 @@ from __future__ import annotations
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from dcs import Point
|
||||
|
||||
from .flightstate import FlightState
|
||||
from ..starttype import StartType
|
||||
|
||||
@@ -20,6 +22,9 @@ class Completed(FlightState):
|
||||
def is_waiting_for_start(self) -> bool:
|
||||
return False
|
||||
|
||||
def estimate_position(self) -> Point:
|
||||
return self.flight.arrival.position
|
||||
|
||||
@property
|
||||
def spawn_type(self) -> StartType:
|
||||
# TODO: May want to do something different to make these uncontrolled?
|
||||
|
||||
@@ -4,6 +4,8 @@ from abc import ABC, abstractmethod
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from dcs import Point
|
||||
|
||||
from game.ato.starttype import StartType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -44,6 +46,10 @@ class FlightState(ABC):
|
||||
def is_waiting_for_start(self) -> bool:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def estimate_position(self) -> Point:
|
||||
...
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def spawn_type(self) -> StartType:
|
||||
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .flightstate import FlightState
|
||||
from .atdeparture import AtDeparture
|
||||
from .taxi import Taxi
|
||||
from ..starttype import StartType
|
||||
|
||||
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
|
||||
|
||||
class StartUp(FlightState):
|
||||
class StartUp(AtDeparture):
|
||||
def __init__(self, flight: Flight, settings: Settings, now: datetime) -> None:
|
||||
super().__init__(flight, settings)
|
||||
self.completion_time = now + flight.flight_plan.estimate_startup()
|
||||
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .flightstate import FlightState
|
||||
from .atdeparture import AtDeparture
|
||||
from .navigating import Navigating
|
||||
from ..starttype import StartType
|
||||
from ...utils import LBS_TO_KG
|
||||
@@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
|
||||
|
||||
class Takeoff(FlightState):
|
||||
class Takeoff(AtDeparture):
|
||||
def __init__(self, flight: Flight, settings: Settings, now: datetime) -> None:
|
||||
super().__init__(flight, settings)
|
||||
# TODO: Not accounted for in FlightPlan, can cause discrepancy without loiter.
|
||||
|
||||
@@ -4,7 +4,7 @@ import logging
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .flightstate import FlightState
|
||||
from .atdeparture import AtDeparture
|
||||
from .takeoff import Takeoff
|
||||
from ..starttype import StartType
|
||||
|
||||
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
|
||||
|
||||
class Taxi(FlightState):
|
||||
class Taxi(AtDeparture):
|
||||
def __init__(self, flight: Flight, settings: Settings, now: datetime) -> None:
|
||||
super().__init__(flight, settings)
|
||||
self.completion_time = now + flight.flight_plan.estimate_ground_ops()
|
||||
|
||||
@@ -3,6 +3,8 @@ from __future__ import annotations
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from dcs import Point
|
||||
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
from .flightstate import FlightState
|
||||
from ..starttype import StartType
|
||||
@@ -21,6 +23,9 @@ class Uninitialized(FlightState):
|
||||
def is_waiting_for_start(self) -> bool:
|
||||
raise RuntimeError("Attempted to simulate flight that is not fully initialized")
|
||||
|
||||
def estimate_position(self) -> Point:
|
||||
raise RuntimeError("Attempted to simulate flight that is not fully initialized")
|
||||
|
||||
@property
|
||||
def spawn_type(self) -> StartType:
|
||||
raise RuntimeError("Attempted to simulate flight that is not fully initialized")
|
||||
|
||||
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from game.ato.starttype import StartType
|
||||
from .atdeparture import AtDeparture
|
||||
from .flightstate import FlightState
|
||||
from .navigating import Navigating
|
||||
from .startup import StartUp
|
||||
@@ -16,7 +17,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
|
||||
|
||||
class WaitingForStart(FlightState):
|
||||
class WaitingForStart(AtDeparture):
|
||||
def __init__(
|
||||
self,
|
||||
flight: Flight,
|
||||
|
||||
0
game/server/combat/__init__.py
Normal file
0
game/server/combat/__init__.py
Normal file
49
game/server/combat/models.py
Normal file
49
game/server/combat/models.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from game.server.leaflet import LeafletLatLon, LeafletPoly, ShapelyUtil
|
||||
from game.sim.combat import FrozenCombat
|
||||
from game.sim.combat.aircombat import AirCombat
|
||||
from game.sim.combat.atip import AtIp
|
||||
from game.sim.combat.defendingsam import DefendingSam
|
||||
from game.theater import ConflictTheater
|
||||
|
||||
|
||||
class FrozenCombatJs(BaseModel):
|
||||
id: UUID
|
||||
flight_position: LeafletLatLon | None
|
||||
target_positions: list[LeafletLatLon] | None
|
||||
footprint: list[LeafletPoly] | None
|
||||
|
||||
@staticmethod
|
||||
def for_combat(combat: FrozenCombat, theater: ConflictTheater) -> FrozenCombatJs:
|
||||
if isinstance(combat, AirCombat):
|
||||
return FrozenCombatJs(
|
||||
id=combat.id,
|
||||
flight_position=None,
|
||||
target_positions=None,
|
||||
footprint=ShapelyUtil.polys_to_leaflet(combat.footprint, theater),
|
||||
)
|
||||
if isinstance(combat, AtIp):
|
||||
return FrozenCombatJs(
|
||||
id=combat.id,
|
||||
flight_position=theater.point_to_ll(combat.flight.position()).as_list(),
|
||||
target_positions=[
|
||||
theater.point_to_ll(combat.flight.package.target.position).as_list()
|
||||
],
|
||||
footprint=None,
|
||||
)
|
||||
if isinstance(combat, DefendingSam):
|
||||
return FrozenCombatJs(
|
||||
id=combat.id,
|
||||
flight_position=theater.point_to_ll(combat.flight.position()).as_list(),
|
||||
target_positions=[
|
||||
theater.point_to_ll(sam.position).as_list()
|
||||
for sam in combat.air_defenses
|
||||
],
|
||||
footprint=None,
|
||||
)
|
||||
raise NotImplementedError(f"Unhandled FrozenCombat type: {combat.__class__}")
|
||||
@@ -5,6 +5,7 @@ from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from game.server.combat.models import FrozenCombatJs
|
||||
from game.server.leaflet import LeafletLatLon
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -14,6 +15,8 @@ if TYPE_CHECKING:
|
||||
|
||||
class GameUpdateEventsJs(BaseModel):
|
||||
updated_flights: dict[UUID, LeafletLatLon]
|
||||
new_combats: list[FrozenCombatJs] = []
|
||||
updated_combats: list[FrozenCombatJs] = []
|
||||
|
||||
@classmethod
|
||||
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
|
||||
@@ -21,5 +24,12 @@ class GameUpdateEventsJs(BaseModel):
|
||||
updated_flights={
|
||||
f[0].id: game.theater.point_to_ll(f[1]).as_list()
|
||||
for f in events.updated_flights
|
||||
}
|
||||
},
|
||||
new_combats=[
|
||||
FrozenCombatJs.for_combat(c, game.theater) for c in events.new_combats
|
||||
],
|
||||
updated_combats=[
|
||||
FrozenCombatJs.for_combat(c, game.theater)
|
||||
for c in events.updated_combats
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Iterator
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -11,6 +12,9 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class FrozenCombat(ABC):
|
||||
def __init__(self) -> None:
|
||||
self.id = uuid.uuid4()
|
||||
|
||||
@abstractmethod
|
||||
def because(self) -> str:
|
||||
...
|
||||
|
||||
Reference in New Issue
Block a user