2022-10-23 19:02:39 +08:00
|
|
|
|
using System;
|
|
|
|
|
using GTA;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
using GTA.Math;
|
2022-07-20 17:50:01 +08:00
|
|
|
|
using GTA.Native;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
using RageCoop.Core;
|
|
|
|
|
|
|
|
|
|
namespace RageCoop.Client
|
|
|
|
|
{
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// <summary>
|
2022-10-23 19:02:39 +08:00
|
|
|
|
/// A synchronized vehicle instance
|
2022-07-01 13:54:18 +08:00
|
|
|
|
/// </summary>
|
2022-08-18 20:44:39 +08:00
|
|
|
|
public partial class SyncedVehicle : SyncedEntity
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-06-11 18:41:10 +08:00
|
|
|
|
internal override void Update()
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-11-20 15:55:11 +08:00
|
|
|
|
// Check if all data available
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (!IsReady || Owner == null) return;
|
2022-08-18 20:44:39 +08:00
|
|
|
|
|
|
|
|
|
// Check existence
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model != Model)
|
2022-07-15 13:45:43 +08:00
|
|
|
|
if (!CreateVehicle())
|
|
|
|
|
return;
|
2022-08-22 19:25:03 +08:00
|
|
|
|
|
|
|
|
|
|
2022-12-04 19:34:54 +08:00
|
|
|
|
DisplayVehicle(NeedUpdate);
|
2022-07-17 19:19:23 +08:00
|
|
|
|
// Skip update if no new sync message has arrived.
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (!NeedUpdate) return;
|
2022-09-06 21:46:35 +08:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
if (SteeringAngle != MainVehicle.SteeringAngle)
|
|
|
|
|
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
|
2022-09-06 21:46:35 +08:00
|
|
|
|
MainVehicle.ThrottlePower = ThrottlePower;
|
|
|
|
|
MainVehicle.BrakePower = BrakePower;
|
|
|
|
|
|
2022-07-17 12:22:11 +08:00
|
|
|
|
if (IsDead)
|
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (MainVehicle.IsDead) return;
|
2022-08-11 14:48:19 +02:00
|
|
|
|
|
|
|
|
|
MainVehicle.Explode();
|
2022-07-17 12:22:11 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (MainVehicle.IsDead)
|
2022-10-09 11:15:09 +08:00
|
|
|
|
WorldThread.Delay(() =>
|
2022-07-21 22:42:29 +08:00
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (MainVehicle.IsDead && !IsDead) MainVehicle.Repair();
|
2022-09-06 21:46:35 +08:00
|
|
|
|
}, 1000);
|
2022-07-17 12:22:11 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-07-17 20:12:25 +08:00
|
|
|
|
if (MainVehicle.IsOnFire)
|
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
if (!Flags.HasVehFlag(VehicleDataFlags.IsOnFire)) Call(STOP_ENTITY_FIRE, MainVehicle);
|
2022-07-17 20:12:25 +08:00
|
|
|
|
}
|
|
|
|
|
else if (Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
|
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(START_ENTITY_FIRE, MainVehicle);
|
2022-07-17 20:12:25 +08:00
|
|
|
|
}
|
2022-07-17 12:22:11 +08:00
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (EngineRunning != MainVehicle.IsEngineRunning) MainVehicle.IsEngineRunning = EngineRunning;
|
2022-07-17 12:22:11 +08:00
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (LightsOn != MainVehicle.AreLightsOn) MainVehicle.AreLightsOn = LightsOn;
|
2022-07-17 12:22:11 +08:00
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (HighBeamsOn != MainVehicle.AreHighBeamsOn) MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
2022-07-17 12:22:11 +08:00
|
|
|
|
|
2022-08-18 20:44:39 +08:00
|
|
|
|
if (IsAircraft)
|
2022-07-17 12:22:11 +08:00
|
|
|
|
{
|
|
|
|
|
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
|
|
|
|
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
|
|
|
|
|
MainVehicle.IsSirenActive = SireneActive;
|
|
|
|
|
|
|
|
|
|
if (HornActive)
|
|
|
|
|
{
|
|
|
|
|
if (!_lastHornActive)
|
|
|
|
|
{
|
|
|
|
|
_lastHornActive = true;
|
|
|
|
|
MainVehicle.SoundHorn(99999);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (_lastHornActive)
|
|
|
|
|
{
|
|
|
|
|
_lastHornActive = false;
|
|
|
|
|
MainVehicle.SoundHorn(1);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (HasRoof && MainVehicle.RoofState != RoofState) MainVehicle.RoofState = RoofState;
|
2022-07-17 12:22:11 +08:00
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) !=
|
2022-11-30 19:08:52 +08:00
|
|
|
|
MainVehicle.IsRocketBoostActive)
|
|
|
|
|
MainVehicle.IsRocketBoostActive = Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive);
|
|
|
|
|
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) &&
|
|
|
|
|
!MainVehicle.IsParachuteDeployed)
|
|
|
|
|
MainVehicle.StartParachuting(false);
|
2022-08-18 20:44:39 +08:00
|
|
|
|
if (IsSubmarineCar)
|
|
|
|
|
{
|
|
|
|
|
if (Transformed)
|
2022-08-17 23:18:06 +08:00
|
|
|
|
{
|
2022-08-18 20:44:39 +08:00
|
|
|
|
if (!_lastTransformed)
|
|
|
|
|
{
|
|
|
|
|
_lastTransformed = true;
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
|
2022-08-17 23:18:06 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-18 20:44:39 +08:00
|
|
|
|
else if (_lastTransformed)
|
|
|
|
|
{
|
|
|
|
|
_lastTransformed = false;
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(TRANSFORM_TO_CAR, MainVehicle.Handle, false);
|
2022-08-17 23:18:06 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-06 21:46:35 +08:00
|
|
|
|
else if (IsDeluxo)
|
2022-08-23 13:45:45 +08:00
|
|
|
|
{
|
2022-08-18 20:44:39 +08:00
|
|
|
|
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (IsDeluxoHovering) MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
2022-08-18 08:25:15 +08:00
|
|
|
|
}
|
2022-08-17 23:18:06 +08:00
|
|
|
|
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
2022-07-17 12:22:11 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-09-06 21:46:35 +08:00
|
|
|
|
MainVehicle.LockStatus = LockStatus;
|
2022-07-17 12:22:11 +08:00
|
|
|
|
|
2022-09-06 21:46:35 +08:00
|
|
|
|
if (LastFullSynced >= LastUpdated)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair();
|
2022-05-22 15:55:26 +08:00
|
|
|
|
if (Colors != null && Colors != _lastVehicleColors)
|
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_VEHICLE_COLOURS, MainVehicle, Colors[0], Colors[1]);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
|
|
|
|
_lastVehicleColors = Colors;
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-09-06 21:46:35 +08:00
|
|
|
|
MainVehicle.EngineHealth = EngineHealth;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
if (Mods != null && !Mods.Compare(_lastVehicleMods))
|
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
foreach (var mod in Mods) MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
|
|
|
|
|
_lastVehicleMods = Mods;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-28 20:51:29 +08:00
|
|
|
|
if (Call<string>(GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate)
|
|
|
|
|
Call(SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
|
2022-07-09 22:18:00 +08:00
|
|
|
|
|
2022-09-06 21:46:35 +08:00
|
|
|
|
if (_lastLivery != Livery)
|
2022-07-09 22:18:00 +08:00
|
|
|
|
{
|
2023-01-28 20:51:29 +08:00
|
|
|
|
Call(SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
2022-09-06 21:46:35 +08:00
|
|
|
|
_lastLivery = Livery;
|
2022-07-09 22:18:00 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-08-22 11:36:52 +08:00
|
|
|
|
MainVehicle.SetDamageModel(DamageModel);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-09-06 21:46:35 +08:00
|
|
|
|
LastUpdated = Main.Ticked;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-09-06 21:46:35 +08:00
|
|
|
|
|
2022-12-04 19:34:54 +08:00
|
|
|
|
private void DisplayVehicle(bool updated)
|
2022-07-17 19:19:23 +08:00
|
|
|
|
{
|
2022-08-22 21:59:01 +08:00
|
|
|
|
_predictedPosition = Predict(Position);
|
2022-07-23 23:45:20 +08:00
|
|
|
|
var current = MainVehicle.ReadPosition();
|
2022-11-20 15:55:11 +08:00
|
|
|
|
var distSquared = current.DistanceToSquared(_predictedPosition);
|
2022-11-20 16:29:11 +08:00
|
|
|
|
var cali = _predictedPosition - current;
|
2022-11-30 20:17:06 +08:00
|
|
|
|
if (!IsTrain) cali += 0.5f * (Velocity - MainVehicle.Velocity);
|
2022-11-20 15:55:11 +08:00
|
|
|
|
if (distSquared > 10 * 10)
|
2022-07-17 19:19:23 +08:00
|
|
|
|
{
|
2022-08-18 22:08:06 +08:00
|
|
|
|
MainVehicle.Position = _predictedPosition;
|
2022-08-10 20:42:47 +08:00
|
|
|
|
MainVehicle.Velocity = Velocity;
|
2022-08-11 14:48:19 +02:00
|
|
|
|
MainVehicle.Quaternion = Quaternion;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-12-04 19:34:54 +08:00
|
|
|
|
// Calibrate position
|
|
|
|
|
if (distSquared > 0.03 * 0.03)
|
|
|
|
|
{
|
|
|
|
|
if (IsTrain || distSquared > 20 * 20) MainVehicle.Velocity = Velocity + cali;
|
|
|
|
|
else MainVehicle.ApplyForce(cali);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Quaternion predictedQuat = updated ? Quaternion :
|
|
|
|
|
Quaternion.Lerp(LastQuaternion, Quaternion, 1 + LastSyncedStopWatch.ElapsedMilliseconds / (float)LastSyncInterval);
|
2022-11-20 15:55:11 +08:00
|
|
|
|
var curQuat = MainVehicle.Quaternion;
|
2022-12-04 19:34:54 +08:00
|
|
|
|
MainVehicle.ApplyForce((predictedQuat * TopExtent - curQuat * TopExtent) * RotCalMult, TopExtent);
|
|
|
|
|
MainVehicle.ApplyForce((predictedQuat * FrontExtent - curQuat * FrontExtent) * RotCalMult, FrontExtent);
|
|
|
|
|
// MainVehicle.ApplyForce((predictedQuat * BottomExtent - curQuat * BottomExtent) * RotCalMult, BottomExtent);
|
|
|
|
|
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-07-15 13:45:43 +08:00
|
|
|
|
private bool CreateVehicle()
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
|
|
|
|
MainVehicle?.Delete();
|
2022-07-15 13:45:43 +08:00
|
|
|
|
MainVehicle = Util.CreateVehicle(Model, Position);
|
|
|
|
|
if (!Model.IsInCdImage)
|
|
|
|
|
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
|
|
|
|
return false;
|
2022-09-06 21:46:35 +08:00
|
|
|
|
if (MainVehicle == null)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
2022-07-15 13:45:43 +08:00
|
|
|
|
Model.Request();
|
|
|
|
|
return false;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
lock (EntityPool.VehiclesLock)
|
|
|
|
|
{
|
2022-07-15 13:45:43 +08:00
|
|
|
|
EntityPool.Add(this);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-06-03 14:40:41 +08:00
|
|
|
|
MainVehicle.Quaternion = Quaternion;
|
2022-10-23 19:02:39 +08:00
|
|
|
|
if (MainVehicle.HasRoof) MainVehicle.RoofState = RoofState;
|
|
|
|
|
foreach (var w in MainVehicle.Wheels) w.Fix();
|
|
|
|
|
if (IsInvincible) MainVehicle.IsInvincible = true;
|
2022-08-18 20:44:39 +08:00
|
|
|
|
SetUpFixedData();
|
2022-07-15 13:45:43 +08:00
|
|
|
|
Model.MarkAsNoLongerNeeded();
|
|
|
|
|
return true;
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
|
|
|
|
#region -- CONSTRUCTORS --
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create a local entity (outgoing sync)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="v"></param>
|
|
|
|
|
internal SyncedVehicle(Vehicle v)
|
|
|
|
|
{
|
|
|
|
|
ID = EntityPool.RequestNewID();
|
|
|
|
|
MainVehicle = v;
|
|
|
|
|
MainVehicle.CanPretendOccupants = false;
|
|
|
|
|
OwnerID = Main.LocalPlayerID;
|
|
|
|
|
SetUpFixedData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SetUpFixedData()
|
|
|
|
|
{
|
|
|
|
|
if (MainVehicle == null) return;
|
|
|
|
|
|
|
|
|
|
IsAircraft = MainVehicle.IsAircraft;
|
|
|
|
|
IsMotorcycle = MainVehicle.IsMotorcycle;
|
|
|
|
|
HasRocketBoost = MainVehicle.HasRocketBoost;
|
|
|
|
|
HasParachute = MainVehicle.HasParachute;
|
|
|
|
|
HasRoof = MainVehicle.HasRoof;
|
|
|
|
|
IsSubmarineCar = MainVehicle.IsSubmarineCar;
|
|
|
|
|
IsDeluxo = MainVehicle.Model == 1483171323;
|
2022-11-20 15:55:11 +08:00
|
|
|
|
IsTrain = MainVehicle.IsTrain;
|
2022-12-04 19:34:54 +08:00
|
|
|
|
// var (rbl, ftr) = MainVehicle.Model.Dimensions;
|
|
|
|
|
FrontExtent = new Vector3(0, ExtentLength, 0);
|
|
|
|
|
RearExtent = -FrontExtent;
|
|
|
|
|
TopExtent = new Vector3(0, ExtentLength, 5);
|
|
|
|
|
BottomExtent = -TopExtent;
|
|
|
|
|
RightExtent = new Vector3(5, ExtentLength, 0);
|
|
|
|
|
LeftExtent = -RightExtent;
|
2022-10-23 19:02:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create an empty VehicleEntity
|
|
|
|
|
/// </summary>
|
|
|
|
|
internal SyncedVehicle()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal SyncedVehicle(int id)
|
|
|
|
|
{
|
|
|
|
|
ID = id;
|
|
|
|
|
LastSynced = Main.Ticked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2022-09-05 13:02:09 +02:00
|
|
|
|
#region -- PEDALING --
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-05-22 15:55:26 +08:00
|
|
|
|
/*
|
|
|
|
|
* Thanks to @oldnapalm.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
private string PedalingAnimDict()
|
|
|
|
|
{
|
2022-07-15 13:45:43 +08:00
|
|
|
|
switch ((VehicleHash)Model)
|
2022-05-22 15:55:26 +08:00
|
|
|
|
{
|
|
|
|
|
case VehicleHash.Bmx:
|
|
|
|
|
return "veh@bicycle@bmx@front@base";
|
|
|
|
|
case VehicleHash.Cruiser:
|
|
|
|
|
return "veh@bicycle@cruiserfront@base";
|
|
|
|
|
case VehicleHash.Scorcher:
|
|
|
|
|
return "veh@bicycle@mountainfront@base";
|
|
|
|
|
default:
|
|
|
|
|
return "veh@bicycle@roadfront@base";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string PedalingAnimName(bool fast)
|
|
|
|
|
{
|
|
|
|
|
return fast ? "fast_pedal_char" : "cruise_pedal_char";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void StartPedalingAnim(bool fast)
|
|
|
|
|
{
|
2022-10-23 19:02:39 +08:00
|
|
|
|
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1,
|
2023-01-28 20:51:29 +08:00
|
|
|
|
AnimationFlags.Loop | AnimationFlags.Secondary, 1.0f);
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void StopPedalingAnim(bool fast)
|
|
|
|
|
{
|
|
|
|
|
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
|
2022-09-06 21:46:35 +08:00
|
|
|
|
#endregion
|
2022-05-22 15:55:26 +08:00
|
|
|
|
}
|
2022-10-23 19:02:39 +08:00
|
|
|
|
}
|