From 4aa42e6573b6ba6d1bfd82f7451715163bbc39c0 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Wed, 28 Dec 2022 13:48:01 -0800 Subject: [PATCH] Remove isinstance use in flight support data. mypy struggles to prove this cast correct when there are two or'd isinstance checks where both types coincidentally have properties of the same name (but no defined protocol making that explicit). I'm not really sure why mypy is happy with this in its current state, but it isn't after a change I'm making. All our isinstance use is a bit of an anti-pattern anyway, so extract a method that exposes the data we care about. The start/end times for tankers aren't actually used, so this could be simplified even more, but that data _should_ be used. --- game/ato/flightplans/airassault.py | 4 ++++ game/ato/flightplans/airlift.py | 4 ++++ game/ato/flightplans/custom.py | 4 ++++ game/ato/flightplans/ferry.py | 4 ++++ game/ato/flightplans/flightplan.py | 12 +++++++++++- game/ato/flightplans/formation.py | 4 ++++ game/ato/flightplans/patrolling.py | 4 ++++ game/ato/flightplans/rtb.py | 4 ++++ game/ato/flightplans/shiprecoverytanker.py | 12 ++++-------- game/ato/flightplans/sweep.py | 4 ++++ .../aircraft/flightgroupconfigurator.py | 15 +++++---------- 11 files changed, 52 insertions(+), 19 deletions(-) diff --git a/game/ato/flightplans/airassault.py b/game/ato/flightplans/airassault.py index 015d287d..0d25074b 100644 --- a/game/ato/flightplans/airassault.py +++ b/game/ato/flightplans/airassault.py @@ -67,6 +67,10 @@ class AirAssaultFlightPlan(StandardFlightPlan[AirAssaultLayout], UiZoneDisplay): def ctld_target_zone_radius(self) -> Distance: return meters(2500) + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + @property def mission_departure_time(self) -> timedelta: return self.package.time_over_target diff --git a/game/ato/flightplans/airlift.py b/game/ato/flightplans/airlift.py index 1f143a35..0771f10f 100644 --- a/game/ato/flightplans/airlift.py +++ b/game/ato/flightplans/airlift.py @@ -75,6 +75,10 @@ class AirliftFlightPlan(StandardFlightPlan[AirliftLayout]): def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None: return None + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + @property def mission_departure_time(self) -> timedelta: return self.package.time_over_target diff --git a/game/ato/flightplans/custom.py b/game/ato/flightplans/custom.py index 35caa8e0..8b249986 100644 --- a/game/ato/flightplans/custom.py +++ b/game/ato/flightplans/custom.py @@ -50,6 +50,10 @@ class CustomFlightPlan(FlightPlan[CustomLayout]): def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None: return None + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + @property def mission_departure_time(self) -> timedelta: return self.package.time_over_target diff --git a/game/ato/flightplans/ferry.py b/game/ato/flightplans/ferry.py index 0ddd82ac..d3382e55 100644 --- a/game/ato/flightplans/ferry.py +++ b/game/ato/flightplans/ferry.py @@ -45,6 +45,10 @@ class FerryFlightPlan(StandardFlightPlan[FerryLayout]): def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None: return None + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + @property def mission_departure_time(self) -> timedelta: return self.package.time_over_target diff --git a/game/ato/flightplans/flightplan.py b/game/ato/flightplans/flightplan.py index fcb1e12a..0ddcae7e 100644 --- a/game/ato/flightplans/flightplan.py +++ b/game/ato/flightplans/flightplan.py @@ -8,7 +8,7 @@ generating the waypoints for the mission. from __future__ import annotations import math -from abc import ABC +from abc import ABC, abstractmethod from collections.abc import Iterator from dataclasses import dataclass from datetime import timedelta @@ -296,6 +296,16 @@ class FlightPlan(ABC, Generic[LayoutT]): else: return timedelta(minutes=8) + @property + @abstractmethod + def mission_begin_on_station_time(self) -> timedelta | None: + """The time that the mission is first on-station. + + Not all mission types will have a time when they can be considered on-station. + Missions that patrol or loiter (CAPs, CAS, refueling, AEW&C, etc) will have this + defined, but strike-like missions will not. + """ + @property def mission_departure_time(self) -> timedelta: """The time that the mission is complete and the flight RTBs.""" diff --git a/game/ato/flightplans/formation.py b/game/ato/flightplans/formation.py index 5aa39263..2c498ce4 100644 --- a/game/ato/flightplans/formation.py +++ b/game/ato/flightplans/formation.py @@ -96,6 +96,10 @@ class FormationFlightPlan(LoiterFlightPlan, ABC): GroundSpeed.for_flight(self.flight, self.layout.hold.alt), ) + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + @property def mission_departure_time(self) -> timedelta: return self.split_time diff --git a/game/ato/flightplans/patrolling.py b/game/ato/flightplans/patrolling.py index eecc1828..247a6c12 100644 --- a/game/ato/flightplans/patrolling.py +++ b/game/ato/flightplans/patrolling.py @@ -89,6 +89,10 @@ class PatrollingFlightPlan(StandardFlightPlan[LayoutT], UiZoneDisplay, ABC): def tot_waypoint(self) -> FlightWaypoint: return self.layout.patrol_start + @property + def mission_begin_on_station_time(self) -> timedelta: + return self.patrol_start_time + @property def mission_departure_time(self) -> timedelta: return self.patrol_end_time diff --git a/game/ato/flightplans/rtb.py b/game/ato/flightplans/rtb.py index 8f1cbfa8..2ae72645 100644 --- a/game/ato/flightplans/rtb.py +++ b/game/ato/flightplans/rtb.py @@ -49,6 +49,10 @@ class RtbFlightPlan(StandardFlightPlan[RtbLayout]): def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None: return None + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + @property def mission_departure_time(self) -> timedelta: return timedelta() diff --git a/game/ato/flightplans/shiprecoverytanker.py b/game/ato/flightplans/shiprecoverytanker.py index cfa20e46..94409d9d 100644 --- a/game/ato/flightplans/shiprecoverytanker.py +++ b/game/ato/flightplans/shiprecoverytanker.py @@ -3,9 +3,9 @@ from __future__ import annotations from dataclasses import dataclass from datetime import timedelta from typing import Iterator, Type -from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout + from game.ato.flightplans.ibuilder import IBuilder -from game.ato.flightplans.standard import StandardLayout +from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout from game.ato.flightplans.waypointbuilder import WaypointBuilder from game.ato.flightwaypoint import FlightWaypoint @@ -37,15 +37,11 @@ class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]): return self.layout.recovery_ship @property - def mission_departure_time(self) -> timedelta: - return self.patrol_end_time - - @property - def patrol_start_time(self) -> timedelta: + def mission_begin_on_station_time(self) -> timedelta: return self.package.time_over_target @property - def patrol_end_time(self) -> timedelta: + def mission_departure_time(self) -> timedelta: return self.tot + timedelta(hours=2) def tot_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None: diff --git a/game/ato/flightplans/sweep.py b/game/ato/flightplans/sweep.py index 1ff3718d..f5043eef 100644 --- a/game/ato/flightplans/sweep.py +++ b/game/ato/flightplans/sweep.py @@ -89,6 +89,10 @@ class SweepFlightPlan(LoiterFlightPlan): GroundSpeed.for_flight(self.flight, self.layout.hold.alt), ) + @property + def mission_begin_on_station_time(self) -> timedelta | None: + return None + def mission_departure_time(self) -> timedelta: return self.sweep_end_time diff --git a/game/missiongenerator/aircraft/flightgroupconfigurator.py b/game/missiongenerator/aircraft/flightgroupconfigurator.py index b3d6e73c..8d7a58aa 100644 --- a/game/missiongenerator/aircraft/flightgroupconfigurator.py +++ b/game/missiongenerator/aircraft/flightgroupconfigurator.py @@ -10,12 +10,11 @@ from dcs.unit import Skill from dcs.unitgroup import FlyingGroup from game.ato import Flight, FlightType -from game.ato.flightplans.shiprecoverytanker import RecoveryTankerFlightPlan from game.callsigns import callsign_for_support_unit from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum -from game.missiongenerator.missiondata import MissionData, AwacsInfo, TankerInfo from game.missiongenerator.lasercoderegistry import LaserCodeRegistry from game.missiongenerator.logisticsgenerator import LogisticsGenerator +from game.missiongenerator.missiondata import AwacsInfo, MissionData, TankerInfo from game.radio.radios import RadioFrequency, RadioRegistry from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage from game.runways import RunwayData @@ -25,8 +24,6 @@ from .aircraftbehavior import AircraftBehavior from .aircraftpainter import AircraftPainter from .flightdata import FlightData from .waypoints import WaypointGenerator -from ...ato.flightplans.aewc import AewcFlightPlan -from ...ato.flightplans.theaterrefueling import TheaterRefuelingFlightPlan if TYPE_CHECKING: from game import Game @@ -149,7 +146,7 @@ class FlightGroupConfigurator: def register_air_support(self, channel: RadioFrequency) -> None: callsign = callsign_for_support_unit(self.group) - if isinstance(self.flight.flight_plan, AewcFlightPlan): + if self.flight.flight_type is FlightType.AEWC: self.mission_data.awacs.append( AwacsInfo( group_name=str(self.group.name), @@ -161,9 +158,7 @@ class FlightGroupConfigurator: blue=self.flight.departure.captured, ) ) - elif isinstance( - self.flight.flight_plan, TheaterRefuelingFlightPlan - ) or isinstance(self.flight.flight_plan, RecoveryTankerFlightPlan): + elif self.flight.flight_type is FlightType.REFUELING: tacan = self.tacan_registry.alloc_for_band(TacanBand.Y, TacanUsage.AirToAir) self.mission_data.tankers.append( TankerInfo( @@ -172,8 +167,8 @@ class FlightGroupConfigurator: variant=self.flight.unit_type.name, freq=channel, tacan=tacan, - start_time=self.flight.flight_plan.patrol_start_time, - end_time=self.flight.flight_plan.patrol_end_time, + start_time=self.flight.flight_plan.mission_begin_on_station_time, + end_time=self.flight.flight_plan.mission_departure_time, blue=self.flight.departure.captured, ) )