Move FlightJs out of MapModel.

This commit is contained in:
Dan Albert
2022-02-22 20:40:58 -08:00
parent ad0d3412fb
commit 45e76e12b6
18 changed files with 333 additions and 326 deletions

View File

@@ -17,8 +17,13 @@ class AirTaskingOrder:
def remove_package(self, package: Package) -> None:
"""Removes a package from the ATO."""
# Remove all the flights individually so the database gets updated.
for flight in list(package.flights):
package.remove_flight(flight)
self.packages.remove(package)
def clear(self) -> None:
"""Removes all packages from the ATO."""
self.packages.clear()
# Remove all packages individually so the database gets updated.
for package in self.packages:
self.remove_package(package)

View File

@@ -22,7 +22,7 @@ class Navigating(InFlight):
self, events: GameUpdateEvents, time: datetime, duration: timedelta
) -> None:
super().on_game_tick(events, time, duration)
events.update_flight(self.flight, self.estimate_position())
events.update_flight_position(self.flight, self.estimate_position())
def progress(self) -> float:
return (

View File

@@ -129,6 +129,9 @@ class Package:
"""Removes a flight from the package."""
self.flights.remove(flight)
self._db.remove(flight.id)
flight.return_pilots_and_aircraft()
if flight.cargo is not None:
flight.cargo.transport = None
if not self.flights:
self.waypoints = None

View File

@@ -92,5 +92,4 @@ class PackageBuilder:
"""Returns any planned flights to the inventory."""
flights = list(self.package.flights)
for flight in flights:
flight.return_pilots_and_aircraft()
self.package.remove_flight(flight)

View File

@@ -6,6 +6,7 @@ from uuid import UUID
from pydantic import BaseModel
from game.server.combat.models import FrozenCombatJs
from game.server.flights.models import FlightJs
from game.server.leaflet import LeafletLatLon
if TYPE_CHECKING:
@@ -14,18 +15,24 @@ if TYPE_CHECKING:
class GameUpdateEventsJs(BaseModel):
updated_flights: dict[UUID, LeafletLatLon]
new_combats: list[FrozenCombatJs] = []
updated_combats: list[FrozenCombatJs] = []
navmesh_updates: set[bool] = set()
unculled_zones_updated: bool = False
threat_zones_updated: bool = False
updated_flight_positions: dict[UUID, LeafletLatLon]
new_combats: list[FrozenCombatJs]
updated_combats: list[FrozenCombatJs]
navmesh_updates: set[bool]
unculled_zones_updated: bool
threat_zones_updated: bool
new_flights: list[FlightJs]
updated_flights: set[UUID]
deleted_flights: set[UUID]
selected_flight: UUID | None
deselected_flight: bool
@classmethod
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
return GameUpdateEventsJs(
updated_flights={
f[0].id: f[1].latlng().as_list() for f in events.updated_flights
updated_flight_positions={
f[0].id: f[1].latlng().as_list()
for f in events.updated_flight_positions
},
new_combats=[
FrozenCombatJs.for_combat(c, game.theater) for c in events.new_combats
@@ -37,4 +44,9 @@ class GameUpdateEventsJs(BaseModel):
navmesh_updates=events.navmesh_updates,
unculled_zones_updated=events.unculled_zones_updated,
threat_zones_updated=events.threat_zones_updated,
new_flights=[FlightJs.for_flight(f) for f in events.new_flights],
updated_flights=events.updated_flights,
deleted_flights=events.deleted_flights,
selected_flight=events.selected_flight,
deselected_flight=events.deselected_flight,
)

View File

@@ -0,0 +1,26 @@
from __future__ import annotations
from uuid import UUID
from dcs.mapping import LatLng
from pydantic import BaseModel
from game.ato import Flight
from game.ato.flightstate import InFlight
class FlightJs(BaseModel):
id: UUID
blue: bool
position: LatLng | None
@staticmethod
def for_flight(flight: Flight) -> FlightJs:
# Don't provide a location for aircraft that aren't in the air. Later we can
# expand the model to include the state data for the UI so that it can make its
# own decisions about whether or not to draw the aircraft, but for now we'll
# filter here.
position = None
if isinstance(flight.state, InFlight):
position = flight.position().latlng()
return FlightJs(id=flight.id, blue=flight.blue, position=position)

View File

@@ -4,13 +4,30 @@ from fastapi import APIRouter, Depends
from shapely.geometry import LineString, Point as ShapelyPoint
from game import Game
from game.server import GameContext
from game.server.leaflet import LeafletPoly, ShapelyUtil
from game.ato.flightplan import CasFlightPlan, PatrollingFlightPlan
from game.server import GameContext
from game.server.flights.models import FlightJs
from game.server.leaflet import LeafletPoly, ShapelyUtil
router: APIRouter = APIRouter(prefix="/flights")
@router.get("/")
def list_flights(game: Game = Depends(GameContext.get)) -> list[FlightJs]:
flights = []
for coalition in game.coalitions:
for package in coalition.ato.packages:
for flight in package.flights:
flights.append(FlightJs.for_flight(flight))
return flights
@router.get("/{flight_id}")
def get_flight(flight_id: UUID, game: Game = Depends(GameContext.get)) -> FlightJs:
flight = game.db.flights.get(flight_id)
return FlightJs.for_flight(flight)
@router.get("/{flight_id}/commit-boundary")
def commit_boundary(
flight_id: UUID, game: Game = Depends(GameContext.get)

View File

@@ -1,55 +1,91 @@
from __future__ import annotations
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
from uuid import UUID
from dcs import Point
if TYPE_CHECKING:
from game.ato import Flight
from game.ato import Flight, Package
from game.sim.combat import FrozenCombat
@dataclass
class GameUpdateEvents:
def __init__(self) -> None:
self.simulation_complete = False
self.new_combats: list[FrozenCombat] = []
self.updated_combats: list[FrozenCombat] = []
self.updated_flights: list[tuple[Flight, Point]] = []
self.navmesh_updates: set[bool] = set()
self.unculled_zones_updated: bool = False
self.threat_zones_updated: bool = False
simulation_complete = False
new_combats: list[FrozenCombat] = field(default_factory=list)
updated_combats: list[FrozenCombat] = field(default_factory=list)
updated_flight_positions: list[tuple[Flight, Point]] = field(default_factory=list)
navmesh_updates: set[bool] = field(default_factory=set)
unculled_zones_updated: bool = False
threat_zones_updated: bool = False
new_flights: set[Flight] = field(default_factory=set)
updated_flights: set[UUID] = field(default_factory=set)
deleted_flights: set[UUID] = field(default_factory=set)
selected_flight: UUID | None = None
deselected_flight: bool = False
@property
def empty(self) -> bool:
return not any(
[
self.simulation_complete,
self.new_combats,
self.updated_combats,
self.updated_flights,
self.navmesh_updates,
self.unculled_zones_updated,
self.threat_zones_updated,
]
)
return self == GameUpdateEvents()
def complete_simulation(self) -> None:
def complete_simulation(self) -> GameUpdateEvents:
self.simulation_complete = True
return self
def new_combat(self, combat: FrozenCombat) -> None:
def new_combat(self, combat: FrozenCombat) -> GameUpdateEvents:
self.new_combats.append(combat)
return self
def update_combat(self, combat: FrozenCombat) -> None:
def update_combat(self, combat: FrozenCombat) -> GameUpdateEvents:
self.updated_combats.append(combat)
return self
def update_flight(self, flight: Flight, new_position: Point) -> None:
self.updated_flights.append((flight, new_position))
def update_flight_position(
self, flight: Flight, new_position: Point
) -> GameUpdateEvents:
self.updated_flight_positions.append((flight, new_position))
return self
def update_navmesh(self, player: bool) -> None:
def update_navmesh(self, player: bool) -> GameUpdateEvents:
self.navmesh_updates.add(player)
return self
def update_unculled_zones(self) -> None:
def update_unculled_zones(self) -> GameUpdateEvents:
self.unculled_zones_updated = True
return self
def update_threat_zones(self) -> None:
def update_threat_zones(self) -> GameUpdateEvents:
self.threat_zones_updated = True
return self
def new_flight(self, flight: Flight) -> GameUpdateEvents:
self.new_flights.add(flight)
return self
def update_flight(self, flight: Flight) -> GameUpdateEvents:
self.updated_flights.add(flight.id)
return self
def update_flights_in_package(self, package: Package) -> GameUpdateEvents:
self.updated_flights.update({f.id for f in package.flights})
return self
def delete_flight(self, flight: Flight) -> GameUpdateEvents:
self.deleted_flights.add(flight.id)
return self
def delete_flights_in_package(self, package: Package) -> GameUpdateEvents:
self.deleted_flights.update({f.id for f in package.flights})
return self
def select_flight(self, flight: Flight) -> GameUpdateEvents:
self.selected_flight = flight.id
self.deselected_flight = False
return self
def deselect_flight(self) -> GameUpdateEvents:
self.deselected_flight = True
self.selected_flight = None
return self

View File

@@ -9,8 +9,8 @@ from typing import Optional, Sequence, TYPE_CHECKING
from faker import Faker
from game.ato import Flight, FlightType, Package
from game.settings import AutoAtoBehavior, Settings
from game.ato.flightplan import FlightPlanBuilder
from game.settings import AutoAtoBehavior, Settings
from .pilot import Pilot, PilotStatus
from ..db.database import Database
from ..utils import meters
@@ -381,7 +381,6 @@ class Squadron:
for flight in list(package.flights):
if flight.squadron == self and flight.flight_type is FlightType.FERRY:
package.remove_flight(flight)
flight.return_pilots_and_aircraft()
if not package.flights:
self.coalition.ato.remove_package(package)

View File

@@ -40,7 +40,10 @@ from typing import Generic, Iterator, List, Optional, Sequence, TYPE_CHECKING, T
from dcs.mapping import Point
from game.ato.ai_flight_planner_db import aircraft_for_task
from game.ato.closestairfields import ObjectiveDistanceCache
from game.ato.flight import Flight
from game.ato.flightplan import FlightPlanBuilder
from game.ato.flighttype import FlightType
from game.ato.package import Package
from game.dcs.aircrafttype import AircraftType
@@ -53,9 +56,6 @@ from game.theater.transitnetwork import (
TransitNetwork,
)
from game.utils import meters, nautical_miles
from game.ato.ai_flight_planner_db import aircraft_for_task
from game.ato.closestairfields import ObjectiveDistanceCache
from game.ato.flightplan import FlightPlanBuilder
if TYPE_CHECKING:
from game import Game
@@ -635,7 +635,6 @@ class PendingTransfers:
flight.package.remove_flight(flight)
if not flight.package.flights:
self.game.ato_for(self.player).remove_package(flight.package)
flight.return_pilots_and_aircraft()
@cancel_transport.register
def _cancel_transport_convoy(