Move unculled zones out of MapModel.

This commit is contained in:
Dan Albert 2022-02-22 19:37:43 -08:00
parent 95836a217c
commit 1c543666b5
8 changed files with 45 additions and 70 deletions

View File

@ -18,6 +18,7 @@ class GameUpdateEventsJs(BaseModel):
new_combats: list[FrozenCombatJs] = [] new_combats: list[FrozenCombatJs] = []
updated_combats: list[FrozenCombatJs] = [] updated_combats: list[FrozenCombatJs] = []
navmesh_updates: set[bool] = set() navmesh_updates: set[bool] = set()
unculled_zones_updated: bool = False
@classmethod @classmethod
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs: def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
@ -33,4 +34,5 @@ class GameUpdateEventsJs(BaseModel):
for c in events.updated_combats for c in events.updated_combats
], ],
navmesh_updates=events.navmesh_updates, navmesh_updates=events.navmesh_updates,
unculled_zones_updated=events.unculled_zones_updated,
) )

View File

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
from dcs.mapping import LatLng
from pydantic import BaseModel from pydantic import BaseModel
from game.server.leaflet import LeafletPoly from game.server.leaflet import LeafletPoly
@ -9,3 +10,8 @@ class MapZonesJs(BaseModel):
inclusion: list[LeafletPoly] inclusion: list[LeafletPoly]
exclusion: list[LeafletPoly] exclusion: list[LeafletPoly]
sea: list[LeafletPoly] sea: list[LeafletPoly]
class UnculledZoneJs(BaseModel):
position: LatLng
radius: float

View File

@ -2,14 +2,14 @@ from fastapi import APIRouter, Depends, HTTPException, status
from game import Game from game import Game
from game.server import GameContext from game.server import GameContext
from .models import MapZonesJs from .models import MapZonesJs, UnculledZoneJs
from ..leaflet import ShapelyUtil from ..leaflet import ShapelyUtil
router: APIRouter = APIRouter(prefix="/map-zones") router: APIRouter = APIRouter(prefix="/map-zones")
@router.get("/") @router.get("/terrain")
def get(game: Game = Depends(GameContext.get)) -> MapZonesJs: def get_terrain(game: Game = Depends(GameContext.get)) -> MapZonesJs:
zones = game.theater.landmap zones = game.theater.landmap
if zones is None: if zones is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
@ -19,3 +19,13 @@ def get(game: Game = Depends(GameContext.get)) -> MapZonesJs:
exclusion=ShapelyUtil.polys_to_leaflet(zones.exclusion_zones, game.theater), exclusion=ShapelyUtil.polys_to_leaflet(zones.exclusion_zones, game.theater),
sea=ShapelyUtil.polys_to_leaflet(zones.sea_zones, game.theater), sea=ShapelyUtil.polys_to_leaflet(zones.sea_zones, game.theater),
) )
@router.get("/unculled")
def get_unculled_zones(game: Game = Depends(GameContext.get)) -> list[UnculledZoneJs]:
return [
UnculledZoneJs(
position=zone.latlng(), radius=game.settings.perf_culling_distance * 1000
)
for zone in game.get_culling_zones()
]

View File

@ -16,6 +16,7 @@ class GameUpdateEvents:
self.updated_combats: list[FrozenCombat] = [] self.updated_combats: list[FrozenCombat] = []
self.updated_flights: list[tuple[Flight, Point]] = [] self.updated_flights: list[tuple[Flight, Point]] = []
self.navmesh_updates: set[bool] = set() self.navmesh_updates: set[bool] = set()
self.unculled_zones_updated: bool = False
@property @property
def empty(self) -> bool: def empty(self) -> bool:
@ -26,6 +27,7 @@ class GameUpdateEvents:
self.updated_combats, self.updated_combats,
self.updated_flights, self.updated_flights,
self.navmesh_updates, self.navmesh_updates,
self.unculled_zones_updated,
] ]
) )
@ -43,3 +45,6 @@ class GameUpdateEvents:
def update_navmesh(self, player: bool) -> None: def update_navmesh(self, player: bool) -> None:
self.navmesh_updates.add(player) self.navmesh_updates.add(player)
def update_unculled_zones(self) -> None:
self.unculled_zones_updated = True

View File

@ -16,12 +16,13 @@ from game.ato.airtaaskingorder import AirTaskingOrder
from game.ato.flight import Flight from game.ato.flight import Flight
from game.ato.flighttype import FlightType from game.ato.flighttype import FlightType
from game.ato.package import Package from game.ato.package import Package
from game.ato.traveltime import TotEstimator
from game.game import Game from game.game import Game
from game.server import EventStream
from game.sim.gameupdateevents import GameUpdateEvents from game.sim.gameupdateevents import GameUpdateEvents
from game.squadrons.squadron import Pilot, Squadron from game.squadrons.squadron import Pilot, Squadron
from game.theater.missiontarget import MissionTarget from game.theater.missiontarget import MissionTarget
from game.transfers import PendingTransfers, TransferOrder from game.transfers import PendingTransfers, TransferOrder
from game.ato.traveltime import TotEstimator
from qt_ui.simcontroller import SimController from qt_ui.simcontroller import SimController
from qt_ui.uiconstants import AIRCRAFT_ICONS from qt_ui.uiconstants import AIRCRAFT_ICONS
@ -279,7 +280,9 @@ class AtoModel(QAbstractListModel):
def on_packages_changed(self) -> None: def on_packages_changed(self) -> None:
if self.game is not None: if self.game is not None:
self.game.compute_unculled_zones() self.game.compute_unculled_zones()
self.packages_changed.emit() events = GameUpdateEvents()
events.update_unculled_zones()
EventStream.put_nowait(events)
def package_at_index(self, index: QModelIndex) -> Package: def package_at_index(self, index: QModelIndex) -> Package:
"""Returns the package at the given index.""" """Returns the package at the given index."""

View File

@ -23,7 +23,6 @@ from .groundobjectjs import GroundObjectJs
from .supplyroutejs import SupplyRouteJs from .supplyroutejs import SupplyRouteJs
from .threatzonecontainerjs import ThreatZoneContainerJs from .threatzonecontainerjs import ThreatZoneContainerJs
from .threatzonesjs import ThreatZonesJs from .threatzonesjs import ThreatZonesJs
from .unculledzonejs import UnculledZone
# **EVERY PROPERTY NEEDS A NOTIFY SIGNAL** # **EVERY PROPERTY NEEDS A NOTIFY SIGNAL**
@ -53,7 +52,6 @@ class MapModel(QObject):
flightsChanged = Signal() flightsChanged = Signal()
frontLinesChanged = Signal() frontLinesChanged = Signal()
threatZonesChanged = Signal() threatZonesChanged = Signal()
unculledZonesChanged = Signal()
selectedFlightChanged = Signal(str) selectedFlightChanged = Signal(str)
def __init__(self, game_model: GameModel) -> None: def __init__(self, game_model: GameModel) -> None:
@ -68,7 +66,6 @@ class MapModel(QObject):
self._threat_zones = ThreatZoneContainerJs( self._threat_zones = ThreatZoneContainerJs(
ThreatZonesJs.empty(), ThreatZonesJs.empty() ThreatZonesJs.empty(), ThreatZonesJs.empty()
) )
self._unculled_zones = []
self._selected_flight_index: Optional[Tuple[int, int]] = None self._selected_flight_index: Optional[Tuple[int, int]] = None
GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load) GameUpdateSignal.get_instance().game_loaded.connect(self.on_game_load)
@ -79,12 +76,6 @@ class MapModel(QObject):
GameUpdateSignal.get_instance().flight_selection_changed.connect( GameUpdateSignal.get_instance().flight_selection_changed.connect(
self.set_flight_selection self.set_flight_selection
) )
self.game_model.ato_model_for(True).packages_changed.connect(
self.on_package_change
),
self.game_model.ato_model_for(False).packages_changed.connect(
self.on_package_change
),
self.reset() self.reset()
def clear(self) -> None: def clear(self) -> None:
@ -96,7 +87,6 @@ class MapModel(QObject):
self._threat_zones = ThreatZoneContainerJs( self._threat_zones = ThreatZoneContainerJs(
ThreatZonesJs.empty(), ThreatZonesJs.empty() ThreatZonesJs.empty(), ThreatZonesJs.empty()
) )
self._unculled_zones = []
self.cleared.emit() self.cleared.emit()
def set_package_selection(self, index: int) -> None: def set_package_selection(self, index: int) -> None:
@ -160,7 +150,6 @@ class MapModel(QObject):
self.reset_atos() self.reset_atos()
self.reset_front_lines() self.reset_front_lines()
self.reset_threat_zones() self.reset_threat_zones()
self.reset_unculled_zones()
def on_game_load(self, game: Optional[Game]) -> None: def on_game_load(self, game: Optional[Game]) -> None:
if game is not None: if game is not None:
@ -292,17 +281,6 @@ class MapModel(QObject):
def threatZones(self) -> ThreatZoneContainerJs: def threatZones(self) -> ThreatZoneContainerJs:
return self._threat_zones return self._threat_zones
def on_package_change(self) -> None:
self.reset_unculled_zones()
def reset_unculled_zones(self) -> None:
self._unculled_zones = list(UnculledZone.each_from_game(self.game))
self.unculledZonesChanged.emit()
@Property(list, notify=unculledZonesChanged)
def unculledZones(self) -> list[UnculledZone]:
return self._unculled_zones
@property @property
def game(self) -> Game: def game(self) -> Game:
if self.game_model.game is None: if self.game_model.game is None:

View File

@ -1,33 +0,0 @@
from __future__ import annotations
from typing import Iterator
from PySide2.QtCore import Property, QObject, Signal
from game import Game
from game.server.leaflet import LeafletLatLon
class UnculledZone(QObject):
positionChanged = Signal()
radiusChanged = Signal()
def __init__(self, position: LeafletLatLon, radius: float) -> None:
super().__init__()
self._position = position
self._radius = radius
@Property(list, notify=positionChanged)
def position(self) -> LeafletLatLon:
return self._position
@Property(float, notify=radiusChanged)
def radius(self) -> float:
return self._radius
@classmethod
def each_from_game(cls, game: Game) -> Iterator[UnculledZone]:
for zone in game.get_culling_zones():
yield UnculledZone(
zone.latlng().as_list(), game.settings.perf_culling_distance * 1000
)

View File

@ -385,7 +385,6 @@ new QWebChannel(qt.webChannelTransport, function (channel) {
game.flightsChanged.connect(drawAircraft); game.flightsChanged.connect(drawAircraft);
game.threatZonesChanged.connect(drawThreatZones); game.threatZonesChanged.connect(drawThreatZones);
game.mapZonesChanged.connect(drawMapZones); game.mapZonesChanged.connect(drawMapZones);
game.unculledZonesChanged.connect(drawUnculledZones);
game.selectedFlightChanged.connect(updateSelectedFlight); game.selectedFlightChanged.connect(updateSelectedFlight);
}); });
@ -402,6 +401,9 @@ function handleStreamedEvents(events) {
for (const player of events.navmesh_updates) { for (const player of events.navmesh_updates) {
drawNavmesh(player); drawNavmesh(player);
} }
if (events.unculled_zones_updated) {
drawUnculledZones();
}
} }
function recenterMap(center) { function recenterMap(center) {
@ -1124,7 +1126,7 @@ function drawMapZones() {
inclusionZones.clearLayers(); inclusionZones.clearLayers();
exclusionZones.clearLayers(); exclusionZones.clearLayers();
getJson("/map-zones").then((zones) => { getJson("/map-zones/terrain").then((zones) => {
for (const zone of zones.sea) { for (const zone of zones.sea) {
L.polygon(zone, { L.polygon(zone, {
color: "#344455", color: "#344455",
@ -1157,7 +1159,8 @@ function drawMapZones() {
function drawUnculledZones() { function drawUnculledZones() {
unculledZones.clearLayers(); unculledZones.clearLayers();
for (const zone of game.unculledZones) { getJson("/map-zones/unculled").then((zones) => {
for (const zone of zones) {
L.circle(zone.position, { L.circle(zone.position, {
radius: zone.radius, radius: zone.radius,
color: "#b4ff8c", color: "#b4ff8c",
@ -1165,6 +1168,7 @@ function drawUnculledZones() {
interactive: false, interactive: false,
}).addTo(unculledZones); }).addTo(unculledZones);
} }
});
} }
function drawIpZones(id) { function drawIpZones(id) {