Migrate sweep ingress's tasks to waypoint actions.

This commit is contained in:
Dan Albert 2023-08-13 22:26:54 -07:00
parent c00f853f34
commit b7723843c6
12 changed files with 149 additions and 35 deletions

View File

@ -5,12 +5,15 @@ from datetime import datetime, timedelta
from typing import Iterator, TYPE_CHECKING, Type
from dcs import Point
from dcs.task import Targets
from game.utils import Heading
from game.flightplan import HoldZoneGeometry
from game.flightplan.waypointactions.engagetargets import EngageTargets
from game.flightplan.waypointoptions.formation import Formation
from game.utils import Heading, nautical_miles
from .ibuilder import IBuilder
from .loiter import LoiterFlightPlan, LoiterLayout
from .waypointbuilder import WaypointBuilder
from ...flightplan import HoldZoneGeometry
if TYPE_CHECKING:
from ..flightwaypoint import FlightWaypoint
@ -89,6 +92,19 @@ class SweepFlightPlan(LoiterFlightPlan[SweepLayout]):
def mission_departure_time(self) -> datetime:
return self.sweep_end_time
def add_waypoint_actions(self) -> None:
super().add_waypoint_actions()
self.layout.sweep_start.set_option(Formation.LINE_ABREAST_OPEN)
self.layout.sweep_start.add_action(
EngageTargets(
nautical_miles(50),
[
Targets.All.Air.Planes.Fighters,
Targets.All.Air.Planes.MultiroleFighters,
],
)
)
class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
def layout(self) -> SweepLayout:

View File

@ -8,6 +8,7 @@ from dcs import Point
from game.ato.flightwaypointtype import FlightWaypointType
from game.flightplan.waypointactions.waypointaction import WaypointAction
from game.flightplan.waypointoptions.waypointoption import WaypointOption
from game.theater.theatergroup import TheaterUnit
from game.utils import Distance, meters
@ -41,6 +42,7 @@ class FlightWaypoint:
min_fuel: float | None = None
actions: list[WaypointAction] = field(default_factory=list)
options: dict[str, WaypointOption] = field(default_factory=dict)
# These are set very late by the air conflict generator (part of mission
# generation). We do it late so that we don't need to propagate changes
@ -52,6 +54,9 @@ class FlightWaypoint:
def add_action(self, action: WaypointAction) -> None:
self.actions.append(action)
def set_option(self, option: WaypointOption) -> None:
self.options[option.id()] = option
@property
def x(self) -> float:
return self.position.x

View File

@ -0,0 +1,35 @@
from collections.abc import Iterator
from datetime import datetime, timedelta
import dcs.task
from dcs.task import Task
from game.ato.flightstate.actionstate import ActionState
from game.utils import Distance
from .taskcontext import TaskContext
from .waypointaction import WaypointAction
class EngageTargets(WaypointAction):
def __init__(
self,
max_distance_from_flight: Distance,
target_types: list[type[dcs.task.TargetType]],
) -> None:
self._max_distance_from_flight = max_distance_from_flight
self._target_types = target_types
def update_state(
self, state: ActionState, time: datetime, duration: timedelta
) -> timedelta:
state.finish()
return duration
def describe(self) -> str:
return "Searching for targets"
def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]:
yield dcs.task.EngageTargets(
max_distance=int(self._max_distance_from_flight.meters),
targets=self._target_types,
)

View File

@ -0,0 +1,21 @@
from collections.abc import Iterator
from enum import Enum
from dcs.task import OptFormation, Task
from game.flightplan.waypointactions.taskcontext import TaskContext
from game.flightplan.waypointoptions.waypointoption import WaypointOption
class Formation(WaypointOption, Enum):
FINGER_FOUR_CLOSE = OptFormation.finger_four_close()
FINGER_FOUR_OPEN = OptFormation.finger_four_open()
LINE_ABREAST_OPEN = OptFormation.line_abreast_open()
SPREAD_FOUR_OPEN = OptFormation.spread_four_open()
TRAIL_OPEN = OptFormation.trail_open()
def id(self) -> str:
return "formation"
def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]:
yield self.value

View File

@ -0,0 +1,16 @@
from __future__ import annotations
from collections.abc import Iterator
from dcs.task import Task
from game.flightplan.waypointactions.taskcontext import TaskContext
# Not explicitly an ABC because that prevents subclasses from deriving Enum.
class WaypointOption:
def id(self) -> str:
raise RuntimeError
def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]:
raise RuntimeError

View File

@ -91,6 +91,9 @@ class PydcsWaypointBuilder:
for action in self.waypoint.actions:
for task in action.iter_tasks(ctx):
waypoint.add_task(task)
for option in self.waypoint.options.values():
for task in option.iter_tasks(ctx):
waypoint.add_task(task)
def set_waypoint_tot(self, waypoint: MovingPoint, tot: datetime) -> None:
self.waypoint.tot = tot

View File

@ -1,31 +0,0 @@
import logging
from dcs.point import MovingPoint
from dcs.task import EngageTargets, OptFormation, Targets
from game.ato.flightplans.sweep import SweepFlightPlan
from game.utils import nautical_miles
from .pydcswaypointbuilder import PydcsWaypointBuilder
class SweepIngressBuilder(PydcsWaypointBuilder):
def add_tasks(self, waypoint: MovingPoint) -> None:
if not isinstance(self.flight.flight_plan, SweepFlightPlan):
flight_plan_type = self.flight.flight_plan.__class__.__name__
logging.error(
f"Cannot create sweep for {self.flight} because "
f"{flight_plan_type} is not a sweep flight plan."
)
return
waypoint.tasks.append(
EngageTargets(
max_distance=int(nautical_miles(50).meters),
targets=[
Targets.All.Air.Planes.Fighters,
Targets.All.Air.Planes.MultiroleFighters,
],
)
)
waypoint.tasks.append(OptFormation.line_abreast_open())

View File

@ -41,7 +41,6 @@ from .refuel import RefuelPointBuilder
from .seadingress import SeadIngressBuilder
from .splitpoint import SplitPointBuilder
from .strikeingress import StrikeIngressBuilder
from .sweepingress import SweepIngressBuilder
from .target import TargetBuilder
@ -138,7 +137,6 @@ class WaypointGenerator:
FlightWaypointType.INGRESS_OCA_RUNWAY: OcaRunwayIngressBuilder,
FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder,
FlightWaypointType.INGRESS_STRIKE: StrikeIngressBuilder,
FlightWaypointType.INGRESS_SWEEP: SweepIngressBuilder,
FlightWaypointType.JOIN: JoinPointBuilder,
FlightWaypointType.LANDING_POINT: LandingPointBuilder,
FlightWaypointType.PATROL: RaceTrackEndBuilder,

View File

@ -0,0 +1,38 @@
from datetime import datetime, timedelta
from dcs.task import Targets
from game.ato.flightstate.actionstate import ActionState
from game.flightplan.waypointactions.engagetargets import EngageTargets
from game.flightplan.waypointactions.taskcontext import TaskContext
from game.utils import meters
def test_engage_targets() -> None:
tasks = list(
EngageTargets(
meters(100), [Targets.All.Air.Planes, Targets.All.Air.Helicopters]
).iter_tasks(TaskContext(datetime.now()))
)
assert len(tasks) == 1
task = tasks[0]
assert task.id == "EngageTargets"
assert task.params["targetTypes"] == {
1: Targets.All.Air.Planes,
2: Targets.All.Air.Helicopters,
}
assert task.params["value"] == "Planes;Helicopters"
assert task.params["maxDist"] == 100
def test_engage_targets_update_state() -> None:
task = EngageTargets(meters(100), [Targets.All])
state = ActionState(task)
assert not task.update_state(state, datetime.now(), timedelta())
assert state.is_finished()
def test_engage_targets_description() -> None:
assert (
EngageTargets(meters(100), [Targets.All]).describe() == "Searching for targets"
)

View File

@ -0,0 +1,13 @@
from datetime import datetime
from dcs.task import OptFormation
from game.flightplan.waypointactions.taskcontext import TaskContext
from game.flightplan.waypointoptions.formation import Formation
def test_formation() -> None:
tasks = list(Formation.LINE_ABREAST_OPEN.iter_tasks(TaskContext(datetime.now())))
assert len(tasks) == 1
task = tasks[0]
assert task.dict() == OptFormation.line_abreast_open().dict()