This commit is contained in:
sardelka9515
2022-10-23 19:02:39 +08:00
parent 6b34ab6e36
commit 2828b9b74f
114 changed files with 7374 additions and 7205 deletions

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
*/
}
}
}
}

View File

@ -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
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}
}

View File

@ -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
}
}
}
}
}

View File

@ -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
}
}
}

View File

@ -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);
}
}
}
}