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:
@ -321,37 +321,21 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
private static void VehicleSync(Packets.VehicleSync packet)
|
private static void VehicleSync(Packets.VehicleSync packet)
|
||||||
{
|
{
|
||||||
var v = EntityPool.GetVehicleByID(packet.ID);
|
var v = EntityPool.GetVehicleByID(packet.ED.ID);
|
||||||
if (v == null) EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ID));
|
if (v == null) EntityPool.ThreadSafe.Add(v = new SyncedVehicle(packet.ED.ID));
|
||||||
if (v.IsLocal) return;
|
if (v.IsLocal) return;
|
||||||
v.ID = packet.ID;
|
v.ID = packet.ED.ID;
|
||||||
v.OwnerID = packet.OwnerID;
|
v.OwnerID = packet.ED.OwnerID;
|
||||||
v.Flags = packet.Flags;
|
v.Position = packet.ED.Position;
|
||||||
v.Position = packet.Position;
|
v.Quaternion = packet.ED.Quaternion;
|
||||||
v.Quaternion = packet.Quaternion;
|
v.Velocity = packet.ED.Velocity;
|
||||||
v.SteeringAngle = packet.SteeringAngle;
|
v.Model = packet.ED.ModelHash;
|
||||||
v.ThrottlePower = packet.ThrottlePower;
|
v.VD = packet.VD;
|
||||||
v.BrakePower = packet.BrakePower;
|
bool full = packet.VD.Flags.HasVehFlag(VehicleDataFlags.IsFullSync);
|
||||||
v.Velocity = packet.Velocity;
|
|
||||||
v.RotationVelocity = packet.RotationVelocity;
|
|
||||||
v.DeluxoWingRatio = packet.DeluxoWingRatio;
|
|
||||||
bool full = packet.Flags.HasVehFlag(VehicleDataFlags.IsFullSync);
|
|
||||||
if (full)
|
if (full)
|
||||||
{
|
{
|
||||||
v.DamageModel = packet.DamageModel;
|
v.VDF = packet.VDF;
|
||||||
v.EngineHealth = packet.EngineHealth;
|
v.VDV = packet.VDV;
|
||||||
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.SetLastSynced(full);
|
v.SetLastSynced(full);
|
||||||
}
|
}
|
||||||
|
@ -103,19 +103,22 @@ namespace RageCoop.Client
|
|||||||
if (v.LastSentStopWatch.ElapsedMilliseconds < SyncInterval) return;
|
if (v.LastSentStopWatch.ElapsedMilliseconds < SyncInterval) return;
|
||||||
var veh = v.MainVehicle;
|
var veh = v.MainVehicle;
|
||||||
var packet = SendPackets.VehicelPacket;
|
var packet = SendPackets.VehicelPacket;
|
||||||
packet.ID = v.ID;
|
packet.ED.ID = v.ID;
|
||||||
packet.OwnerID = v.OwnerID;
|
packet.ED.OwnerID = v.OwnerID;
|
||||||
packet.Flags = v.GetVehicleFlags();
|
packet.ED.Position = veh.ReadPosition();
|
||||||
packet.SteeringAngle = veh.SteeringAngle;
|
packet.ED.Velocity = veh.Velocity;
|
||||||
packet.Position = veh.ReadPosition();
|
packet.ED.Quaternion = veh.ReadQuaternion();
|
||||||
packet.Velocity = veh.Velocity;
|
packet.ED.ModelHash = veh.Model.Hash;
|
||||||
packet.Quaternion = veh.ReadQuaternion();
|
packet.VD.Flags = v.GetVehicleFlags();
|
||||||
packet.RotationVelocity = veh.WorldRotationVelocity;
|
packet.VD.SteeringAngle = veh.SteeringAngle;
|
||||||
packet.ThrottlePower = veh.ThrottlePower;
|
packet.VD.ThrottlePower = veh.ThrottlePower;
|
||||||
packet.BrakePower = veh.BrakePower;
|
packet.VD.BrakePower = veh.BrakePower;
|
||||||
|
packet.VD.Flags |= VehicleDataFlags.IsFullSync;
|
||||||
|
packet.VD.LockStatus = veh.LockStatus;
|
||||||
|
|
||||||
v.LastSentStopWatch.Restart();
|
v.LastSentStopWatch.Restart();
|
||||||
if (packet.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
|
if (packet.VD.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering))
|
||||||
packet.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio();
|
packet.VD.DeluxoWingRatio = v.MainVehicle.GetDeluxoWingRatio();
|
||||||
if (full)
|
if (full)
|
||||||
{
|
{
|
||||||
byte primaryColor = 0;
|
byte primaryColor = 0;
|
||||||
@ -125,23 +128,21 @@ namespace RageCoop.Client
|
|||||||
Call<byte>(GET_VEHICLE_COLOURS, veh, &primaryColor, &secondaryColor);
|
Call<byte>(GET_VEHICLE_COLOURS, veh, &primaryColor, &secondaryColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
packet.Flags |= VehicleDataFlags.IsFullSync;
|
packet.VDF.LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0;
|
||||||
packet.Colors = (primaryColor, secondaryColor);
|
packet.VDF.RoofState = (byte)veh.RoofState;
|
||||||
packet.DamageModel = veh.GetVehicleDamageModel();
|
packet.VDF.Colors = (primaryColor, secondaryColor);
|
||||||
packet.LandingGear = veh.IsAircraft ? (byte)veh.LandingGearState : (byte)0;
|
packet.VDF.DamageModel = veh.GetVehicleDamageModel();
|
||||||
packet.RoofState = (byte)veh.RoofState;
|
packet.VDF.EngineHealth = veh.EngineHealth;
|
||||||
packet.Mods = v.GetVehicleMods(out packet.ToggleModsMask);
|
packet.VDF.Livery = Call<int>(GET_VEHICLE_LIVERY, veh);
|
||||||
packet.ModelHash = veh.Model.Hash;
|
packet.VDF.HeadlightColor = (byte)Call<int>(GET_VEHICLE_XENON_LIGHT_COLOR_INDEX, veh);
|
||||||
packet.EngineHealth = veh.EngineHealth;
|
packet.VDF.ExtrasMask = v.GetVehicleExtras();
|
||||||
packet.LockStatus = veh.LockStatus;
|
packet.VDF.RadioStation = v.MainVehicle == LastV
|
||||||
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
|
|
||||||
? Util.GetPlayerRadioIndex() : byte.MaxValue;
|
? Util.GetPlayerRadioIndex() : byte.MaxValue;
|
||||||
if (packet.EngineHealth > v.LastEngineHealth) packet.Flags |= VehicleDataFlags.Repaired;
|
if (packet.VDF.EngineHealth > v.LastEngineHealth) packet.VD.Flags |= VehicleDataFlags.Repaired;
|
||||||
v.LastEngineHealth = packet.EngineHealth;
|
|
||||||
|
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);
|
SendSync(packet, ConnectionChannel.VehicleSync);
|
||||||
|
@ -12,42 +12,23 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
|
|
||||||
#region -- SYNC DATA --
|
#region -- SYNC DATA --
|
||||||
|
internal VehicleData VD;
|
||||||
internal Vector3 RotationVelocity { get; set; }
|
internal VehicleDataFull VDF;
|
||||||
internal float SteeringAngle { get; set; }
|
internal VehicleDataVar VDV;
|
||||||
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;
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region FLAGS
|
#region FLAGS
|
||||||
|
|
||||||
internal bool EngineRunning => Flags.HasVehFlag(VehicleDataFlags.IsEngineRunning);
|
internal bool EngineRunning => VD.Flags.HasVehFlag(VehicleDataFlags.IsEngineRunning);
|
||||||
internal bool Transformed => Flags.HasVehFlag(VehicleDataFlags.IsTransformed);
|
internal bool Transformed => VD.Flags.HasVehFlag(VehicleDataFlags.IsTransformed);
|
||||||
internal bool HornActive => Flags.HasVehFlag(VehicleDataFlags.IsHornActive);
|
internal bool HornActive => VD.Flags.HasVehFlag(VehicleDataFlags.IsHornActive);
|
||||||
internal bool LightsOn => Flags.HasVehFlag(VehicleDataFlags.AreLightsOn);
|
internal bool LightsOn => VD.Flags.HasVehFlag(VehicleDataFlags.AreLightsOn);
|
||||||
internal bool BrakeLightsOn => Flags.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn);
|
internal bool BrakeLightsOn => VD.Flags.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn);
|
||||||
internal bool HighBeamsOn => Flags.HasVehFlag(VehicleDataFlags.AreHighBeamsOn);
|
internal bool HighBeamsOn => VD.Flags.HasVehFlag(VehicleDataFlags.AreHighBeamsOn);
|
||||||
internal bool SireneActive => Flags.HasVehFlag(VehicleDataFlags.IsSirenActive);
|
internal bool SireneActive => VD.Flags.HasVehFlag(VehicleDataFlags.IsSirenActive);
|
||||||
internal bool IsDead => Flags.HasVehFlag(VehicleDataFlags.IsDead);
|
internal bool IsDead => VD.Flags.HasVehFlag(VehicleDataFlags.IsDead);
|
||||||
internal bool IsDeluxoHovering => Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering);
|
internal bool IsDeluxoHovering => VD.Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -69,15 +50,13 @@ namespace RageCoop.Client
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PRIVATE
|
#region PRIVATE
|
||||||
private byte _lastToggleMods;
|
private VehicleData _lastVD;
|
||||||
private (byte, byte) _lastVehicleColors;
|
private VehicleDataFull _lastVDF;
|
||||||
private ushort _lastExtras;
|
private VehicleDataVar _lastVDV;
|
||||||
private (int, int)[] _lastVehicleMods = Array.Empty<(int, int)>();
|
|
||||||
private bool _lastHornActive;
|
|
||||||
private bool _lastTransformed;
|
|
||||||
private int _lastLivery = -1;
|
|
||||||
private byte _lastHeadlightColor = 255;
|
|
||||||
private Vector3 _predictedPosition;
|
private Vector3 _predictedPosition;
|
||||||
|
internal bool _lastTransformed => _lastVD.Flags.HasVehFlag(VehicleDataFlags.IsTransformed);
|
||||||
|
internal bool _lastHornActive => _lastVD.Flags.HasVehFlag(VehicleDataFlags.IsHornActive);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region OUTGOING
|
#region OUTGOING
|
||||||
|
@ -29,10 +29,10 @@ namespace RageCoop.Client
|
|||||||
// Skip update if no new sync message has arrived.
|
// Skip update if no new sync message has arrived.
|
||||||
if (!NeedUpdate) return;
|
if (!NeedUpdate) return;
|
||||||
|
|
||||||
if (SteeringAngle != MainVehicle.SteeringAngle)
|
if (VD.SteeringAngle != MainVehicle.SteeringAngle)
|
||||||
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
|
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * VD.SteeringAngle);
|
||||||
MainVehicle.ThrottlePower = ThrottlePower;
|
MainVehicle.ThrottlePower = VD.ThrottlePower;
|
||||||
MainVehicle.BrakePower = BrakePower;
|
MainVehicle.BrakePower = VD.BrakePower;
|
||||||
|
|
||||||
if (IsDead)
|
if (IsDead)
|
||||||
{
|
{
|
||||||
@ -51,9 +51,9 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
if (MainVehicle.IsOnFire)
|
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);
|
Call(START_ENTITY_FIRE, MainVehicle);
|
||||||
}
|
}
|
||||||
@ -64,12 +64,7 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
if (HighBeamsOn != MainVehicle.AreHighBeamsOn) MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
if (HighBeamsOn != MainVehicle.AreHighBeamsOn) MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
||||||
|
|
||||||
if (IsAircraft)
|
if (!IsAircraft)
|
||||||
{
|
|
||||||
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
|
||||||
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
|
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
|
||||||
MainVehicle.IsSirenActive = SireneActive;
|
MainVehicle.IsSirenActive = SireneActive;
|
||||||
@ -78,22 +73,18 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
if (!_lastHornActive)
|
if (!_lastHornActive)
|
||||||
{
|
{
|
||||||
_lastHornActive = true;
|
|
||||||
MainVehicle.SoundHorn(99999);
|
MainVehicle.SoundHorn(99999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_lastHornActive)
|
else if (_lastVD.Flags.HasVehFlag(VehicleDataFlags.IsHornActive))
|
||||||
{
|
{
|
||||||
_lastHornActive = false;
|
|
||||||
MainVehicle.SoundHorn(1);
|
MainVehicle.SoundHorn(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasRoof && MainVehicle.RoofState != RoofState) MainVehicle.RoofState = RoofState;
|
if (HasRocketBoost && VD.Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) !=
|
||||||
|
|
||||||
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) !=
|
|
||||||
MainVehicle.IsRocketBoostActive)
|
MainVehicle.IsRocketBoostActive)
|
||||||
MainVehicle.IsRocketBoostActive = Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive);
|
MainVehicle.IsRocketBoostActive = VD.Flags.HasVehFlag(VehicleDataFlags.IsRocketBoostActive);
|
||||||
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) &&
|
if (HasParachute && VD.Flags.HasFlag(VehicleDataFlags.IsParachuteActive) &&
|
||||||
!MainVehicle.IsParachuteDeployed)
|
!MainVehicle.IsParachuteDeployed)
|
||||||
MainVehicle.StartParachuting(false);
|
MainVehicle.StartParachuting(false);
|
||||||
if (IsSubmarineCar)
|
if (IsSubmarineCar)
|
||||||
@ -102,75 +93,68 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
if (!_lastTransformed)
|
if (!_lastTransformed)
|
||||||
{
|
{
|
||||||
_lastTransformed = true;
|
|
||||||
Call(TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
|
Call(TRANSFORM_TO_SUBMARINE, MainVehicle.Handle, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_lastTransformed)
|
else if (_lastTransformed)
|
||||||
{
|
{
|
||||||
_lastTransformed = false;
|
|
||||||
Call(TRANSFORM_TO_CAR, MainVehicle.Handle, false);
|
Call(TRANSFORM_TO_CAR, MainVehicle.Handle, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsDeluxo)
|
else if (IsDeluxo)
|
||||||
{
|
{
|
||||||
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
||||||
if (IsDeluxoHovering) MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
if (IsDeluxoHovering) MainVehicle.SetDeluxoWingRatio(VD.DeluxoWingRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
Call(SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
Call(SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
||||||
|
MainVehicle.LockStatus = VD.LockStatus;
|
||||||
}
|
}
|
||||||
|
_lastVD = VD;
|
||||||
MainVehicle.LockStatus = LockStatus;
|
|
||||||
|
|
||||||
if (LastFullSynced >= LastUpdated)
|
if (LastFullSynced >= LastUpdated)
|
||||||
{
|
{
|
||||||
if (Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair();
|
if (IsAircraft)
|
||||||
if (Colors != _lastVehicleColors)
|
|
||||||
{
|
{
|
||||||
Call(SET_VEHICLE_COLOURS, MainVehicle, Colors.Item1, Colors.Item2);
|
if (VDF.LandingGear != (byte)MainVehicle.LandingGearState)
|
||||||
|
MainVehicle.LandingGearState = (VehicleLandingGearState)VDF.LandingGear;
|
||||||
|
}
|
||||||
|
if (HasRoof && MainVehicle.RoofState != (VehicleRoofState)VDF.RoofState)
|
||||||
|
MainVehicle.RoofState = (VehicleRoofState)VDF.RoofState;
|
||||||
|
|
||||||
_lastVehicleColors = Colors;
|
if (VD.Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair();
|
||||||
|
if (VDF.Colors != _lastVDF.Colors)
|
||||||
|
{
|
||||||
|
Call(SET_VEHICLE_COLOURS, MainVehicle, VDF.Colors.Item1, VDF.Colors.Item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainVehicle.EngineHealth = EngineHealth;
|
MainVehicle.EngineHealth = VDF.EngineHealth;
|
||||||
if (Mods != null && !Mods.SequenceEqual(_lastVehicleMods))
|
|
||||||
{
|
|
||||||
Call(SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
|
||||||
|
|
||||||
foreach (var mod in Mods) MainVehicle.Mods[(VehicleModType)mod.Item1].Index = mod.Item2;
|
if (VDF.ToggleModsMask != _lastVDF.ToggleModsMask)
|
||||||
|
|
||||||
_lastVehicleMods = Mods;
|
|
||||||
}
|
|
||||||
if (ToggleModsMask != _lastToggleMods)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 7; i++)
|
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)
|
||||||
if (Call<string>(GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate)
|
|
||||||
Call(SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
|
|
||||||
|
|
||||||
if (_lastLivery != Livery)
|
|
||||||
{
|
{
|
||||||
Call(SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
Call(SET_VEHICLE_LIVERY, MainVehicle, VDF.Livery);
|
||||||
_lastLivery = Livery;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_lastHeadlightColor != HeadlightColor)
|
if (VDF.HeadlightColor != _lastVDF.HeadlightColor)
|
||||||
{
|
{
|
||||||
Call(SET_VEHICLE_XENON_LIGHT_COLOR_INDEX, MainVehicle.Handle, HeadlightColor);
|
Call(SET_VEHICLE_XENON_LIGHT_COLOR_INDEX, MainVehicle.Handle, VDF.HeadlightColor);
|
||||||
_lastHeadlightColor = HeadlightColor;
|
|
||||||
}
|
}
|
||||||
MainVehicle.SetDamageModel(DamageModel);
|
|
||||||
|
|
||||||
if (MainVehicle.Handle == V?.Handle && Util.GetPlayerRadioIndex() != RadioStation)
|
if (!CoreUtils.StructCmp(VDF.DamageModel, _lastVDF.DamageModel))
|
||||||
Util.SetPlayerRadioIndex(MainVehicle.Handle, RadioStation);
|
{
|
||||||
|
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++)
|
for (int i = 1; i < 15; i++)
|
||||||
{
|
{
|
||||||
@ -179,11 +163,21 @@ namespace RageCoop.Client
|
|||||||
if (!hasExtra)
|
if (!hasExtra)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var on = (ExtrasMask & flag) != 0;
|
var on = (VDF.ExtrasMask & flag) != 0;
|
||||||
Call(SET_VEHICLE_EXTRA, MainVehicle.Handle, i, !on);
|
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;
|
LastUpdated = Ticked;
|
||||||
@ -240,7 +234,7 @@ namespace RageCoop.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
MainVehicle.Quaternion = Quaternion;
|
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();
|
foreach (var w in MainVehicle.Wheels) w.Fix();
|
||||||
if (IsInvincible) MainVehicle.IsInvincible = true;
|
if (IsInvincible) MainVehicle.IsInvincible = true;
|
||||||
SetUpFixedData();
|
SetUpFixedData();
|
||||||
@ -248,6 +242,8 @@ namespace RageCoop.Client
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region -- CONSTRUCTORS --
|
#region -- CONSTRUCTORS --
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -31,7 +31,7 @@ namespace RageCoop.Client
|
|||||||
protected override void OnStart()
|
protected override void OnStart()
|
||||||
{
|
{
|
||||||
base.OnStart();
|
base.OnStart();
|
||||||
while(Game.IsLoading)
|
while (Game.IsLoading)
|
||||||
Yield();
|
Yield();
|
||||||
|
|
||||||
Notification.Show(NotificationIcon.AllPlayersConf, "RAGECOOP", "Welcome!",
|
Notification.Show(NotificationIcon.AllPlayersConf, "RAGECOOP", "Welcome!",
|
||||||
@ -41,6 +41,18 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
base.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;
|
if (Game.IsLoading) return;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -224,5 +236,21 @@ namespace RageCoop.Client
|
|||||||
QueuedActions.Clear();
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -113,32 +113,6 @@ namespace RageCoop.Core
|
|||||||
Encoding.UTF8.GetBytes(str, new(pBody, cbBody));
|
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<float>(2);
|
|
||||||
faddr[0] = vec2.X;
|
|
||||||
faddr[1] = vec2.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(ref Vector3 vec3)
|
|
||||||
{
|
|
||||||
var faddr = Alloc<float>(3);
|
|
||||||
faddr[0] = vec3.X;
|
|
||||||
faddr[1] = vec3.Y;
|
|
||||||
faddr[2] = vec3.Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(ref Quaternion quat)
|
|
||||||
{
|
|
||||||
var faddr = Alloc<float>(4);
|
|
||||||
faddr[0] = quat.X;
|
|
||||||
faddr[1] = quat.Y;
|
|
||||||
faddr[2] = quat.Z;
|
|
||||||
faddr[3] = quat.W;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write<T>(ReadOnlySpan<T> source) where T : unmanaged
|
public void Write<T>(ReadOnlySpan<T> source) where T : unmanaged
|
||||||
{
|
{
|
||||||
var len = source.Length;
|
var len = source.Length;
|
||||||
@ -237,39 +211,6 @@ namespace RageCoop.Core
|
|||||||
str = Encoding.UTF8.GetString(Alloc(cbBody), cbBody);
|
str = Encoding.UTF8.GetString(Alloc(cbBody), cbBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Read(out Vector2 vec)
|
|
||||||
{
|
|
||||||
var faddr = Alloc<float>(2);
|
|
||||||
vec = new()
|
|
||||||
{
|
|
||||||
X = faddr[0],
|
|
||||||
Y = faddr[1],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Read(out Vector3 vec)
|
|
||||||
{
|
|
||||||
var faddr = Alloc<float>(3);
|
|
||||||
vec = new()
|
|
||||||
{
|
|
||||||
X = faddr[0],
|
|
||||||
Y = faddr[1],
|
|
||||||
Z = faddr[2],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Read(out Quaternion quat)
|
|
||||||
{
|
|
||||||
var faddr = Alloc<float>(4);
|
|
||||||
quat = new()
|
|
||||||
{
|
|
||||||
X = faddr[0],
|
|
||||||
Y = faddr[1],
|
|
||||||
Z = faddr[2],
|
|
||||||
W = faddr[3],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read a span of type <typeparamref name="T"/> from current position to <paramref name="destination"/>
|
/// Read a span of type <typeparamref name="T"/> from current position to <paramref name="destination"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
22
Core/CompactVectors.cs
Normal file
22
Core/CompactVectors.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,7 @@ using GTA.Math;
|
|||||||
|
|
||||||
namespace RageCoop.Core.CompactVectors
|
namespace RageCoop.Core.CompactVectors
|
||||||
{
|
{
|
||||||
|
internal struct LQuaternion : IEquatable<LQuaternion>
|
||||||
public struct LQuaternion : IEquatable<LQuaternion>
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the X component of the quaternion.
|
/// Gets or sets the X component of the quaternion.
|
||||||
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace RageCoop.Core
|
namespace RageCoop.Core
|
||||||
{
|
{
|
||||||
public struct LVector2 : IEquatable<LVector2>
|
internal struct LVector2 : IEquatable<LVector2>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the X component of the vector.
|
/// Gets or sets the X component of the vector.
|
||||||
|
@ -24,7 +24,7 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct LVector3 : IEquatable<LVector3>
|
internal struct LVector3 : IEquatable<LVector3>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the X component of the vector.
|
/// Gets or sets the X component of the vector.
|
||||||
|
@ -31,7 +31,10 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
internal static class CoreUtils
|
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<Random> _randInstance
|
||||||
|
= new(() => new Random(Interlocked.Increment(ref _randSeed)));
|
||||||
|
|
||||||
private static readonly HashSet<string> ToIgnore = new()
|
private static readonly HashSet<string> ToIgnore = new()
|
||||||
{
|
{
|
||||||
@ -72,7 +75,7 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public static int RandInt(int start, int end)
|
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)
|
public static string GetTempDirectory(string dir = null)
|
||||||
@ -91,7 +94,7 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
return new string(Enumerable.Repeat(chars, length)
|
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")
|
public static Version GetLatestVersion(string branch = "dev-nightly")
|
||||||
@ -139,79 +142,6 @@ namespace RageCoop.Core
|
|||||||
return Path.GetFullPath(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<byte, byte[]> 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)
|
public static IPEndPoint StringToEndPoint(string endpointstring)
|
||||||
{
|
{
|
||||||
return StringToEndPoint(endpointstring, -1);
|
return StringToEndPoint(endpointstring, -1);
|
||||||
@ -386,6 +316,65 @@ namespace RageCoop.Core
|
|||||||
hash += hash << 15;
|
hash += hash << 15;
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe bool StructCmp<T>(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>(T left, T right) where T : unmanaged
|
||||||
|
{
|
||||||
|
return MemCmp(&left, &right, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _simdSupported = System.Numerics.Vector<byte>.IsSupported;
|
||||||
|
static int _simdSlots = _simdSupported ? System.Numerics.Vector<byte>.Count : 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SIMD-accelerated memory comparer
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static unsafe bool MemCmp(void* p1, void* p2, int cbToCompare)
|
||||||
|
{
|
||||||
|
int numVectors = cbToCompare / _simdSlots;
|
||||||
|
int ceiling = numVectors * _simdSlots;
|
||||||
|
if (numVectors > 0)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<System.Numerics.Vector<byte>> leftVecArray = new(p1, numVectors);
|
||||||
|
ReadOnlySpan<System.Numerics.Vector<byte>> 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
|
internal class IpInfo
|
||||||
@ -407,33 +396,6 @@ namespace RageCoop.Core
|
|||||||
return Encoding.UTF8.GetString(data);
|
return Encoding.UTF8.GetString(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GetBytes(this Vector3 vec)
|
|
||||||
{
|
|
||||||
// 12 bytes
|
|
||||||
return new List<byte[]>
|
|
||||||
{ 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<byte[]> { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y) }.Join(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="qua"></param>
|
|
||||||
/// <returns>An array of bytes with length 16</returns>
|
|
||||||
public static byte[] GetBytes(this Quaternion qua)
|
|
||||||
{
|
|
||||||
// 16 bytes
|
|
||||||
return new List<byte[]>
|
|
||||||
{
|
|
||||||
BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z),
|
|
||||||
BitConverter.GetBytes(qua.W)
|
|
||||||
}.Join(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
|
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
|
||||||
{
|
{
|
||||||
var p = new T();
|
var p = new T();
|
||||||
|
@ -12,9 +12,9 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
#region MESSAGE-READ
|
#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(),
|
X = m.ReadFloat(),
|
||||||
Y = m.ReadFloat(),
|
Y = m.ReadFloat(),
|
||||||
@ -22,9 +22,9 @@ namespace RageCoop.Core
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector2 ReadVector2(this NetIncomingMessage m)
|
public static LVector2 ReadVector2(this NetIncomingMessage m)
|
||||||
{
|
{
|
||||||
return new Vector2
|
return new LVector2
|
||||||
{
|
{
|
||||||
X = m.ReadFloat(),
|
X = m.ReadFloat(),
|
||||||
Y = m.ReadFloat()
|
Y = m.ReadFloat()
|
||||||
@ -51,7 +51,7 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
#region MESSAGE-WRITE
|
#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.X);
|
||||||
m.Write(v.Y);
|
m.Write(v.Y);
|
||||||
|
74
Core/Packets/EntityData.cs
Normal file
74
Core/Packets/EntityData.cs
Normal file
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common data for synchronizing an entity
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Non-fixed vehicle data
|
||||||
|
/// </summary>
|
||||||
|
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)>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,15 +20,15 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public int Health { get; set; }
|
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 byte Speed { get; set; }
|
||||||
|
|
||||||
public Vector3 AimCoords { get; set; }
|
public LVector3 AimCoords { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public float Heading { get; set; }
|
public float Heading { get; set; }
|
||||||
@ -178,9 +178,9 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
#region RAGDOLL
|
#region RAGDOLL
|
||||||
|
|
||||||
public Vector3 HeadPosition { get; set; }
|
public LVector3 HeadPosition { get; set; }
|
||||||
public Vector3 RightFootPosition { get; set; }
|
public LVector3 RightFootPosition { get; set; }
|
||||||
public Vector3 LeftFootPosition { get; set; }
|
public LVector3 LeftFootPosition { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public float Latency { get; set; }
|
public float Latency { get; set; }
|
||||||
public Vector3 Position { get; set; }
|
public LVector3 Position { get; set; }
|
||||||
|
|
||||||
protected override void Serialize(NetOutgoingMessage m)
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
|
@ -13,11 +13,11 @@ namespace RageCoop.Core
|
|||||||
public int ShooterID { get; set; }
|
public int ShooterID { get; set; }
|
||||||
public uint WeaponHash { 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; }
|
public ProjectileDataFlags Flags { get; set; }
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
public uint WeaponHash { get; set; }
|
public uint WeaponHash { get; set; }
|
||||||
|
|
||||||
public Vector3 EndPosition { get; set; }
|
public LVector3 EndPosition { get; set; }
|
||||||
|
|
||||||
protected override void Serialize(NetOutgoingMessage m)
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
|
@ -10,208 +10,32 @@ namespace RageCoop.Core
|
|||||||
public class VehicleSync : Packet
|
public class VehicleSync : Packet
|
||||||
{
|
{
|
||||||
public override PacketType Type => PacketType.VehicleSync;
|
public override PacketType Type => PacketType.VehicleSync;
|
||||||
public int ID { get; set; }
|
public EntityData ED;
|
||||||
|
public VehicleData VD;
|
||||||
public int OwnerID { get; set; }
|
public VehicleDataFull VDF;
|
||||||
|
public VehicleDataVar VDV;
|
||||||
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;
|
|
||||||
|
|
||||||
protected override void Serialize(NetOutgoingMessage m)
|
protected override void Serialize(NetOutgoingMessage m)
|
||||||
{
|
{
|
||||||
m.Write(ID);
|
m.Write(ref ED);
|
||||||
m.Write(OwnerID);
|
m.Write(ref VD);
|
||||||
m.Write((ushort)Flags);
|
if (VD.Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
|
||||||
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(ModelHash);
|
m.Write(ref VDF);
|
||||||
m.Write(EngineHealth);
|
VDV.WriteTo(m);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Deserialize(NetIncomingMessage m)
|
public override void Deserialize(NetIncomingMessage m)
|
||||||
{
|
{
|
||||||
#region NetIncomingMessageToPacket
|
m.Read(out ED);
|
||||||
|
m.Read(out VD);
|
||||||
ID = m.ReadInt32();
|
if (VD.Flags.HasVehFlag(VehicleDataFlags.IsFullSync))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
// Read vehicle model hash
|
m.Read(out VDF);
|
||||||
ModelHash = m.ReadInt32();
|
VDV.ReadFrom(m);
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -193,14 +193,29 @@ namespace RageCoop.Core.Scripting
|
|||||||
b.Write(value);
|
b.Write(value);
|
||||||
break;
|
break;
|
||||||
case Vector2 value:
|
case Vector2 value:
|
||||||
|
b.WriteVal(T_VEC2);
|
||||||
|
var vec2 = (LVector2)value;
|
||||||
|
b.Write(ref vec2);
|
||||||
|
break;
|
||||||
|
case LVector2 value:
|
||||||
b.WriteVal(T_VEC2);
|
b.WriteVal(T_VEC2);
|
||||||
b.Write(ref value);
|
b.Write(ref value);
|
||||||
break;
|
break;
|
||||||
case Vector3 value:
|
case Vector3 value:
|
||||||
|
b.WriteVal(T_VEC3);
|
||||||
|
var vec3 = (LVector3)value;
|
||||||
|
b.Write(ref vec3);
|
||||||
|
break;
|
||||||
|
case LVector3 value:
|
||||||
b.WriteVal(T_VEC3);
|
b.WriteVal(T_VEC3);
|
||||||
b.Write(ref value);
|
b.Write(ref value);
|
||||||
break;
|
break;
|
||||||
case Quaternion value:
|
case Quaternion value:
|
||||||
|
b.WriteVal(T_QUAT);
|
||||||
|
var quat = (LQuaternion)value;
|
||||||
|
b.Write(ref quat);
|
||||||
|
break;
|
||||||
|
case LQuaternion value:
|
||||||
b.WriteVal(T_QUAT);
|
b.WriteVal(T_QUAT);
|
||||||
b.Write(ref value);
|
b.Write(ref value);
|
||||||
break;
|
break;
|
||||||
@ -261,19 +276,19 @@ namespace RageCoop.Core.Scripting
|
|||||||
Args[i] = str;
|
Args[i] = str;
|
||||||
break;
|
break;
|
||||||
case T_VEC3:
|
case T_VEC3:
|
||||||
r.Read(out Vector3 vec);
|
r.Read(out LVector3 vec);
|
||||||
Args[i] = vec;
|
Args[i] = (Vector3)vec;
|
||||||
break;
|
break;
|
||||||
case T_QUAT:
|
case T_QUAT:
|
||||||
r.Read(out Quaternion quat);
|
r.Read(out LQuaternion quat);
|
||||||
Args[i] = quat;
|
Args[i] = (Quaternion)quat;
|
||||||
break;
|
break;
|
||||||
case T_MODEL:
|
case T_MODEL:
|
||||||
Args[i] = r.ReadVal<Model>();
|
Args[i] = r.ReadVal<Model>();
|
||||||
break;
|
break;
|
||||||
case T_VEC2:
|
case T_VEC2:
|
||||||
r.Read(out Vector2 vec2);
|
r.Read(out LVector2 vec2);
|
||||||
Args[i] = vec2;
|
Args[i] = (Vector2)vec2;
|
||||||
break;
|
break;
|
||||||
case T_BYTEARR:
|
case T_BYTEARR:
|
||||||
Args[i] = r.ReadArray<byte>();
|
Args[i] = r.ReadArray<byte>();
|
||||||
|
@ -40,7 +40,7 @@ public partial class Server
|
|||||||
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
private void VehicleSync(Packets.VehicleSync packet, Client client)
|
||||||
{
|
{
|
||||||
QueueJob(() => Entities.Update(packet, 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;
|
if (Settings.UseP2P) return;
|
||||||
@ -51,10 +51,10 @@ public partial class Server
|
|||||||
{
|
{
|
||||||
// Player's vehicle
|
// Player's vehicle
|
||||||
if (Settings.PlayerStreamingDistance != -1 &&
|
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 &&
|
else if (Settings.NpcStreamingDistance != -1 &&
|
||||||
packet.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance)
|
packet.ED.Position.DistanceTo(c.Player.Position) > Settings.NpcStreamingDistance)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -194,14 +194,14 @@ public class ServerEntities
|
|||||||
|
|
||||||
internal void Update(Packets.VehicleSync 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));
|
Vehicles.TryAdd(p.ED.ID, veh = new ServerVehicle(Server));
|
||||||
veh.ID = p.ID;
|
veh.ID = p.ED.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
veh._pos = p.Position + p.Velocity * sender.Latency;
|
veh._pos = p.ED.Position + p.ED.Velocity * sender.Latency;
|
||||||
veh._quat = p.Quaternion;
|
veh._quat = p.ED.Quaternion;
|
||||||
if (veh.Owner != sender)
|
if (veh.Owner != sender)
|
||||||
{
|
{
|
||||||
if (veh.Owner != null) veh.Owner.EntitiesCount--;
|
if (veh.Owner != null) veh.Owner.EntitiesCount--;
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
using GTA.Math;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Running;
|
||||||
|
using GTA.Math;
|
||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using RageCoop.Core.Scripting;
|
using RageCoop.Core.Scripting;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace UnitTest
|
namespace UnitTest
|
||||||
@ -23,10 +27,16 @@ namespace UnitTest
|
|||||||
public Quaternion quat;
|
public Quaternion quat;
|
||||||
public string str;
|
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)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
|
||||||
TestElement[] test = new TestElement[1024];
|
TestElement[] test = new TestElement[1024];
|
||||||
Console.WriteLine("Testing buffers");
|
Console.WriteLine("Testing buffers");
|
||||||
var buf = new BufferWriter(1024);
|
var buf = new BufferWriter(1024);
|
||||||
@ -78,15 +88,70 @@ namespace UnitTest
|
|||||||
buf.Reset();
|
buf.Reset();
|
||||||
CustomEvents.WriteObjects(buf, objs);
|
CustomEvents.WriteObjects(buf, objs);
|
||||||
var payload = buf.ToByteArray(buf.Position);
|
var payload = buf.ToByteArray(buf.Position);
|
||||||
fixed(byte* p = payload)
|
fixed (byte* p = payload)
|
||||||
{
|
{
|
||||||
reader.Initialise(p, payload.Length);
|
reader.Initialise(p, payload.Length);
|
||||||
}
|
}
|
||||||
|
var result = CustomEvents.ReadObjects(reader);
|
||||||
if (!CustomEvents.ReadObjects(reader).SequenceEqual(objs))
|
if (!result.SequenceEqual(objs))
|
||||||
throw new Exception("CustomEvents fail");
|
throw new Exception("CustomEvents fail");
|
||||||
|
|
||||||
Console.WriteLine("CustomEvents OK");
|
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<MemCmpTest>();
|
||||||
|
#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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,8 +5,13 @@
|
|||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
<OutDir>$(SolutionDir)bin\Tools\UnitTest</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Core\RageCoop.Core.csproj" />
|
<ProjectReference Include="..\..\Core\RageCoop.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
Submodule libs/Lidgren.Network updated: 3b64c652e9...ade2fba5b5
Reference in New Issue
Block a user