|
|
|
@@ -1,4 +1,5 @@
|
|
|
|
|
// Prepared control mechanism only. No global hooks, force allocation or HQ selection.
|
|
|
|
|
// Explicitly started control mechanism. The exact-owner production bridge adds
|
|
|
|
|
// no force allocation, flight creation or HQ selection.
|
|
|
|
|
enum ERR_AircraftFlightState
|
|
|
|
|
{
|
|
|
|
|
IDLE, HOOKS, STARTING, POSITIVE, NEGATIVE, CLIMB, LANDING, SHUTDOWN,
|
|
|
|
@@ -150,11 +151,36 @@ class ERR_AircraftFlight
|
|
|
|
|
{
|
|
|
|
|
if (!GetGame() || !GetGame().GetWorld() || !GetGame().GetPlayerManager()) return false;
|
|
|
|
|
if (!Replication.IsServer() || !m_Mode || m_Mode != ERR_GameMode.Get() || !m_Mode.Active() || !m_Aircraft || !m_Group || !m_Pilot) return false;
|
|
|
|
|
if (m_Mode.GetWorld() != GetGame().GetWorld() || m_Aircraft.GetWorld() != m_Mode.GetWorld() || m_Pilot.GetWorld() != m_Mode.GetWorld()) return false;
|
|
|
|
|
if (!m_Controller || m_Controller.GetOwner() != m_Aircraft || !m_Seat || m_Controller.GetPilotCompartmentSlot() != m_Seat || m_Seat.GetOccupant() != m_Pilot) return false;
|
|
|
|
|
if (CompartmentAccessComponent.GetVehicleIn(m_Pilot) != m_Aircraft || ERR_Actors.Group(m_Pilot) != m_Group || m_Group.GetFaction() != m_Mode.EnemyFaction()) return false;
|
|
|
|
|
if (SCR_FactionManager.SGetFaction(m_Aircraft) != m_Mode.EnemyFaction() || !NoPlayers()) return false;
|
|
|
|
|
return m_Agent && m_Agent.GetControlledEntity() == m_Pilot && m_Agent.GetActionManager() == m_Actions && m_Actions && m_Actions != GetGame().GetInputManager();
|
|
|
|
|
}
|
|
|
|
|
// Registry lookup never adopts an aircraft or starts a flight. Recheck the
|
|
|
|
|
// original lease/ownership before dispatch, including human capture. The
|
|
|
|
|
// character lookup is O(1), based on the callback actor's physical vehicle.
|
|
|
|
|
static void DispatchActions(CharacterControllerComponent controller, IEntity owner, ActionManager actions, float dt, bool player)
|
|
|
|
|
{
|
|
|
|
|
if (!Replication.IsServer() || !s_Owners || !controller || !owner || !actions) return;
|
|
|
|
|
Vehicle aircraft = Vehicle.Cast(CompartmentAccessComponent.GetVehicleIn(owner));
|
|
|
|
|
if (!aircraft) return;
|
|
|
|
|
ERR_AircraftFlight flight = s_Owners.Get(aircraft);
|
|
|
|
|
if (!flight || !flight.Lease()) return;
|
|
|
|
|
if (!flight.Owns()) { flight.Relinquish("native character callback lost original ownership"); return; }
|
|
|
|
|
if (player) return;
|
|
|
|
|
flight.PrepareActions(controller, owner, actions, dt);
|
|
|
|
|
}
|
|
|
|
|
static void DispatchHelicopter(HelicopterControllerComponent controller)
|
|
|
|
|
{
|
|
|
|
|
if (!Replication.IsServer() || !s_Owners || !controller) return;
|
|
|
|
|
Vehicle aircraft = Vehicle.Cast(controller.GetOwner());
|
|
|
|
|
if (!aircraft) return;
|
|
|
|
|
ERR_AircraftFlight flight = s_Owners.Get(aircraft);
|
|
|
|
|
if (!flight || !flight.Lease()) return;
|
|
|
|
|
if (!flight.Owns()) { flight.Relinquish("native helicopter callback lost original ownership"); return; }
|
|
|
|
|
flight.PrepareHelicopter(controller);
|
|
|
|
|
}
|
|
|
|
|
protected bool Healthy()
|
|
|
|
|
{
|
|
|
|
|
if (!ERR_Actors.Alive(m_Aircraft) || !ERR_Actors.CanFight(m_Pilot) || !m_Simulation || !m_Simulation.IsValid() || !m_Fuel || !m_Fuel.HasFuel()) return false;
|
|
|
|
@@ -170,7 +196,8 @@ class ERR_AircraftFlight
|
|
|
|
|
return ERR_AircraftFlightRules.Landed(m_Simulation.HasAnyGroundContact(), transform[3][1] - m_Home[1], m_Simulation.GetVelocity().Length(), m_Simulation.GetAngularVelocity().Length(), transform[1][1]);
|
|
|
|
|
}
|
|
|
|
|
// Single use. A future HQ owner supplies its immutable unique order token and
|
|
|
|
|
// retains this instance, calling Tick and the two scoped callbacks until terminal.
|
|
|
|
|
// retains this instance and calls Tick until terminal. The production bridge
|
|
|
|
|
// dispatches the two exact-owner native callbacks; callers must not duplicate them.
|
|
|
|
|
bool Start(ERR_GameMode mode, Vehicle aircraft, SCR_AIGroup group, IEntity pilot, PilotCompartmentSlot seat, ERR_AircraftFlightEnvelope qualification, int token, float deadline)
|
|
|
|
|
{
|
|
|
|
|
if (m_StartAttempted || m_State != ERR_AircraftFlightState.IDLE || m_Token != 0 || !Replication.IsServer() || !GetGame() || !qualification || !aircraft || !pilot || !group || !seat) return false;
|
|
|
|
|