diff --git a/Client/Scripts/Networking/Receive.cs b/Client/Scripts/Networking/Receive.cs index e36115e8..bdb7038d 100644 --- a/Client/Scripts/Networking/Receive.cs +++ b/Client/Scripts/Networking/Receive.cs @@ -321,37 +321,21 @@ private static void PedSync(Packets.PedSync packet) 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); } diff --git a/Client/Scripts/Networking/Send.cs b/Client/Scripts/Networking/Send.cs index 765d74da..83420357 100644 --- a/Client/Scripts/Networking/Send.cs +++ b/Client/Scripts/Networking/Send.cs @@ -103,19 +103,22 @@ public static void SendVehicle(SyncedVehicle v, bool full) 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 @@ public static void SendVehicle(SyncedVehicle v, bool full) Call(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(GET_VEHICLE_NUMBER_PLATE_TEXT, veh); - packet.Livery = Call(GET_VEHICLE_LIVERY, veh); - packet.HeadlightColor = (byte)Call(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(GET_VEHICLE_LIVERY, veh); + packet.VDF.HeadlightColor = (byte)Call(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(GET_VEHICLE_NUMBER_PLATE_TEXT, veh); + v.LastEngineHealth = packet.VDF.EngineHealth; } SendSync(packet, ConnectionChannel.VehicleSync); diff --git a/Client/Scripts/Scripting/BaseScript.cs b/Client/Scripts/Scripting/BaseScript.cs index 92310051..6e747d7c 100644 --- a/Client/Scripts/Scripting/BaseScript.cs +++ b/Client/Scripts/Scripting/BaseScript.cs @@ -44,13 +44,13 @@ public static void OnStart() { unsafe { - var time = World.CurrentTimeOfDay; + var date = World.CurrentDate; var weather1 = default(int); var weather2 = default(int); var percent2 = default(float); Call(GET_CURR_WEATHER_STATE, &weather1, &weather2, &percent2); - API.SendCustomEvent(CustomEvents.WeatherTimeSync, time.Hours, time.Minutes, - time.Seconds, weather1, weather2, percent2); + API.SendCustomEvent(CustomEvents.WeatherTimeSync, date.Year, date.Month, date.Day, date.Hour, date.Minute, + date.Second, weather1, weather2, percent2); } }); @@ -61,8 +61,8 @@ public static void OnStart() private static void WeatherTimeSync(CustomEventReceivedArgs e) { - World.CurrentTimeOfDay = new TimeSpan((int)e.Args[0], (int)e.Args[1], (int)e.Args[2]); - Call(SET_CURR_WEATHER_STATE, (int)e.Args[3], (int)e.Args[4], (float)e.Args[5]); + World.CurrentDate = new DateTime((int)e.Args[0], (int)e.Args[1], (int)e.Args[2], (int)e.Args[3], (int)e.Args[4], (int)e.Args[5]); + Call(SET_CURR_WEATHER_STATE, (int)e.Args[6], (int)e.Args[7], (float)e.Args[8]); } private static void SetDisplayNameTag(CustomEventReceivedArgs e) diff --git a/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.Variables.cs b/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.Variables.cs index 2efe3416..4a35ff50 100644 --- a/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.Variables.cs +++ b/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.Variables.cs @@ -12,42 +12,23 @@ public partial class SyncedVehicle #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 @@ public partial class SyncedVehicle #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 diff --git a/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.cs b/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.cs index 6167ef12..61ef93bd 100644 --- a/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.cs +++ b/Client/Scripts/Sync/Entities/Vehicle/SyncedVehicle.cs @@ -29,10 +29,10 @@ internal override void Update() // 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 @@ internal override void Update() 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 @@ internal override void Update() 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 @@ internal override void Update() { 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 @@ internal override void Update() { 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)) - { - Call(SET_VEHICLE_MOD_KIT, MainVehicle, 0); + if (HasRoof && MainVehicle.RoofState != (VehicleRoofState)VDF.RoofState) + MainVehicle.RoofState = (VehicleRoofState)VDF.RoofState; - foreach (var mod in Mods) MainVehicle.Mods[(VehicleModType)mod.Item1].Index = mod.Item2; - - _lastVehicleMods = Mods; + if (VD.Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair(); + if (VDF.Colors != _lastVDF.Colors) + { + 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 (VDF.Livery != _lastVDF.Livery) + { + Call(SET_VEHICLE_LIVERY, MainVehicle, VDF.Livery); } - if (Call(GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate) - Call(SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate); - - if (_lastLivery != Livery) + if (VDF.HeadlightColor != _lastVDF.HeadlightColor) { - Call(SET_VEHICLE_LIVERY, MainVehicle, Livery); - _lastLivery = Livery; + Call(SET_VEHICLE_XENON_LIGHT_COLOR_INDEX, MainVehicle.Handle, VDF.HeadlightColor); } - if (_lastHeadlightColor != HeadlightColor) + if (!CoreUtils.StructCmp(VDF.DamageModel, _lastVDF.DamageModel)) { - Call(SET_VEHICLE_XENON_LIGHT_COLOR_INDEX, MainVehicle.Handle, HeadlightColor); - _lastHeadlightColor = HeadlightColor; + MainVehicle.SetDamageModel(VDF.DamageModel); } - MainVehicle.SetDamageModel(DamageModel); - if (MainVehicle.Handle == V?.Handle && Util.GetPlayerRadioIndex() != RadioStation) - Util.SetPlayerRadioIndex(MainVehicle.Handle, RadioStation); + if (MainVehicle.Handle == V?.Handle && Util.GetPlayerRadioIndex() != VDF.RadioStation) + Util.SetPlayerRadioIndex(MainVehicle.Handle, VDF.RadioStation); - if (_lastExtras != ExtrasMask) + if (VDF.ExtrasMask != _lastVDF.ExtrasMask) { for (int i = 1; i < 15; i++) { @@ -179,11 +163,21 @@ internal override void Update() 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 @@ private bool CreateVehicle() } 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 @@ private bool CreateVehicle() return true; } + + #region -- CONSTRUCTORS -- /// diff --git a/Client/Scripts/WorldThread.cs b/Client/Scripts/WorldThread.cs index 48593a1c..ec0241cb 100644 --- a/Client/Scripts/WorldThread.cs +++ b/Client/Scripts/WorldThread.cs @@ -31,8 +31,8 @@ public WorldThread() 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 @@ protected override void OnTick() { 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 @@ internal static void ClearQueuedActions() 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; + }); + } } } \ No newline at end of file diff --git a/Core/Buffer.cs b/Core/Buffer.cs index fb979283..a3d15aa9 100644 --- a/Core/Buffer.cs +++ b/Core/Buffer.cs @@ -113,32 +113,6 @@ public void Write(ReadOnlySpan str) Encoding.UTF8.GetBytes(str, new(pBody, cbBody)); } - // Struct in GTA.Math have pack/padding for memory alignment, we don't want it to waste the bandwidth - - public void Write(ref Vector2 vec2) - { - var faddr = Alloc(2); - faddr[0] = vec2.X; - faddr[1] = vec2.Y; - } - - public void Write(ref Vector3 vec3) - { - var faddr = Alloc(3); - faddr[0] = vec3.X; - faddr[1] = vec3.Y; - faddr[2] = vec3.Z; - } - - public void Write(ref Quaternion quat) - { - var faddr = Alloc(4); - faddr[0] = quat.X; - faddr[1] = quat.Y; - faddr[2] = quat.Z; - faddr[3] = quat.W; - } - public void Write(ReadOnlySpan source) where T : unmanaged { var len = source.Length; @@ -237,39 +211,6 @@ public void Read(out string str) str = Encoding.UTF8.GetString(Alloc(cbBody), cbBody); } - public void Read(out Vector2 vec) - { - var faddr = Alloc(2); - vec = new() - { - X = faddr[0], - Y = faddr[1], - }; - } - - public void Read(out Vector3 vec) - { - var faddr = Alloc(3); - vec = new() - { - X = faddr[0], - Y = faddr[1], - Z = faddr[2], - }; - } - - public void Read(out Quaternion quat) - { - var faddr = Alloc(4); - quat = new() - { - X = faddr[0], - Y = faddr[1], - Z = faddr[2], - W = faddr[3], - }; - } - /// /// Read a span of type from current position to /// diff --git a/Core/CompactVectors.cs b/Core/CompactVectors.cs new file mode 100644 index 00000000..88af4fe5 --- /dev/null +++ b/Core/CompactVectors.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using GTA.Math; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace RageCoop.Core +{ + + internal struct LQuaternion + { + public LQuaternion(float x, float y, float z, float w) + { + X = x; Y = y; Z = z; W = w; + } + public float X, Y, Z, W; + public static implicit operator LQuaternion(Quaternion q) => new(q.X, q.Y, q.Z, q.W); + public static implicit operator Quaternion(LQuaternion q) => new(q.X, q.Y, q.Z, q.W); + } +} diff --git a/Core/CompactVectors/LQuaternion.cs b/Core/CompactVectors/LQuaternion.cs index 6733201c..07d297a5 100644 --- a/Core/CompactVectors/LQuaternion.cs +++ b/Core/CompactVectors/LQuaternion.cs @@ -8,8 +8,7 @@ namespace RageCoop.Core.CompactVectors { - - public struct LQuaternion : IEquatable + internal struct LQuaternion : IEquatable { /// /// Gets or sets the X component of the quaternion. diff --git a/Core/CompactVectors/LVector2.cs b/Core/CompactVectors/LVector2.cs index 8202ca67..6233e76c 100644 --- a/Core/CompactVectors/LVector2.cs +++ b/Core/CompactVectors/LVector2.cs @@ -8,7 +8,7 @@ namespace RageCoop.Core { - public struct LVector2 : IEquatable + internal struct LVector2 : IEquatable { /// /// Gets or sets the X component of the vector. diff --git a/Core/CompactVectors/LVector3.cs b/Core/CompactVectors/LVector3.cs index 2b5b954a..b59bc535 100644 --- a/Core/CompactVectors/LVector3.cs +++ b/Core/CompactVectors/LVector3.cs @@ -24,7 +24,7 @@ namespace RageCoop.Core { [Serializable] - public struct LVector3 : IEquatable + internal struct LVector3 : IEquatable { /// /// Gets or sets the X component of the vector. diff --git a/Core/CoreUtils.cs b/Core/CoreUtils.cs index 5738d04d..85436958 100644 --- a/Core/CoreUtils.cs +++ b/Core/CoreUtils.cs @@ -31,7 +31,10 @@ namespace RageCoop.Core { internal static class CoreUtils { - private static readonly Random random = new(); + internal static Random SafeRandom => _randInstance.Value; + private static int _randSeed = Environment.TickCount; + private static readonly ThreadLocal _randInstance + = new(() => new Random(Interlocked.Increment(ref _randSeed))); private static readonly HashSet ToIgnore = new() { @@ -72,7 +75,7 @@ public static string ToHex(this uint value) public static int RandInt(int start, int end) { - return random.Next(start, end); + return SafeRandom.Next(start, end); } public static string GetTempDirectory(string dir = null) @@ -91,7 +94,7 @@ public static string RandomString(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; return new string(Enumerable.Repeat(chars, length) - .Select(s => s[random.Next(s.Length)]).ToArray()); + .Select(s => s[SafeRandom.Next(s.Length)]).ToArray()); } public static Version GetLatestVersion(string branch = "dev-nightly") @@ -139,79 +142,6 @@ public static string ToFullPath(this string path) return Path.GetFullPath(path); } - public static void GetBytesFromObject(object obj, NetOutgoingMessage m) - { - switch (obj) - { - case byte value: - m.Write((byte)0x01); - m.Write(value); - break; - case short value: - m.Write((byte)0x02); - m.Write(value); - break; - case ushort value: - m.Write((byte)0x03); - m.Write(value); - break; - case int value: - m.Write((byte)0x04); - m.Write(value); - break; - case uint value: - m.Write((byte)0x05); - m.Write(value); - break; - case long value: - m.Write((byte)0x06); - m.Write(value); - break; - case ulong value: - m.Write((byte)0x07); - m.Write(value); - break; - case float value: - m.Write((byte)0x08); - m.Write(value); - break; - case bool value: - m.Write((byte)0x09); - m.Write(value); - break; - case string value: - m.Write((byte)0x10); - m.Write(value); - break; - case Vector3 value: - m.Write((byte)0x11); - m.Write(value); - break; - case Quaternion value: - m.Write((byte)0x12); - m.Write(value); - break; - case Model value: - m.Write((byte)0x13); - m.Write(value); - break; - case Vector2 value: - m.Write((byte)0x14); - m.Write(value); - break; - case byte[] value: - m.Write((byte)0x15); - m.WriteByteArray(value); - break; - case Tuple value: - m.Write(value.Item1); - m.Write(value.Item2); - break; - default: - throw new Exception("Unsupported object type: " + obj.GetType()); - } - } - public static IPEndPoint StringToEndPoint(string endpointstring) { return StringToEndPoint(endpointstring, -1); @@ -386,6 +316,65 @@ public static uint JoaatHash(string key) hash += hash << 15; return hash; } + + public static unsafe bool StructCmp(ref T left, ref T right) where T : unmanaged + { + fixed (T* pLeft = &left, pRight = &right) + { + return MemCmp(pLeft, pRight, sizeof(T)); + } + } + + + public static unsafe bool StructCmp(T left, T right) where T : unmanaged + { + return MemCmp(&left, &right, sizeof(T)); + } + + static bool _simdSupported = System.Numerics.Vector.IsSupported; + static int _simdSlots = _simdSupported ? System.Numerics.Vector.Count : 0; + + /// + /// SIMD-accelerated memory comparer + /// + /// + public static unsafe bool MemCmp(void* p1, void* p2, int cbToCompare) + { + int numVectors = cbToCompare / _simdSlots; + int ceiling = numVectors * _simdSlots; + if (numVectors > 0) + { + ReadOnlySpan> leftVecArray = new(p1, numVectors); + ReadOnlySpan> rightVecArray = new(p2, numVectors); + + for (int i = 0; i < numVectors; i++) + { + if (leftVecArray[i] != rightVecArray[i]) + return false; + } + } + + int numWords = cbToCompare / sizeof(IntPtr); + var pwLeft = (IntPtr*)p1; + var pwRight = (IntPtr*)p2; + + for (int i = (ceiling / sizeof(IntPtr)); i < numWords; i++) + { + if (pwLeft[i] != pwRight[i]) + return false; + } + + var pbLeft = (byte*)p1; + var pbRight = (byte*)p2; + + for (int i = ceiling + (numWords * sizeof(IntPtr)); i < cbToCompare; i++) + { + if (pbLeft[i] != pbRight[i]) + return false; + } + + return true; + } } internal class IpInfo @@ -407,33 +396,6 @@ public static string GetString(this byte[] data) return Encoding.UTF8.GetString(data); } - public static byte[] GetBytes(this Vector3 vec) - { - // 12 bytes - return new List - { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y), BitConverter.GetBytes(vec.Z) }.Join(4); - } - - public static byte[] GetBytes(this Vector2 vec) - { - // 8 bytes - return new List { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y) }.Join(4); - } - - /// - /// - /// - /// An array of bytes with length 16 - public static byte[] GetBytes(this Quaternion qua) - { - // 16 bytes - return new List - { - BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z), - BitConverter.GetBytes(qua.W) - }.Join(4); - } - public static T GetPacket(this NetIncomingMessage msg) where T : Packet, new() { var p = new T(); diff --git a/Core/PacketExtensions.cs b/Core/PacketExtensions.cs index 58793799..e0a78480 100644 --- a/Core/PacketExtensions.cs +++ b/Core/PacketExtensions.cs @@ -12,9 +12,9 @@ internal static bool IsSyncEvent(this PacketType p) #region MESSAGE-READ - public static Vector3 ReadVector3(this NetIncomingMessage m) + public static LVector3 ReadVector3(this NetIncomingMessage m) { - return new Vector3 + return new LVector3 { X = m.ReadFloat(), Y = m.ReadFloat(), @@ -22,9 +22,9 @@ public static Vector3 ReadVector3(this NetIncomingMessage m) }; } - public static Vector2 ReadVector2(this NetIncomingMessage m) + public static LVector2 ReadVector2(this NetIncomingMessage m) { - return new Vector2 + return new LVector2 { X = m.ReadFloat(), Y = m.ReadFloat() @@ -51,7 +51,7 @@ public static byte[] ReadByteArray(this NetIncomingMessage m) #region MESSAGE-WRITE - public static void Write(this NetOutgoingMessage m, Vector3 v) + public static void Write(this NetOutgoingMessage m, LVector3 v) { m.Write(v.X); m.Write(v.Y); diff --git a/Core/Packets/EntityData.cs b/Core/Packets/EntityData.cs new file mode 100644 index 00000000..230c1390 --- /dev/null +++ b/Core/Packets/EntityData.cs @@ -0,0 +1,74 @@ +using GTA; +using Lidgren.Network; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RageCoop.Core +{ + /// + /// Common data for synchronizing an entity + /// + internal struct EntityData + { + public int ID; + public int OwnerID; + public LQuaternion Quaternion; + public LVector3 Position; + public LVector3 Velocity; + public int ModelHash; + } + + internal struct VehicleData + { + public VehicleDataFlags Flags; + public float ThrottlePower; + public float BrakePower; + public float SteeringAngle; + public VehicleLockStatus LockStatus; + public float DeluxoWingRatio; + } + internal struct VehicleDataFull + { + + public float EngineHealth; + public (byte, byte) Colors; + public byte ToggleModsMask; + public VehicleDamageModel DamageModel; + public int Livery; + public byte HeadlightColor; + public byte RadioStation; + public ushort ExtrasMask; + public byte RoofState; + public byte LandingGear; + } + + /// + /// Non-fixed vehicle data + /// + internal struct VehicleDataVar + { + public string LicensePlate; + public (int, int)[] Mods; + public void WriteTo(NetOutgoingMessage m) + { + m.Write(LicensePlate); + m.Write((byte)Mods.Length); + for(int i = 0;i < Mods.Length; i++) + { + m.Write(ref Mods[i]); + } + } + public void ReadFrom(NetIncomingMessage m) + { + LicensePlate = m.ReadString(); + Mods = new (int, int)[m.ReadByte()]; + for(int i = 0; i < Mods.Length; i++) + { + Mods[i] = m.Read<(int, int)>(); + } + } + } +} diff --git a/Core/Packets/PedSync.cs b/Core/Packets/PedSync.cs index f2f2cfb0..c5c6aa1c 100644 --- a/Core/Packets/PedSync.cs +++ b/Core/Packets/PedSync.cs @@ -20,15 +20,15 @@ internal class PedSync : Packet public int Health { get; set; } - public Vector3 Position { get; set; } + public LVector3 Position { get; set; } - public Vector3 Rotation { get; set; } + public LVector3 Rotation { get; set; } - public Vector3 Velocity { get; set; } + public LVector3 Velocity { get; set; } public byte Speed { get; set; } - public Vector3 AimCoords { get; set; } + public LVector3 AimCoords { get; set; } public float Heading { get; set; } @@ -178,9 +178,9 @@ public override void Deserialize(NetIncomingMessage m) #region RAGDOLL - public Vector3 HeadPosition { get; set; } - public Vector3 RightFootPosition { get; set; } - public Vector3 LeftFootPosition { get; set; } + public LVector3 HeadPosition { get; set; } + public LVector3 RightFootPosition { get; set; } + public LVector3 LeftFootPosition { get; set; } #endregion diff --git a/Core/Packets/PlayerPackets.cs b/Core/Packets/PlayerPackets.cs index 6208940a..c7451a57 100644 --- a/Core/Packets/PlayerPackets.cs +++ b/Core/Packets/PlayerPackets.cs @@ -176,7 +176,7 @@ public class PlayerInfoUpdate : Packet public string Username { get; set; } public float Latency { get; set; } - public Vector3 Position { get; set; } + public LVector3 Position { get; set; } protected override void Serialize(NetOutgoingMessage m) { diff --git a/Core/Packets/ProjectileSync.cs b/Core/Packets/ProjectileSync.cs index 93867280..ae8e22b7 100644 --- a/Core/Packets/ProjectileSync.cs +++ b/Core/Packets/ProjectileSync.cs @@ -13,11 +13,11 @@ internal class ProjectileSync : Packet public int ShooterID { get; set; } public uint WeaponHash { get; set; } - public Vector3 Position { get; set; } + public LVector3 Position { get; set; } - public Vector3 Rotation { get; set; } + public LVector3 Rotation { get; set; } - public Vector3 Velocity { get; set; } + public LVector3 Velocity { get; set; } public ProjectileDataFlags Flags { get; set; } diff --git a/Core/Packets/SyncEvents/BulletShot.cs b/Core/Packets/SyncEvents/BulletShot.cs index 0d05b093..f0e0b749 100644 --- a/Core/Packets/SyncEvents/BulletShot.cs +++ b/Core/Packets/SyncEvents/BulletShot.cs @@ -12,7 +12,7 @@ internal class BulletShot : Packet public uint WeaponHash { get; set; } - public Vector3 EndPosition { get; set; } + public LVector3 EndPosition { get; set; } protected override void Serialize(NetOutgoingMessage m) { diff --git a/Core/Packets/VehicleSync.cs b/Core/Packets/VehicleSync.cs index 3621968f..30be4ff4 100644 --- a/Core/Packets/VehicleSync.cs +++ b/Core/Packets/VehicleSync.cs @@ -10,208 +10,32 @@ internal partial class Packets public class VehicleSync : Packet { public override PacketType Type => PacketType.VehicleSync; - public int ID { get; set; } - - public int OwnerID { get; set; } - - public VehicleDataFlags Flags { get; set; } - - public Vector3 Position { get; set; } - - public Quaternion Quaternion { get; set; } - // public Vector3 Rotation { get; set; } - - public Vector3 Velocity { get; set; } - - public Vector3 RotationVelocity { get; set; } - - public float ThrottlePower { get; set; } - public float BrakePower { get; set; } - public float SteeringAngle { get; set; } - public float DeluxoWingRatio { get; set; } = -1; + public EntityData ED; + public VehicleData VD; + public VehicleDataFull VDF; + public VehicleDataVar VDV; protected override void Serialize(NetOutgoingMessage m) { - m.Write(ID); - m.Write(OwnerID); - m.Write((ushort)Flags); - m.Write(Position); - m.Write(Quaternion); - m.Write(Velocity); - m.Write(RotationVelocity); - m.Write(ThrottlePower); - m.Write(BrakePower); - m.Write(SteeringAngle); - - if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) m.Write(DeluxoWingRatio); - - if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync)) + m.Write(ref ED); + m.Write(ref VD); + if (VD.Flags.HasVehFlag(VehicleDataFlags.IsFullSync)) { - m.Write(ModelHash); - m.Write(EngineHealth); - - // Check - if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft)) - // Write the vehicle landing gear - m.Write(LandingGear); - if (Flags.HasVehFlag(VehicleDataFlags.HasRoof)) m.Write(RoofState); - - // Write vehicle colors - m.Write(Colors.Item1); - m.Write(Colors.Item2); - - // Write vehicle mods - // Write the count of mods - m.Write((short)Mods.Length); - foreach (var mod in Mods) - { - // Write the mod value - m.Write(mod.Item1); - m.Write(mod.Item2); - } - - m.Write(ToggleModsMask); - - if (!DamageModel.Equals(default(VehicleDamageModel))) - { - // Write boolean = true - m.Write(true); - // Write vehicle damage model - m.Write(DamageModel.BrokenDoors); - m.Write(DamageModel.OpenedDoors); - m.Write(DamageModel.BrokenWindows); - m.Write(DamageModel.BurstedTires); - m.Write(DamageModel.LeftHeadLightBroken); - m.Write(DamageModel.RightHeadLightBroken); - } - else - { - // Write boolean = false - m.Write(false); - } - - // Write LockStatus - m.Write((byte)LockStatus); - - // Write RadioStation - m.Write(RadioStation); - - // Write LicensePlate - m.Write(LicensePlate); - - m.Write((byte)(Livery + 1)); - - m.Write(HeadlightColor); - - m.Write(ExtrasMask); + m.Write(ref VDF); + VDV.WriteTo(m); } } public override void Deserialize(NetIncomingMessage m) { - #region NetIncomingMessageToPacket - - ID = m.ReadInt32(); - OwnerID = m.ReadInt32(); - Flags = (VehicleDataFlags)m.ReadUInt16(); - Position = m.ReadVector3(); - Quaternion = m.ReadQuaternion(); - Velocity = m.ReadVector3(); - RotationVelocity = m.ReadVector3(); - ThrottlePower = m.ReadFloat(); - BrakePower = m.ReadFloat(); - SteeringAngle = m.ReadFloat(); - - - if (Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering)) DeluxoWingRatio = m.ReadFloat(); - - if (Flags.HasVehFlag(VehicleDataFlags.IsFullSync)) + m.Read(out ED); + m.Read(out VD); + if (VD.Flags.HasVehFlag(VehicleDataFlags.IsFullSync)) { - // Read vehicle model hash - ModelHash = m.ReadInt32(); - - // Read vehicle engine health - EngineHealth = m.ReadFloat(); - - - // Check - if (Flags.HasVehFlag(VehicleDataFlags.IsAircraft)) - // Read vehicle landing gear - LandingGear = m.ReadByte(); - if (Flags.HasVehFlag(VehicleDataFlags.HasRoof)) RoofState = m.ReadByte(); - - // Read vehicle colors - Colors = (m.ReadByte(), m.ReadByte()); - - // Read vehicle mods - // Create new Dictionary - // Read count of mods - var vehModCount = m.ReadInt16(); - Mods = new (int, int)[vehModCount]; - // Loop - for (var i = 0; i < vehModCount; i++) - // Read the mod value - Mods[i] = (m.ReadInt32(), m.ReadInt32()); - - ToggleModsMask = m.ReadByte(); - - if (m.ReadBoolean()) - // Read vehicle damage model - DamageModel = new VehicleDamageModel - { - BrokenDoors = m.ReadByte(), - OpenedDoors = m.ReadByte(), - BrokenWindows = m.ReadByte(), - BurstedTires = m.ReadInt16(), - LeftHeadLightBroken = m.ReadByte(), - RightHeadLightBroken = m.ReadByte() - }; - - - // Read LockStatus - LockStatus = (VehicleLockStatus)m.ReadByte(); - - // Read RadioStation - RadioStation = m.ReadByte(); - - LicensePlate = m.ReadString(); - - Livery = m.ReadByte() - 1; - - HeadlightColor = m.ReadByte(); - - ExtrasMask = m.ReadUInt16(); + m.Read(out VDF); + VDV.ReadFrom(m); } - - #endregion } - - #region FULL-SYNC - - public int ModelHash { get; set; } - - public float EngineHealth { get; set; } - - public (byte, byte) Colors { get; set; } - - public (int, int)[] Mods { get; set; } - - public byte ToggleModsMask; - public VehicleDamageModel DamageModel { get; set; } - - public byte LandingGear { get; set; } - public byte RoofState { get; set; } - - - public VehicleLockStatus LockStatus { get; set; } - - public int Livery { get; set; } = -1; - public byte HeadlightColor { get; set; } = 255; - public byte RadioStation { get; set; } = 255; - public string LicensePlate { get; set; } - - public ushort ExtrasMask; - #endregion } } } \ No newline at end of file diff --git a/Core/Scripting/CustomEvents.cs b/Core/Scripting/CustomEvents.cs index 2855464c..1ed438f0 100644 --- a/Core/Scripting/CustomEvents.cs +++ b/Core/Scripting/CustomEvents.cs @@ -193,14 +193,29 @@ public static void WriteObjects(BufferWriter b, params object[] objs) b.Write(value); break; case Vector2 value: + b.WriteVal(T_VEC2); + var vec2 = (LVector2)value; + b.Write(ref vec2); + break; + case LVector2 value: b.WriteVal(T_VEC2); b.Write(ref value); break; case Vector3 value: + b.WriteVal(T_VEC3); + var vec3 = (LVector3)value; + b.Write(ref vec3); + break; + case LVector3 value: b.WriteVal(T_VEC3); b.Write(ref value); break; case Quaternion value: + b.WriteVal(T_QUAT); + var quat = (LQuaternion)value; + b.Write(ref quat); + break; + case LQuaternion value: b.WriteVal(T_QUAT); b.Write(ref value); break; @@ -261,19 +276,19 @@ public static object[] ReadObjects(BufferReader r) Args[i] = str; break; case T_VEC3: - r.Read(out Vector3 vec); - Args[i] = vec; + r.Read(out LVector3 vec); + Args[i] = (Vector3)vec; break; case T_QUAT: - r.Read(out Quaternion quat); - Args[i] = quat; + r.Read(out LQuaternion quat); + Args[i] = (Quaternion)quat; break; case T_MODEL: Args[i] = r.ReadVal(); break; case T_VEC2: - r.Read(out Vector2 vec2); - Args[i] = vec2; + r.Read(out LVector2 vec2); + Args[i] = (Vector2)vec2; break; case T_BYTEARR: Args[i] = r.ReadArray(); diff --git a/Server/Networking/Server.EntitySync.cs b/Server/Networking/Server.EntitySync.cs index 3d2d2e59..ea74b257 100644 --- a/Server/Networking/Server.EntitySync.cs +++ b/Server/Networking/Server.EntitySync.cs @@ -40,7 +40,7 @@ private void PedSync(Packets.PedSync packet, Client client) private void VehicleSync(Packets.VehicleSync packet, Client client) { QueueJob(() => Entities.Update(packet, client)); - var isPlayer = packet.ID == client.Player?.LastVehicle?.ID; + var isPlayer = packet.ED.ID == client.Player?.LastVehicle?.ID; if (Settings.UseP2P) return; @@ -51,10 +51,10 @@ private void VehicleSync(Packets.VehicleSync packet, Client client) { // Player's vehicle if (Settings.PlayerStreamingDistance != -1 && - packet.Position.DistanceTo(c.Player.Position) > Settings.PlayerStreamingDistance) continue; + packet.ED.Position.DistanceTo(c.Player.Position) > Settings.PlayerStreamingDistance) continue; } else if (Settings.NpcStreamingDistance != -1 && - packet.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance) + packet.ED.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance) { continue; } diff --git a/Server/Scripting/ServerEntities.cs b/Server/Scripting/ServerEntities.cs index e9d9e1ee..0d282c35 100644 --- a/Server/Scripting/ServerEntities.cs +++ b/Server/Scripting/ServerEntities.cs @@ -194,14 +194,14 @@ internal void Update(Packets.PedSync p, Client sender) internal void Update(Packets.VehicleSync p, Client sender) { - if (!Vehicles.TryGetValue(p.ID, out var veh)) + if (!Vehicles.TryGetValue(p.ED.ID, out var veh)) { - Vehicles.TryAdd(p.ID, veh = new ServerVehicle(Server)); - veh.ID = p.ID; + Vehicles.TryAdd(p.ED.ID, veh = new ServerVehicle(Server)); + veh.ID = p.ED.ID; } - veh._pos = p.Position + p.Velocity * sender.Latency; - veh._quat = p.Quaternion; + veh._pos = p.ED.Position + p.ED.Velocity * sender.Latency; + veh._quat = p.ED.Quaternion; if (veh.Owner != sender) { if (veh.Owner != null) veh.Owner.EntitiesCount--; diff --git a/Tools/UnitTest/Program.cs b/Tools/UnitTest/Program.cs index dd6744cc..ec72ded4 100644 --- a/Tools/UnitTest/Program.cs +++ b/Tools/UnitTest/Program.cs @@ -1,6 +1,10 @@ -using GTA.Math; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; +using GTA.Math; using RageCoop.Core; using RageCoop.Core.Scripting; +using System.Diagnostics; +using System.Runtime.InteropServices; using System.Security.Cryptography; namespace UnitTest @@ -23,10 +27,16 @@ public TestElement(int i) public Quaternion quat; public string str; } - internal unsafe class Program + struct TestStruct + { + public ulong val1; + public ulong val2; + } + public unsafe partial class Program { static void Main(string[] args) { + TestElement[] test = new TestElement[1024]; Console.WriteLine("Testing buffers"); var buf = new BufferWriter(1024); @@ -72,21 +82,76 @@ static void Main(string[] args) Console.WriteLine("Buffers OK"); Console.WriteLine("Testing CustomEvents"); - var objs = new object[] { (byte)236, (short)82, (ushort)322, + var objs = new object[] { (byte)236, (short)82, (ushort)322, "test", 123, 123U, 456UL, 345L, 5F, new Vector2(15, 54), new Vector3(22, 45, 25), new Quaternion(2, 3, 222, 5) }; buf.Reset(); CustomEvents.WriteObjects(buf, objs); var payload = buf.ToByteArray(buf.Position); - fixed(byte* p = payload) + fixed (byte* p = payload) { reader.Initialise(p, payload.Length); } - - if (!CustomEvents.ReadObjects(reader).SequenceEqual(objs)) + var result = CustomEvents.ReadObjects(reader); + if (!result.SequenceEqual(objs)) throw new Exception("CustomEvents fail"); Console.WriteLine("CustomEvents OK"); + + var sArr1 = new TestStruct[200]; + var sArr2 = new TestStruct[200]; + var sArr3 = new TestStruct[200]; + for (int i = 0; i < 200; i++) + { + sArr1[i] = sArr2[i] = new() { val1 = 123, val2 = 456 }; + sArr3[i] = new() { val1 = 456, val2 = 789 }; + } + fixed (TestStruct* p1 = sArr1, p2 = sArr2, p3 = sArr3) + { + Debug.Assert(CoreUtils.MemCmp(p1, p2, sizeof(TestStruct))); + Debug.Assert(!CoreUtils.MemCmp(p1, p3, sizeof(TestStruct))); + Debug.Assert(!CoreUtils.MemCmp(p2, p3, sizeof(TestStruct))); + } +#if !DEBUG + var summary = BenchmarkRunner.Run(); +#endif + } + + public class MemCmpTest + { + private const int N = 10000; + TestStruct* p1; + TestStruct* p2; + TestStruct* p3; + int size = sizeof(TestStruct) * N; + public MemCmpTest() + { + p1 = (TestStruct*)Marshal.AllocHGlobal(N * sizeof(TestStruct)); + p2 = (TestStruct*)Marshal.AllocHGlobal(N * sizeof(TestStruct)); + p3 = (TestStruct*)Marshal.AllocHGlobal(N * sizeof(TestStruct)); + for (int i = 0; i < 200; i++) + { + p1[i] = p2[i] = new() { val1 = 123, val2 = 456 }; + p3[i] = new() { val1 = 456, val2 = 789 }; + } + } + + [Benchmark] + public void Simd() + { + CoreUtils.MemCmp(p1, p2, size); + } + + [Benchmark] + public void Win32() + { + memcmp(p1, p2, (UIntPtr)size); + } + } + + + [DllImport("msvcrt.dll")] + public static extern int memcmp(void* b1, void* b2, UIntPtr count); } } \ No newline at end of file diff --git a/Tools/UnitTest/UnitTest.csproj b/Tools/UnitTest/UnitTest.csproj index 723d28b9..c9ac8380 100644 --- a/Tools/UnitTest/UnitTest.csproj +++ b/Tools/UnitTest/UnitTest.csproj @@ -5,8 +5,13 @@ net7.0 enable True + $(SolutionDir)bin\Tools\UnitTest + + + + diff --git a/dummy.txt b/dummy.txt new file mode 100644 index 00000000..421376db --- /dev/null +++ b/dummy.txt @@ -0,0 +1 @@ +dummy diff --git a/libs/Lidgren.Network b/libs/Lidgren.Network index 3b64c652..ade2fba5 160000 --- a/libs/Lidgren.Network +++ b/libs/Lidgren.Network @@ -1 +1 @@ -Subproject commit 3b64c652e97233a9b384b034475a45d90b1ca0ff +Subproject commit ade2fba5b50b49467c147c1ef4bace0417ed237b