Clean up
This commit is contained in:
@ -19,13 +19,16 @@ namespace RageCoop.Client
|
||||
switch (MainPed.Gender)
|
||||
{
|
||||
case Gender.Male:
|
||||
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1", "facials@gen_male@variations@normal");
|
||||
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1",
|
||||
"facials@gen_male@variations@normal");
|
||||
break;
|
||||
case Gender.Female:
|
||||
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1", "facials@gen_female@variations@normal");
|
||||
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1",
|
||||
"facials@gen_female@variations@normal");
|
||||
break;
|
||||
default:
|
||||
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1", "facials@mime@variations@normal");
|
||||
Function.Call(Hash.PLAY_FACIAL_ANIM, MainPed.Handle, "mood_normal_1",
|
||||
"facials@mime@variations@normal");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -40,7 +43,7 @@ namespace RageCoop.Client
|
||||
var flag = AnimationFlags.Loop;
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed, animDict, ourAnim, 3))
|
||||
{
|
||||
if (LoadAnim(animDict) == null) { return; }
|
||||
if (LoadAnim(animDict) == null) return;
|
||||
|
||||
MainPed.Task.ClearAll();
|
||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, animDict, ourAnim, 8f, 10f, -1, flag, -8f, 1, 1, 1);
|
||||
@ -61,6 +64,7 @@ namespace RageCoop.Client
|
||||
|
||||
return IsInCoverFacingLeft ? "idle_l_corner" : "idle_r_corner";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -86,31 +90,31 @@ namespace RageCoop.Client
|
||||
{
|
||||
switch (weapon)
|
||||
{
|
||||
case unchecked((uint)WeaponHash.Unarmed):
|
||||
case (uint)WeaponHash.Unarmed:
|
||||
return 0;
|
||||
|
||||
case unchecked((uint)WeaponHash.RPG):
|
||||
case unchecked((uint)WeaponHash.HomingLauncher):
|
||||
case unchecked((uint)WeaponHash.Firework):
|
||||
case (uint)WeaponHash.RPG:
|
||||
case (uint)WeaponHash.HomingLauncher:
|
||||
case (uint)WeaponHash.Firework:
|
||||
return 5;
|
||||
|
||||
case unchecked((uint)WeaponHash.Minigun):
|
||||
case (uint)WeaponHash.Minigun:
|
||||
return 5;
|
||||
|
||||
case unchecked((uint)WeaponHash.GolfClub):
|
||||
case unchecked((uint)WeaponHash.PoolCue):
|
||||
case unchecked((uint)WeaponHash.Bat):
|
||||
case (uint)WeaponHash.GolfClub:
|
||||
case (uint)WeaponHash.PoolCue:
|
||||
case (uint)WeaponHash.Bat:
|
||||
return 4;
|
||||
|
||||
case unchecked((uint)WeaponHash.Knife):
|
||||
case unchecked((uint)WeaponHash.Nightstick):
|
||||
case unchecked((uint)WeaponHash.Hammer):
|
||||
case unchecked((uint)WeaponHash.Crowbar):
|
||||
case unchecked((uint)WeaponHash.Wrench):
|
||||
case unchecked((uint)WeaponHash.BattleAxe):
|
||||
case unchecked((uint)WeaponHash.Dagger):
|
||||
case unchecked((uint)WeaponHash.Hatchet):
|
||||
case unchecked((uint)WeaponHash.KnuckleDuster):
|
||||
case (uint)WeaponHash.Knife:
|
||||
case (uint)WeaponHash.Nightstick:
|
||||
case (uint)WeaponHash.Hammer:
|
||||
case (uint)WeaponHash.Crowbar:
|
||||
case (uint)WeaponHash.Wrench:
|
||||
case (uint)WeaponHash.BattleAxe:
|
||||
case (uint)WeaponHash.Dagger:
|
||||
case (uint)WeaponHash.Hatchet:
|
||||
case (uint)WeaponHash.KnuckleDuster:
|
||||
case unchecked((uint)-581044007):
|
||||
case unchecked((uint)-102323637):
|
||||
case unchecked((uint)-538741184):
|
||||
@ -118,25 +122,25 @@ namespace RageCoop.Client
|
||||
|
||||
case unchecked((uint)-1357824103):
|
||||
case unchecked((uint)-1074790547):
|
||||
case unchecked(2132975508):
|
||||
case 2132975508:
|
||||
case unchecked((uint)-2084633992):
|
||||
case unchecked((uint)-952879014):
|
||||
case unchecked(100416529):
|
||||
case unchecked((uint)WeaponHash.Gusenberg):
|
||||
case unchecked((uint)WeaponHash.MG):
|
||||
case unchecked((uint)WeaponHash.CombatMG):
|
||||
case unchecked((uint)WeaponHash.CombatPDW):
|
||||
case unchecked((uint)WeaponHash.AssaultSMG):
|
||||
case unchecked((uint)WeaponHash.SMG):
|
||||
case unchecked((uint)WeaponHash.HeavySniper):
|
||||
case unchecked((uint)WeaponHash.PumpShotgun):
|
||||
case unchecked((uint)WeaponHash.HeavyShotgun):
|
||||
case unchecked((uint)WeaponHash.Musket):
|
||||
case unchecked((uint)WeaponHash.AssaultShotgun):
|
||||
case unchecked((uint)WeaponHash.BullpupShotgun):
|
||||
case unchecked((uint)WeaponHash.SawnOffShotgun):
|
||||
case unchecked((uint)WeaponHash.SweeperShotgun):
|
||||
case unchecked((uint)WeaponHash.CompactRifle):
|
||||
case 100416529:
|
||||
case (uint)WeaponHash.Gusenberg:
|
||||
case (uint)WeaponHash.MG:
|
||||
case (uint)WeaponHash.CombatMG:
|
||||
case (uint)WeaponHash.CombatPDW:
|
||||
case (uint)WeaponHash.AssaultSMG:
|
||||
case (uint)WeaponHash.SMG:
|
||||
case (uint)WeaponHash.HeavySniper:
|
||||
case (uint)WeaponHash.PumpShotgun:
|
||||
case (uint)WeaponHash.HeavyShotgun:
|
||||
case (uint)WeaponHash.Musket:
|
||||
case (uint)WeaponHash.AssaultShotgun:
|
||||
case (uint)WeaponHash.BullpupShotgun:
|
||||
case (uint)WeaponHash.SawnOffShotgun:
|
||||
case (uint)WeaponHash.SweeperShotgun:
|
||||
case (uint)WeaponHash.CompactRifle:
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -150,7 +154,8 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash.REQUEST_ANIM_DICT, anim);
|
||||
return null;
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +1,45 @@
|
||||
using GTA;
|
||||
using System.Collections.Generic;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// ?
|
||||
/// </summary>
|
||||
public partial class SyncedPed : SyncedEntity
|
||||
{
|
||||
internal Blip PedBlip = null;
|
||||
private readonly string[] _currentAnimation = new string[2] { "", "" };
|
||||
private byte[] _lastClothes;
|
||||
internal bool _lastDriveBy;
|
||||
private bool _lastInCover;
|
||||
private bool _lastIsJumping;
|
||||
private bool _lastRagdoll;
|
||||
private ulong _lastRagdollTime;
|
||||
private Dictionary<uint, bool> _lastWeaponComponents;
|
||||
private Entity _weaponObj;
|
||||
internal BlipColor BlipColor = (BlipColor)255;
|
||||
internal BlipSprite BlipSprite = 0;
|
||||
internal float BlipScale = 1;
|
||||
internal BlipSprite BlipSprite = 0;
|
||||
internal PedDataFlags Flags;
|
||||
|
||||
private bool LastMoving;
|
||||
internal Blip PedBlip = null;
|
||||
internal VehicleSeat Seat;
|
||||
|
||||
internal int VehicleID
|
||||
{
|
||||
get => CurrentVehicle?.ID ?? 0;
|
||||
set
|
||||
{
|
||||
if (CurrentVehicle == null || value != CurrentVehicle?.ID)
|
||||
{
|
||||
CurrentVehicle = EntityPool.GetVehicleByID(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal SyncedVehicle CurrentVehicle { get; private set; }
|
||||
internal VehicleSeat Seat;
|
||||
public bool IsPlayer { get => OwnerID == ID && ID != 0; }
|
||||
public bool IsPlayer => OwnerID == ID && ID != 0;
|
||||
public Ped MainPed { get; internal set; }
|
||||
internal int Health { get; set; }
|
||||
|
||||
@ -36,10 +48,6 @@ namespace RageCoop.Client
|
||||
internal Vector3 LeftFootPosition { get; set; }
|
||||
|
||||
internal byte WeaponTint { get; set; }
|
||||
private bool _lastRagdoll = false;
|
||||
private ulong _lastRagdollTime = 0;
|
||||
private bool _lastInCover = false;
|
||||
private byte[] _lastClothes = null;
|
||||
internal byte[] Clothes { get; set; }
|
||||
|
||||
internal float Heading { get; set; }
|
||||
@ -47,11 +55,8 @@ namespace RageCoop.Client
|
||||
internal ulong LastSpeakingTime { get; set; } = 0;
|
||||
internal bool IsSpeaking { get; set; } = false;
|
||||
public byte Speed { get; set; }
|
||||
private bool _lastIsJumping = false;
|
||||
internal PedDataFlags Flags;
|
||||
|
||||
internal bool IsAiming => Flags.HasPedFlag(PedDataFlags.IsAiming);
|
||||
internal bool _lastDriveBy;
|
||||
internal bool IsReloading => Flags.HasPedFlag(PedDataFlags.IsReloading);
|
||||
internal bool IsJumping => Flags.HasPedFlag(PedDataFlags.IsJumping);
|
||||
internal bool IsRagdoll => Flags.HasPedFlag(PedDataFlags.IsRagdoll);
|
||||
@ -67,15 +72,7 @@ namespace RageCoop.Client
|
||||
internal bool IsInStealthMode => Flags.HasPedFlag(PedDataFlags.IsInStealthMode);
|
||||
internal Prop ParachuteProp { get; set; } = null;
|
||||
internal uint CurrentWeaponHash { get; set; }
|
||||
private Dictionary<uint, bool> _lastWeaponComponents = null;
|
||||
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
||||
private Entity _weaponObj;
|
||||
internal Vector3 AimCoords { get; set; }
|
||||
|
||||
|
||||
private readonly string[] _currentAnimation = new string[2] { "", "" };
|
||||
|
||||
private bool LastMoving;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,24 @@
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using LemonUI.Elements;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using GTA.NaturalMotion;
|
||||
using GTA.UI;
|
||||
using LemonUI.Elements;
|
||||
using RageCoop.Core;
|
||||
using Font = GTA.UI.Font;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// ?
|
||||
/// </summary>
|
||||
public partial class SyncedPed : SyncedEntity
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
internal SyncedPed(Ped p)
|
||||
@ -31,11 +32,10 @@ namespace RageCoop.Client
|
||||
Function.Call(Hash._SET_PED_CAN_PLAY_INJURED_ANIMS, false);
|
||||
MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableHurt, true);
|
||||
// MainPed.SetConfigFlag((int)PedConfigFlags.CPED_CONFIG_FLAG_DisableMelee, true);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty character with ID
|
||||
/// Create an empty character with ID
|
||||
/// </summary>
|
||||
internal SyncedPed(int id)
|
||||
{
|
||||
@ -45,43 +45,37 @@ namespace RageCoop.Client
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
if (Owner == null) { OwnerID = OwnerID; return; }
|
||||
if (IsPlayer)
|
||||
if (Owner == null)
|
||||
{
|
||||
RenderNameTag();
|
||||
OwnerID = OwnerID;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPlayer) RenderNameTag();
|
||||
|
||||
// Check if all data avalible
|
||||
if (!IsReady) { return; }
|
||||
if (!IsReady) return;
|
||||
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate) { return; }
|
||||
if (!NeedUpdate) return;
|
||||
|
||||
if (MainPed == null || !MainPed.Exists())
|
||||
{
|
||||
if (!CreateCharacter())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to update state
|
||||
if (LastFullSynced >= LastUpdated)
|
||||
{
|
||||
if (MainPed != null && (Model != MainPed.Model.Hash))
|
||||
{
|
||||
if (MainPed != null && Model != MainPed.Model.Hash)
|
||||
if (!CreateCharacter())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (((byte)BlipColor == 255) && (PedBlip != null))
|
||||
if ((byte)BlipColor == 255 && PedBlip != null)
|
||||
{
|
||||
PedBlip.Delete();
|
||||
PedBlip = null;
|
||||
}
|
||||
else if (((byte)BlipColor != 255) && PedBlip == null)
|
||||
else if ((byte)BlipColor != 255 && PedBlip == null)
|
||||
{
|
||||
PedBlip = MainPed.AddBlip();
|
||||
|
||||
@ -90,26 +84,15 @@ namespace RageCoop.Client
|
||||
PedBlip.Sprite = BlipSprite;
|
||||
PedBlip.Scale = BlipScale;
|
||||
}
|
||||
|
||||
if (PedBlip != null)
|
||||
{
|
||||
if (PedBlip.Color != BlipColor)
|
||||
{
|
||||
PedBlip.Color = BlipColor;
|
||||
}
|
||||
if (PedBlip.Sprite != BlipSprite)
|
||||
{
|
||||
PedBlip.Sprite = BlipSprite;
|
||||
}
|
||||
if (IsPlayer)
|
||||
{
|
||||
PedBlip.Name = Owner.Username;
|
||||
}
|
||||
if (PedBlip.Color != BlipColor) PedBlip.Color = BlipColor;
|
||||
if (PedBlip.Sprite != BlipSprite) PedBlip.Sprite = BlipSprite;
|
||||
if (IsPlayer) PedBlip.Name = Owner.Username;
|
||||
}
|
||||
|
||||
if (!Clothes.SequenceEqual(_lastClothes))
|
||||
{
|
||||
SetClothes();
|
||||
}
|
||||
if (!Clothes.SequenceEqual(_lastClothes)) SetClothes();
|
||||
|
||||
CheckCurrentWeapon();
|
||||
}
|
||||
@ -119,16 +102,12 @@ namespace RageCoop.Client
|
||||
if (Health > 0)
|
||||
{
|
||||
if (IsPlayer)
|
||||
{
|
||||
MainPed.Resurrect();
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncEvents.TriggerPedKilled(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsPlayer && (MainPed.Health != Health))
|
||||
else if (IsPlayer && MainPed.Health != Health)
|
||||
{
|
||||
MainPed.Health = Health;
|
||||
|
||||
@ -146,7 +125,12 @@ namespace RageCoop.Client
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainPed.IsInVehicle()) { MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut); return; }
|
||||
if (MainPed.IsInVehicle())
|
||||
{
|
||||
MainPed.Task.LeaveVehicle(LeaveVehicleFlags.WarpOut);
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayOnFoot();
|
||||
}
|
||||
|
||||
@ -170,21 +154,19 @@ namespace RageCoop.Client
|
||||
|
||||
private void RenderNameTag()
|
||||
{
|
||||
if (!Owner.DisplayNameTag || (MainPed == null) || !MainPed.IsVisible || !MainPed.IsInRange(Main.PlayerPosition, 40f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!Owner.DisplayNameTag || MainPed == null || !MainPed.IsVisible ||
|
||||
!MainPed.IsInRange(Main.PlayerPosition, 40f)) return;
|
||||
|
||||
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position + Vector3.WorldUp * 0.5f;
|
||||
var targetPos = MainPed.Bones[Bone.IKHead].Position + Vector3.WorldUp * 0.5f;
|
||||
Point toDraw = default;
|
||||
if (Util.WorldToScreen(targetPos, ref toDraw))
|
||||
{
|
||||
toDraw.Y -= 100;
|
||||
new ScaledText(toDraw, Owner.Username, 0.4f, GTA.UI.Font.ChaletLondon)
|
||||
new ScaledText(toDraw, Owner.Username, 0.4f, Font.ChaletLondon)
|
||||
{
|
||||
Outline = true,
|
||||
Alignment = GTA.UI.Alignment.Center,
|
||||
Color = Owner.HasDirectConnection ? Color.FromArgb(179, 229, 252) : Color.White,
|
||||
Alignment = Alignment.Center,
|
||||
Color = Owner.HasDirectConnection ? Color.FromArgb(179, 229, 252) : Color.White
|
||||
}.Draw();
|
||||
}
|
||||
}
|
||||
@ -209,16 +191,14 @@ namespace RageCoop.Client
|
||||
PedBlip.Delete();
|
||||
PedBlip = null;
|
||||
}
|
||||
|
||||
if (!Model.IsLoaded)
|
||||
{
|
||||
Model.Request();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((MainPed = Util.CreatePed(Model, Position)) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ((MainPed = Util.CreatePed(Model, Position)) == null) return false;
|
||||
|
||||
Model.MarkAsNoLongerNeeded();
|
||||
|
||||
@ -251,8 +231,8 @@ namespace RageCoop.Client
|
||||
|
||||
SetClothes();
|
||||
|
||||
if (IsPlayer) { MainPed.IsInvincible = true; }
|
||||
if (IsInvincible) { MainPed.IsInvincible = true; }
|
||||
if (IsPlayer) MainPed.IsInvincible = true;
|
||||
if (IsInvincible) MainPed.IsInvincible = true;
|
||||
|
||||
lock (EntityPool.PedsLock)
|
||||
{
|
||||
@ -266,16 +246,14 @@ namespace RageCoop.Client
|
||||
private void SetClothes()
|
||||
{
|
||||
for (byte i = 0; i < 12; i++)
|
||||
{
|
||||
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i], (int)Clothes[i + 12], (int)Clothes[i + 24]);
|
||||
}
|
||||
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, MainPed.Handle, i, (int)Clothes[i],
|
||||
(int)Clothes[i + 12], (int)Clothes[i + 24]);
|
||||
_lastClothes = Clothes;
|
||||
}
|
||||
|
||||
|
||||
private void DisplayOnFoot()
|
||||
{
|
||||
|
||||
if (IsInParachuteFreeFall)
|
||||
{
|
||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
|
||||
@ -285,9 +263,10 @@ namespace RageCoop.Client
|
||||
{
|
||||
// Skip update if animation is not loaded
|
||||
var dict = LoadAnim("skydive@base");
|
||||
if (dict == null) { return; }
|
||||
if (dict == null) return;
|
||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed.Handle, dict, "free_idle", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -299,13 +278,16 @@ namespace RageCoop.Client
|
||||
model.Request(1000);
|
||||
if (model != null)
|
||||
{
|
||||
ParachuteProp = World.CreateProp(model, MainPed.ReadPosition(), MainPed.ReadRotation(), false, false);
|
||||
ParachuteProp = World.CreateProp(model, MainPed.ReadPosition(), MainPed.ReadRotation(), false,
|
||||
false);
|
||||
model.MarkAsNoLongerNeeded();
|
||||
ParachuteProp.IsPositionFrozen = true;
|
||||
ParachuteProp.IsCollisionEnabled = false;
|
||||
|
||||
ParachuteProp.AttachTo(MainPed.Bones[Bone.SkelSpine2], new Vector3(3.6f, 0f, 0f), new Vector3(0f, 90f, 0f));
|
||||
ParachuteProp.AttachTo(MainPed.Bones[Bone.SkelSpine2], new Vector3(3.6f, 0f, 0f),
|
||||
new Vector3(0f, 90f, 0f));
|
||||
}
|
||||
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
MainPed.Task.ClearSecondary();
|
||||
}
|
||||
@ -313,21 +295,20 @@ namespace RageCoop.Client
|
||||
MainPed.PositionNoOffset = Vector3.Lerp(MainPed.ReadPosition(), Position + Velocity, 0.5f);
|
||||
MainPed.Quaternion = Rotation.ToQuaternion();
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@parachute@first_person", "chute_idle_right", 3))
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "skydive@parachute@first_person",
|
||||
"chute_idle_right", 3))
|
||||
{
|
||||
var dict = LoadAnim("skydive@parachute@first_person");
|
||||
if (dict == null) { return; }
|
||||
if (dict == null) return;
|
||||
Function.Call(Hash.TASK_PLAY_ANIM, MainPed, dict, "chute_idle_right", 8f, 10f, -1, 0, -8f, 1, 1, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ParachuteProp != null)
|
||||
{
|
||||
if (ParachuteProp.Exists())
|
||||
{
|
||||
ParachuteProp.Delete();
|
||||
}
|
||||
if (ParachuteProp.Exists()) ParachuteProp.Delete();
|
||||
ParachuteProp = null;
|
||||
}
|
||||
|
||||
@ -335,7 +316,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (Velocity.Z < 0)
|
||||
{
|
||||
string anim = Velocity.Z < -2f ? "slide_climb_down" : "climb_down";
|
||||
var anim = Velocity.Z < -2f ? "slide_climb_down" : "climb_down";
|
||||
if (_currentAnimation[1] != anim)
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
@ -343,9 +324,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", anim, 3))
|
||||
{
|
||||
MainPed.Task.PlayAnimation("laddersbase", anim, 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -357,10 +336,9 @@ namespace RageCoop.Client
|
||||
_currentAnimation[1] = "base_left_hand_up";
|
||||
}
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", "base_left_hand_up", 3))
|
||||
{
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase",
|
||||
"base_left_hand_up", 3))
|
||||
MainPed.Task.PlayAnimation("laddersbase", "base_left_hand_up", 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -370,17 +348,16 @@ namespace RageCoop.Client
|
||||
_currentAnimation[1] = "climb_up";
|
||||
}
|
||||
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", "climb_up", 3))
|
||||
{
|
||||
MainPed.Task.PlayAnimation("laddersbase", "climb_up", 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
if (!Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, MainPed.Handle, "laddersbase", "climb_up",
|
||||
3)) MainPed.Task.PlayAnimation("laddersbase", "climb_up", 8f, -1, AnimationFlags.Loop);
|
||||
}
|
||||
}
|
||||
|
||||
SmoothTransition();
|
||||
return;
|
||||
}
|
||||
else if (MainPed.IsTaskActive(TaskType.CTaskGoToAndClimbLadder))
|
||||
|
||||
if (MainPed.IsTaskActive(TaskType.CTaskGoToAndClimbLadder))
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
_currentAnimation[1] = "";
|
||||
@ -388,28 +365,18 @@ namespace RageCoop.Client
|
||||
|
||||
if (IsVaulting)
|
||||
{
|
||||
if (!MainPed.IsVaulting)
|
||||
{
|
||||
MainPed.Task.Climb();
|
||||
}
|
||||
if (!MainPed.IsVaulting) MainPed.Task.Climb();
|
||||
|
||||
SmoothTransition();
|
||||
|
||||
return;
|
||||
}
|
||||
if (!IsVaulting && MainPed.IsVaulting)
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
}
|
||||
|
||||
if (!IsVaulting && MainPed.IsVaulting) MainPed.Task.ClearAllImmediately();
|
||||
|
||||
if (IsOnFire && !MainPed.IsOnFire)
|
||||
{
|
||||
Function.Call(Hash.START_ENTITY_FIRE, MainPed);
|
||||
}
|
||||
else if (!IsOnFire && MainPed.IsOnFire)
|
||||
{
|
||||
Function.Call(Hash.STOP_ENTITY_FIRE, MainPed);
|
||||
}
|
||||
else if (!IsOnFire && MainPed.IsOnFire) Function.Call(Hash.STOP_ENTITY_FIRE, MainPed);
|
||||
|
||||
if (IsJumping)
|
||||
{
|
||||
@ -422,42 +389,35 @@ namespace RageCoop.Client
|
||||
SmoothTransition();
|
||||
return;
|
||||
}
|
||||
|
||||
_lastIsJumping = false;
|
||||
|
||||
if (IsRagdoll || Health == 0)
|
||||
{
|
||||
if (!MainPed.IsRagdoll)
|
||||
{
|
||||
MainPed.Ragdoll();
|
||||
}
|
||||
if (!MainPed.IsRagdoll) MainPed.Ragdoll();
|
||||
SmoothTransition();
|
||||
if (!_lastRagdoll)
|
||||
{
|
||||
_lastRagdoll = true;
|
||||
_lastRagdollTime = Main.Ticked;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (MainPed.IsRagdoll)
|
||||
{
|
||||
if (Speed == 0)
|
||||
{
|
||||
MainPed.CancelRagdoll();
|
||||
}
|
||||
else
|
||||
{
|
||||
MainPed.Task.ClearAllImmediately();
|
||||
}
|
||||
_lastRagdoll = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsReloading)
|
||||
{
|
||||
if (!MainPed.IsTaskActive(TaskType.CTaskReloadGun))
|
||||
{
|
||||
MainPed.Task.ReloadWeapon();
|
||||
}
|
||||
if (!MainPed.IsTaskActive(TaskType.CTaskReloadGun)) MainPed.Task.ReloadWeapon();
|
||||
/*
|
||||
if (!_isPlayingAnimation)
|
||||
{
|
||||
@ -474,10 +434,7 @@ namespace RageCoop.Client
|
||||
}
|
||||
else if (IsInCover)
|
||||
{
|
||||
if (!_lastInCover)
|
||||
{
|
||||
Function.Call(Hash.TASK_STAY_IN_COVER, MainPed.Handle);
|
||||
}
|
||||
if (!_lastInCover) Function.Call(Hash.TASK_STAY_IN_COVER, MainPed.Handle);
|
||||
|
||||
_lastInCover = true;
|
||||
if (IsAiming)
|
||||
@ -511,48 +468,39 @@ namespace RageCoop.Client
|
||||
|
||||
private void CheckCurrentWeapon()
|
||||
{
|
||||
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(_lastWeaponComponents) || (Speed <= 3 && _weaponObj?.IsVisible != true))
|
||||
if (MainPed.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash ||
|
||||
!WeaponComponents.Compare(_lastWeaponComponents) || (Speed <= 3 && _weaponObj?.IsVisible != true))
|
||||
{
|
||||
new WeaponAsset(CurrentWeaponHash).Request();
|
||||
|
||||
MainPed.Weapons.RemoveAll();
|
||||
_weaponObj = Entity.FromHandle(Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0));
|
||||
if (_weaponObj == null) { return; }
|
||||
_weaponObj = Entity.FromHandle(Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1,
|
||||
Position.X, Position.Y, Position.Z, true, 0, 0));
|
||||
if (_weaponObj == null) return;
|
||||
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
||||
{
|
||||
if (WeaponComponents != null && WeaponComponents.Count != 0)
|
||||
{
|
||||
foreach (KeyValuePair<uint, bool> comp in WeaponComponents)
|
||||
{
|
||||
foreach (var comp in WeaponComponents)
|
||||
if (comp.Value)
|
||||
{
|
||||
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, _weaponObj, comp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, _weaponObj, MainPed.Handle);
|
||||
}
|
||||
|
||||
_lastWeaponComponents = WeaponComponents;
|
||||
}
|
||||
|
||||
if (Function.Call<int>(Hash.GET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash) != WeaponTint)
|
||||
{
|
||||
Function.Call<int>(Hash.SET_PED_WEAPON_TINT_INDEX, MainPed, CurrentWeaponHash, WeaponTint);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayAiming()
|
||||
{
|
||||
if (Velocity == default)
|
||||
{
|
||||
MainPed.Task.AimAt(AimCoords, 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, MainPed.Handle,
|
||||
Position.X + Velocity.X, Position.Y + Velocity.Y, Position.Z + Velocity.Z,
|
||||
AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, false, 0x3F000000, 0x40800000, false, 512, false, 0);
|
||||
|
||||
}
|
||||
Position.X + Velocity.X, Position.Y + Velocity.Y, Position.Z + Velocity.Z,
|
||||
AimCoords.X, AimCoords.Y, AimCoords.Z, 3f, false, 0x3F000000, 0x40800000, false, 512, false, 0);
|
||||
SmoothTransition();
|
||||
}
|
||||
|
||||
@ -560,23 +508,21 @@ namespace RageCoop.Client
|
||||
{
|
||||
MainPed.Task.ClearAll();
|
||||
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, MainPed, IsInStealthMode, 0);
|
||||
Vector3 predictPosition = Predict(Position) + Velocity;
|
||||
float range = predictPosition.DistanceToSquared(MainPed.ReadPosition());
|
||||
var predictPosition = Predict(Position) + Velocity;
|
||||
var range = predictPosition.DistanceToSquared(MainPed.ReadPosition());
|
||||
|
||||
switch (Speed)
|
||||
{
|
||||
case 1:
|
||||
if (!MainPed.IsWalking || range > 0.25f)
|
||||
{
|
||||
float nrange = range * 2;
|
||||
if (nrange > 1.0f)
|
||||
{
|
||||
nrange = 1.0f;
|
||||
}
|
||||
var nrange = range * 2;
|
||||
if (nrange > 1.0f) nrange = 1.0f;
|
||||
|
||||
MainPed.Task.GoStraightTo(predictPosition);
|
||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, MainPed.Handle, nrange);
|
||||
}
|
||||
|
||||
LastMoving = true;
|
||||
break;
|
||||
case 2:
|
||||
@ -585,15 +531,18 @@ namespace RageCoop.Client
|
||||
MainPed.Task.RunTo(predictPosition, true);
|
||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, MainPed.Handle, 1.0f);
|
||||
}
|
||||
|
||||
LastMoving = true;
|
||||
break;
|
||||
case 3:
|
||||
if (!MainPed.IsSprinting || range > 0.75f)
|
||||
{
|
||||
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, MainPed.Handle, predictPosition.X, predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
||||
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, MainPed.Handle, predictPosition.X,
|
||||
predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
||||
Function.Call(Hash.SET_RUN_SPRINT_MULTIPLIER_FOR_PLAYER, MainPed.Handle, 1.49f);
|
||||
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, MainPed.Handle, 1.0f);
|
||||
}
|
||||
|
||||
LastMoving = true;
|
||||
break;
|
||||
default:
|
||||
@ -602,8 +551,10 @@ namespace RageCoop.Client
|
||||
MainPed.Task.StandStill(2000);
|
||||
LastMoving = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SmoothTransition();
|
||||
}
|
||||
|
||||
@ -617,26 +568,28 @@ namespace RageCoop.Client
|
||||
MainPed.PositionNoOffset = predicted;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(localRagdoll || MainPed.IsDead))
|
||||
{
|
||||
if (!IsAiming && !MainPed.IsGettingUp)
|
||||
{
|
||||
var cur = MainPed.Heading;
|
||||
var diff = Heading - cur;
|
||||
if (diff > 180) { diff -= 360; }
|
||||
else if (diff < -180) { diff += 360; }
|
||||
if (diff > 180)
|
||||
diff -= 360;
|
||||
else if (diff < -180) diff += 360;
|
||||
|
||||
MainPed.Heading = cur + diff / 2;
|
||||
}
|
||||
|
||||
MainPed.Velocity = Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
|
||||
}
|
||||
else if (Main.Ticked - _lastRagdollTime < 10)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (IsRagdoll)
|
||||
{
|
||||
var helper = new GTA.NaturalMotion.ApplyImpulseHelper(MainPed);
|
||||
var helper = new ApplyImpulseHelper(MainPed);
|
||||
var head = MainPed.Bones[Bone.SkelHead];
|
||||
var rightFoot = MainPed.Bones[Bone.SkelRightFoot];
|
||||
var leftFoot = MainPed.Bones[Bone.SkelLeftFoot];
|
||||
@ -644,7 +597,7 @@ namespace RageCoop.Client
|
||||
// 20:head, 3:left foot, 6:right foot, 17:right hand,
|
||||
|
||||
amount = 20 * (Predict(HeadPosition) - head.Position);
|
||||
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||
if (amount.Length() > 50) amount = amount.Normalized * 50;
|
||||
helper.EqualizeAmount = 1;
|
||||
helper.PartIndex = 20;
|
||||
helper.Impulse = amount;
|
||||
@ -652,7 +605,7 @@ namespace RageCoop.Client
|
||||
helper.Stop();
|
||||
|
||||
amount = 20 * (Predict(RightFootPosition) - rightFoot.Position);
|
||||
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||
if (amount.Length() > 50) amount = amount.Normalized * 50;
|
||||
helper.EqualizeAmount = 1;
|
||||
helper.PartIndex = 6;
|
||||
helper.Impulse = amount;
|
||||
@ -660,7 +613,7 @@ namespace RageCoop.Client
|
||||
helper.Stop();
|
||||
|
||||
amount = 20 * (Predict(LeftFootPosition) - leftFoot.Position);
|
||||
if (amount.Length() > 50) { amount = amount.Normalized * 50; }
|
||||
if (amount.Length() > 50) amount = amount.Normalized * 50;
|
||||
helper.EqualizeAmount = 1;
|
||||
helper.PartIndex = 3;
|
||||
helper.Impulse = amount;
|
||||
@ -671,35 +624,35 @@ namespace RageCoop.Client
|
||||
{
|
||||
// localRagdoll
|
||||
var force = Velocity - MainPed.Velocity + 5 * dist * (predicted - MainPed.ReadPosition());
|
||||
if (force.Length() > 20) { force = force.Normalized * 20; }
|
||||
if (force.Length() > 20) force = force.Normalized * 20;
|
||||
MainPed.ApplyForce(force);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayInVehicle()
|
||||
{
|
||||
if (CurrentVehicle?.MainVehicle == null) { return; }
|
||||
if (CurrentVehicle?.MainVehicle == null) return;
|
||||
switch (Speed)
|
||||
{
|
||||
case 4:
|
||||
if (MainPed.CurrentVehicle != CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat || (!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
|
||||
{
|
||||
if (MainPed.CurrentVehicle != CurrentVehicle.MainVehicle || MainPed.SeatIndex != Seat ||
|
||||
(!MainPed.IsSittingInVehicle() && !MainPed.IsBeingJacked))
|
||||
MainPed.SetIntoVehicle(CurrentVehicle.MainVehicle, Seat);
|
||||
}
|
||||
if (MainPed.IsOnTurretSeat())
|
||||
{
|
||||
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
||||
}
|
||||
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y,
|
||||
AimCoords.Z);
|
||||
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)
|
||||
{
|
||||
// World.DrawMarker(MarkerType.DebugSphere,AimCoords,default,default,new Vector3(0.2f,0.2f,0.2f),Color.AliceBlue);
|
||||
if (IsAiming)
|
||||
{
|
||||
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z);
|
||||
Function.Call(Hash.SET_DRIVEBY_TASK_TARGET, MainPed, 0, 0, AimCoords.X, AimCoords.Y,
|
||||
AimCoords.Z);
|
||||
if (!_lastDriveBy)
|
||||
{
|
||||
_lastDriveBy = true;
|
||||
Function.Call(Hash.TASK_DRIVE_BY, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z, 1, 100, 1, FiringPattern.SingleShot);
|
||||
Function.Call(Hash.TASK_DRIVE_BY, MainPed, 0, 0, AimCoords.X, AimCoords.Y, AimCoords.Z,
|
||||
1, 100, 1, FiringPattern.SingleShot);
|
||||
}
|
||||
}
|
||||
else if (_lastDriveBy || MainPed.IsTaskActive(TaskType.CTaskAimGunVehicleDriveBy))
|
||||
@ -707,33 +660,32 @@ namespace RageCoop.Client
|
||||
MainPed.Task.ClearAll();
|
||||
_lastDriveBy = false;
|
||||
}
|
||||
|
||||
}
|
||||
else if (MainPed.VehicleWeapon != (VehicleWeaponHash)CurrentWeaponHash)
|
||||
{
|
||||
MainPed.VehicleWeapon = (VehicleWeaponHash)CurrentWeaponHash;
|
||||
}
|
||||
|
||||
break;
|
||||
case 5:
|
||||
if (MainPed.VehicleTryingToEnter != CurrentVehicle.MainVehicle || MainPed.GetSeatTryingToEnter() != Seat)
|
||||
{
|
||||
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle, Seat, -1, 5, EnterVehicleFlags.AllowJacking);
|
||||
}
|
||||
if (MainPed.VehicleTryingToEnter != CurrentVehicle.MainVehicle ||
|
||||
MainPed.GetSeatTryingToEnter() != Seat)
|
||||
MainPed.Task.EnterVehicle(CurrentVehicle.MainVehicle, Seat, -1, 5,
|
||||
EnterVehicleFlags.AllowJacking);
|
||||
break;
|
||||
case 6:
|
||||
if (!MainPed.IsTaskActive(TaskType.CTaskExitVehicle))
|
||||
{
|
||||
MainPed.Task.LeaveVehicle(CurrentVehicle.Velocity.Length() > 5f ? LeaveVehicleFlags.BailOut : LeaveVehicleFlags.None);
|
||||
}
|
||||
MainPed.Task.LeaveVehicle(CurrentVehicle.Velocity.Length() > 5f
|
||||
? LeaveVehicleFlags.BailOut
|
||||
: LeaveVehicleFlags.None);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Function.Call(Hash.SET_PED_STEALTH_MOVEMENT, P,true, 0);
|
||||
return Function.Call<bool>(Hash.GET_PED_STEALTH_MOVEMENT, P);
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,116 +1,114 @@
|
||||
using GTA;
|
||||
using System.Diagnostics;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class SyncedEntity
|
||||
{
|
||||
private float _accumulatedOff;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current player is responsible for syncing this entity.
|
||||
/// </summary>
|
||||
public bool IsLocal
|
||||
{
|
||||
get => OwnerID == Main.LocalPlayerID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Network ID for this entity
|
||||
/// </summary>
|
||||
public int ID { get; internal set; }
|
||||
protected internal bool _lastFrozen = false;
|
||||
|
||||
|
||||
private int _ownerID;
|
||||
public Stopwatch LastSyncedStopWatch = new Stopwatch();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current player is responsible for syncing this entity.
|
||||
/// </summary>
|
||||
public bool IsLocal => OwnerID == Main.LocalPlayerID;
|
||||
|
||||
/// <summary>
|
||||
/// Network ID for this entity
|
||||
/// </summary>
|
||||
public int ID { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int OwnerID
|
||||
{
|
||||
get => _ownerID;
|
||||
internal set
|
||||
{
|
||||
if (value == _ownerID && Owner != null) { return; }
|
||||
if (value == _ownerID && Owner != null) return;
|
||||
_ownerID = value;
|
||||
Owner = PlayerList.GetPlayer(value);
|
||||
if (this is SyncedPed && Owner != null)
|
||||
{
|
||||
Owner.Character = ((SyncedPed)this);
|
||||
}
|
||||
if (this is SyncedPed && Owner != null) Owner.Character = (SyncedPed)this;
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual Player Owner { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool IsOutOfSync
|
||||
{
|
||||
get => Main.Ticked - LastSynced > 200 && ID != 0;
|
||||
}
|
||||
internal bool IsReady
|
||||
{
|
||||
get => LastSynced > 0 || LastFullSynced == 0;
|
||||
}
|
||||
public bool IsOutOfSync => Main.Ticked - LastSynced > 200 && ID != 0;
|
||||
|
||||
internal bool IsReady => LastSynced > 0 || LastFullSynced == 0;
|
||||
|
||||
internal bool IsInvincible { get; set; } = false;
|
||||
internal bool NeedUpdate
|
||||
{
|
||||
get => LastSynced >= LastUpdated;
|
||||
}
|
||||
#region LAST STATE
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastSynced { get; set; } = 0;
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastFullSynced { get; internal set; } = 0;
|
||||
/// <summary>
|
||||
/// Last time the local entity has been updated,
|
||||
/// </summary>
|
||||
public ulong LastUpdated { get; set; } = 0;
|
||||
|
||||
|
||||
internal Stopwatch LastSentStopWatch { get; set; } = Stopwatch.StartNew();
|
||||
#endregion
|
||||
internal bool NeedUpdate => LastSynced >= LastUpdated;
|
||||
|
||||
public bool SendNextFrame { get; set; } = false;
|
||||
public bool SendFullNextFrame { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected internal bool _lastFrozen = false;
|
||||
internal Model Model { get; set; }
|
||||
internal Vector3 Position { get; set; }
|
||||
internal Vector3 Rotation { get; set; }
|
||||
internal Quaternion Quaternion { get; set; }
|
||||
internal Vector3 Velocity { get; set; }
|
||||
public Stopwatch LastSyncedStopWatch = new Stopwatch();
|
||||
internal abstract void Update();
|
||||
|
||||
internal void PauseUpdate(ulong frames)
|
||||
{
|
||||
LastUpdated = Main.Ticked + frames;
|
||||
}
|
||||
|
||||
protected Vector3 Predict(Vector3 input)
|
||||
{
|
||||
return (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Velocity + input;
|
||||
}
|
||||
private float _accumulatedOff = 0;
|
||||
|
||||
protected bool IsOff(float thisOff, float tolerance = 3, float limit = 30)
|
||||
{
|
||||
_accumulatedOff += thisOff - tolerance;
|
||||
if (_accumulatedOff < 0) { _accumulatedOff = 0; }
|
||||
if (_accumulatedOff < 0)
|
||||
{
|
||||
_accumulatedOff = 0;
|
||||
}
|
||||
else if (_accumulatedOff >= limit)
|
||||
{
|
||||
_accumulatedOff = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#region LAST STATE
|
||||
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastSynced { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Last time a new sync message arrived.
|
||||
/// </summary>
|
||||
public ulong LastFullSynced { get; internal set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Last time the local entity has been updated,
|
||||
/// </summary>
|
||||
public ulong LastUpdated { get; set; }
|
||||
|
||||
|
||||
internal Stopwatch LastSentStopWatch { get; set; } = Stopwatch.StartNew();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
@ -7,57 +7,18 @@ namespace RageCoop.Client
|
||||
{
|
||||
internal class SyncedProjectile : SyncedEntity
|
||||
{
|
||||
public ProjectileDataFlags Flags { private get; set; } = ProjectileDataFlags.None;
|
||||
|
||||
public readonly Vector3 Origin;
|
||||
private bool _firstSend = false;
|
||||
private bool _firstSend;
|
||||
|
||||
|
||||
public bool IsValid { get; private set; } = true;
|
||||
public new bool IsLocal { get; private set; } = false;
|
||||
public Projectile MainProjectile { get; set; }
|
||||
public SyncedEntity Shooter { get; set; }
|
||||
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
|
||||
|
||||
internal override Player Owner => Shooter.Owner;
|
||||
/// <summary>
|
||||
/// Invalid property for projectile.
|
||||
/// </summary>
|
||||
private new int OwnerID { set { } }
|
||||
public WeaponHash WeaponHash { get; set; }
|
||||
private WeaponAsset Asset { get; set; }
|
||||
public void ExtractData(ref Packets.ProjectileSync p)
|
||||
{
|
||||
p.Position = MainProjectile.Position;
|
||||
p.Velocity = MainProjectile.Velocity;
|
||||
p.Rotation = MainProjectile.Rotation;
|
||||
p.ID = ID;
|
||||
p.ShooterID = Shooter.ID;
|
||||
p.WeaponHash = (uint)MainProjectile.WeaponHash;
|
||||
p.Flags = ProjectileDataFlags.None;
|
||||
if (MainProjectile.IsDead)
|
||||
{
|
||||
p.Flags |= ProjectileDataFlags.Exploded;
|
||||
}
|
||||
if (MainProjectile.AttachedEntity != null)
|
||||
{
|
||||
p.Flags |= ProjectileDataFlags.IsAttached;
|
||||
}
|
||||
if (Shooter is SyncedVehicle)
|
||||
{
|
||||
p.Flags |= ProjectileDataFlags.IsShotByVehicle;
|
||||
}
|
||||
if (_firstSend)
|
||||
{
|
||||
p.Flags |= ProjectileDataFlags.IsAttached;
|
||||
_firstSend = false;
|
||||
}
|
||||
|
||||
}
|
||||
public SyncedProjectile(Projectile p)
|
||||
{
|
||||
var owner = p.OwnerEntity;
|
||||
if (owner == null) { IsValid = false; return; }
|
||||
if (owner == null)
|
||||
{
|
||||
IsValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ID = EntityPool.RequestNewID();
|
||||
MainProjectile = p;
|
||||
Origin = p.Position;
|
||||
@ -65,12 +26,13 @@ namespace RageCoop.Client
|
||||
{
|
||||
if (shooter.MainPed != null
|
||||
&& (p.AttachedEntity == shooter.MainPed.Weapons.CurrentWeaponObject
|
||||
|| p.AttachedEntity == shooter.MainPed))
|
||||
|| p.AttachedEntity == shooter.MainPed))
|
||||
{
|
||||
// Reloading
|
||||
IsValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Shooter = shooter;
|
||||
IsLocal = shooter.IsLocal;
|
||||
}
|
||||
@ -84,22 +46,65 @@ namespace RageCoop.Client
|
||||
IsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public SyncedProjectile(int id)
|
||||
{
|
||||
ID = id;
|
||||
IsLocal = false;
|
||||
}
|
||||
|
||||
public ProjectileDataFlags Flags { private get; set; } = ProjectileDataFlags.None;
|
||||
|
||||
|
||||
public bool IsValid { get; } = true;
|
||||
public new bool IsLocal { get; }
|
||||
public Projectile MainProjectile { get; set; }
|
||||
public SyncedEntity Shooter { get; set; }
|
||||
public bool Exploded => Flags.HasProjDataFlag(ProjectileDataFlags.Exploded);
|
||||
|
||||
internal override Player Owner => Shooter.Owner;
|
||||
|
||||
/// <summary>
|
||||
/// Invalid property for projectile.
|
||||
/// </summary>
|
||||
private new int OwnerID
|
||||
{
|
||||
set { }
|
||||
}
|
||||
|
||||
public WeaponHash WeaponHash { get; set; }
|
||||
private WeaponAsset Asset { get; set; }
|
||||
|
||||
public void ExtractData(ref Packets.ProjectileSync p)
|
||||
{
|
||||
p.Position = MainProjectile.Position;
|
||||
p.Velocity = MainProjectile.Velocity;
|
||||
p.Rotation = MainProjectile.Rotation;
|
||||
p.ID = ID;
|
||||
p.ShooterID = Shooter.ID;
|
||||
p.WeaponHash = (uint)MainProjectile.WeaponHash;
|
||||
p.Flags = ProjectileDataFlags.None;
|
||||
if (MainProjectile.IsDead) p.Flags |= ProjectileDataFlags.Exploded;
|
||||
if (MainProjectile.AttachedEntity != null) p.Flags |= ProjectileDataFlags.IsAttached;
|
||||
if (Shooter is SyncedVehicle) p.Flags |= ProjectileDataFlags.IsShotByVehicle;
|
||||
if (_firstSend)
|
||||
{
|
||||
p.Flags |= ProjectileDataFlags.IsAttached;
|
||||
_firstSend = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate) { return; }
|
||||
if (!NeedUpdate) return;
|
||||
|
||||
if (MainProjectile == null || !MainProjectile.Exists())
|
||||
{
|
||||
CreateProjectile();
|
||||
return;
|
||||
}
|
||||
|
||||
MainProjectile.Velocity = Velocity + 10 * (Predict(Position) - MainProjectile.Position);
|
||||
MainProjectile.Rotation = Rotation;
|
||||
LastUpdated = Main.Ticked;
|
||||
@ -108,13 +113,20 @@ namespace RageCoop.Client
|
||||
private void CreateProjectile()
|
||||
{
|
||||
Asset = new WeaponAsset(WeaponHash);
|
||||
if (!Asset.IsLoaded) { Asset.Request(); return; }
|
||||
if (Shooter == null) { return; }
|
||||
if (!Asset.IsLoaded)
|
||||
{
|
||||
Asset.Request();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Shooter == null) return;
|
||||
Entity owner;
|
||||
owner = (Shooter as SyncedPed)?.MainPed ?? (Entity)(Shooter as SyncedVehicle)?.MainVehicle;
|
||||
Position = (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Shooter.Velocity + Position;
|
||||
Position = (Owner.PacketTravelTime + 0.001f * LastSyncedStopWatch.ElapsedMilliseconds) * Shooter.Velocity +
|
||||
Position;
|
||||
var end = Position + Velocity;
|
||||
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z, end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1);
|
||||
Function.Call(Hash.SHOOT_SINGLE_BULLET_BETWEEN_COORDS_IGNORE_ENTITY, Position.X, Position.Y, Position.Z,
|
||||
end.X, end.Y, end.Z, 0, 1, WeaponHash, owner?.Handle ?? 0, 1, 0, -1);
|
||||
var ps = World.GetAllProjectiles();
|
||||
MainProjectile = ps[ps.Length - 1];
|
||||
MainProjectile.Position = Position;
|
||||
@ -123,4 +135,4 @@ namespace RageCoop.Client
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Synchronized prop, mostly owned by server
|
||||
/// Synchronized prop, mostly owned by server
|
||||
/// </summary>
|
||||
public class SyncedProp : SyncedEntity
|
||||
{
|
||||
@ -11,32 +11,35 @@ namespace RageCoop.Client
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The real entity
|
||||
/// The real entity
|
||||
/// </summary>
|
||||
public Prop MainProp { get; set; }
|
||||
internal new int OwnerID
|
||||
{
|
||||
get
|
||||
{
|
||||
// alwayse owned by server
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal new int OwnerID =>
|
||||
// alwayse owned by server
|
||||
0;
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
if (!NeedUpdate) return;
|
||||
if (!Model.IsLoaded)
|
||||
{
|
||||
Model.Request();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NeedUpdate) { return; }
|
||||
if (!Model.IsLoaded) { Model.Request(); return; }
|
||||
if (MainProp == null || !MainProp.Exists())
|
||||
{
|
||||
MainProp = World.CreateProp(Model, Position, Rotation, false, false);
|
||||
MainProp.IsInvincible = true;
|
||||
}
|
||||
|
||||
MainProp.Position = Position;
|
||||
MainProp.Rotation = Rotation;
|
||||
MainProp.SetFrozen(true);
|
||||
LastUpdated = Main.Ticked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using RageCoop.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -11,6 +11,7 @@ namespace RageCoop.Client
|
||||
|
||||
|
||||
#region -- SYNC DATA --
|
||||
|
||||
internal Vector3 RotationVelocity { get; set; }
|
||||
internal float SteeringAngle { get; set; }
|
||||
internal float ThrottlePower { get; set; }
|
||||
@ -34,23 +35,23 @@ namespace RageCoop.Client
|
||||
|
||||
#region FLAGS
|
||||
|
||||
internal bool EngineRunning { get => Flags.HasVehFlag(VehicleDataFlags.IsEngineRunning); }
|
||||
internal bool Transformed { get => Flags.HasVehFlag(VehicleDataFlags.IsTransformed); }
|
||||
internal bool HornActive { get => Flags.HasVehFlag(VehicleDataFlags.IsHornActive); }
|
||||
internal bool LightsOn { get => Flags.HasVehFlag(VehicleDataFlags.AreLightsOn); }
|
||||
internal bool BrakeLightsOn { get => Flags.HasVehFlag(VehicleDataFlags.AreBrakeLightsOn); }
|
||||
internal bool HighBeamsOn { get => Flags.HasVehFlag(VehicleDataFlags.AreHighBeamsOn); }
|
||||
internal bool SireneActive { get => Flags.HasVehFlag(VehicleDataFlags.IsSirenActive); }
|
||||
internal bool IsDead { get => Flags.HasVehFlag(VehicleDataFlags.IsDead); }
|
||||
internal bool IsDeluxoHovering { get => Flags.HasVehFlag(VehicleDataFlags.IsDeluxoHovering); }
|
||||
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);
|
||||
|
||||
#endregion
|
||||
|
||||
#region FIXED-DATA
|
||||
|
||||
internal bool IsFlipped
|
||||
{
|
||||
get => IsMotorcycle || ((Quaternion * Vector3.RelativeTop).Z - (Quaternion * Vector3.RelativeBottom).Z) < 0.5;
|
||||
}
|
||||
internal bool IsFlipped => IsMotorcycle ||
|
||||
(Quaternion * Vector3.RelativeTop).Z - (Quaternion * Vector3.RelativeBottom).Z < 0.5;
|
||||
|
||||
internal bool IsMotorcycle;
|
||||
internal bool IsAircraft;
|
||||
internal bool HasRocketBoost;
|
||||
@ -62,21 +63,25 @@ namespace RageCoop.Client
|
||||
#endregion
|
||||
|
||||
#region PRIVATE
|
||||
private byte[] _lastVehicleColors = new byte[] { 0, 0 };
|
||||
|
||||
private byte[] _lastVehicleColors = { 0, 0 };
|
||||
private Dictionary<int, int> _lastVehicleMods = new Dictionary<int, int>();
|
||||
private bool _lastHornActive = false;
|
||||
private bool _lastTransformed = false;
|
||||
private bool _lastHornActive;
|
||||
private bool _lastTransformed;
|
||||
internal int _lastLivery = -1;
|
||||
private readonly List<Vector3> _predictedTrace = new List<Vector3>();
|
||||
private readonly List<Vector3> _orgTrace = new List<Vector3>();
|
||||
private Vector3 _predictedPosition;
|
||||
|
||||
#endregion
|
||||
|
||||
#region OUTGOING
|
||||
|
||||
internal float LastNozzleAngle { get; set; }
|
||||
|
||||
internal float LastEngineHealth { get; set; }
|
||||
internal Vector3 LastVelocity { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,64 +1,19 @@
|
||||
using GTA;
|
||||
using System;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using GTA.Native;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// A synchronized vehicle instance
|
||||
/// A synchronized vehicle instance
|
||||
/// </summary>
|
||||
public partial class SyncedVehicle : SyncedEntity
|
||||
{
|
||||
|
||||
#region -- CONSTRUCTORS --
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// VehicleSeat,ID
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
internal SyncedVehicle(Vehicle v)
|
||||
{
|
||||
|
||||
ID = EntityPool.RequestNewID();
|
||||
MainVehicle = v;
|
||||
MainVehicle.CanPretendOccupants = false;
|
||||
OwnerID = Main.LocalPlayerID;
|
||||
SetUpFixedData();
|
||||
|
||||
}
|
||||
internal void SetUpFixedData()
|
||||
{
|
||||
if (MainVehicle == null) { return; }
|
||||
|
||||
IsAircraft = MainVehicle.IsAircraft;
|
||||
IsMotorcycle = MainVehicle.IsMotorcycle;
|
||||
HasRocketBoost = MainVehicle.HasRocketBoost;
|
||||
HasParachute = MainVehicle.HasParachute;
|
||||
HasRoof = MainVehicle.HasRoof;
|
||||
IsSubmarineCar = MainVehicle.IsSubmarineCar;
|
||||
IsDeluxo = MainVehicle.Model == 1483171323;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty VehicleEntity
|
||||
/// </summary>
|
||||
internal SyncedVehicle()
|
||||
{
|
||||
|
||||
}
|
||||
internal SyncedVehicle(int id)
|
||||
{
|
||||
ID = id;
|
||||
LastSynced = Main.Ticked;
|
||||
}
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// VehicleSeat,ID
|
||||
/// </summary>
|
||||
|
||||
internal override void Update()
|
||||
{
|
||||
#if DEBUG_VEH
|
||||
@ -74,94 +29,62 @@ namespace RageCoop.Client
|
||||
|
||||
|
||||
// Check if all data avalible
|
||||
if (!IsReady || Owner == null) { return; }
|
||||
if (!IsReady || Owner == null) return;
|
||||
|
||||
// Check existence
|
||||
if ((MainVehicle == null) || (!MainVehicle.Exists()) || (MainVehicle.Model != Model))
|
||||
{
|
||||
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model != Model)
|
||||
if (!CreateVehicle())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DisplayVehicle();
|
||||
// Skip update if no new sync message has arrived.
|
||||
if (!NeedUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!NeedUpdate) return;
|
||||
|
||||
if (SteeringAngle != MainVehicle.SteeringAngle)
|
||||
{
|
||||
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * SteeringAngle);
|
||||
}
|
||||
MainVehicle.ThrottlePower = ThrottlePower;
|
||||
MainVehicle.BrakePower = BrakePower;
|
||||
|
||||
if (IsDead)
|
||||
{
|
||||
if (MainVehicle.IsDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (MainVehicle.IsDead) return;
|
||||
|
||||
MainVehicle.Explode();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainVehicle.IsDead)
|
||||
{
|
||||
WorldThread.Delay(() =>
|
||||
{
|
||||
if (MainVehicle.IsDead && !IsDead)
|
||||
{
|
||||
MainVehicle.Repair();
|
||||
}
|
||||
if (MainVehicle.IsDead && !IsDead) MainVehicle.Repair();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (MainVehicle.IsOnFire)
|
||||
{
|
||||
if (!Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
|
||||
{
|
||||
Function.Call(Hash.STOP_ENTITY_FIRE, MainVehicle);
|
||||
}
|
||||
if (!Flags.HasVehFlag(VehicleDataFlags.IsOnFire)) Function.Call(Hash.STOP_ENTITY_FIRE, MainVehicle);
|
||||
}
|
||||
else if (Flags.HasVehFlag(VehicleDataFlags.IsOnFire))
|
||||
{
|
||||
Function.Call(Hash.START_ENTITY_FIRE, MainVehicle);
|
||||
}
|
||||
|
||||
if (EngineRunning != MainVehicle.IsEngineRunning)
|
||||
{
|
||||
MainVehicle.IsEngineRunning = EngineRunning;
|
||||
}
|
||||
if (EngineRunning != MainVehicle.IsEngineRunning) MainVehicle.IsEngineRunning = EngineRunning;
|
||||
|
||||
if (LightsOn != MainVehicle.AreLightsOn)
|
||||
{
|
||||
MainVehicle.AreLightsOn = LightsOn;
|
||||
}
|
||||
if (LightsOn != MainVehicle.AreLightsOn) MainVehicle.AreLightsOn = LightsOn;
|
||||
|
||||
if (HighBeamsOn != MainVehicle.AreHighBeamsOn)
|
||||
{
|
||||
MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
||||
}
|
||||
if (HighBeamsOn != MainVehicle.AreHighBeamsOn) MainVehicle.AreHighBeamsOn = HighBeamsOn;
|
||||
|
||||
if (IsAircraft)
|
||||
{
|
||||
if (LandingGear != (byte)MainVehicle.LandingGearState)
|
||||
{
|
||||
MainVehicle.LandingGearState = (VehicleLandingGearState)LandingGear;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MainVehicle.HasSiren && SireneActive != MainVehicle.IsSirenActive)
|
||||
{
|
||||
MainVehicle.IsSirenActive = SireneActive;
|
||||
}
|
||||
|
||||
if (HornActive)
|
||||
{
|
||||
@ -177,19 +100,14 @@ namespace RageCoop.Client
|
||||
MainVehicle.SoundHorn(1);
|
||||
}
|
||||
|
||||
if (HasRoof && MainVehicle.RoofState != RoofState)
|
||||
{
|
||||
MainVehicle.RoofState = RoofState;
|
||||
}
|
||||
if (HasRoof && MainVehicle.RoofState != RoofState) MainVehicle.RoofState = RoofState;
|
||||
|
||||
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) != MainVehicle.IsRocketBoostActive())
|
||||
{
|
||||
if (HasRocketBoost && Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive) !=
|
||||
MainVehicle.IsRocketBoostActive())
|
||||
MainVehicle.SetRocketBoostActive(Flags.HasFlag(VehicleDataFlags.IsRocketBoostActive));
|
||||
}
|
||||
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) != MainVehicle.IsParachuteActive())
|
||||
{
|
||||
if (HasParachute && Flags.HasFlag(VehicleDataFlags.IsParachuteActive) !=
|
||||
MainVehicle.IsParachuteActive())
|
||||
MainVehicle.SetParachuteActive(Flags.HasFlag(VehicleDataFlags.IsParachuteActive));
|
||||
}
|
||||
if (IsSubmarineCar)
|
||||
{
|
||||
if (Transformed)
|
||||
@ -209,55 +127,46 @@ namespace RageCoop.Client
|
||||
else if (IsDeluxo)
|
||||
{
|
||||
MainVehicle.SetDeluxoHoverState(IsDeluxoHovering);
|
||||
if (IsDeluxoHovering)
|
||||
{
|
||||
MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||
}
|
||||
if (IsDeluxoHovering) MainVehicle.SetDeluxoWingRatio(DeluxoWingRatio);
|
||||
}
|
||||
|
||||
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle.Handle, BrakeLightsOn);
|
||||
|
||||
|
||||
}
|
||||
|
||||
MainVehicle.LockStatus = LockStatus;
|
||||
|
||||
if (LastFullSynced >= LastUpdated)
|
||||
{
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.Repaired))
|
||||
{
|
||||
MainVehicle.Repair();
|
||||
}
|
||||
if (Flags.HasVehFlag(VehicleDataFlags.Repaired)) MainVehicle.Repair();
|
||||
if (Colors != null && Colors != _lastVehicleColors)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, Colors[0], Colors[1]);
|
||||
|
||||
_lastVehicleColors = Colors;
|
||||
}
|
||||
|
||||
MainVehicle.EngineHealth = EngineHealth;
|
||||
if (Mods != null && !Mods.Compare(_lastVehicleMods))
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
||||
|
||||
foreach (KeyValuePair<int, int> mod in Mods)
|
||||
{
|
||||
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
||||
}
|
||||
foreach (var mod in Mods) MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
||||
|
||||
_lastVehicleMods = Mods;
|
||||
}
|
||||
|
||||
if (Function.Call<string>(Hash.GET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle) != LicensePlate)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_NUMBER_PLATE_TEXT, MainVehicle, LicensePlate);
|
||||
}
|
||||
|
||||
if (_lastLivery != Livery)
|
||||
{
|
||||
Function.Call(Hash.SET_VEHICLE_LIVERY, MainVehicle, Livery);
|
||||
_lastLivery = Livery;
|
||||
}
|
||||
|
||||
MainVehicle.SetDamageModel(DamageModel);
|
||||
}
|
||||
|
||||
LastUpdated = Main.Ticked;
|
||||
}
|
||||
|
||||
@ -267,7 +176,7 @@ namespace RageCoop.Client
|
||||
var current = MainVehicle.ReadPosition();
|
||||
var dist = current.DistanceTo(_predictedPosition);
|
||||
var cali = dist * (_predictedPosition - current);
|
||||
if (Velocity.Length() < 0.1) { cali *= 10; }
|
||||
if (Velocity.Length() < 0.1) cali *= 10;
|
||||
if (dist > 10)
|
||||
{
|
||||
MainVehicle.Position = _predictedPosition;
|
||||
@ -275,10 +184,8 @@ namespace RageCoop.Client
|
||||
MainVehicle.Quaternion = Quaternion;
|
||||
return;
|
||||
}
|
||||
if (dist > 0.03)
|
||||
{
|
||||
MainVehicle.Velocity = Velocity + cali;
|
||||
}
|
||||
|
||||
if (dist > 0.03) MainVehicle.Velocity = Velocity + cali;
|
||||
|
||||
Vector3 calirot;
|
||||
if (IsFlipped || (calirot = GetCalibrationRotation()).Length() > 50)
|
||||
@ -287,57 +194,104 @@ namespace RageCoop.Client
|
||||
MainVehicle.RotationVelocity = RotationVelocity;
|
||||
return;
|
||||
}
|
||||
|
||||
MainVehicle.RotationVelocity = RotationVelocity + calirot * 0.2f;
|
||||
}
|
||||
|
||||
private Vector3 GetCalibrationRotation()
|
||||
{
|
||||
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop).ToEulerAngles();
|
||||
var curRot = Quaternion.LookRotation(MainVehicle.ReadQuaternion() * Vector3.RelativeFront, MainVehicle.ReadQuaternion() * Vector3.RelativeTop).ToEulerAngles();
|
||||
var rot = Quaternion.LookRotation(Quaternion * Vector3.RelativeFront, Quaternion * Vector3.RelativeTop)
|
||||
.ToEulerAngles();
|
||||
var curRot = Quaternion.LookRotation(MainVehicle.ReadQuaternion() * Vector3.RelativeFront,
|
||||
MainVehicle.ReadQuaternion() * Vector3.RelativeTop).ToEulerAngles();
|
||||
|
||||
var r = (rot - curRot).ToDegree();
|
||||
if (r.X > 180) { r.X = r.X - 360; }
|
||||
else if (r.X < -180) { r.X = 360 + r.X; }
|
||||
if (r.X > 180)
|
||||
r.X = r.X - 360;
|
||||
else if (r.X < -180) r.X = 360 + r.X;
|
||||
|
||||
if (r.Y > 180) { r.Y = r.Y - 360; }
|
||||
else if (r.Y < -180) { r.Y = 360 + r.Y; }
|
||||
if (r.Y > 180)
|
||||
r.Y = r.Y - 360;
|
||||
else if (r.Y < -180) r.Y = 360 + r.Y;
|
||||
|
||||
if (r.Z > 180) { r.Z = r.Z - 360; }
|
||||
else if (r.Z < -180) { r.Z = 360 + r.Z; }
|
||||
if (r.Z > 180)
|
||||
r.Z = r.Z - 360;
|
||||
else if (r.Z < -180) r.Z = 360 + r.Z;
|
||||
return r;
|
||||
}
|
||||
|
||||
private bool CreateVehicle()
|
||||
{
|
||||
MainVehicle?.Delete();
|
||||
MainVehicle = Util.CreateVehicle(Model, Position);
|
||||
if (!Model.IsInCdImage)
|
||||
{
|
||||
// GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
||||
return false;
|
||||
}
|
||||
if (MainVehicle == null)
|
||||
{
|
||||
Model.Request();
|
||||
return false;
|
||||
}
|
||||
|
||||
lock (EntityPool.VehiclesLock)
|
||||
{
|
||||
EntityPool.Add(this);
|
||||
}
|
||||
|
||||
MainVehicle.Quaternion = Quaternion;
|
||||
if (MainVehicle.HasRoof)
|
||||
{
|
||||
MainVehicle.RoofState = RoofState;
|
||||
}
|
||||
foreach (var w in MainVehicle.Wheels)
|
||||
{
|
||||
w.Fix();
|
||||
}
|
||||
if (IsInvincible) { MainVehicle.IsInvincible = true; }
|
||||
if (MainVehicle.HasRoof) MainVehicle.RoofState = RoofState;
|
||||
foreach (var w in MainVehicle.Wheels) w.Fix();
|
||||
if (IsInvincible) MainVehicle.IsInvincible = true;
|
||||
SetUpFixedData();
|
||||
Model.MarkAsNoLongerNeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
#region -- CONSTRUCTORS --
|
||||
|
||||
/// <summary>
|
||||
/// Create a local entity (outgoing sync)
|
||||
/// </summary>
|
||||
/// <param name="v"></param>
|
||||
internal SyncedVehicle(Vehicle v)
|
||||
{
|
||||
ID = EntityPool.RequestNewID();
|
||||
MainVehicle = v;
|
||||
MainVehicle.CanPretendOccupants = false;
|
||||
OwnerID = Main.LocalPlayerID;
|
||||
SetUpFixedData();
|
||||
}
|
||||
|
||||
internal void SetUpFixedData()
|
||||
{
|
||||
if (MainVehicle == null) return;
|
||||
|
||||
IsAircraft = MainVehicle.IsAircraft;
|
||||
IsMotorcycle = MainVehicle.IsMotorcycle;
|
||||
HasRocketBoost = MainVehicle.HasRocketBoost;
|
||||
HasParachute = MainVehicle.HasParachute;
|
||||
HasRoof = MainVehicle.HasRoof;
|
||||
IsSubmarineCar = MainVehicle.IsSubmarineCar;
|
||||
IsDeluxo = MainVehicle.Model == 1483171323;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an empty VehicleEntity
|
||||
/// </summary>
|
||||
internal SyncedVehicle()
|
||||
{
|
||||
}
|
||||
|
||||
internal SyncedVehicle(int id)
|
||||
{
|
||||
ID = id;
|
||||
LastSynced = Main.Ticked;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region -- PEDALING --
|
||||
|
||||
/*
|
||||
* Thanks to @oldnapalm.
|
||||
*/
|
||||
@ -364,14 +318,15 @@ namespace RageCoop.Client
|
||||
|
||||
private void StartPedalingAnim(bool fast)
|
||||
{
|
||||
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
|
||||
|
||||
MainVehicle.Driver?.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1,
|
||||
AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
|
||||
}
|
||||
|
||||
private void StopPedalingAnim(bool fast)
|
||||
{
|
||||
MainVehicle.Driver.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Client.Scripting;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using GTA;
|
||||
using GTA.Native;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Client.Scripting;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -13,9 +13,10 @@ namespace RageCoop.Client
|
||||
{
|
||||
public static object PedsLock = new object();
|
||||
#if BENCHMARK
|
||||
private static Stopwatch PerfCounter=new Stopwatch();
|
||||
private static Stopwatch PerfCounter2=Stopwatch.StartNew();
|
||||
private static Stopwatch PerfCounter = new Stopwatch();
|
||||
private static Stopwatch PerfCounter2 = Stopwatch.StartNew();
|
||||
#endif
|
||||
|
||||
#region ACTIVE INSTANCES
|
||||
|
||||
public static Dictionary<int, SyncedPed> PedsByID = new Dictionary<int, SyncedPed>();
|
||||
@ -41,64 +42,70 @@ namespace RageCoop.Client
|
||||
public static object BlipsLock = new object();
|
||||
|
||||
#endregion
|
||||
|
||||
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
|
||||
{
|
||||
foreach (var ped in PedsByID.Values.ToArray())
|
||||
{
|
||||
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
|
||||
if ((keepPlayer && ped.ID == Main.LocalPlayerID) ||
|
||||
(keepMine && ped.OwnerID == Main.LocalPlayerID)) continue;
|
||||
RemovePed(ped.ID);
|
||||
}
|
||||
|
||||
PedsByID.Clear();
|
||||
PedsByHandle.Clear();
|
||||
|
||||
foreach (int id in VehiclesByID.Keys.ToArray())
|
||||
foreach (var id in VehiclesByID.Keys.ToArray())
|
||||
{
|
||||
if (keepMine && (VehiclesByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
|
||||
if (keepMine && VehiclesByID[id].OwnerID == Main.LocalPlayerID) continue;
|
||||
RemoveVehicle(id);
|
||||
}
|
||||
|
||||
VehiclesByID.Clear();
|
||||
VehiclesByHandle.Clear();
|
||||
|
||||
foreach (var p in ProjectilesByID.Values.ToArray())
|
||||
{
|
||||
if (p.Shooter.ID != Main.LocalPlayerID && p.MainProjectile != null && p.MainProjectile.Exists())
|
||||
{
|
||||
p.MainProjectile.Delete();
|
||||
}
|
||||
}
|
||||
ProjectilesByID.Clear();
|
||||
ProjectilesByHandle.Clear();
|
||||
|
||||
foreach (var p in ServerProps.Values)
|
||||
{
|
||||
p?.MainProp?.Delete();
|
||||
}
|
||||
foreach (var p in ServerProps.Values) p?.MainProp?.Delete();
|
||||
ServerProps.Clear();
|
||||
|
||||
foreach (var b in ServerBlips.Values)
|
||||
{
|
||||
if (b.Exists())
|
||||
{
|
||||
b.Delete();
|
||||
}
|
||||
}
|
||||
ServerBlips.Clear();
|
||||
}
|
||||
|
||||
#region PEDS
|
||||
public static SyncedPed GetPedByID(int id) => PedsByID.TryGetValue(id, out var p) ? p : null;
|
||||
public static SyncedPed GetPedByHandle(int handle) => PedsByHandle.TryGetValue(handle, out var p) ? p : null;
|
||||
public static List<int> GetPedIDs() => new List<int>(PedsByID.Keys);
|
||||
|
||||
public static SyncedPed GetPedByID(int id)
|
||||
{
|
||||
return PedsByID.TryGetValue(id, out var p) ? p : null;
|
||||
}
|
||||
|
||||
public static SyncedPed GetPedByHandle(int handle)
|
||||
{
|
||||
return PedsByHandle.TryGetValue(handle, out var p) ? p : null;
|
||||
}
|
||||
|
||||
public static List<int> GetPedIDs()
|
||||
{
|
||||
return new List<int>(PedsByID.Keys);
|
||||
}
|
||||
|
||||
public static bool AddPlayer()
|
||||
{
|
||||
Ped p = Game.Player.Character;
|
||||
var p = Game.Player.Character;
|
||||
// var clipset=p.Gender==Gender.Male? "MOVE_M@TOUGH_GUY@" : "MOVE_F@TOUGH_GUY@";
|
||||
// Function.Call(Hash.SET_PED_MOVEMENT_CLIPSET,p,clipset,1f);
|
||||
SyncedPed player = GetPedByID(Main.LocalPlayerID);
|
||||
var player = GetPedByID(Main.LocalPlayerID);
|
||||
if (player == null)
|
||||
{
|
||||
Main.Logger.Debug($"Creating SyncEntity for player, handle:{p.Handle}");
|
||||
SyncedPed c = new SyncedPed(p);
|
||||
var c = new SyncedPed(p);
|
||||
Main.LocalPlayerID = c.OwnerID = c.ID;
|
||||
Add(c);
|
||||
Main.Logger.Debug($"Local player ID is:{c.ID}");
|
||||
@ -119,51 +126,37 @@ namespace RageCoop.Client
|
||||
|
||||
// Re-add
|
||||
PedsByHandle.Remove(pair.Key);
|
||||
if (PedsByHandle.ContainsKey(p.Handle))
|
||||
{
|
||||
RemovePed(PedsByHandle[p.Handle].ID);
|
||||
}
|
||||
if (PedsByHandle.ContainsKey(p.Handle)) RemovePed(PedsByHandle[p.Handle].ID);
|
||||
PedsByHandle.Add(p.Handle, player);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Add(SyncedPed c)
|
||||
{
|
||||
if (PedsByID.ContainsKey(c.ID))
|
||||
{
|
||||
PedsByID[c.ID] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
PedsByID.Add(c.ID, c);
|
||||
}
|
||||
if (c.MainPed == null) { return; }
|
||||
if (c.MainPed == null) return;
|
||||
if (PedsByHandle.ContainsKey(c.MainPed.Handle))
|
||||
{
|
||||
PedsByHandle[c.MainPed.Handle] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
PedsByHandle.Add(c.MainPed.Handle, c);
|
||||
}
|
||||
if (c.IsLocal)
|
||||
{
|
||||
API.Events.InvokePedSpawned(c);
|
||||
}
|
||||
if (c.IsLocal) API.Events.InvokePedSpawned(c);
|
||||
}
|
||||
|
||||
public static void RemovePed(int id, string reason = "Cleanup")
|
||||
{
|
||||
if (PedsByID.ContainsKey(id))
|
||||
{
|
||||
SyncedPed c = PedsByID[id];
|
||||
var c = PedsByID[id];
|
||||
var p = c.MainPed;
|
||||
if (p != null)
|
||||
{
|
||||
if (PedsByHandle.ContainsKey(p.Handle))
|
||||
{
|
||||
PedsByHandle.Remove(p.Handle);
|
||||
}
|
||||
if (PedsByHandle.ContainsKey(p.Handle)) PedsByHandle.Remove(p.Handle);
|
||||
// Main.Logger.Debug($"Removing ped {c.ID}. Reason:{reason}");
|
||||
p.AttachedBlip?.Delete();
|
||||
p.Kill();
|
||||
@ -171,123 +164,128 @@ namespace RageCoop.Client
|
||||
p.MarkAsNoLongerNeeded();
|
||||
p.Delete();
|
||||
}
|
||||
|
||||
c.PedBlip?.Delete();
|
||||
c.ParachuteProp?.Delete();
|
||||
PedsByID.Remove(id);
|
||||
if (c.IsLocal)
|
||||
{
|
||||
API.Events.InvokePedDeleted(c);
|
||||
}
|
||||
if (c.IsLocal) API.Events.InvokePedDeleted(c);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region VEHICLES
|
||||
public static SyncedVehicle GetVehicleByID(int id) => VehiclesByID.TryGetValue(id, out var v) ? v : null;
|
||||
public static SyncedVehicle GetVehicleByHandle(int handle) => VehiclesByHandle.TryGetValue(handle, out var v) ? v : null;
|
||||
public static List<int> GetVehicleIDs() => new List<int>(VehiclesByID.Keys);
|
||||
|
||||
public static SyncedVehicle GetVehicleByID(int id)
|
||||
{
|
||||
return VehiclesByID.TryGetValue(id, out var v) ? v : null;
|
||||
}
|
||||
|
||||
public static SyncedVehicle GetVehicleByHandle(int handle)
|
||||
{
|
||||
return VehiclesByHandle.TryGetValue(handle, out var v) ? v : null;
|
||||
}
|
||||
|
||||
public static List<int> GetVehicleIDs()
|
||||
{
|
||||
return new List<int>(VehiclesByID.Keys);
|
||||
}
|
||||
|
||||
public static void Add(SyncedVehicle v)
|
||||
{
|
||||
if (VehiclesByID.ContainsKey(v.ID))
|
||||
{
|
||||
VehiclesByID[v.ID] = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
VehiclesByID.Add(v.ID, v);
|
||||
}
|
||||
if (v.MainVehicle == null) { return; }
|
||||
if (v.MainVehicle == null) return;
|
||||
if (VehiclesByHandle.ContainsKey(v.MainVehicle.Handle))
|
||||
{
|
||||
VehiclesByHandle[v.MainVehicle.Handle] = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
VehiclesByHandle.Add(v.MainVehicle.Handle, v);
|
||||
}
|
||||
if (v.IsLocal)
|
||||
{
|
||||
API.Events.InvokeVehicleSpawned(v);
|
||||
}
|
||||
if (v.IsLocal) API.Events.InvokeVehicleSpawned(v);
|
||||
}
|
||||
|
||||
public static void RemoveVehicle(int id, string reason = "Cleanup")
|
||||
{
|
||||
if (VehiclesByID.ContainsKey(id))
|
||||
{
|
||||
SyncedVehicle v = VehiclesByID[id];
|
||||
var v = VehiclesByID[id];
|
||||
var veh = v.MainVehicle;
|
||||
if (veh != null)
|
||||
{
|
||||
if (VehiclesByHandle.ContainsKey(veh.Handle))
|
||||
{
|
||||
VehiclesByHandle.Remove(veh.Handle);
|
||||
}
|
||||
if (VehiclesByHandle.ContainsKey(veh.Handle)) VehiclesByHandle.Remove(veh.Handle);
|
||||
// Main.Logger.Debug($"Removing vehicle {v.ID}. Reason:{reason}");
|
||||
veh.AttachedBlip?.Delete();
|
||||
veh.Model.MarkAsNoLongerNeeded();
|
||||
veh.MarkAsNoLongerNeeded();
|
||||
veh.Delete();
|
||||
}
|
||||
|
||||
VehiclesByID.Remove(id);
|
||||
if (v.IsLocal) { API.Events.InvokeVehicleDeleted(v); }
|
||||
if (v.IsLocal) API.Events.InvokeVehicleDeleted(v);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PROJECTILES
|
||||
|
||||
public static SyncedProjectile GetProjectileByID(int id)
|
||||
{
|
||||
return ProjectilesByID.TryGetValue(id, out var p) ? p : null;
|
||||
}
|
||||
|
||||
public static void Add(SyncedProjectile p)
|
||||
{
|
||||
if (!p.IsValid) { return; }
|
||||
if (!p.IsValid) return;
|
||||
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank)
|
||||
{
|
||||
Networking.SendBullet(p.Position, p.Position + p.Velocity, (uint)VehicleWeaponHash.Tank, ((SyncedVehicle)p.Shooter).MainVehicle.Driver.GetSyncEntity().ID);
|
||||
}
|
||||
Networking.SendBullet(p.Position, p.Position + p.Velocity, (uint)VehicleWeaponHash.Tank,
|
||||
((SyncedVehicle)p.Shooter).MainVehicle.Driver.GetSyncEntity().ID);
|
||||
if (ProjectilesByID.ContainsKey(p.ID))
|
||||
{
|
||||
ProjectilesByID[p.ID] = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectilesByID.Add(p.ID, p);
|
||||
}
|
||||
if (p.MainProjectile == null) { return; }
|
||||
if (p.MainProjectile == null) return;
|
||||
if (ProjectilesByHandle.ContainsKey(p.MainProjectile.Handle))
|
||||
{
|
||||
ProjectilesByHandle[p.MainProjectile.Handle] = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectilesByHandle.Add(p.MainProjectile.Handle, p);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveProjectile(int id, string reason)
|
||||
{
|
||||
if (ProjectilesByID.ContainsKey(id))
|
||||
{
|
||||
SyncedProjectile sp = ProjectilesByID[id];
|
||||
var sp = ProjectilesByID[id];
|
||||
var p = sp.MainProjectile;
|
||||
if (p != null)
|
||||
{
|
||||
if (ProjectilesByHandle.ContainsKey(p.Handle))
|
||||
{
|
||||
ProjectilesByHandle.Remove(p.Handle);
|
||||
}
|
||||
if (ProjectilesByHandle.ContainsKey(p.Handle)) ProjectilesByHandle.Remove(p.Handle);
|
||||
Main.Logger.Debug($"Removing projectile {sp.ID}. Reason:{reason}");
|
||||
p.Explode();
|
||||
}
|
||||
|
||||
ProjectilesByID.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool PedExists(int id) => PedsByID.ContainsKey(id);
|
||||
public static bool VehicleExists(int id) => VehiclesByID.ContainsKey(id);
|
||||
public static bool ProjectileExists(int id) => ProjectilesByID.ContainsKey(id);
|
||||
public static bool PedExists(int id)
|
||||
{
|
||||
return PedsByID.ContainsKey(id);
|
||||
}
|
||||
|
||||
public static bool VehicleExists(int id)
|
||||
{
|
||||
return VehiclesByID.ContainsKey(id);
|
||||
}
|
||||
|
||||
public static bool ProjectileExists(int id)
|
||||
{
|
||||
return ProjectilesByID.ContainsKey(id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static int vehStateIndex;
|
||||
private static int pedStateIndex;
|
||||
private static int vehStatesPerFrame;
|
||||
@ -302,7 +300,7 @@ namespace RageCoop.Client
|
||||
UpdateTargets();
|
||||
#if BENCHMARK
|
||||
PerfCounter.Restart();
|
||||
Debug.TimeStamps[TimeStamp.CheckProjectiles]=PerfCounter.ElapsedTicks;
|
||||
Debug.TimeStamps[TimeStamp.CheckProjectiles] = PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
allPeds = World.GetAllPeds();
|
||||
allVehicles = World.GetAllVehicles();
|
||||
@ -310,48 +308,35 @@ namespace RageCoop.Client
|
||||
vehStatesPerFrame = allVehicles.Length * 2 / (int)Game.FPS + 1;
|
||||
pedStatesPerFrame = allPeds.Length * 2 / (int)Game.FPS + 1;
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.GetAllEntities]=PerfCounter.ElapsedTicks;
|
||||
Debug.TimeStamps[TimeStamp.GetAllEntities] = PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
|
||||
lock (ProjectilesLock)
|
||||
{
|
||||
|
||||
foreach (Projectile p in allProjectiles)
|
||||
{
|
||||
foreach (var p in allProjectiles)
|
||||
if (!ProjectilesByHandle.ContainsKey(p.Handle))
|
||||
{
|
||||
Add(new SyncedProjectile(p));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SyncedProjectile p in ProjectilesByID.Values.ToArray())
|
||||
{
|
||||
foreach (var p in ProjectilesByID.Values.ToArray())
|
||||
// Outgoing sync
|
||||
if (p.IsLocal)
|
||||
{
|
||||
if (p.MainProjectile.AttachedEntity == null)
|
||||
{
|
||||
// Prevent projectiles from exploding next to vehicle
|
||||
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank || (p.MainProjectile.OwnerEntity?.EntityType == EntityType.Vehicle && p.MainProjectile.Position.DistanceTo(p.Origin) < 2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (p.WeaponHash == (WeaponHash)VehicleWeaponHash.Tank ||
|
||||
(p.MainProjectile.OwnerEntity?.EntityType == EntityType.Vehicle &&
|
||||
p.MainProjectile.Position.DistanceTo(p.Origin) < 2)) continue;
|
||||
Networking.SendProjectile(p);
|
||||
}
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
if (p.Exploded || p.IsOutOfSync)
|
||||
{
|
||||
RemoveProjectile(p.ID, "OutOfSync | Exploded");
|
||||
}
|
||||
else
|
||||
{
|
||||
p.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = -1;
|
||||
@ -360,16 +345,18 @@ namespace RageCoop.Client
|
||||
{
|
||||
AddPlayer();
|
||||
|
||||
foreach (Ped p in allPeds)
|
||||
foreach (var p in allPeds)
|
||||
{
|
||||
SyncedPed c = GetPedByHandle(p.Handle);
|
||||
if (c == null && (p != Game.Player.Character))
|
||||
var c = GetPedByHandle(p.Handle);
|
||||
if (c == null && p != Game.Player.Character)
|
||||
{
|
||||
if (allPeds.Length > Main.Settings.WorldPedSoftLimit && p.PopulationType == EntityPopulationType.RandomAmbient && !p.IsInVehicle())
|
||||
if (allPeds.Length > Main.Settings.WorldPedSoftLimit &&
|
||||
p.PopulationType == EntityPopulationType.RandomAmbient && !p.IsInVehicle())
|
||||
{
|
||||
p.Delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Main.Logger.Trace($"Creating SyncEntity for ped, handle:{p.Handle}");
|
||||
c = new SyncedPed(p);
|
||||
|
||||
@ -377,20 +364,16 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
|
||||
Debug.TimeStamps[TimeStamp.AddPeds]=PerfCounter.ElapsedTicks;
|
||||
Debug.TimeStamps[TimeStamp.AddPeds] = PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
var ps = PedsByID.Values.ToArray();
|
||||
pedStateIndex += pedStatesPerFrame;
|
||||
if (pedStateIndex >= ps.Length)
|
||||
{
|
||||
pedStateIndex = 0;
|
||||
}
|
||||
if (pedStateIndex >= ps.Length) pedStateIndex = 0;
|
||||
|
||||
foreach (SyncedPed c in ps)
|
||||
foreach (var c in ps)
|
||||
{
|
||||
i++;
|
||||
if ((c.MainPed != null) && (!c.MainPed.Exists()))
|
||||
if (c.MainPed != null && !c.MainPed.Exists())
|
||||
{
|
||||
RemovePed(c.ID, "non-existent");
|
||||
continue;
|
||||
@ -405,10 +388,10 @@ namespace RageCoop.Client
|
||||
// event check
|
||||
SyncEvents.Check(c);
|
||||
|
||||
Networking.SendPed(c, (i - pedStateIndex) < pedStatesPerFrame);
|
||||
Networking.SendPed(c, i - pedStateIndex < pedStatesPerFrame);
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.SendPed]=PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
Debug.TimeStamps[TimeStamp.SendPed] = PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
@ -416,25 +399,22 @@ namespace RageCoop.Client
|
||||
var start = PerfCounter2.ElapsedTicks;
|
||||
#endif
|
||||
c.Update();
|
||||
if (c.IsOutOfSync)
|
||||
{
|
||||
RemovePed(c.ID, "OutOfSync");
|
||||
}
|
||||
if (c.IsOutOfSync) RemovePed(c.ID, "OutOfSync");
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.UpdatePed]=PerfCounter2.ElapsedTicks-start;
|
||||
Debug.TimeStamps[TimeStamp.UpdatePed] = PerfCounter2.ElapsedTicks-start;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.PedTotal]=PerfCounter.ElapsedTicks;
|
||||
Debug.TimeStamps[TimeStamp.PedTotal] = PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
var check = Main.Ticked % 100 == 0;
|
||||
i = -1;
|
||||
lock (VehiclesLock)
|
||||
{
|
||||
foreach (Vehicle veh in allVehicles)
|
||||
{
|
||||
foreach (var veh in allVehicles)
|
||||
if (!VehiclesByHandle.ContainsKey(veh.Handle))
|
||||
{
|
||||
if (allVehicles.Length > Main.Settings.WorldVehicleSoftLimit)
|
||||
@ -446,11 +426,9 @@ namespace RageCoop.Client
|
||||
{
|
||||
p.Delete();
|
||||
var c = GetPedByHandle(p.Handle);
|
||||
if (c != null)
|
||||
{
|
||||
RemovePed(c.ID, "ThrottleTraffic");
|
||||
}
|
||||
if (c != null) RemovePed(c.ID, "ThrottleTraffic");
|
||||
}
|
||||
|
||||
veh.Delete();
|
||||
continue;
|
||||
}
|
||||
@ -459,51 +437,43 @@ namespace RageCoop.Client
|
||||
|
||||
Add(new SyncedVehicle(veh));
|
||||
}
|
||||
}
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.AddVehicles]=PerfCounter.ElapsedTicks;
|
||||
Debug.TimeStamps[TimeStamp.AddVehicles] = PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
var vs = VehiclesByID.Values.ToArray();
|
||||
vehStateIndex += vehStatesPerFrame;
|
||||
if (vehStateIndex >= vs.Length)
|
||||
{
|
||||
vehStateIndex = 0;
|
||||
}
|
||||
if (vehStateIndex >= vs.Length) vehStateIndex = 0;
|
||||
|
||||
foreach (SyncedVehicle v in vs)
|
||||
foreach (var v in vs)
|
||||
{
|
||||
i++;
|
||||
if ((v.MainVehicle != null) && (!v.MainVehicle.Exists()))
|
||||
if (v.MainVehicle != null && !v.MainVehicle.Exists())
|
||||
{
|
||||
RemoveVehicle(v.ID, "non-existent");
|
||||
continue;
|
||||
}
|
||||
if (check)
|
||||
{
|
||||
v.SetUpFixedData();
|
||||
}
|
||||
|
||||
if (check) v.SetUpFixedData();
|
||||
// Outgoing sync
|
||||
if (v.IsLocal)
|
||||
{
|
||||
if (!v.MainVehicle.IsVisible) { continue; }
|
||||
if (!v.MainVehicle.IsVisible) continue;
|
||||
SyncEvents.Check(v);
|
||||
|
||||
Networking.SendVehicle(v, (i - vehStateIndex) < vehStatesPerFrame);
|
||||
Networking.SendVehicle(v, i - vehStateIndex < vehStatesPerFrame);
|
||||
}
|
||||
else // Incoming sync
|
||||
{
|
||||
v.Update();
|
||||
if (v.IsOutOfSync)
|
||||
{
|
||||
RemoveVehicle(v.ID, "OutOfSync");
|
||||
}
|
||||
if (v.IsOutOfSync) RemoveVehicle(v.ID, "OutOfSync");
|
||||
}
|
||||
}
|
||||
|
||||
#if BENCHMARK
|
||||
Debug.TimeStamps[TimeStamp.VehicleTotal]=PerfCounter.ElapsedTicks;
|
||||
Debug.TimeStamps[TimeStamp.VehicleTotal] = PerfCounter.ElapsedTicks;
|
||||
#endif
|
||||
}
|
||||
|
||||
Networking.Peer.FlushSendQueue();
|
||||
}
|
||||
|
||||
@ -511,52 +481,44 @@ namespace RageCoop.Client
|
||||
{
|
||||
Networking.Targets = new List<NetConnection>(PlayerList.Players.Count) { Networking.ServerConnection };
|
||||
foreach (var p in PlayerList.Players.Values.ToArray())
|
||||
{
|
||||
if (p.HasDirectConnection && p.Position.DistanceTo(Main.PlayerPosition) < 500)
|
||||
{
|
||||
Networking.Targets.Add(p.Connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveAllFromPlayer(int playerPedId)
|
||||
{
|
||||
foreach (SyncedPed p in PedsByID.Values.ToArray())
|
||||
{
|
||||
foreach (var p in PedsByID.Values.ToArray())
|
||||
if (p.OwnerID == playerPedId)
|
||||
{
|
||||
RemovePed(p.ID);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SyncedVehicle v in VehiclesByID.Values.ToArray())
|
||||
{
|
||||
foreach (var v in VehiclesByID.Values.ToArray())
|
||||
if (v.OwnerID == playerPedId)
|
||||
{
|
||||
RemoveVehicle(v.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int RequestNewID()
|
||||
{
|
||||
int ID = 0;
|
||||
while ((ID == 0) || PedsByID.ContainsKey(ID) || VehiclesByID.ContainsKey(ID) || ProjectilesByID.ContainsKey(ID))
|
||||
var ID = 0;
|
||||
while (ID == 0 || PedsByID.ContainsKey(ID) || VehiclesByID.ContainsKey(ID) ||
|
||||
ProjectilesByID.ContainsKey(ID))
|
||||
{
|
||||
byte[] rngBytes = new byte[4];
|
||||
var rngBytes = new byte[4];
|
||||
|
||||
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
||||
|
||||
// Convert the bytes into an integer
|
||||
ID = BitConverter.ToInt32(rngBytes, 0);
|
||||
}
|
||||
|
||||
return ID;
|
||||
}
|
||||
|
||||
private static void SetBudget(int b)
|
||||
{
|
||||
Function.Call(Hash.SET_PED_POPULATION_BUDGET, b); // 0 - 3
|
||||
Function.Call(Hash.SET_VEHICLE_POPULATION_BUDGET, b); // 0 - 3
|
||||
}
|
||||
|
||||
public static string DumpDebug()
|
||||
{
|
||||
return $"\nID_Peds: {PedsByID.Count}" +
|
||||
@ -568,6 +530,7 @@ namespace RageCoop.Client
|
||||
$"\npedStatesPerFrame: {pedStatesPerFrame}" +
|
||||
$"\nvehStatesPerFrame: {vehStatesPerFrame}";
|
||||
}
|
||||
|
||||
public static class ThreadSafe
|
||||
{
|
||||
public static void Add(SyncedVehicle v)
|
||||
@ -577,6 +540,7 @@ namespace RageCoop.Client
|
||||
EntityPool.Add(v);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(SyncedPed p)
|
||||
{
|
||||
lock (PedsLock)
|
||||
@ -584,6 +548,7 @@ namespace RageCoop.Client
|
||||
EntityPool.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(SyncedProjectile sp)
|
||||
{
|
||||
lock (ProjectilesLock)
|
||||
@ -593,4 +558,4 @@ namespace RageCoop.Client
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +1,28 @@
|
||||
using GTA;
|
||||
using System;
|
||||
using GTA;
|
||||
using GTA.Math;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Client.Scripting;
|
||||
using RageCoop.Core;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class SyncEvents
|
||||
{
|
||||
|
||||
#region TRIGGER
|
||||
|
||||
public static void TriggerPedKilled(SyncedPed victim)
|
||||
{
|
||||
Networking.SendSync(new Packets.PedKilled() { VictimID = victim.ID }, ConnectionChannel.SyncEvents);
|
||||
Networking.SendSync(new Packets.PedKilled { VictimID = victim.ID }, ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
public static void TriggerChangeOwner(int vehicleID, int newOwnerID)
|
||||
{
|
||||
|
||||
Networking.SendSync(new Packets.OwnerChanged()
|
||||
Networking.SendSync(new Packets.OwnerChanged
|
||||
{
|
||||
ID = vehicleID,
|
||||
NewOwnerID = newOwnerID,
|
||||
NewOwnerID = newOwnerID
|
||||
}, ConnectionChannel.SyncEvents, NetDeliveryMethod.ReliableOrdered);
|
||||
|
||||
}
|
||||
|
||||
public static void TriggerBulletShot(uint hash, SyncedPed owner, Vector3 impactPosition)
|
||||
@ -33,10 +31,8 @@ namespace RageCoop.Client
|
||||
|
||||
var start = owner.MainPed.GetMuzzlePosition();
|
||||
if (start.DistanceTo(impactPosition) > 10)
|
||||
{
|
||||
// Reduce latency
|
||||
start = impactPosition - (impactPosition - start).Normalized * 10;
|
||||
}
|
||||
Networking.SendBullet(start, impactPosition, hash, owner.ID);
|
||||
}
|
||||
|
||||
@ -44,17 +40,15 @@ namespace RageCoop.Client
|
||||
{
|
||||
int i;
|
||||
if ((i = veh.GetMuzzleIndex(owner.MainPed.VehicleWeapon)) != -1)
|
||||
{
|
||||
Networking.SendVehicleBullet(hash, owner, veh.Bones[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Main.Logger.Warning($"Failed to get muzzle info for vehicle:{veh.DisplayName}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void TriggerNozzleTransform(int vehID, bool hover)
|
||||
{
|
||||
Networking.SendSync(new Packets.NozzleTransform() { VehicleID = vehID, Hover = hover }, ConnectionChannel.SyncEvents);
|
||||
Networking.SendSync(new Packets.NozzleTransform { VehicleID = vehID, Hover = hover },
|
||||
ConnectionChannel.SyncEvents);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -67,79 +61,92 @@ namespace RageCoop.Client
|
||||
{
|
||||
EntityPool.GetPedByID(p.VictimID)?.MainPed?.Kill();
|
||||
}
|
||||
|
||||
private static void HandleOwnerChanged(Packets.OwnerChanged p)
|
||||
{
|
||||
var v = EntityPool.GetVehicleByID(p.ID);
|
||||
if (v == null) { return; }
|
||||
if (v == null) return;
|
||||
v.OwnerID = p.NewOwnerID;
|
||||
v.LastSynced = Main.Ticked;
|
||||
v.Position = v.MainVehicle.Position;
|
||||
v.Quaternion = v.MainVehicle.Quaternion;
|
||||
}
|
||||
|
||||
private static void HandleNozzleTransform(Packets.NozzleTransform p)
|
||||
{
|
||||
EntityPool.GetVehicleByID(p.VehicleID)?.MainVehicle?.SetNozzleAngel(p.Hover ? 1 : 0);
|
||||
}
|
||||
|
||||
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
|
||||
{
|
||||
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
|
||||
if (p == null) { p = Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
|
||||
if (p == null)
|
||||
{
|
||||
p = Game.Player.Character;
|
||||
Main.Logger.Warning("Failed to find owner for bullet");
|
||||
}
|
||||
|
||||
var damage = (int)p.GetWeaponDamage(weaponHash);
|
||||
weaponHash = WeaponUtil.GetWeaponFix(weaponHash);
|
||||
|
||||
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
|
||||
if (!CorePFXAsset.IsLoaded) CorePFXAsset.Request();
|
||||
var asset = new WeaponAsset(weaponHash);
|
||||
if (!asset.IsLoaded) { asset.Request(); }
|
||||
if (!asset.IsLoaded) asset.Request();
|
||||
World.ShootBullet(start, end, p, asset, damage);
|
||||
Prop w;
|
||||
var turret = false;
|
||||
if ((((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid)) || (turret = p.IsOnTurretSeat()))
|
||||
{
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset, p.Weapons.Current.Components.GetSuppressorComponent().Active ? "muz_pistol_silencer" : WeaponUtil.GetFlashFX((WeaponHash)weaponHash, turret), p.GetMuzzlePosition(), turret ? p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).GetRotation() : w.Rotation, 1);
|
||||
}
|
||||
if (((w = p.Weapons.CurrentWeaponObject) != null && p.VehicleWeapon == VehicleWeaponHash.Invalid) ||
|
||||
(turret = p.IsOnTurretSeat()))
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset,
|
||||
p.Weapons.Current.Components.GetSuppressorComponent().Active
|
||||
? "muz_pistol_silencer"
|
||||
: ((WeaponHash)weaponHash).GetFlashFX(turret), p.GetMuzzlePosition(),
|
||||
turret ? p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).GetRotation() : w.Rotation);
|
||||
}
|
||||
|
||||
public static void HandleVehicleBulletShot(Packets.VehicleBulletShot p)
|
||||
{
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
var v = EntityPool.GetPedByID(p.OwnerID)?.MainPed.CurrentVehicle;
|
||||
if (v == null) { return; }
|
||||
if (v == null) return;
|
||||
var b = v.Bones[p.Bone];
|
||||
World.CreateParticleEffectNonLooped(CorePFXAsset,
|
||||
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash, true),
|
||||
b.Position, b.GetRotation(), 1);
|
||||
((WeaponHash)p.WeaponHash).GetFlashFX(true),
|
||||
b.Position, b.GetRotation());
|
||||
}
|
||||
|
||||
public static void HandleEvent(PacketType type, NetIncomingMessage msg)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PacketType.BulletShot:
|
||||
{
|
||||
var p = msg.GetPacket<Packets.BulletShot>();
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
{
|
||||
var p = msg.GetPacket<Packets.BulletShot>();
|
||||
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
|
||||
break;
|
||||
}
|
||||
case PacketType.VehicleBulletShot:
|
||||
{
|
||||
HandleVehicleBulletShot(msg.GetPacket<Packets.VehicleBulletShot>());
|
||||
break;
|
||||
}
|
||||
{
|
||||
HandleVehicleBulletShot(msg.GetPacket<Packets.VehicleBulletShot>());
|
||||
break;
|
||||
}
|
||||
case PacketType.OwnerChanged:
|
||||
{
|
||||
HandleOwnerChanged(msg.GetPacket<Packets.OwnerChanged>());
|
||||
}
|
||||
{
|
||||
HandleOwnerChanged(msg.GetPacket<Packets.OwnerChanged>());
|
||||
}
|
||||
break;
|
||||
case PacketType.PedKilled:
|
||||
{
|
||||
HandlePedKilled(msg.GetPacket<Packets.PedKilled>());
|
||||
}
|
||||
{
|
||||
HandlePedKilled(msg.GetPacket<Packets.PedKilled>());
|
||||
}
|
||||
break;
|
||||
case PacketType.NozzleTransform:
|
||||
{
|
||||
HandleNozzleTransform(msg.GetPacket<Packets.NozzleTransform>());
|
||||
break;
|
||||
}
|
||||
{
|
||||
HandleNozzleTransform(msg.GetPacket<Packets.NozzleTransform>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Networking.Peer.Recycle(msg);
|
||||
}
|
||||
|
||||
@ -147,53 +154,45 @@ namespace RageCoop.Client
|
||||
|
||||
#region CHECK EVENTS
|
||||
|
||||
|
||||
public static void Check(SyncedPed c)
|
||||
{
|
||||
Ped subject = c.MainPed;
|
||||
var subject = c.MainPed;
|
||||
|
||||
// Check bullets
|
||||
if (subject.IsShooting)
|
||||
{
|
||||
if (!subject.IsUsingProjectileWeapon())
|
||||
{
|
||||
int i = 0;
|
||||
Func<bool> getBulletImpact = (() =>
|
||||
var i = 0;
|
||||
Func<bool> getBulletImpact = () =>
|
||||
{
|
||||
Vector3 endPos = subject.LastWeaponImpactPosition;
|
||||
var endPos = subject.LastWeaponImpactPosition;
|
||||
if (endPos == default)
|
||||
{
|
||||
if (++i <= 5) { return false; }
|
||||
if (++i <= 5) return false;
|
||||
|
||||
endPos = subject.GetAimCoord();
|
||||
if (subject.IsInVehicle() && subject.VehicleWeapon != VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if (subject.IsOnTurretSeat())
|
||||
{
|
||||
TriggerBulletShot((uint)subject.VehicleWeapon, c, endPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerBulletShot((uint)subject.Weapons.Current.Hash, c, endPos);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (subject.IsInVehicle() && subject.VehicleWeapon != VehicleWeaponHash.Invalid)
|
||||
{
|
||||
if (subject.IsOnTurretSeat())
|
||||
{
|
||||
TriggerBulletShot((uint)subject.VehicleWeapon, c, endPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerVehBulletShot((uint)subject.VehicleWeapon, subject.CurrentVehicle, c);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,12 +200,9 @@ namespace RageCoop.Client
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
if (!getBulletImpact())
|
||||
{
|
||||
Scripting.API.QueueAction(getBulletImpact);
|
||||
}
|
||||
if (!getBulletImpact()) API.QueueAction(getBulletImpact);
|
||||
}
|
||||
else if (subject.VehicleWeapon == VehicleWeaponHash.Tank && subject.LastWeaponImpactPosition != default)
|
||||
{
|
||||
@ -217,21 +213,14 @@ namespace RageCoop.Client
|
||||
|
||||
public static void Check(SyncedVehicle v)
|
||||
{
|
||||
if (v.MainVehicle == null || !v.MainVehicle.HasNozzle())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (v.MainVehicle == null || !v.MainVehicle.HasNozzle()) return;
|
||||
|
||||
if ((v.LastNozzleAngle == 1) && (v.MainVehicle.GetNozzleAngel() != 1))
|
||||
{
|
||||
if (v.LastNozzleAngle == 1 && v.MainVehicle.GetNozzleAngel() != 1)
|
||||
TriggerNozzleTransform(v.ID, false);
|
||||
}
|
||||
else if ((v.LastNozzleAngle == 0) && (v.MainVehicle.GetNozzleAngel() != 0))
|
||||
{
|
||||
TriggerNozzleTransform(v.ID, true);
|
||||
}
|
||||
else if (v.LastNozzleAngle == 0 && v.MainVehicle.GetNozzleAngel() != 0) TriggerNozzleTransform(v.ID, true);
|
||||
v.LastNozzleAngle = v.MainVehicle.GetNozzleAngel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,27 @@
|
||||
using NAudio.Wave;
|
||||
using System.Threading;
|
||||
using System.Threading;
|
||||
using NAudio.Wave;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
internal static class Voice
|
||||
{
|
||||
private static WaveInEvent _waveIn;
|
||||
private static readonly BufferedWaveProvider _waveProvider = new BufferedWaveProvider(new WaveFormat(16000, 16, 1));
|
||||
|
||||
private static readonly BufferedWaveProvider _waveProvider =
|
||||
new BufferedWaveProvider(new WaveFormat(16000, 16, 1));
|
||||
|
||||
private static Thread _thread;
|
||||
|
||||
public static bool WasInitialized() => _thread != null;
|
||||
public static bool IsRecording() => _waveIn != null;
|
||||
public static bool WasInitialized()
|
||||
{
|
||||
return _thread != null;
|
||||
}
|
||||
|
||||
public static bool IsRecording()
|
||||
{
|
||||
return _waveIn != null;
|
||||
}
|
||||
|
||||
public static void ClearAll()
|
||||
{
|
||||
_waveProvider.ClearBuffer();
|
||||
@ -41,22 +51,17 @@ namespace RageCoop.Client
|
||||
return;
|
||||
|
||||
// I tried without thread but the game will lag without
|
||||
_thread = new Thread(new ThreadStart(() =>
|
||||
_thread = new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
using (var wo = new WaveOutEvent())
|
||||
{
|
||||
wo.Init(_waveProvider);
|
||||
wo.Play();
|
||||
|
||||
while (wo.PlaybackState == PlaybackState.Playing)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
while (wo.PlaybackState == PlaybackState.Playing) Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
@ -90,4 +95,4 @@ namespace RageCoop.Client
|
||||
Networking.SendVoiceMessage(e.Buffer, e.BytesRecorded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user