From 73a8ec02b2c2f8026ab943b789394652fe5fcb77 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Mon, 7 Mar 2022 21:19:04 -0800 Subject: [PATCH] Speed up game tick by caching TGO threat regions. Still more could be done here by caching the merged poly at the theater level, but this goes a long way. Aircraft commit regions are already cached (in the FlightState), so those are already fairly fast. The combined A2A commit boundary could also potentially be cached at the theater level. --- game/sim/combat/samengagementzones.py | 13 +++------- game/theater/theatergroundobject.py | 35 ++++++++++++++++++++++++--- game/theater/theatergroup.py | 1 + 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/game/sim/combat/samengagementzones.py b/game/sim/combat/samengagementzones.py index 0d4c9177..fcaeefa3 100644 --- a/game/sim/combat/samengagementzones.py +++ b/game/sim/combat/samengagementzones.py @@ -1,12 +1,12 @@ from __future__ import annotations from collections.abc import Iterator -from typing import Any, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING from dcs import Point from shapely.ops import unary_union -from game.utils import dcs_to_shapely_point, meters +from game.utils import dcs_to_shapely_point if TYPE_CHECKING: from game.theater import ConflictTheater, TheaterGroundObject @@ -36,14 +36,7 @@ class SamEngagementZones: individual_zones = [] for cp in theater.control_points_for(player): for tgo in cp.connected_objectives: - if (region := cls.threat_region(tgo)) is not None: + if (region := tgo.threat_poly()) is not None: commit_regions.append(region) individual_zones.append((tgo, region)) return SamEngagementZones(unary_union(commit_regions), individual_zones) - - @classmethod - def threat_region(cls, tgo: TheaterGroundObject) -> Optional[ThreatPoly]: - threat_range = tgo.max_threat_range() - if threat_range <= meters(0): - return None - return dcs_to_shapely_point(tgo.position).buffer(threat_range.meters) diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py index aa431cb4..a748c28d 100644 --- a/game/theater/theatergroundobject.py +++ b/game/theater/theatergroundobject.py @@ -3,10 +3,11 @@ from __future__ import annotations import itertools import uuid from abc import ABC -from typing import Iterator, List, Optional, TYPE_CHECKING +from typing import Any, Iterator, List, Optional, TYPE_CHECKING from dcs.mapping import Point from dcs.unittype import VehicleType +from shapely.geometry import Point as ShapelyPoint from game.sidc import ( Entity, @@ -19,15 +20,16 @@ from game.sidc import ( Status, SymbolSet, ) +from .missiontarget import MissionTarget from ..data.radar_db import LAUNCHER_TRACKER_PAIRS, TELARS, TRACK_RADARS from ..utils import Distance, Heading, meters if TYPE_CHECKING: + from game.ato.flighttype import FlightType + from game.threatzones import ThreatPoly from .theatergroup import TheaterUnit, TheaterGroup from .controlpoint import ControlPoint - from ..ato.flighttype import FlightType -from .missiontarget import MissionTarget NAME_BY_CATEGORY = { "ewr": "Early Warning Radar", @@ -69,6 +71,16 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC): self.control_point = control_point self.sea_object = sea_object self.groups: List[TheaterGroup] = [] + self._threat_poly: ThreatPoly | None = None + + def __getstate__(self) -> dict[str, Any]: + state = self.__dict__.copy() + del state["_threat_poly"] + return state + + def __setstate__(self, state: dict[str, Any]) -> None: + state["_threat_poly"] = None + self.__dict__.update(state) @property def sidc_status(self) -> Status: @@ -193,6 +205,22 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC): def threat_range(self, group: TheaterGroup, radar_only: bool = False) -> Distance: return self._max_range_of_type(group, "threat_range") + def threat_poly(self) -> ThreatPoly | None: + if self._threat_poly is None: + self._threat_poly = self._make_threat_poly() + return self._threat_poly + + def invalidate_threat_poly(self) -> None: + self._threat_poly = None + + def _make_threat_poly(self) -> ThreatPoly | None: + threat_range = self.max_threat_range() + if not threat_range: + return None + + point = ShapelyPoint(self.position.x, self.position.y) + return point.buffer(threat_range.meters) + @property def is_ammo_depot(self) -> bool: return self.category == "ammo" @@ -215,6 +243,7 @@ class TheaterGroundObject(MissionTarget, SidcDescribable, ABC): yield self.position def clear(self) -> None: + self.invalidate_threat_poly() self.groups = [] @property diff --git a/game/theater/theatergroup.py b/game/theater/theatergroup.py index f6bfe5ec..6b761f0b 100644 --- a/game/theater/theatergroup.py +++ b/game/theater/theatergroup.py @@ -58,6 +58,7 @@ class TheaterUnit: def kill(self, events: GameUpdateEvents) -> None: self.alive = False + self.ground_object.invalidate_threat_poly() events.update_tgo(self.ground_object) @property