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 typing import Iterator, TYPE_CHECKING, Type
|
||||||
|
|
||||||
from dcs import Point
|
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 .ibuilder import IBuilder
|
||||||
from .loiter import LoiterFlightPlan, LoiterLayout
|
from .loiter import LoiterFlightPlan, LoiterLayout
|
||||||
from .waypointbuilder import WaypointBuilder
|
from .waypointbuilder import WaypointBuilder
|
||||||
from ...flightplan import HoldZoneGeometry
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from ..flightwaypoint import FlightWaypoint
|
from ..flightwaypoint import FlightWaypoint
|
||||||
@ -89,6 +92,19 @@ class SweepFlightPlan(LoiterFlightPlan[SweepLayout]):
|
|||||||
def mission_departure_time(self) -> datetime:
|
def mission_departure_time(self) -> datetime:
|
||||||
return self.sweep_end_time
|
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]):
|
class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
|
||||||
def layout(self) -> SweepLayout:
|
def layout(self) -> SweepLayout:
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from dcs import Point
|
|||||||
|
|
||||||
from game.ato.flightwaypointtype import FlightWaypointType
|
from game.ato.flightwaypointtype import FlightWaypointType
|
||||||
from game.flightplan.waypointactions.waypointaction import WaypointAction
|
from game.flightplan.waypointactions.waypointaction import WaypointAction
|
||||||
|
from game.flightplan.waypointoptions.waypointoption import WaypointOption
|
||||||
from game.theater.theatergroup import TheaterUnit
|
from game.theater.theatergroup import TheaterUnit
|
||||||
from game.utils import Distance, meters
|
from game.utils import Distance, meters
|
||||||
|
|
||||||
@ -41,6 +42,7 @@ class FlightWaypoint:
|
|||||||
min_fuel: float | None = None
|
min_fuel: float | None = None
|
||||||
|
|
||||||
actions: list[WaypointAction] = field(default_factory=list)
|
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
|
# 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
|
# 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:
|
def add_action(self, action: WaypointAction) -> None:
|
||||||
self.actions.append(action)
|
self.actions.append(action)
|
||||||
|
|
||||||
|
def set_option(self, option: WaypointOption) -> None:
|
||||||
|
self.options[option.id()] = option
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def x(self) -> float:
|
def x(self) -> float:
|
||||||
return self.position.x
|
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 action in self.waypoint.actions:
|
||||||
for task in action.iter_tasks(ctx):
|
for task in action.iter_tasks(ctx):
|
||||||
waypoint.add_task(task)
|
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:
|
def set_waypoint_tot(self, waypoint: MovingPoint, tot: datetime) -> None:
|
||||||
self.waypoint.tot = tot
|
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 .seadingress import SeadIngressBuilder
|
||||||
from .splitpoint import SplitPointBuilder
|
from .splitpoint import SplitPointBuilder
|
||||||
from .strikeingress import StrikeIngressBuilder
|
from .strikeingress import StrikeIngressBuilder
|
||||||
from .sweepingress import SweepIngressBuilder
|
|
||||||
from .target import TargetBuilder
|
from .target import TargetBuilder
|
||||||
|
|
||||||
|
|
||||||
@ -138,7 +137,6 @@ class WaypointGenerator:
|
|||||||
FlightWaypointType.INGRESS_OCA_RUNWAY: OcaRunwayIngressBuilder,
|
FlightWaypointType.INGRESS_OCA_RUNWAY: OcaRunwayIngressBuilder,
|
||||||
FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder,
|
FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder,
|
||||||
FlightWaypointType.INGRESS_STRIKE: StrikeIngressBuilder,
|
FlightWaypointType.INGRESS_STRIKE: StrikeIngressBuilder,
|
||||||
FlightWaypointType.INGRESS_SWEEP: SweepIngressBuilder,
|
|
||||||
FlightWaypointType.JOIN: JoinPointBuilder,
|
FlightWaypointType.JOIN: JoinPointBuilder,
|
||||||
FlightWaypointType.LANDING_POINT: LandingPointBuilder,
|
FlightWaypointType.LANDING_POINT: LandingPointBuilder,
|
||||||
FlightWaypointType.PATROL: RaceTrackEndBuilder,
|
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