Move threat zones out of MapModel.

This commit is contained in:
Dan Albert 2022-02-22 19:59:29 -08:00
parent 1c543666b5
commit b1356551c6
10 changed files with 62 additions and 142 deletions

View File

@ -119,8 +119,9 @@ class Coalition:
def adjust_budget(self, amount: float) -> None:
self.budget += amount
def compute_threat_zones(self) -> None:
def compute_threat_zones(self, events: GameUpdateEvents) -> None:
self._threat_zone = ThreatZones.for_faction(self.game, self.player)
events.update_threat_zones()
def compute_nav_meshes(self, events: GameUpdateEvents) -> None:
self._navmesh = NavMesh.from_threat_zones(

View File

@ -421,8 +421,8 @@ class Game:
return TransitNetworkBuilder(self.theater, player).build()
def compute_threat_zones(self, events: GameUpdateEvents) -> None:
self.blue.compute_threat_zones()
self.red.compute_threat_zones()
self.blue.compute_threat_zones(events)
self.red.compute_threat_zones(events)
self.blue.compute_nav_meshes(events)
self.red.compute_nav_meshes(events)

View File

@ -19,6 +19,7 @@ class GameUpdateEventsJs(BaseModel):
updated_combats: list[FrozenCombatJs] = []
navmesh_updates: set[bool] = set()
unculled_zones_updated: bool = False
threat_zones_updated: bool = False
@classmethod
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
@ -35,4 +36,5 @@ class GameUpdateEventsJs(BaseModel):
],
navmesh_updates=events.navmesh_updates,
unculled_zones_updated=events.unculled_zones_updated,
threat_zones_updated=events.threat_zones_updated,
)

View File

@ -3,7 +3,9 @@ from __future__ import annotations
from dcs.mapping import LatLng
from pydantic import BaseModel
from game.server.leaflet import LeafletPoly
from game.server.leaflet import LeafletPoly, ShapelyUtil
from game.theater import ConflictTheater
from game.threatzones import ThreatZones
class MapZonesJs(BaseModel):
@ -15,3 +17,24 @@ class MapZonesJs(BaseModel):
class UnculledZoneJs(BaseModel):
position: LatLng
radius: float
class ThreatZonesJs(BaseModel):
full: list[LeafletPoly]
aircraft: list[LeafletPoly]
air_defenses: list[LeafletPoly]
radar_sams: list[LeafletPoly]
@classmethod
def from_zones(cls, zones: ThreatZones, theater: ConflictTheater) -> ThreatZonesJs:
return ThreatZonesJs(
full=ShapelyUtil.polys_to_leaflet(zones.all, theater),
aircraft=ShapelyUtil.polys_to_leaflet(zones.airbases, theater),
air_defenses=ShapelyUtil.polys_to_leaflet(zones.air_defenses, theater),
radar_sams=ShapelyUtil.polys_to_leaflet(zones.radar_sam_threats, theater),
)
class ThreatZoneContainerJs(BaseModel):
blue: ThreatZonesJs
red: ThreatZonesJs

View File

@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
from game import Game
from game.server import GameContext
from .models import MapZonesJs, UnculledZoneJs
from .models import MapZonesJs, ThreatZoneContainerJs, ThreatZonesJs, UnculledZoneJs
from ..leaflet import ShapelyUtil
router: APIRouter = APIRouter(prefix="/map-zones")
@ -29,3 +29,11 @@ def get_unculled_zones(game: Game = Depends(GameContext.get)) -> list[UnculledZo
)
for zone in game.get_culling_zones()
]
@router.get("/threats")
def get_threat_zones(game: Game = Depends(GameContext.get)) -> ThreatZoneContainerJs:
return ThreatZoneContainerJs(
blue=ThreatZonesJs.from_zones(game.threat_zone_for(player=True), game.theater),
red=ThreatZonesJs.from_zones(game.threat_zone_for(player=False), game.theater),
)

View File

@ -17,6 +17,7 @@ class GameUpdateEvents:
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
@property
def empty(self) -> bool:
@ -28,6 +29,7 @@ class GameUpdateEvents:
self.updated_flights,
self.navmesh_updates,
self.unculled_zones_updated,
self.threat_zones_updated,
]
)
@ -48,3 +50,6 @@ class GameUpdateEvents:
def update_unculled_zones(self) -> None:
self.unculled_zones_updated = True
def update_threat_zones(self) -> None:
self.threat_zones_updated = True

View File

@ -21,8 +21,6 @@ from .flightjs import FlightJs
from .frontlinejs import FrontLineJs
from .groundobjectjs import GroundObjectJs
from .supplyroutejs import SupplyRouteJs
from .threatzonecontainerjs import ThreatZoneContainerJs
from .threatzonesjs import ThreatZonesJs
# **EVERY PROPERTY NEEDS A NOTIFY SIGNAL**
@ -51,7 +49,6 @@ class MapModel(QObject):
supplyRoutesChanged = Signal()
flightsChanged = Signal()
frontLinesChanged = Signal()
threatZonesChanged = Signal()
selectedFlightChanged = Signal(str)
def __init__(self, game_model: GameModel) -> None:
@ -63,9 +60,7 @@ class MapModel(QObject):
self._supply_routes = []
self._flights: dict[tuple[bool, int, int], FlightJs] = {}
self._front_lines = []
self._threat_zones = ThreatZoneContainerJs(
ThreatZonesJs.empty(), ThreatZonesJs.empty()
)
self._selected_flight_index: Optional[Tuple[int, int]] = None
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
@ -84,9 +79,6 @@ class MapModel(QObject):
self._ground_objects = []
self._flights = {}
self._front_lines = []
self._threat_zones = ThreatZoneContainerJs(
ThreatZonesJs.empty(), ThreatZonesJs.empty()
)
self.cleared.emit()
def set_package_selection(self, index: int) -> None:
@ -149,7 +141,6 @@ class MapModel(QObject):
self.reset_routes()
self.reset_atos()
self.reset_front_lines()
self.reset_threat_zones()
def on_game_load(self, game: Optional[Game]) -> None:
if game is not None:
@ -266,21 +257,6 @@ class MapModel(QObject):
def frontLines(self) -> List[FrontLineJs]:
return self._front_lines
def reset_threat_zones(self) -> None:
self._threat_zones = ThreatZoneContainerJs(
ThreatZonesJs.from_zones(
self.game.threat_zone_for(player=True), self.game.theater
),
ThreatZonesJs.from_zones(
self.game.threat_zone_for(player=False), self.game.theater
),
)
self.threatZonesChanged.emit()
@Property(ThreatZoneContainerJs, notify=threatZonesChanged)
def threatZones(self) -> ThreatZoneContainerJs:
return self._threat_zones
@property
def game(self) -> Game:
if self.game_model.game is None:

View File

@ -1,23 +0,0 @@
from __future__ import annotations
from PySide2.QtCore import Property, QObject, Signal
from .threatzonesjs import ThreatZonesJs
class ThreatZoneContainerJs(QObject):
blueChanged = Signal()
redChanged = Signal()
def __init__(self, blue: ThreatZonesJs, red: ThreatZonesJs) -> None:
super().__init__()
self._blue = blue
self._red = red
@Property(ThreatZonesJs, notify=blueChanged)
def blue(self) -> ThreatZonesJs:
return self._blue
@Property(ThreatZonesJs, notify=redChanged)
def red(self) -> ThreatZonesJs:
return self._red

View File

@ -1,56 +0,0 @@
from __future__ import annotations
from PySide2.QtCore import Property, QObject, Signal
from game.server.leaflet import LeafletPoly, ShapelyUtil
from game.theater import ConflictTheater
from game.threatzones import ThreatZones
class ThreatZonesJs(QObject):
fullChanged = Signal()
aircraftChanged = Signal()
airDefensesChanged = Signal()
radarSamsChanged = Signal()
def __init__(
self,
full: list[LeafletPoly],
aircraft: list[LeafletPoly],
air_defenses: list[LeafletPoly],
radar_sams: list[LeafletPoly],
) -> None:
super().__init__()
self._full = full
self._aircraft = aircraft
self._air_defenses = air_defenses
self._radar_sams = radar_sams
@Property(list, notify=fullChanged)
def full(self) -> list[LeafletPoly]:
return self._full
@Property(list, notify=aircraftChanged)
def aircraft(self) -> list[LeafletPoly]:
return self._aircraft
@Property(list, notify=airDefensesChanged)
def airDefenses(self) -> list[LeafletPoly]:
return self._air_defenses
@Property(list, notify=radarSamsChanged)
def radarSams(self) -> list[LeafletPoly]:
return self._radar_sams
@classmethod
def from_zones(cls, zones: ThreatZones, theater: ConflictTheater) -> ThreatZonesJs:
return ThreatZonesJs(
ShapelyUtil.polys_to_leaflet(zones.all, theater),
ShapelyUtil.polys_to_leaflet(zones.airbases, theater),
ShapelyUtil.polys_to_leaflet(zones.air_defenses, theater),
ShapelyUtil.polys_to_leaflet(zones.radar_sam_threats, theater),
)
@classmethod
def empty(cls) -> ThreatZonesJs:
return ThreatZonesJs([], [], [], [])

View File

@ -383,7 +383,6 @@ new QWebChannel(qt.webChannelTransport, function (channel) {
game.supplyRoutesChanged.connect(drawSupplyRoutes);
game.frontLinesChanged.connect(drawFrontLines);
game.flightsChanged.connect(drawAircraft);
game.threatZonesChanged.connect(drawThreatZones);
game.mapZonesChanged.connect(drawMapZones);
game.selectedFlightChanged.connect(updateSelectedFlight);
});
@ -404,6 +403,9 @@ function handleStreamedEvents(events) {
if (events.unculled_zones_updated) {
drawUnculledZones();
}
if (events.threat_zones_updated) {
drawThreatZones();
}
}
function recenterMap(center) {
@ -1063,39 +1065,21 @@ function drawThreatZones() {
redAirDefenseThreatZones.clearLayers();
redRadarSamThreatZones.clearLayers();
_drawThreatZones(game.threatZones.blue.full, blueFullThreatZones, true);
_drawThreatZones(
game.threatZones.blue.aircraft,
blueAircraftThreatZones,
true
);
_drawThreatZones(
game.threatZones.blue.airDefenses,
blueAirDefenseThreatZones,
true
);
_drawThreatZones(
game.threatZones.blue.radarSams,
blueRadarSamThreatZones,
true
);
getJson("/map-zones/threats").then((threats) => {
_drawThreatZones(threats.blue.full, blueFullThreatZones, true);
_drawThreatZones(threats.blue.aircraft, blueAircraftThreatZones, true);
_drawThreatZones(
threats.blue.air_defenses,
blueAirDefenseThreatZones,
true
);
_drawThreatZones(threats.blue.radar_sams, blueRadarSamThreatZones, true);
_drawThreatZones(game.threatZones.red.full, redFullThreatZones, false);
_drawThreatZones(
game.threatZones.red.aircraft,
redAircraftThreatZones,
false
);
_drawThreatZones(
game.threatZones.red.airDefenses,
redAirDefenseThreatZones,
false
);
_drawThreatZones(
game.threatZones.red.radarSams,
redRadarSamThreatZones,
false
);
_drawThreatZones(threats.red.full, redFullThreatZones, false);
_drawThreatZones(threats.red.aircraft, redAircraftThreatZones, false);
_drawThreatZones(threats.red.air_defenses, redAirDefenseThreatZones, false);
_drawThreatZones(threats.red.radar_sams, redRadarSamThreatZones, false);
});
}
function drawNavmesh(player) {