mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Move NavMesh out of MapModel.
This commit is contained in:
@@ -21,10 +21,11 @@ from game.threatzones import ThreatZones
|
||||
from game.transfers import PendingTransfers
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.campaignloader import CampaignAirWingConfig
|
||||
from game.data.doctrine import Doctrine
|
||||
from game.factions.faction import Faction
|
||||
from .campaignloader import CampaignAirWingConfig
|
||||
from .data.doctrine import Doctrine
|
||||
from .factions.faction import Faction
|
||||
from .game import Game
|
||||
from .sim import GameUpdateEvents
|
||||
|
||||
|
||||
class Coalition:
|
||||
@@ -121,10 +122,11 @@ class Coalition:
|
||||
def compute_threat_zones(self) -> None:
|
||||
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.opponent.threat_zone, self.game.theater
|
||||
)
|
||||
events.update_navmesh(self.player)
|
||||
|
||||
def update_transit_network(self) -> None:
|
||||
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 faker import Faker
|
||||
|
||||
from game.ato.closestairfields import ObjectiveDistanceCache
|
||||
from game.ground_forces.ai_ground_planner import GroundPlanner
|
||||
from game.models.game_stats import GameStats
|
||||
from game.plugins import LuaPluginManager
|
||||
from game.utils import Distance
|
||||
from game.ato.closestairfields import ObjectiveDistanceCache
|
||||
from . import naming, persistency
|
||||
from .ato.flighttype import FlightType
|
||||
from .campaignloader import CampaignAirWingConfig
|
||||
@@ -40,10 +40,11 @@ from .weather import Conditions, TimeOfDay
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .ato.airtaaskingorder import AirTaskingOrder
|
||||
from .factions.faction import Faction
|
||||
from .navmesh import NavMesh
|
||||
from .sim import GameUpdateEvents
|
||||
from .squadrons import AirWing
|
||||
from .threatzones import ThreatZones
|
||||
from .factions.faction import Faction
|
||||
|
||||
COMMISION_UNIT_VARIETY = 4
|
||||
COMMISION_LIMITS_SCALE = 1.5
|
||||
@@ -203,6 +204,8 @@ class Game:
|
||||
self.coalition_for(player).adjust_budget(amount)
|
||||
|
||||
def on_load(self, game_still_initializing: bool = False) -> None:
|
||||
from .sim import GameUpdateEvents
|
||||
|
||||
if not hasattr(self, "name_generator"):
|
||||
self.name_generator = naming.namegen
|
||||
# Hack: Replace the global name generator state with the state from the save
|
||||
@@ -215,7 +218,9 @@ class Game:
|
||||
ObjectiveDistanceCache.set_theater(self.theater)
|
||||
self.compute_unculled_zones()
|
||||
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:
|
||||
"""Finalizes the current turn and advances to the next turn.
|
||||
@@ -266,9 +271,13 @@ class Game:
|
||||
|
||||
def begin_turn_0(self) -> None:
|
||||
"""Initialization for the first turn of the game."""
|
||||
from .sim import GameUpdateEvents
|
||||
|
||||
self.blue.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:
|
||||
"""Ends the current turn and initializes the new turn.
|
||||
@@ -278,11 +287,18 @@ class Game:
|
||||
Args:
|
||||
no_action: True if the turn was skipped.
|
||||
"""
|
||||
from .server import EventStream
|
||||
from .sim import GameUpdateEvents
|
||||
|
||||
logging.info("Pass turn")
|
||||
with logged_duration("Turn finalization"):
|
||||
self.finish_turn(no_action)
|
||||
|
||||
events = GameUpdateEvents()
|
||||
with logged_duration("Turn initialization"):
|
||||
self.initialize_turn()
|
||||
self.initialize_turn(events)
|
||||
|
||||
EventStream.put_nowait(events)
|
||||
|
||||
# Autosave progress
|
||||
persistency.autosave(self)
|
||||
@@ -307,7 +323,9 @@ class Game:
|
||||
self.blue.bullseye = Bullseye(enemy_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.
|
||||
|
||||
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.
|
||||
|
||||
Args:
|
||||
events: Game update event container for turn initialization.
|
||||
for_red: True if opfor 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
|
||||
with logged_duration("Threat zone computation"):
|
||||
self.compute_threat_zones()
|
||||
self.compute_threat_zones(events)
|
||||
|
||||
# Plan Coalition specific turn
|
||||
if for_blue:
|
||||
@@ -401,11 +420,11 @@ class Game:
|
||||
def compute_transit_network_for(self, player: bool) -> TransitNetwork:
|
||||
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.red.compute_threat_zones()
|
||||
self.blue.compute_nav_meshes()
|
||||
self.red.compute_nav_meshes()
|
||||
self.blue.compute_nav_meshes(events)
|
||||
self.red.compute_nav_meshes(events)
|
||||
|
||||
def threat_zone_for(self, player: bool) -> ThreatZones:
|
||||
return self.coalition_for(player).threat_zone
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
from . import debuggeometries, eventstream, flights, waypoints
|
||||
from . import debuggeometries, eventstream, flights, navmesh, waypoints
|
||||
from .security import ApiKeyManager
|
||||
|
||||
app = FastAPI(dependencies=[Depends(ApiKeyManager.verify)])
|
||||
app.include_router(debuggeometries.router)
|
||||
app.include_router(eventstream.router)
|
||||
app.include_router(flights.router)
|
||||
app.include_router(navmesh.router)
|
||||
app.include_router(waypoints.router)
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
from game import Game
|
||||
from qt_ui.models import GameModel
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from qt_ui.models import GameModel
|
||||
|
||||
|
||||
class GameContext:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from asyncio import Queue
|
||||
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.sim import GameUpdateEvents
|
||||
|
||||
|
||||
class EventStream:
|
||||
|
||||
@@ -10,13 +10,14 @@ from game.server.leaflet import LeafletLatLon
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.sim import GameUpdateEvents
|
||||
|
||||
|
||||
class GameUpdateEventsJs(BaseModel):
|
||||
updated_flights: dict[UUID, LeafletLatLon]
|
||||
new_combats: list[FrozenCombatJs] = []
|
||||
updated_combats: list[FrozenCombatJs] = []
|
||||
navmesh_updates: set[bool] = set()
|
||||
|
||||
@classmethod
|
||||
def from_events(cls, events: GameUpdateEvents, game: Game) -> GameUpdateEventsJs:
|
||||
@@ -31,4 +32,5 @@ class GameUpdateEventsJs(BaseModel):
|
||||
FrozenCombatJs.for_combat(c, game.theater)
|
||||
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
|
||||
|
||||
@@ -15,6 +15,7 @@ class GameUpdateEvents:
|
||||
self.new_combats: list[FrozenCombat] = []
|
||||
self.updated_combats: list[FrozenCombat] = []
|
||||
self.updated_flights: list[tuple[Flight, Point]] = []
|
||||
self.navmesh_updates: set[bool] = set()
|
||||
|
||||
@property
|
||||
def empty(self) -> bool:
|
||||
@@ -24,6 +25,7 @@ class GameUpdateEvents:
|
||||
self.new_combats,
|
||||
self.updated_combats,
|
||||
self.updated_flights,
|
||||
self.navmesh_updates,
|
||||
]
|
||||
)
|
||||
|
||||
@@ -38,3 +40,6 @@ class GameUpdateEvents:
|
||||
|
||||
def update_flight(self, flight: Flight, new_position: Point) -> None:
|
||||
self.updated_flights.append((flight, new_position))
|
||||
|
||||
def update_navmesh(self, player: bool) -> None:
|
||||
self.navmesh_updates.add(player)
|
||||
|
||||
Reference in New Issue
Block a user