mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Migrate sweep ingress's tasks to waypoint actions.
This commit is contained in:
parent
c00f853f34
commit
b7723843c6
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
35
game/flightplan/waypointactions/engagetargets.py
Normal file
35
game/flightplan/waypointactions/engagetargets.py
Normal 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,
|
||||
)
|
||||
0
game/flightplan/waypointoptions/__init__.py
Normal file
0
game/flightplan/waypointoptions/__init__.py
Normal file
21
game/flightplan/waypointoptions/formation.py
Normal file
21
game/flightplan/waypointoptions/formation.py
Normal 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
|
||||
16
game/flightplan/waypointoptions/waypointoption.py
Normal file
16
game/flightplan/waypointoptions/waypointoption.py
Normal 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
|
||||
@ -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
|
||||
|
||||
@ -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())
|
||||
@ -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,
|
||||
|
||||
38
tests/flightplan/waypointactions/test_engagetargets.py
Normal file
38
tests/flightplan/waypointactions/test_engagetargets.py
Normal 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"
|
||||
)
|
||||
0
tests/flightplan/waypointoptions/__init__.py
Normal file
0
tests/flightplan/waypointoptions/__init__.py
Normal file
13
tests/flightplan/waypointoptions/test_formation.py
Normal file
13
tests/flightplan/waypointoptions/test_formation.py
Normal 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()
|
||||
Loading…
x
Reference in New Issue
Block a user