Use struct to serialize vehicle data

This gonna reduce the tedious work needed to add a new sync, also beings a performance boost
Ped, projectile sync will be updated later
This commit is contained in:
Sardelka9515
2023-03-26 15:36:15 +08:00
parent 826e80c5d8
commit 4fbdd86566
24 changed files with 445 additions and 550 deletions

View File

@ -321,37 +321,21 @@ namespace RageCoop.Client
private static void VehicleSync(Packets.VehicleSync packet)
{
var v = EntityPool.GetVehicleByID(packet.ID);
if (v == null) EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ID));
var v = EntityPool.GetVehicleByID(packet.ED.ID);
if (v == null) EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ED.ID));
if (v.IsLocal) return;
v.ID = packet.ID;
v.OwnerID = packet.OwnerID;
v.Flags = packet.Flags;
v.Position = packet.Position;
v.Quaternion = packet.Quaternion;
v.SteeringAngle = packet.SteeringAngle;
v.ThrottlePower = packet.ThrottlePower;
v.BrakePower = packet.BrakePower;
v.Velocity = packet.Velocity;
v.RotationVelocity = packet.RotationVelocity;
v.DeluxoWingRatio = packet.DeluxoWingRatio;
bool full = packet.Flags.HasVehFlag(VehicleDataFlags.IsFullSync);
v.ID = packet.ED.ID;
v.OwnerID = packet.ED.OwnerID;
v.Position = packet.ED.Position;
v.Quaternion = packet.ED.Quaternion;
v.Velocity = packet.ED.Velocity;
v.Model = packet.ED.ModelHash;
v.VD = packet.VD;
bool full = packet.VD.Flags.HasVehFlag(VehicleDataFlags.IsFullSync);
if (full)
{
v.DamageModel = packet.DamageModel;
v.EngineHealth = packet.EngineHealth;
v.Mods = packet.Mods;
v.ToggleModsMask = packet.ToggleModsMask;
v.Model = packet.ModelHash;
v.Colors = packet.Colors;
v.LandingGear = packet.LandingGear;
v.RoofState = (VehicleRoofState)packet.RoofState;
v.LockStatus = packet.LockStatus;
v.RadioStation = packet.RadioStation;
v.LicensePlate = packet.LicensePlate;
v.Livery = packet.Livery;
v.HeadlightColor = packet.HeadlightColor;
v.ExtrasMask = packet.ExtrasMask;
v.VDF = packet.VDF;
v.VDV = packet.VDV;
}
v.SetLastSynced(full);
}

View File

@ -103,19 +103,22 @@ namespace RageCoop.Client
if (v.LastSentStopWatch.ElapsedMilliseconds < SyncInterval) return;
var veh = v.MainVehicle;
var packet = SendPackets.VehicelPacket;
packet.ID = v.ID;
packet.OwnerID = v.OwnerID;
packet.Flags = v.GetVehicleFlags();
packet.SteeringAngle = veh.SteeringAngle;
packet.Position = veh.ReadPosition();
packet.Velocity = veh.Velocity;
packet.Quaternion = veh.ReadQuaternion();
packet.RotationVelocity = veh.WorldRotationVelocity;
packet.ThrottlePower = veh.ThrottlePower;
packet.BrakePower = veh.BrakePower;
packet.ED.ID = v.ID;
packet.ED.OwnerID = v.OwnerID;
packet.ED.Position = veh.ReadPosition();
packet.ED.Velocity = veh.Velocity;
packet.ED.Quaternion = veh.ReadQuaternion();
packet.ED.ModelHash = veh.Model.Hash;
packet.VD.Flags = v.GetVehicleFlags();
packet.VD.SteeringAngle = veh.SteeringAngle;
packet.VD.ThrottlePower = veh.ThrottlePower;
packet.VD.BrakePower = veh.BrakePower;
packet.VD.Flags |= VehicleDataFlags.IsFullSync;
packet.VD.LockStatus = veh.LockStatus;
v.LastSentStopWatch.Restart();
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
packet.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio();
if (packet.VD.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
packet.VD.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio();
if (full)
{
byte primaryColor = 0;
@ -125,23 +128,21 @@ namespace RageCoop.Client
Call<byte>(GET_VEHICLE_COLOURS, veh, &primaryColor, &secondaryColor);
}
packet.Flags |= VehicleDataFlags.IsFullSync;
packet.Colors = (primaryColor, secondaryColor);
packet.DamageModel = veh.GetVehicleDamageModel();
packet.LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0;
packet.RoofState = (byte)veh.RoofState;
packet.Mods = v.GetVehicleMods(out packet.ToggleModsMask);
packet.ModelHash = veh.Model.Hash;
packet.EngineHealth = veh.EngineHealth;
packet.LockStatus = veh.LockStatus;
packet.LicensePlate = Call<string>(GET_VEHICLE_NUMBER_PLATE_TEXT, veh);
packet.Livery = Call<int>(GET_VEHICLE_LIVERY, veh);
packet.HeadlightColor = (byte)Call<int>(GET_VEHICLE_XENON_LIGHT_COLOR_INDEX, veh);
packet.ExtrasMask = v.GetVehicleExtras();
packet.RadioStation = v.MainVehicle == LastV
packet.VDF.LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0;
packet.VDF.RoofState = (byte)veh.RoofState;
packet.VDF.Colors = (primaryColor, secondaryColor);
packet.VDF.DamageModel = veh.GetVehicleDamageModel();
packet.VDF.EngineHealth = veh.EngineHealth;
packet.VDF.Livery = Call<int>(GET_VEHICLE_LIVERY, veh);
packet.VDF.HeadlightColor = (byte)Call<int>(GET_VEHICLE_XENON_LIGHT_COLOR_INDEX, veh);
packet.VDF.ExtrasMask = v.GetVehicleExtras();
packet.VDF.RadioStation = v.MainVehicle == LastV
? Util.GetPlayerRadioIndex() : byte.MaxValue;
if (packet.EngineHealth > v.LastEngineHealth) packet.Flags |= VehicleDataFlags.Repaired;
v.LastEngineHealth = packet.EngineHealth;
if (packet.VDF.EngineHealth > v.LastEngineHealth) packet.VD.Flags |= VehicleDataFlags.Repaired;
packet.VDV.Mods = v.GetVehicleMods(out packet.VDF.ToggleModsMask);
packet.VDV.LicensePlate = Call<string>(GET_VEHICLE_NUMBER_PLATE_TEXT, veh);
v.LastEngineHealth = packet.VDF.EngineHealth;
}
SendSync(packet, ConnectionChannel.VehicleSync);

View File

@ -12,42 +12,23 @@ namespace RageCoop.Client
#region -- SYNC DATA --
internal Vector3 RotationVelocity { get; set; }
internal float SteeringAngle { get; set; }
internal float ThrottlePower { get; set; }
internal float BrakePower { get; set; }
internal float DeluxoWingRatio { get; set; } = -1;
internal byte LandingGear { get; set; }
internal VehicleRoofState RoofState { get; set; }
internal VehicleDamageModel DamageModel { get; set; }
internal (byte, byte) Colors { get; set; }
internal (int, int)[] Mods { get; set; }
internal float EngineHealth { get; set; }
internal VehicleLockStatus LockStatus { get; set; }
internal byte RadioStation = 255;
internal string LicensePlate { get; set; }
internal int Livery { get; set; } = -1;
internal byte HeadlightColor { get; set; } = 255;
internal VehicleDataFlags Flags { get; set; }
internal ushort ExtrasMask;
internal byte ToggleModsMask;
internal VehicleData VD;
internal VehicleDataFull VDF;
internal VehicleDataVar VDV;
#endregion
#region FLAGS
internal bool EngineRunning => Flags.HasVehFlag(VehicleDataFlags.IsEngineRunning);
internal bool Transformed => Flags.HasVehFlag(VehicleDataFlags.IsTransformed);
internal bool HornActive => Flags.HasVehFlag(VehicleDataFlags.IsHornActive);
internal bool LightsOn => Flags.HasVehFlag(VehicleDataFlags.AreLightsOn);
internal bool BrakeLightsOn => Flags.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn);
internal bool HighBeamsOn => Flags.HasVehFlag(VehicleDataFlags.AreHighBeamsOn);
internal bool SireneActive => Flags.HasVehFlag(VehicleDataFlags.IsSirenActive);
internal bool IsDead => Flags.HasVehFlag(VehicleDataFlags.IsDead);
internal bool IsDeluxoHovering => Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering);
internal bool EngineRunning => VD.Flags.HasVehFlag(VehicleDataFlags.IsEngineRunning);
internal bool Transformed => VD.Flags.HasVehFlag(VehicleDataFlags.IsTransformed);
internal bool HornActive => VD.Flags.HasVehFlag(VehicleDataFlags.IsHornActive);
internal bool LightsOn => VD.Flags.HasVehFlag(VehicleDataFlags.AreLightsOn);
internal bool BrakeLightsOn => VD.Flags.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn);
internal bool HighBeamsOn => VD.Flags.HasVehFlag(VehicleDataFlags.AreHighBeamsOn);
internal bool SireneActive => VD.Flags.HasVehFlag(VehicleDataFlags.IsSirenActive);
internal bool IsDead => VD.Flags.HasVehFlag(VehicleDataFlags.IsDead);
internal bool IsDeluxoHovering => VD.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering);
#endregion
@ -69,15 +50,13 @@ namespace RageCoop.Client
#endregion
#region PRIVATE
private byte _lastToggleMods;
private (byte, byte) _lastVehicleColors;
private ushort _lastExtras;
private (int, int)[] _lastVehicleMods = Array.Empty<(int, int)>();
private bool _lastHornActive;
private bool _lastTransformed;
private int _lastLivery = -1;
private byte _lastHeadlightColor = 255;
private VehicleData _lastVD;
private VehicleDataFull _lastVDF;
private VehicleDataVar _lastVDV;
private Vector3 _predictedPosition;
internal bool _lastTransformed => _lastVD.Flags.HasVehFlag(VehicleDataFlags.IsTransformed);
internal bool _lastHornActive => _lastVD.Flags.HasVehFlag(VehicleDataFlags.IsHornActive);
#endregion
#region OUTGOING

View File

@ -29,10 +29,10 @@ namespace RageCoop.Client
// Skip update if no new sync message has arrived.
if (!NeedUpdate) return;
if (SteeringAngle != MainVehicle.SteeringAngle)
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
MainVehicle.ThrottlePower = ThrottlePower;
MainVehicle.BrakePower = BrakePower;
if (VD.SteeringAngle != MainVehicle.SteeringAngle)
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * VD.SteeringAngle);
MainVehicle.ThrottlePower = VD.ThrottlePower;
MainVehicle.BrakePower = VD.BrakePower;
if (IsDead)
{
@ -51,9 +51,9 @@ namespace RageCoop.Client
if (MainVehicle.IsOnFire)
{
if (!Flags.HasVehFlag(VehicleDataFlags.IsOnFire)) Call(STOP_ENTITY_FIRE, MainVehicle);
if (!VD.Flags.HasVehFlag(VehicleDataFlags.IsOnFire)) Call(STOP_ENTITY_FIRE, MainVehicle);
}
else if (Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
else if (VD.Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
{
Call(START_ENTITY_FIRE, MainVehicle);
}
@ -64,12 +64,7 @@ namespace RageCoop.Client
if (HighBeamsOn != MainVehicle.AreHighBeamsOn) MainVehicle.AreHighBeamsOn = HighBeamsOn;
if (IsAircraft)
{
if (LandingGear != (byte)MainVehicle.LandingGearState)
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
}
else
if (!IsAircraft)
{
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
MainVehicle.IsSirenActive = SireneActive;
@ -78,22 +73,18 @@ namespace RageCoop.Client
{
if (!_lastHornActive)
{
_lastHornActive = true;
MainVehicle.SoundHorn(99999);
}
}
else if (_lastHornActive)
else if (_lastVD.Flags.HasVehFlag(VehicleDataFlags.IsHornActive))
{
_lastHornActive = false;
MainVehicle.SoundHorn(1);
}
if (HasRoof && MainVehicle.RoofState != RoofState) MainVehicle.RoofState = RoofState;
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) !=
if (HasRocketBoost && VD.Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) !=
MainVehicle.IsRocketBoostActive)
MainVehicle.IsRocketBoostActive = Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive);
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) &&
MainVehicle.IsRocketBoostActive = VD.Flags.HasVehFlag(VehicleDataFlags.IsRocketBoostActive);
if (HasParachute && VD.Flags.HasFlag(VehicleDataFlags.IsParachuteActive) &&
!MainVehicle.IsParachuteDeployed)
MainVehicle.StartParachuting(false);
if (IsSubmarineCar)
@ -102,75 +93,68 @@ namespace RageCoop.Client
{
if (!_lastTransformed)
{
_lastTransformed = true;
Call(TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
}
}
else if (_lastTransformed)
{
_lastTransformed = false;
Call(TRANSFORM_TO_CAR, MainVehicle.Handle, false);
}
}
else if (IsDeluxo)
{
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
if (IsDeluxoHovering) MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
if (IsDeluxoHovering) MainVehicle.SetDeluxoWingRatio(VD.DeluxoWingRatio);
}
Call(SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
MainVehicle.LockStatus = VD.LockStatus;
}
MainVehicle.LockStatus = LockStatus;
_lastVD = VD;
if (LastFullSynced >= LastUpdated)
{
if (Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair();
if (Colors != _lastVehicleColors)
if (IsAircraft)
{
Call(SET_VEHICLE_COLOURS, MainVehicle, Colors.Item1, Colors.Item2);
_lastVehicleColors = Colors;
if (VDF.LandingGear != (byte)MainVehicle.LandingGearState)
MainVehicle.LandingGearState = (VehicleLandingGearState)VDF.LandingGear;
}
MainVehicle.EngineHealth = EngineHealth;
if (Mods != null && !Mods.SequenceEqual(_lastVehicleMods))
if (HasRoof && MainVehicle.RoofState != (VehicleRoofState)VDF.RoofState)
MainVehicle.RoofState = (VehicleRoofState)VDF.RoofState;
if (VD.Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair();
if (VDF.Colors != _lastVDF.Colors)
{
Call(SET_VEHICLE_MOD_KIT, MainVehicle, 0);
foreach (var mod in Mods) MainVehicle.Mods[(VehicleModType)mod.Item1].Index = mod.Item2;
_lastVehicleMods = Mods;
Call(SET_VEHICLE_COLOURS, MainVehicle, VDF.Colors.Item1, VDF.Colors.Item2);
}
if (ToggleModsMask != _lastToggleMods)
MainVehicle.EngineHealth = VDF.EngineHealth;
if (VDF.ToggleModsMask != _lastVDF.ToggleModsMask)
{
for (int i = 0; i < 7; i++)
{
Call(TOGGLE_VEHICLE_MOD, MainVehicle.Handle, i + 17, (ToggleModsMask & (1 << i)) != 0);
Call(TOGGLE_VEHICLE_MOD, MainVehicle.Handle, i + 17, (VDF.ToggleModsMask & (1 << i)) != 0);
}
_lastToggleMods = ToggleModsMask;
}
if (Call<string>(GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate)
Call(SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
if (_lastLivery != Livery)
if (VDF.Livery != _lastVDF.Livery)
{
Call(SET_VEHICLE_LIVERY, MainVehicle, Livery);
_lastLivery = Livery;
Call(SET_VEHICLE_LIVERY, MainVehicle, VDF.Livery);
}
if (_lastHeadlightColor != HeadlightColor)
if (VDF.HeadlightColor != _lastVDF.HeadlightColor)
{
Call(SET_VEHICLE_XENON_LIGHT_COLOR_INDEX, MainVehicle.Handle, HeadlightColor);
_lastHeadlightColor = HeadlightColor;
Call(SET_VEHICLE_XENON_LIGHT_COLOR_INDEX, MainVehicle.Handle, VDF.HeadlightColor);
}
MainVehicle.SetDamageModel(DamageModel);
if (MainVehicle.Handle == V?.Handle && Util.GetPlayerRadioIndex() != RadioStation)
Util.SetPlayerRadioIndex(MainVehicle.Handle, RadioStation);
if (!CoreUtils.StructCmp(VDF.DamageModel, _lastVDF.DamageModel))
{
MainVehicle.SetDamageModel(VDF.DamageModel);
}
if (_lastExtras != ExtrasMask)
if (MainVehicle.Handle == V?.Handle && Util.GetPlayerRadioIndex() != VDF.RadioStation)
Util.SetPlayerRadioIndex(MainVehicle.Handle, VDF.RadioStation);
if (VDF.ExtrasMask != _lastVDF.ExtrasMask)
{
for (int i = 1; i < 15; i++)
{
@ -179,11 +163,21 @@ namespace RageCoop.Client
if (!hasExtra)
continue;
var on = (ExtrasMask & flag) != 0;
var on = (VDF.ExtrasMask & flag) != 0;
Call(SET_VEHICLE_EXTRA, MainVehicle.Handle, i, !on);
}
_lastExtras = ExtrasMask;
}
if (VDV.Mods != null && (_lastVDV.Mods == null || !VDV.Mods.SequenceEqual(_lastVDV.Mods)))
{
Call(SET_VEHICLE_MOD_KIT, MainVehicle, 0);
foreach (var mod in VDV.Mods) MainVehicle.Mods[(VehicleModType)mod.Item1].Index = mod.Item2;
}
if (VDV.LicensePlate != _lastVDV.LicensePlate)
Call(SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, VDV.LicensePlate);
_lastVDF = VDF;
_lastVDV = VDV;
}
LastUpdated = Ticked;
@ -240,7 +234,7 @@ namespace RageCoop.Client
}
MainVehicle.Quaternion = Quaternion;
if (MainVehicle.HasRoof) MainVehicle.RoofState = RoofState;
if (MainVehicle.HasRoof) MainVehicle.RoofState = (VehicleRoofState)VDF.RoofState;
foreach (var w in MainVehicle.Wheels) w.Fix();
if (IsInvincible) MainVehicle.IsInvincible = true;
SetUpFixedData();
@ -248,6 +242,8 @@ namespace RageCoop.Client
return true;
}
#region -- CONSTRUCTORS --
/// <summary>

View File

@ -31,8 +31,8 @@ namespace RageCoop.Client
protected override void OnStart()
{
base.OnStart();
while(Game.IsLoading)
Yield();
while (Game.IsLoading)
Yield();
Notification.Show(NotificationIcon.AllPlayersConf, "RAGECOOP", "Welcome!",
$"Press ~g~{Settings.MenuKey}~s~ to open the menu.");
@ -41,6 +41,18 @@ namespace RageCoop.Client
{
base.OnTick();
if (_sleeping)
{
Game.Pause(true);
while (_sleeping)
{
// Don't wait longer than 5 seconds or the game will crash
Thread.Sleep(4500);
Yield();
}
Game.Pause(false);
}
if (Game.IsLoading) return;
try
@ -224,5 +236,21 @@ namespace RageCoop.Client
QueuedActions.Clear();
}
}
private static bool _sleeping;
[ConsoleCommand("Put the game to sleep state by blocking main thread, press any key in the debug console to resume")]
public static void Sleep()
{
if (_sleeping)
throw new InvalidOperationException("Already in sleep state");
_sleeping = true;
Task.Run(() =>
{
System.Console.WriteLine("Press any key to put the game out of sleep state");
System.Console.ReadKey();
System.Console.WriteLine("Game resumed");
_sleeping = false;
});
}
}
}