mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Move NavMesh out of MapModel.
This commit is contained in:
parent
1a9930b93a
commit
0e6a303c17
@ -21,10 +21,11 @@ from game.threatzones import ThreatZones
|
|||||||
from game.transfers import PendingTransfers
|
from game.transfers import PendingTransfers
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from .campaignloader import CampaignAirWingConfig
|
||||||
from game.campaignloader import CampaignAirWingConfig
|
from .data.doctrine import Doctrine
|
||||||
from game.data.doctrine import Doctrine
|
from .factions.faction import Faction
|
||||||
from game.factions.faction import Faction
|
from .game import Game
|
||||||
|
from .sim import GameUpdateEvents
|
||||||
|
|
||||||
|
|
||||||
class Coalition:
|
class Coalition:
|
||||||
@ -121,10 +122,11 @@ class Coalition:
|
|||||||
def compute_threat_zones(self) -> None:
|
def compute_threat_zones(self) -> None:
|
||||||
self._threat_zone = ThreatZones.for_faction(self.game, self.player)
|
self._threat_zone = ThreatZones.for_faction(self.game, self.player)
|
||||||
|
|
||||||
def compute_nav_meshes(self) -> None:
|
def compute_nav_meshes(self, events: GameUpdateEvents) -> None:
|
||||||
self._navmesh = NavMesh.from_threat_zones(
|
self._navmesh = NavMesh.from_threat_zones(
|
||||||
self.opponent.threat_zone, self.game.theater
|
self.opponent.threat_zone, self.game.theater
|
||||||
)
|
)
|
||||||
|
events.update_navmesh(self.player)
|
||||||
|
|
||||||
def update_transit_network(self) -> None:
|
def update_transit_network(self) -> None:
|
||||||
self.transit_network = TransitNetworkBuilder(
|
self.transit_network = TransitNetworkBuilder(
|
||||||
|
|||||||
39
game/game.py
39
game/game.py
@ -15,11 +15,11 @@ from dcs.task import CAP, CAS, PinpointStrike
|
|||||||
from dcs.vehicles import AirDefence
|
from dcs.vehicles import AirDefence
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
|
|
||||||
|
from game.ato.closestairfields import ObjectiveDistanceCache
|
||||||
from game.ground_forces.ai_ground_planner import GroundPlanner
|
from game.ground_forces.ai_ground_planner import GroundPlanner
|
||||||
from game.models.game_stats import GameStats
|
from game.models.game_stats import GameStats
|
||||||
from game.plugins import LuaPluginManager
|
from game.plugins import LuaPluginManager
|
||||||
from game.utils import Distance
|
from game.utils import Distance
|
||||||
from game.ato.closestairfields import ObjectiveDistanceCache
|
|
||||||
from . import naming, persistency
|
from . import naming, persistency
|
||||||
from .ato.flighttype import FlightType
|
from .ato.flighttype import FlightType
|
||||||
from .campaignloader import CampaignAirWingConfig
|
from .campaignloader import CampaignAirWingConfig
|
||||||
@ -40,10 +40,11 @@ from .weather import Conditions, TimeOfDay
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .ato.airtaaskingorder import AirTaskingOrder
|
from .ato.airtaaskingorder import AirTaskingOrder
|
||||||
|
from .factions.faction import Faction
|
||||||
from .navmesh import NavMesh
|
from .navmesh import NavMesh
|
||||||
|
from .sim import GameUpdateEvents
|
||||||
from .squadrons import AirWing
|
from .squadrons import AirWing
|
||||||
from .threatzones import ThreatZones
|
from .threatzones import ThreatZones
|
||||||
from .factions.faction import Faction
|
|
||||||
|
|
||||||
COMMISION_UNIT_VARIETY = 4
|
COMMISION_UNIT_VARIETY = 4
|
||||||
COMMISION_LIMITS_SCALE = 1.5
|
COMMISION_LIMITS_SCALE = 1.5
|
||||||
@ -203,6 +204,8 @@ class Game:
|
|||||||
self.coalition_for(player).adjust_budget(amount)
|
self.coalition_for(player).adjust_budget(amount)
|
||||||
|
|
||||||
def on_load(self, game_still_initializing: bool = False) -> None:
|
def on_load(self, game_still_initializing: bool = False) -> None:
|
||||||
|
from .sim import GameUpdateEvents
|
||||||
|
|
||||||
if not hasattr(self, "name_generator"):
|
if not hasattr(self, "name_generator"):
|
||||||
self.name_generator = naming.namegen
|
self.name_generator = naming.namegen
|
||||||
# Hack: Replace the global name generator state with the state from the save
|
# Hack: Replace the global name generator state with the state from the save
|
||||||
@ -215,7 +218,9 @@ class Game:
|
|||||||
ObjectiveDistanceCache.set_theater(self.theater)
|
ObjectiveDistanceCache.set_theater(self.theater)
|
||||||
self.compute_unculled_zones()
|
self.compute_unculled_zones()
|
||||||
if not game_still_initializing:
|
if not game_still_initializing:
|
||||||
self.compute_threat_zones()
|
# We don't need to push events that happen during load. The UI will fully
|
||||||
|
# reset when we're done.
|
||||||
|
self.compute_threat_zones(GameUpdateEvents())
|
||||||
|
|
||||||
def finish_turn(self, skipped: bool = False) -> None:
|
def finish_turn(self, skipped: bool = False) -> None:
|
||||||
"""Finalizes the current turn and advances to the next turn.
|
"""Finalizes the current turn and advances to the next turn.
|
||||||
@ -266,9 +271,13 @@ class Game:
|
|||||||
|
|
||||||
def begin_turn_0(self) -> None:
|
def begin_turn_0(self) -> None:
|
||||||
"""Initialization for the first turn of the game."""
|
"""Initialization for the first turn of the game."""
|
||||||
|
from .sim import GameUpdateEvents
|
||||||
|
|
||||||
self.blue.preinit_turn_0()
|
self.blue.preinit_turn_0()
|
||||||
self.red.preinit_turn_0()
|
self.red.preinit_turn_0()
|
||||||
self.initialize_turn()
|
# We don't need to actually stream events for turn zero because we haven't given
|
||||||
|
# *any* state to the UI yet, so it will need to do a full draw once we do.
|
||||||
|
self.initialize_turn(GameUpdateEvents())
|
||||||
|
|
||||||
def pass_turn(self, no_action: bool = False) -> None:
|
def pass_turn(self, no_action: bool = False) -> None:
|
||||||
"""Ends the current turn and initializes the new turn.
|
"""Ends the current turn and initializes the new turn.
|
||||||
@ -278,11 +287,18 @@ class Game:
|
|||||||
Args:
|
Args:
|
||||||
no_action: True if the turn was skipped.
|
no_action: True if the turn was skipped.
|
||||||
"""
|
"""
|
||||||
|
from .server import EventStream
|
||||||
|
from .sim import GameUpdateEvents
|
||||||
|
|
||||||
logging.info("Pass turn")
|
logging.info("Pass turn")
|
||||||
with logged_duration("Turn finalization"):
|
with logged_duration("Turn finalization"):
|
||||||
self.finish_turn(no_action)
|
self.finish_turn(no_action)
|
||||||
|
|
||||||
|
events = GameUpdateEvents()
|
||||||
with logged_duration("Turn initialization"):
|
with logged_duration("Turn initialization"):
|
||||||
self.initialize_turn()
|
self.initialize_turn(events)
|
||||||
|
|
||||||
|
EventStream.put_nowait(events)
|
||||||
|
|
||||||
# Autosave progress
|
# Autosave progress
|
||||||
persistency.autosave(self)
|
persistency.autosave(self)
|
||||||
@ -307,7 +323,9 @@ class Game:
|
|||||||
self.blue.bullseye = Bullseye(enemy_cp.position)
|
self.blue.bullseye = Bullseye(enemy_cp.position)
|
||||||
self.red.bullseye = Bullseye(player_cp.position)
|
self.red.bullseye = Bullseye(player_cp.position)
|
||||||
|
|
||||||
def initialize_turn(self, for_red: bool = True, for_blue: bool = True) -> None:
|
def initialize_turn(
|
||||||
|
self, events: GameUpdateEvents, for_red: bool = True, for_blue: bool = True
|
||||||
|
) -> None:
|
||||||
"""Performs turn initialization for the specified players.
|
"""Performs turn initialization for the specified players.
|
||||||
|
|
||||||
Turn initialization performs all of the beginning-of-turn actions. *End-of-turn*
|
Turn initialization performs all of the beginning-of-turn actions. *End-of-turn*
|
||||||
@ -338,6 +356,7 @@ class Game:
|
|||||||
impactful but also likely to be early, so they also cause a blue replan.
|
impactful but also likely to be early, so they also cause a blue replan.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
events: Game update event container for turn initialization.
|
||||||
for_red: True if opfor should be re-initialized.
|
for_red: True if opfor should be re-initialized.
|
||||||
for_blue: True if the player coalition should be re-initialized.
|
for_blue: True if the player coalition should be re-initialized.
|
||||||
"""
|
"""
|
||||||
@ -353,7 +372,7 @@ class Game:
|
|||||||
|
|
||||||
# Plan flights & combat for next turn
|
# Plan flights & combat for next turn
|
||||||
with logged_duration("Threat zone computation"):
|
with logged_duration("Threat zone computation"):
|
||||||
self.compute_threat_zones()
|
self.compute_threat_zones(events)
|
||||||
|
|
||||||
# Plan Coalition specific turn
|
# Plan Coalition specific turn
|
||||||
if for_blue:
|
if for_blue:
|
||||||
@ -401,11 +420,11 @@ class Game:
|
|||||||
def compute_transit_network_for(self, player: bool) -> TransitNetwork:
|
def compute_transit_network_for(self, player: bool) -> TransitNetwork:
|
||||||
return TransitNetworkBuilder(self.theater, player).build()
|
return TransitNetworkBuilder(self.theater, player).build()
|
||||||
|
|
||||||
def compute_threat_zones(self) -> None:
|
def compute_threat_zones(self, events: GameUpdateEvents) -> None:
|
||||||
self.blue.compute_threat_zones()
|
self.blue.compute_threat_zones()
|
||||||
self.red.compute_threat_zones()
|
self.red.compute_threat_zones()
|
||||||
self.blue.compute_nav_meshes()
|
self.blue.compute_nav_meshes(events)
|
||||||
self.red.compute_nav_meshes()
|
self.red.compute_nav_meshes(events)
|
||||||
|
|
||||||
def threat_zone_for(self, player: bool) -> ThreatZones:
|
def threat_zone_for(self, player: bool) -> ThreatZones:
|
||||||
return self.coalition_for(player).threat_zone
|
return self.coalition_for(player).threat_zone
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
from fastapi import Depends, FastAPI
|
from fastapi import Depends, FastAPI
|
||||||
|
|
||||||
from . import debuggeometries, eventstream, flights, waypoints
|
from . import debuggeometries, eventstream, flights, navmesh, waypoints
|
||||||
from .security import ApiKeyManager
|
from .security import ApiKeyManager
|
||||||
|
|
||||||
app = FastAPI(dependencies=[Depends(ApiKeyManager.verify)])
|
app = FastAPI(dependencies=[Depends(ApiKeyManager.verify)])
|
||||||
app.include_router(debuggeometries.router)
|
app.include_router(debuggeometries.router)
|
||||||
app.include_router(eventstream.router)
|
app.include_router(eventstream.router)
|
||||||
app.include_router(flights.router)
|
app.include_router(flights.router)
|
||||||
|
app.include_router(navmesh.router)
|
||||||
app.include_router(waypoints.router)
|
app.include_router(waypoints.router)
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
from game import Game
|
from __future__ import annotations
|
||||||
from qt_ui.models import GameModel
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from game import Game
|
||||||
|
from qt_ui.models import GameModel
|
||||||
|
|
||||||
|
|
||||||
class GameContext:
|
class GameContext:
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from asyncio import Queue
|
from asyncio import Queue
|
||||||
|
|
||||||
from game.sim.gameupdateevents import GameUpdateEvents
|
from game.sim import GameUpdateEvents
|
||||||
|
|
||||||
|
|
||||||
class EventStream:
|
class EventStream:
|
||||||
|
|||||||
@ -10,13 +10,14 @@ from game.server.leaflet import LeafletLatLon
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
from game.sim.gameupdateevents import GameUpdateEvents
|
from game.sim import GameUpdateEvents
|
||||||
|
|
||||||
|
|
||||||
class GameUpdateEventsJs(BaseModel):
|
class GameUpdateEventsJs(BaseModel):
|
||||||
updated_flights: dict[UUID, LeafletLatLon]
|
updated_flights: dict[UUID, LeafletLatLon]
|
||||||
new_combats: list[FrozenCombatJs] = []
|
new_combats: list[FrozenCombatJs] = []
|
||||||
updated_combats: list[FrozenCombatJs] = []
|
updated_combats: list[FrozenCombatJs] = []
|
||||||
|
navmesh_updates: set[bool] = set()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
|
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
|
||||||
@ -31,4 +32,5 @@ class GameUpdateEventsJs(BaseModel):
|
|||||||
FrozenCombatJs.for_combat(c, game.theater)
|
FrozenCombatJs.for_combat(c, game.theater)
|
||||||
for c in events.updated_combats
|
for c in events.updated_combats
|
||||||
],
|
],
|
||||||
|
navmesh_updates=events.navmesh_updates,
|
||||||
)
|
)
|
||||||
|
|||||||
1
game/server/navmesh/__init__.py
Normal file
1
game/server/navmesh/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .routes import router
|
||||||
10
game/server/navmesh/models.py
Normal file
10
game/server/navmesh/models.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from game.server.leaflet import LeafletPoly
|
||||||
|
|
||||||
|
|
||||||
|
class NavMeshPolyJs(BaseModel):
|
||||||
|
poly: LeafletPoly
|
||||||
|
threatened: bool
|
||||||
20
game/server/navmesh/routes.py
Normal file
20
game/server/navmesh/routes.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from game.server import GameContext
|
||||||
|
from .models import NavMeshPolyJs
|
||||||
|
from ..leaflet import ShapelyUtil
|
||||||
|
|
||||||
|
router: APIRouter = APIRouter(prefix="/navmesh")
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/", response_model=list[NavMeshPolyJs])
|
||||||
|
def get(for_player: bool, game: Game = Depends(GameContext.get)) -> list[NavMeshPolyJs]:
|
||||||
|
mesh = game.coalition_for(for_player).nav_mesh
|
||||||
|
return [
|
||||||
|
NavMeshPolyJs(
|
||||||
|
poly=ShapelyUtil.poly_to_leaflet(p.poly, game.theater),
|
||||||
|
threatened=p.threatened,
|
||||||
|
)
|
||||||
|
for p in mesh.polys
|
||||||
|
]
|
||||||
@ -1 +1,2 @@
|
|||||||
|
from .gameupdateevents import GameUpdateEvents
|
||||||
from .missionsimulation import MissionSimulation
|
from .missionsimulation import MissionSimulation
|
||||||
|
|||||||
@ -15,6 +15,7 @@ class GameUpdateEvents:
|
|||||||
self.new_combats: list[FrozenCombat] = []
|
self.new_combats: list[FrozenCombat] = []
|
||||||
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()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def empty(self) -> bool:
|
def empty(self) -> bool:
|
||||||
@ -24,6 +25,7 @@ class GameUpdateEvents:
|
|||||||
self.new_combats,
|
self.new_combats,
|
||||||
self.updated_combats,
|
self.updated_combats,
|
||||||
self.updated_flights,
|
self.updated_flights,
|
||||||
|
self.navmesh_updates,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,3 +40,6 @@ class GameUpdateEvents:
|
|||||||
|
|
||||||
def update_flight(self, flight: Flight, new_position: Point) -> None:
|
def update_flight(self, flight: Flight, new_position: Point) -> None:
|
||||||
self.updated_flights.append((flight, new_position))
|
self.updated_flights.append((flight, new_position))
|
||||||
|
|
||||||
|
def update_navmesh(self, player: bool) -> None:
|
||||||
|
self.navmesh_updates.add(player)
|
||||||
|
|||||||
@ -21,7 +21,6 @@ from .flightjs import FlightJs
|
|||||||
from .frontlinejs import FrontLineJs
|
from .frontlinejs import FrontLineJs
|
||||||
from .groundobjectjs import GroundObjectJs
|
from .groundobjectjs import GroundObjectJs
|
||||||
from .mapzonesjs import MapZonesJs
|
from .mapzonesjs import MapZonesJs
|
||||||
from .navmeshjs import NavMeshJs
|
|
||||||
from .supplyroutejs import SupplyRouteJs
|
from .supplyroutejs import SupplyRouteJs
|
||||||
from .threatzonecontainerjs import ThreatZoneContainerJs
|
from .threatzonecontainerjs import ThreatZoneContainerJs
|
||||||
from .threatzonesjs import ThreatZonesJs
|
from .threatzonesjs import ThreatZonesJs
|
||||||
@ -55,7 +54,6 @@ class MapModel(QObject):
|
|||||||
flightsChanged = Signal()
|
flightsChanged = Signal()
|
||||||
frontLinesChanged = Signal()
|
frontLinesChanged = Signal()
|
||||||
threatZonesChanged = Signal()
|
threatZonesChanged = Signal()
|
||||||
navmeshesChanged = Signal()
|
|
||||||
mapZonesChanged = Signal()
|
mapZonesChanged = Signal()
|
||||||
unculledZonesChanged = Signal()
|
unculledZonesChanged = Signal()
|
||||||
selectedFlightChanged = Signal(str)
|
selectedFlightChanged = Signal(str)
|
||||||
@ -72,7 +70,6 @@ class MapModel(QObject):
|
|||||||
self._threat_zones = ThreatZoneContainerJs(
|
self._threat_zones = ThreatZoneContainerJs(
|
||||||
ThreatZonesJs.empty(), ThreatZonesJs.empty()
|
ThreatZonesJs.empty(), ThreatZonesJs.empty()
|
||||||
)
|
)
|
||||||
self._navmeshes = NavMeshJs([], [])
|
|
||||||
self._map_zones = MapZonesJs([], [], [])
|
self._map_zones = MapZonesJs([], [], [])
|
||||||
self._unculled_zones = []
|
self._unculled_zones = []
|
||||||
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
self._selected_flight_index: Optional[Tuple[int, int]] = None
|
||||||
@ -102,7 +99,6 @@ class MapModel(QObject):
|
|||||||
self._threat_zones = ThreatZoneContainerJs(
|
self._threat_zones = ThreatZoneContainerJs(
|
||||||
ThreatZonesJs.empty(), ThreatZonesJs.empty()
|
ThreatZonesJs.empty(), ThreatZonesJs.empty()
|
||||||
)
|
)
|
||||||
self._navmeshes = NavMeshJs([], [])
|
|
||||||
self._map_zones = MapZonesJs([], [], [])
|
self._map_zones = MapZonesJs([], [], [])
|
||||||
self._unculled_zones = []
|
self._unculled_zones = []
|
||||||
self.cleared.emit()
|
self.cleared.emit()
|
||||||
@ -168,7 +164,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_navmeshes()
|
|
||||||
self.reset_map_zones()
|
self.reset_map_zones()
|
||||||
self.reset_unculled_zones()
|
self.reset_unculled_zones()
|
||||||
|
|
||||||
@ -302,20 +297,12 @@ class MapModel(QObject):
|
|||||||
def threatZones(self) -> ThreatZoneContainerJs:
|
def threatZones(self) -> ThreatZoneContainerJs:
|
||||||
return self._threat_zones
|
return self._threat_zones
|
||||||
|
|
||||||
def reset_navmeshes(self) -> None:
|
|
||||||
self._navmeshes = NavMeshJs.from_game(self.game)
|
|
||||||
self.navmeshesChanged.emit()
|
|
||||||
|
|
||||||
@Property(NavMeshJs, notify=navmeshesChanged)
|
|
||||||
def navmeshes(self) -> NavMeshJs:
|
|
||||||
return self._navmeshes
|
|
||||||
|
|
||||||
def reset_map_zones(self) -> None:
|
def reset_map_zones(self) -> None:
|
||||||
self._map_zones = MapZonesJs.from_game(self.game)
|
self._map_zones = MapZonesJs.from_game(self.game)
|
||||||
self.mapZonesChanged.emit()
|
self.mapZonesChanged.emit()
|
||||||
|
|
||||||
@Property(MapZonesJs, notify=mapZonesChanged)
|
@Property(MapZonesJs, notify=mapZonesChanged)
|
||||||
def mapZones(self) -> NavMeshJs:
|
def mapZones(self) -> MapZonesJs:
|
||||||
return self._map_zones
|
return self._map_zones
|
||||||
|
|
||||||
def on_package_change(self) -> None:
|
def on_package_change(self) -> None:
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from PySide2.QtCore import Property, QObject, Signal
|
|
||||||
|
|
||||||
from game import Game
|
|
||||||
from game.navmesh import NavMesh
|
|
||||||
from game.server.leaflet import LeafletPoly
|
|
||||||
from game.theater import ConflictTheater
|
|
||||||
from .navmeshpolyjs import NavMeshPolyJs
|
|
||||||
|
|
||||||
|
|
||||||
class NavMeshJs(QObject):
|
|
||||||
blueChanged = Signal()
|
|
||||||
redChanged = Signal()
|
|
||||||
|
|
||||||
def __init__(self, blue: list[NavMeshPolyJs], red: list[NavMeshPolyJs]) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self._blue = blue
|
|
||||||
self._red = red
|
|
||||||
# TODO: Boundary markers.
|
|
||||||
# TODO: Numbering.
|
|
||||||
# TODO: Localization debugging.
|
|
||||||
|
|
||||||
@Property(list, notify=blueChanged)
|
|
||||||
def blue(self) -> list[LeafletPoly]:
|
|
||||||
return self._blue
|
|
||||||
|
|
||||||
@Property(list, notify=redChanged)
|
|
||||||
def red(self) -> list[LeafletPoly]:
|
|
||||||
return self._red
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_polys(navmesh: NavMesh, theater: ConflictTheater) -> list[NavMeshPolyJs]:
|
|
||||||
polys = []
|
|
||||||
for poly in navmesh.polys:
|
|
||||||
polys.append(NavMeshPolyJs.from_navmesh(poly, theater))
|
|
||||||
return polys
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_game(cls, game: Game) -> NavMeshJs:
|
|
||||||
return NavMeshJs(
|
|
||||||
cls.to_polys(game.blue.nav_mesh, game.theater),
|
|
||||||
cls.to_polys(game.red.nav_mesh, game.theater),
|
|
||||||
)
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from PySide2.QtCore import Property, QObject, Signal
|
|
||||||
|
|
||||||
from game.navmesh import NavMeshPoly
|
|
||||||
from game.server.leaflet import LeafletPoly, ShapelyUtil
|
|
||||||
from game.theater import ConflictTheater
|
|
||||||
|
|
||||||
|
|
||||||
class NavMeshPolyJs(QObject):
|
|
||||||
polyChanged = Signal()
|
|
||||||
threatenedChanged = Signal()
|
|
||||||
|
|
||||||
def __init__(self, poly: LeafletPoly, threatened: bool) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self._poly = poly
|
|
||||||
self._threatened = threatened
|
|
||||||
|
|
||||||
@Property(list, notify=polyChanged)
|
|
||||||
def poly(self) -> LeafletPoly:
|
|
||||||
return self._poly
|
|
||||||
|
|
||||||
@Property(bool, notify=threatenedChanged)
|
|
||||||
def threatened(self) -> bool:
|
|
||||||
return self._threatened
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_navmesh(cls, poly: NavMeshPoly, theater: ConflictTheater) -> NavMeshPolyJs:
|
|
||||||
return NavMeshPolyJs(
|
|
||||||
ShapelyUtil.poly_to_leaflet(poly.poly, theater), poly.threatened
|
|
||||||
)
|
|
||||||
@ -384,7 +384,6 @@ new QWebChannel(qt.webChannelTransport, function (channel) {
|
|||||||
game.frontLinesChanged.connect(drawFrontLines);
|
game.frontLinesChanged.connect(drawFrontLines);
|
||||||
game.flightsChanged.connect(drawAircraft);
|
game.flightsChanged.connect(drawAircraft);
|
||||||
game.threatZonesChanged.connect(drawThreatZones);
|
game.threatZonesChanged.connect(drawThreatZones);
|
||||||
game.navmeshesChanged.connect(drawNavmeshes);
|
|
||||||
game.mapZonesChanged.connect(drawMapZones);
|
game.mapZonesChanged.connect(drawMapZones);
|
||||||
game.unculledZonesChanged.connect(drawUnculledZones);
|
game.unculledZonesChanged.connect(drawUnculledZones);
|
||||||
game.selectedFlightChanged.connect(updateSelectedFlight);
|
game.selectedFlightChanged.connect(updateSelectedFlight);
|
||||||
@ -400,6 +399,9 @@ function handleStreamedEvents(events) {
|
|||||||
for (const combat of events.updated_combats) {
|
for (const combat of events.updated_combats) {
|
||||||
redrawCombat(combat);
|
redrawCombat(combat);
|
||||||
}
|
}
|
||||||
|
for (const player of events.navmesh_updates) {
|
||||||
|
drawNavmesh(player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function recenterMap(center) {
|
function recenterMap(center) {
|
||||||
@ -1094,26 +1096,27 @@ function drawThreatZones() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawNavmesh(zones, layer) {
|
function drawNavmesh(player) {
|
||||||
for (const zone of zones) {
|
const layer = player ? blueNavmesh : redNavmesh;
|
||||||
L.polyline(zone.poly, {
|
layer.clearLayers();
|
||||||
color: "#000000",
|
getJson(`/navmesh?for_player=${player}`).then((zones) => {
|
||||||
weight: 1,
|
for (const zone of zones) {
|
||||||
fillColor: zone.threatened ? "#ff0000" : "#00ff00",
|
L.polyline(zone.poly, {
|
||||||
fill: true,
|
color: "#000000",
|
||||||
fillOpacity: 0.1,
|
weight: 1,
|
||||||
noClip: true,
|
fillColor: zone.threatened ? "#ff0000" : "#00ff00",
|
||||||
interactive: false,
|
fill: true,
|
||||||
}).addTo(layer);
|
fillOpacity: 0.1,
|
||||||
}
|
noClip: true,
|
||||||
|
interactive: false,
|
||||||
|
}).addTo(layer);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawNavmeshes() {
|
function drawNavmeshes() {
|
||||||
blueNavmesh.clearLayers();
|
drawNavmesh(true);
|
||||||
redNavmesh.clearLayers();
|
drawNavmesh(false);
|
||||||
|
|
||||||
drawNavmesh(game.navmeshes.blue, blueNavmesh);
|
|
||||||
drawNavmesh(game.navmeshes.red, redNavmesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawMapZones() {
|
function drawMapZones() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user