mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Create a WaypointAction class that defines the actions taken at a waypoint. These will often map one-to-one with DCS waypoint actions but can also be higher level and generate multiple actions. Once everything has migrated all waypoint-type-specific behaviors of PydcsWaypointBuilder will be gone, and it'll be easier to keep the sim behaviors in sync with the mission generator behaviors. For now only hold has been migrated. This is actually probably the most complicated action we have (starting with this may have been a mistake, but it did find all the rough edges quickly) since it affects waypoint timings and flight position during simulation. That part isn't handled as neatly as I'd like because the FlightState still has to special case LOITER points to avoid simulating the wrong waypoint position. At some point we should probably start tracking real positions in FlightState, and when we do that will be solved.
55 lines
2.0 KiB
Python
55 lines
2.0 KiB
Python
from collections.abc import Iterator
|
|
from datetime import datetime, timedelta
|
|
|
|
from dcs.task import Task, OrbitAction, ControlledTask
|
|
|
|
from game.ato.flightstate.actionstate import ActionState
|
|
from game.provider import Provider
|
|
from game.utils import Distance, Speed
|
|
from .taskcontext import TaskContext
|
|
from .waypointaction import WaypointAction
|
|
|
|
|
|
class Hold(WaypointAction):
|
|
"""Loiter at a location until a push time to synchronize with other flights.
|
|
|
|
Taxi behavior is extremely unpredictable, so we cannot reliably predict ETAs for
|
|
waypoints without first fixing a time for one waypoint by holding until a sync time.
|
|
This is typically done with a dedicated hold point. If the flight reaches the hold
|
|
point before their push time, they will loiter at that location rather than fly to
|
|
their next waypoint as a speed that's often dangerously slow.
|
|
"""
|
|
|
|
def __init__(
|
|
self, push_time_provider: Provider[datetime], altitude: Distance, speed: Speed
|
|
) -> None:
|
|
self._push_time_provider = push_time_provider
|
|
self._altitude = altitude
|
|
self._speed = speed
|
|
|
|
def describe(self) -> str:
|
|
return self._push_time_provider().strftime("Holding until %H:%M:%S")
|
|
|
|
def update_state(
|
|
self, state: ActionState, time: datetime, duration: timedelta
|
|
) -> None:
|
|
if self._push_time_provider() <= time:
|
|
state.finish()
|
|
|
|
def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]:
|
|
remaining_time = self._push_time_provider() - ctx.mission_start_time
|
|
if remaining_time <= timedelta():
|
|
return
|
|
|
|
loiter = ControlledTask(
|
|
OrbitAction(
|
|
altitude=int(self._altitude.meters),
|
|
pattern=OrbitAction.OrbitPattern.Circle,
|
|
speed=self._speed.kph,
|
|
)
|
|
)
|
|
# The DCS task is serialized using the time from mission start, not the actual
|
|
# time.
|
|
loiter.stop_after_time(int(remaining_time.total_seconds()))
|
|
yield loiter
|