NPC and Player split
This commit is contained in:
@ -2,6 +2,8 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
using CoopClient.Entities.Player;
|
||||||
|
|
||||||
namespace CoopClient
|
namespace CoopClient
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -134,7 +136,7 @@ namespace CoopClient
|
|||||||
Dictionary<long, int?> result = new Dictionary<long, int?>();
|
Dictionary<long, int?> result = new Dictionary<long, int?>();
|
||||||
lock (Main.Players)
|
lock (Main.Players)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<long, Entities.EntitiesPlayer> player in Main.Players.Where(x => x.Key != Main.LocalNetHandle))
|
foreach (KeyValuePair<long, EntitiesPlayer> player in Main.Players.Where(x => x.Key != Main.LocalNetHandle))
|
||||||
{
|
{
|
||||||
result.Add(player.Key, player.Value.Character?.Handle);
|
result.Add(player.Key, player.Value.Character?.Handle);
|
||||||
}
|
}
|
||||||
@ -146,7 +148,7 @@ namespace CoopClient
|
|||||||
/// Get a player using their Lidgren Network net handle
|
/// Get a player using their Lidgren Network net handle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="handle">Lidgren-Network net handle</param>
|
/// <param name="handle">Lidgren-Network net handle</param>
|
||||||
public static Entities.EntitiesPlayer GetPlayer(long handle)
|
public static EntitiesPlayer GetPlayer(long handle)
|
||||||
{
|
{
|
||||||
lock (Main.Players)
|
lock (Main.Players)
|
||||||
{
|
{
|
||||||
|
@ -74,11 +74,13 @@
|
|||||||
<Compile Include="BitReader.cs" />
|
<Compile Include="BitReader.cs" />
|
||||||
<Compile Include="Chat.cs" />
|
<Compile Include="Chat.cs" />
|
||||||
<Compile Include="COOPAPI.cs" />
|
<Compile Include="COOPAPI.cs" />
|
||||||
<Compile Include="Entities\EntitiesPed.cs" />
|
<Compile Include="Entities\NPC\EntitiesNPC.cs" />
|
||||||
<Compile Include="Entities\EntitiesPlayer.cs" />
|
<Compile Include="Entities\NPC\Sync\OnFootSync.cs" />
|
||||||
|
<Compile Include="Entities\NPC\Sync\VehicleSync.cs" />
|
||||||
|
<Compile Include="Entities\Player\EntitiesPlayer.cs" />
|
||||||
<Compile Include="Entities\EntitiesThread.cs" />
|
<Compile Include="Entities\EntitiesThread.cs" />
|
||||||
<Compile Include="Entities\Sync\OnFootSync.cs" />
|
<Compile Include="Entities\Player\Sync\OnFootSync.cs" />
|
||||||
<Compile Include="Entities\Sync\VehicleSync.cs" />
|
<Compile Include="Entities\Player\Sync\VehicleSync.cs" />
|
||||||
<Compile Include="Main.cs" />
|
<Compile Include="Main.cs" />
|
||||||
<Compile Include="Menus\MenusMain.cs" />
|
<Compile Include="Menus\MenusMain.cs" />
|
||||||
<Compile Include="Menus\Sub\Servers.cs" />
|
<Compile Include="Menus\Sub\Servers.cs" />
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
namespace CoopClient.Entities
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ?
|
|
||||||
/// </summary>
|
|
||||||
public class EntitiesPlayer : EntitiesPed
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ?
|
|
||||||
/// </summary>
|
|
||||||
public string Username { get; set; } = "Player";
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,13 +32,13 @@ namespace CoopClient.Entities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<long, EntitiesPed> localNPCs = null;
|
Dictionary<long, NPC.EntitiesNPC> localNPCs = null;
|
||||||
lock (Main.NPCs)
|
lock (Main.NPCs)
|
||||||
{
|
{
|
||||||
localNPCs = new Dictionary<long, EntitiesPed>(Main.NPCs);
|
localNPCs = new Dictionary<long, NPC.EntitiesNPC>(Main.NPCs);
|
||||||
|
|
||||||
ulong tickCount = Util.GetTickCount64();
|
ulong tickCount = Util.GetTickCount64();
|
||||||
foreach (KeyValuePair<long, EntitiesPed> npc in new Dictionary<long, EntitiesPed>(localNPCs))
|
foreach (KeyValuePair<long, NPC.EntitiesNPC> npc in new Dictionary<long, NPC.EntitiesNPC>(localNPCs))
|
||||||
{
|
{
|
||||||
if ((tickCount - npc.Value.LastUpdateReceived) > 2500)
|
if ((tickCount - npc.Value.LastUpdateReceived) > 2500)
|
||||||
{
|
{
|
||||||
@ -51,13 +51,13 @@ namespace CoopClient.Entities
|
|||||||
|
|
||||||
if (npc.Value.MainVehicle != null && npc.Value.MainVehicle.Exists() && npc.Value.MainVehicle.IsSeatFree(VehicleSeat.Driver) && npc.Value.MainVehicle.PassengerCount == 0)
|
if (npc.Value.MainVehicle != null && npc.Value.MainVehicle.Exists() && npc.Value.MainVehicle.IsSeatFree(VehicleSeat.Driver) && npc.Value.MainVehicle.PassengerCount == 0)
|
||||||
{
|
{
|
||||||
if (npc.Value.NPCVehHandle != 0)
|
if (npc.Value.PlayerVehicleHandle != 0)
|
||||||
{
|
{
|
||||||
lock (Main.NPCsVehicles)
|
lock (Main.NPCsVehicles)
|
||||||
{
|
{
|
||||||
if (Main.NPCsVehicles.ContainsKey(npc.Value.NPCVehHandle))
|
if (Main.NPCsVehicles.ContainsKey(npc.Value.PlayerVehicleHandle))
|
||||||
{
|
{
|
||||||
Main.NPCsVehicles.Remove(npc.Value.NPCVehHandle);
|
Main.NPCsVehicles.Remove(npc.Value.PlayerVehicleHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,9 +75,9 @@ namespace CoopClient.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (EntitiesPed npc in localNPCs.Values)
|
foreach (NPC.EntitiesNPC npc in localNPCs.Values)
|
||||||
{
|
{
|
||||||
npc.DisplayLocally(null);
|
npc.DisplayLocally();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only if that player wants to share his NPCs with others
|
// Only if that player wants to share his NPCs with others
|
||||||
|
156
Client/Entities/NPC/EntitiesNPC.cs
Normal file
156
Client/Entities/NPC/EntitiesNPC.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using GTA;
|
||||||
|
using GTA.Native;
|
||||||
|
using GTA.Math;
|
||||||
|
|
||||||
|
namespace CoopClient.Entities.NPC
|
||||||
|
{
|
||||||
|
internal partial class EntitiesNPC
|
||||||
|
{
|
||||||
|
internal bool LastSyncWasFull { get; set; } = false;
|
||||||
|
public ulong LastUpdateReceived { get; set; }
|
||||||
|
|
||||||
|
internal Ped Character { get; set; }
|
||||||
|
internal int Health { get; set; }
|
||||||
|
private int LastModelHash = 0;
|
||||||
|
private int CurrentModelHash = 0;
|
||||||
|
|
||||||
|
internal int ModelHash
|
||||||
|
{
|
||||||
|
get => CurrentModelHash;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LastModelHash = LastModelHash == 0 ? value : CurrentModelHash;
|
||||||
|
CurrentModelHash = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Dictionary<byte, short> LastClothes = null;
|
||||||
|
internal Dictionary<byte, short> Clothes { get; set; }
|
||||||
|
|
||||||
|
internal Vector3 Position { get; set; }
|
||||||
|
internal Vector3 AimCoords { get; set; }
|
||||||
|
|
||||||
|
internal void DisplayLocally()
|
||||||
|
{
|
||||||
|
#region NOT_IN_RANGE
|
||||||
|
if (!Game.Player.Character.IsInRange(Position, 500f))
|
||||||
|
{
|
||||||
|
if (Character != null && Character.Exists())
|
||||||
|
{
|
||||||
|
Character.Kill();
|
||||||
|
Character.MarkAsNoLongerNeeded();
|
||||||
|
Character.Delete();
|
||||||
|
Character = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IS_IN_RANGE
|
||||||
|
bool characterExist = Character != null && Character.Exists();
|
||||||
|
|
||||||
|
if (!characterExist)
|
||||||
|
{
|
||||||
|
if (!CreateCharacter())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (LastSyncWasFull)
|
||||||
|
{
|
||||||
|
if (CurrentModelHash != LastModelHash)
|
||||||
|
{
|
||||||
|
Character.Kill();
|
||||||
|
Character.Delete();
|
||||||
|
|
||||||
|
if (!CreateCharacter())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!Clothes.Compare(LastClothes))
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<byte, short> cloth in Clothes)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, Character.Handle, cloth.Key, cloth.Value, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
LastClothes = Clothes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.IsDead)
|
||||||
|
{
|
||||||
|
if (Health <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Character.IsInvincible = true;
|
||||||
|
Character.Resurrect();
|
||||||
|
}
|
||||||
|
else if (Character.Health != Health)
|
||||||
|
{
|
||||||
|
Character.Health = Health;
|
||||||
|
|
||||||
|
if (Health <= 0 && !Character.IsDead)
|
||||||
|
{
|
||||||
|
Character.IsInvincible = false;
|
||||||
|
Character.Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsInVehicle)
|
||||||
|
{
|
||||||
|
DisplayInVehicle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisplayOnFoot();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CreateCharacter()
|
||||||
|
{
|
||||||
|
Model characterModel = CurrentModelHash.ModelRequest();
|
||||||
|
|
||||||
|
if (characterModel == null)
|
||||||
|
{
|
||||||
|
//GTA.UI.Notification.Show($"~r~(Character)Model ({CurrentModelHash}) cannot be loaded!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Character = World.CreatePed(characterModel, Position, Rotation.Z);
|
||||||
|
characterModel.MarkAsNoLongerNeeded();
|
||||||
|
|
||||||
|
// ?
|
||||||
|
Character.RelationshipGroup = Main.RelationshipGroup;
|
||||||
|
|
||||||
|
if (IsInVehicle)
|
||||||
|
{
|
||||||
|
Character.IsVisible = false;
|
||||||
|
}
|
||||||
|
Character.BlockPermanentEvents = true;
|
||||||
|
Character.CanRagdoll = false;
|
||||||
|
Character.IsInvincible = true;
|
||||||
|
Character.Health = Health;
|
||||||
|
|
||||||
|
Character.CanBeTargetted = true;
|
||||||
|
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, Character.Handle, Game.Player, true);
|
||||||
|
|
||||||
|
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, Character.Handle, false);
|
||||||
|
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, Character.Handle, false);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<byte, short> cloth in Clothes)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, Character.Handle, cloth.Key, cloth.Value, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,9 @@ using GTA;
|
|||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
|
|
||||||
namespace CoopClient.Entities
|
namespace CoopClient.Entities.NPC
|
||||||
{
|
{
|
||||||
public partial class EntitiesPed
|
internal partial class EntitiesNPC
|
||||||
{
|
{
|
||||||
#region -- ON FOOT --
|
#region -- ON FOOT --
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -91,7 +91,7 @@ namespace CoopClient.Entities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsReloading)
|
if (IsReloading && Character.IsInRange(Position, 0.5f))
|
||||||
{
|
{
|
||||||
if (!Character.IsReloading)
|
if (!Character.IsReloading)
|
||||||
{
|
{
|
||||||
@ -203,7 +203,11 @@ namespace CoopClient.Entities
|
|||||||
LastMoving = true;
|
LastMoving = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (LastMoving)
|
if (range > 0.25f)
|
||||||
|
{
|
||||||
|
goto case 1;
|
||||||
|
}
|
||||||
|
else if (LastMoving)
|
||||||
{
|
{
|
||||||
Character.Task.StandStill(2000);
|
Character.Task.StandStill(2000);
|
||||||
LastMoving = false;
|
LastMoving = false;
|
315
Client/Entities/NPC/Sync/VehicleSync.cs
Normal file
315
Client/Entities/NPC/Sync/VehicleSync.cs
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using GTA;
|
||||||
|
using GTA.Native;
|
||||||
|
using GTA.Math;
|
||||||
|
|
||||||
|
namespace CoopClient.Entities.NPC
|
||||||
|
{
|
||||||
|
internal partial class EntitiesNPC
|
||||||
|
{
|
||||||
|
#region -- VARIABLES --
|
||||||
|
internal long PlayerVehicleHandle = 0;
|
||||||
|
private ulong VehicleStopTime { get; set; }
|
||||||
|
|
||||||
|
internal bool IsInVehicle { get; set; }
|
||||||
|
internal int VehicleModelHash { get; set; }
|
||||||
|
private byte[] LastVehicleColors = new byte[] { 0, 0 };
|
||||||
|
internal byte[] VehicleColors { get; set; }
|
||||||
|
private Dictionary<int, int> LastVehicleMods = new Dictionary<int, int>();
|
||||||
|
internal Dictionary<int, int> VehicleMods { get; set; }
|
||||||
|
internal bool VehicleDead { get; set; }
|
||||||
|
internal float VehicleEngineHealth { get; set; }
|
||||||
|
internal short VehicleSeatIndex { get; set; }
|
||||||
|
internal Vehicle MainVehicle { get; set; }
|
||||||
|
internal Quaternion VehicleRotation { get; set; }
|
||||||
|
internal Vector3 VehicleVelocity { get; set; }
|
||||||
|
private float LastVehicleSpeed { get; set; }
|
||||||
|
private float CurrentVehicleSpeed { get; set; }
|
||||||
|
internal float VehicleSpeed
|
||||||
|
{
|
||||||
|
get => CurrentVehicleSpeed;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LastVehicleSpeed = CurrentVehicleSpeed;
|
||||||
|
CurrentVehicleSpeed = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal float VehicleSteeringAngle { get; set; }
|
||||||
|
private int LastVehicleAim;
|
||||||
|
internal bool VehIsEngineRunning { get; set; }
|
||||||
|
internal float VehRPM { get; set; }
|
||||||
|
private bool LastTransformed = false;
|
||||||
|
internal bool Transformed { get; set; }
|
||||||
|
private bool LastHornActive = false;
|
||||||
|
internal bool IsHornActive { get; set; }
|
||||||
|
internal bool VehAreLightsOn { get; set; }
|
||||||
|
internal bool VehAreHighBeamsOn { get; set; }
|
||||||
|
internal byte VehLandingGear { get; set; }
|
||||||
|
internal bool VehRoofOpened { get; set; }
|
||||||
|
internal bool VehIsSireneActive { get; set; }
|
||||||
|
internal VehicleDamageModel VehDamageModel { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void DisplayInVehicle()
|
||||||
|
{
|
||||||
|
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model.Hash != VehicleModelHash)
|
||||||
|
{
|
||||||
|
bool vehFound = false;
|
||||||
|
|
||||||
|
lock (Main.NPCsVehicles)
|
||||||
|
{
|
||||||
|
if (Main.NPCsVehicles.ContainsKey(PlayerVehicleHandle))
|
||||||
|
{
|
||||||
|
Vehicle targetVehicle = World.GetAllVehicles().FirstOrDefault(x => x.Handle == Main.NPCsVehicles[PlayerVehicleHandle]);
|
||||||
|
if (targetVehicle == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle = targetVehicle;
|
||||||
|
vehFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vehFound)
|
||||||
|
{
|
||||||
|
Model vehicleModel = VehicleModelHash.ModelRequest();
|
||||||
|
if (vehicleModel == null)
|
||||||
|
{
|
||||||
|
//GTA.UI.Notification.Show($"~r~(Vehicle)Model ({CurrentVehicleModelHash}) cannot be loaded!");
|
||||||
|
Character.IsVisible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle = World.CreateVehicle(vehicleModel, Position);
|
||||||
|
lock (Main.NPCsVehicles)
|
||||||
|
{
|
||||||
|
Main.NPCsVehicles.Add(PlayerVehicleHandle, MainVehicle.Handle);
|
||||||
|
}
|
||||||
|
vehicleModel.MarkAsNoLongerNeeded();
|
||||||
|
MainVehicle.Quaternion = VehicleRotation;
|
||||||
|
|
||||||
|
if (MainVehicle.HasRoof)
|
||||||
|
{
|
||||||
|
bool roofOpened = MainVehicle.RoofState == VehicleRoofState.Opened || MainVehicle.RoofState == VehicleRoofState.Opening;
|
||||||
|
if (roofOpened != VehRoofOpened)
|
||||||
|
{
|
||||||
|
MainVehicle.RoofState = VehRoofOpened ? VehicleRoofState.Opened : VehicleRoofState.Closed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Character.IsInVehicle() || (int)Character.SeatIndex != VehicleSeatIndex || Character.CurrentVehicle.Handle != MainVehicle.Handle)
|
||||||
|
{
|
||||||
|
if (VehicleSeatIndex == -1 &&
|
||||||
|
Game.Player.Character.IsInVehicle() &&
|
||||||
|
(int)Game.Player.Character.SeatIndex == -1 &&
|
||||||
|
Game.Player.Character.CurrentVehicle.Handle == MainVehicle.Handle)
|
||||||
|
{
|
||||||
|
Game.Player.Character.Task.WarpOutOfVehicle(MainVehicle);
|
||||||
|
GTA.UI.Notification.Show("~r~Car jacked!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Character.SetIntoVehicle(MainVehicle, (VehicleSeat)VehicleSeatIndex);
|
||||||
|
Character.IsVisible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region -- VEHICLE SYNC --
|
||||||
|
if (MainVehicle.GetResponsiblePedHandle() != Character.Handle)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehicleColors != null && VehicleColors != LastVehicleColors)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.SET_VEHICLE_COLOURS, MainVehicle, VehicleColors[0], VehicleColors[1]);
|
||||||
|
|
||||||
|
LastVehicleColors = VehicleColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.IsOnBike && MainVehicle.ClassType == VehicleClass.Cycles)
|
||||||
|
{
|
||||||
|
bool isFastPedaling = Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, PedalingAnimDict(), "fast_pedal_char", 3);
|
||||||
|
if (CurrentVehicleSpeed < 0.2f)
|
||||||
|
{
|
||||||
|
StopPedalingAnim(isFastPedaling);
|
||||||
|
}
|
||||||
|
else if (CurrentVehicleSpeed < 11f && !Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Character.Handle, PedalingAnimDict(), "cruise_pedal_char", 3))
|
||||||
|
{
|
||||||
|
StartPedalingAnim(false);
|
||||||
|
}
|
||||||
|
else if (CurrentVehicleSpeed >= 11f && !isFastPedaling)
|
||||||
|
{
|
||||||
|
StartPedalingAnim(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (VehicleMods != null && !VehicleMods.Compare(LastVehicleMods))
|
||||||
|
{
|
||||||
|
Function.Call(Hash.SET_VEHICLE_MOD_KIT, MainVehicle, 0);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<int, int> mod in VehicleMods)
|
||||||
|
{
|
||||||
|
MainVehicle.Mods[(VehicleModType)mod.Key].Index = mod.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
LastVehicleMods = VehicleMods;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle.EngineHealth = VehicleEngineHealth;
|
||||||
|
|
||||||
|
if (VehicleDead && !MainVehicle.IsDead)
|
||||||
|
{
|
||||||
|
MainVehicle.Explode();
|
||||||
|
}
|
||||||
|
else if (!VehicleDead && MainVehicle.IsDead)
|
||||||
|
{
|
||||||
|
MainVehicle.Repair();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehIsEngineRunning != MainVehicle.IsEngineRunning)
|
||||||
|
{
|
||||||
|
MainVehicle.IsEngineRunning = VehIsEngineRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainVehicle.CurrentRPM = VehRPM;
|
||||||
|
|
||||||
|
if (VehAreLightsOn != MainVehicle.AreLightsOn)
|
||||||
|
{
|
||||||
|
MainVehicle.AreLightsOn = VehAreLightsOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehAreHighBeamsOn != MainVehicle.AreHighBeamsOn)
|
||||||
|
{
|
||||||
|
MainVehicle.AreHighBeamsOn = VehAreHighBeamsOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle.IsSubmarineCar)
|
||||||
|
{
|
||||||
|
if (Transformed && !LastTransformed)
|
||||||
|
{
|
||||||
|
LastTransformed = true;
|
||||||
|
Function.Call(Hash._TRANSFORM_VEHICLE_TO_SUBMARINE, MainVehicle.Handle, false);
|
||||||
|
}
|
||||||
|
else if (!Transformed && LastTransformed)
|
||||||
|
{
|
||||||
|
LastTransformed = false;
|
||||||
|
Function.Call(Hash._TRANSFORM_SUBMARINE_TO_VEHICLE, MainVehicle.Handle, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle.IsPlane)
|
||||||
|
{
|
||||||
|
if (VehLandingGear != (byte)MainVehicle.LandingGearState)
|
||||||
|
{
|
||||||
|
MainVehicle.LandingGearState = (VehicleLandingGearState)VehLandingGear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (MainVehicle.HasSiren && VehIsSireneActive != MainVehicle.IsSirenActive)
|
||||||
|
{
|
||||||
|
MainVehicle.IsSirenActive = VehIsSireneActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsHornActive && !LastHornActive)
|
||||||
|
{
|
||||||
|
LastHornActive = true;
|
||||||
|
MainVehicle.SoundHorn(99999);
|
||||||
|
}
|
||||||
|
else if (!IsHornActive && LastHornActive)
|
||||||
|
{
|
||||||
|
LastHornActive = false;
|
||||||
|
MainVehicle.SoundHorn(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle.HasRoof)
|
||||||
|
{
|
||||||
|
bool roofOpened = MainVehicle.RoofState == VehicleRoofState.Opened || MainVehicle.RoofState == VehicleRoofState.Opening;
|
||||||
|
if (roofOpened != VehRoofOpened)
|
||||||
|
{
|
||||||
|
MainVehicle.RoofState = VehRoofOpened ? VehicleRoofState.Opening : VehicleRoofState.Closing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function.Call(Hash.SET_VEHICLE_BRAKE_LIGHTS, MainVehicle, CurrentVehicleSpeed > 0.2f && LastVehicleSpeed > CurrentVehicleSpeed);
|
||||||
|
|
||||||
|
if (LastSyncWasFull)
|
||||||
|
{
|
||||||
|
MainVehicle.SetVehicleDamageModel(VehDamageModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VehicleSteeringAngle != MainVehicle.SteeringAngle)
|
||||||
|
{
|
||||||
|
MainVehicle.CustomSteeringAngle((float)(Math.PI / 180) * VehicleSteeringAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Good enough for now, but we need to create a better sync
|
||||||
|
if (CurrentVehicleSpeed > 0.05f && MainVehicle.IsInRange(Position, 7.0f))
|
||||||
|
{
|
||||||
|
int forceMultiplier = (Game.Player.Character.IsInVehicle() && MainVehicle.IsTouching(Game.Player.Character.CurrentVehicle)) ? 1 : 3;
|
||||||
|
|
||||||
|
MainVehicle.Velocity = VehicleVelocity + forceMultiplier * (Position - MainVehicle.Position);
|
||||||
|
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.Quaternion, VehicleRotation, 0.5f);
|
||||||
|
|
||||||
|
VehicleStopTime = Util.GetTickCount64();
|
||||||
|
}
|
||||||
|
else if ((Util.GetTickCount64() - VehicleStopTime) <= 1000)
|
||||||
|
{
|
||||||
|
Vector3 posTarget = Util.LinearVectorLerp(MainVehicle.Position, Position + (Position - MainVehicle.Position), Util.GetTickCount64() - VehicleStopTime, 1000);
|
||||||
|
|
||||||
|
MainVehicle.PositionNoOffset = posTarget;
|
||||||
|
MainVehicle.Quaternion = Quaternion.Slerp(MainVehicle.Quaternion, VehicleRotation, 0.5f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MainVehicle.PositionNoOffset = Position;
|
||||||
|
MainVehicle.Quaternion = VehicleRotation;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#region -- PEDALING --
|
||||||
|
/*
|
||||||
|
* Thanks to @oldnapalm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private string PedalingAnimDict()
|
||||||
|
{
|
||||||
|
switch ((VehicleHash)VehicleModelHash)
|
||||||
|
{
|
||||||
|
case VehicleHash.Bmx:
|
||||||
|
return "veh@bicycle@bmx@front@base";
|
||||||
|
case VehicleHash.Cruiser:
|
||||||
|
return "veh@bicycle@cruiserfront@base";
|
||||||
|
case VehicleHash.Scorcher:
|
||||||
|
return "veh@bicycle@mountainfront@base";
|
||||||
|
default:
|
||||||
|
return "veh@bicycle@roadfront@base";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string PedalingAnimName(bool fast)
|
||||||
|
{
|
||||||
|
return fast ? "fast_pedal_char" : "cruise_pedal_char";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartPedalingAnim(bool fast)
|
||||||
|
{
|
||||||
|
Character.Task.PlayAnimation(PedalingAnimDict(), PedalingAnimName(fast), 8.0f, -8.0f, -1, AnimationFlags.Loop | AnimationFlags.AllowRotation, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopPedalingAnim(bool fast)
|
||||||
|
{
|
||||||
|
Character.Task.ClearAnimation(PedalingAnimDict(), PedalingAnimName(fast));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
@ -9,46 +8,24 @@ using GTA.Math;
|
|||||||
|
|
||||||
using LemonUI.Elements;
|
using LemonUI.Elements;
|
||||||
|
|
||||||
namespace CoopClient.Entities
|
namespace CoopClient.Entities.Player
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ?
|
/// ?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class EntitiesPed
|
public partial class EntitiesPlayer
|
||||||
{
|
{
|
||||||
// If this NPC is in a vehicle, we can find the handle of this vehicle in Main.NPCsVehicles[NPCVehHandle] and prevent multiple vehicles from being created
|
/// <summary>
|
||||||
internal long NPCVehHandle { get; set; } = 0;
|
/// ?
|
||||||
|
/// </summary>
|
||||||
|
public string Username { get; set; } = "Player";
|
||||||
|
|
||||||
private bool AllDataAvailable = false;
|
private bool AllDataAvailable = false;
|
||||||
internal bool LastSyncWasFull { get; set; } = false;
|
internal bool LastSyncWasFull { get; set; } = false;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// PLEASE USE LastUpdateReceived
|
|
||||||
/// </summary>
|
|
||||||
private ulong LastUpdate;
|
|
||||||
/// <summary>
|
|
||||||
/// Get the last update = TickCount64()
|
/// Get the last update = TickCount64()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong LastUpdateReceived
|
public ulong LastUpdateReceived { get; set; }
|
||||||
{
|
|
||||||
get => LastUpdate;
|
|
||||||
internal set
|
|
||||||
{
|
|
||||||
if (LastUpdate != 0)
|
|
||||||
{
|
|
||||||
LatencyAverager.Enqueue(value - LastUpdate);
|
|
||||||
if (LatencyAverager.Count >= 10)
|
|
||||||
{
|
|
||||||
LatencyAverager.Dequeue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LastUpdate = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Queue<double> LatencyAverager = new Queue<double>();
|
|
||||||
private double AverageLatency
|
|
||||||
{
|
|
||||||
get => LatencyAverager.Count == 0 ? 0 : LatencyAverager.Average();
|
|
||||||
}
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the player latency
|
/// Get the player latency
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -87,14 +64,6 @@ namespace CoopClient.Entities
|
|||||||
|
|
||||||
internal void DisplayLocally(string username)
|
internal void DisplayLocally(string username)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* username: string
|
|
||||||
* string: null
|
|
||||||
* ped: npc
|
|
||||||
* string: value
|
|
||||||
* ped: player
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Check beforehand whether ped has all the required data
|
// Check beforehand whether ped has all the required data
|
||||||
if (!AllDataAvailable)
|
if (!AllDataAvailable)
|
||||||
{
|
{
|
266
Client/Entities/Player/Sync/OnFootSync.cs
Normal file
266
Client/Entities/Player/Sync/OnFootSync.cs
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using GTA;
|
||||||
|
using GTA.Native;
|
||||||
|
using GTA.Math;
|
||||||
|
|
||||||
|
namespace CoopClient.Entities.Player
|
||||||
|
{
|
||||||
|
public partial class EntitiesPlayer
|
||||||
|
{
|
||||||
|
#region -- ON FOOT --
|
||||||
|
/// <summary>
|
||||||
|
/// The latest character rotation (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Rotation { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The latest character velocity (may not have been applied yet)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3 Velocity { get; internal set; }
|
||||||
|
internal byte Speed { get; set; }
|
||||||
|
private bool LastIsJumping = false;
|
||||||
|
internal bool IsJumping { get; set; }
|
||||||
|
internal bool IsRagdoll { get; set; }
|
||||||
|
internal bool IsOnFire { get; set; }
|
||||||
|
internal bool IsAiming { get; set; }
|
||||||
|
internal bool IsShooting { get; set; }
|
||||||
|
internal bool IsReloading { get; set; }
|
||||||
|
internal uint CurrentWeaponHash { get; set; }
|
||||||
|
private Dictionary<uint, bool> LastWeaponComponents = null;
|
||||||
|
internal Dictionary<uint, bool> WeaponComponents { get; set; } = null;
|
||||||
|
private int LastWeaponObj = 0;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void DisplayOnFoot()
|
||||||
|
{
|
||||||
|
if (Character.IsInVehicle())
|
||||||
|
{
|
||||||
|
Character.Task.LeaveVehicle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainVehicle != null)
|
||||||
|
{
|
||||||
|
MainVehicle = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsOnFire && !Character.IsOnFire)
|
||||||
|
{
|
||||||
|
Character.IsInvincible = false;
|
||||||
|
|
||||||
|
Function.Call(Hash.START_ENTITY_FIRE, Character.Handle);
|
||||||
|
}
|
||||||
|
else if (!IsOnFire && Character.IsOnFire)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.STOP_ENTITY_FIRE, Character.Handle);
|
||||||
|
|
||||||
|
Character.IsInvincible = true;
|
||||||
|
|
||||||
|
if (Character.IsDead)
|
||||||
|
{
|
||||||
|
Character.Resurrect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsJumping && !LastIsJumping)
|
||||||
|
{
|
||||||
|
Character.Task.Jump();
|
||||||
|
}
|
||||||
|
|
||||||
|
LastIsJumping = IsJumping;
|
||||||
|
|
||||||
|
if (IsRagdoll)
|
||||||
|
{
|
||||||
|
if (!Character.IsRagdoll)
|
||||||
|
{
|
||||||
|
// CanRagdoll = true, inside this function
|
||||||
|
Character.Ragdoll();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateOnFootPosition(false, false, true);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!IsRagdoll && Character.IsRagdoll)
|
||||||
|
{
|
||||||
|
Character.CanRagdoll = false;
|
||||||
|
Character.Task.ClearAllImmediately();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsJumping || IsOnFire)
|
||||||
|
{
|
||||||
|
UpdateOnFootPosition(true, true, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsReloading)
|
||||||
|
{
|
||||||
|
if (!Character.IsReloading)
|
||||||
|
{
|
||||||
|
Character.Task.ClearAll();
|
||||||
|
Character.Task.ReloadWeapon();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateOnFootPosition();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Character.Weapons.Current.Hash != (WeaponHash)CurrentWeaponHash || !WeaponComponents.Compare(LastWeaponComponents))
|
||||||
|
{
|
||||||
|
Character.Weapons.RemoveAll();
|
||||||
|
|
||||||
|
if (CurrentWeaponHash != (uint)WeaponHash.Unarmed)
|
||||||
|
{
|
||||||
|
if (WeaponComponents == null || WeaponComponents.Count == 0)
|
||||||
|
{
|
||||||
|
Character.Weapons.Give((WeaponHash)CurrentWeaponHash, -1, true, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LastWeaponObj = Function.Call<int>(Hash.CREATE_WEAPON_OBJECT, CurrentWeaponHash, -1, Position.X, Position.Y, Position.Z, true, 0, 0);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<uint, bool> comp in WeaponComponents)
|
||||||
|
{
|
||||||
|
if (comp.Value)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.GIVE_WEAPON_COMPONENT_TO_WEAPON_OBJECT, LastWeaponObj, comp.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Function.Call(Hash.GIVE_WEAPON_OBJECT_TO_PED, LastWeaponObj, Character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LastWeaponComponents = WeaponComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsShooting)
|
||||||
|
{
|
||||||
|
if (!Character.IsInRange(Position, 0.5f))
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
||||||
|
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, Speed == 3 ? 3f : 2.5f, true, 0x3F000000, 0x40800000, false, 0, false,
|
||||||
|
unchecked((int)FiringPattern.FullAuto));
|
||||||
|
UpdateOnFootPosition();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_SHOOT_AT_COORD, Character.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z, 1500, unchecked((int)FiringPattern.FullAuto));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsAiming)
|
||||||
|
{
|
||||||
|
if (!Character.IsInRange(Position, 0.5f))
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_GO_TO_COORD_WHILE_AIMING_AT_COORD, Character.Handle, Position.X, Position.Y,
|
||||||
|
Position.Z, AimCoords.X, AimCoords.Y, AimCoords.Z, Speed == 3 ? 3f : 2.5f, false, 0x3F000000, 0x40800000, false, 512, false,
|
||||||
|
unchecked((int)FiringPattern.FullAuto));
|
||||||
|
UpdateOnFootPosition();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Character.Task.AimAt(AimCoords, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WalkTo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool LastMoving;
|
||||||
|
private void WalkTo()
|
||||||
|
{
|
||||||
|
Vector3 predictPosition = Position + (Position - Character.Position) + Velocity;
|
||||||
|
float range = predictPosition.DistanceToSquared(Character.Position);
|
||||||
|
|
||||||
|
switch (Speed)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
if (!Character.IsWalking || range > 0.25f)
|
||||||
|
{
|
||||||
|
float nrange = range * 2;
|
||||||
|
if (nrange > 1.0f)
|
||||||
|
{
|
||||||
|
nrange = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Character.Task.GoStraightTo(predictPosition);
|
||||||
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, nrange);
|
||||||
|
}
|
||||||
|
LastMoving = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!Character.IsRunning || range > 0.50f)
|
||||||
|
{
|
||||||
|
Character.Task.RunTo(predictPosition, true);
|
||||||
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
||||||
|
}
|
||||||
|
LastMoving = true;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!Character.IsSprinting || range > 0.75f)
|
||||||
|
{
|
||||||
|
Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, Character.Handle, predictPosition.X, predictPosition.Y, predictPosition.Z, 3.0f, -1, 0.0f, 0.0f);
|
||||||
|
Function.Call(Hash.SET_RUN_SPRINT_MULTIPLIER_FOR_PLAYER, Character.Handle, 1.49f);
|
||||||
|
Function.Call(Hash.SET_PED_DESIRED_MOVE_BLEND_RATIO, Character.Handle, 1.0f);
|
||||||
|
}
|
||||||
|
LastMoving = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (LastMoving)
|
||||||
|
{
|
||||||
|
Character.Task.StandStill(2000);
|
||||||
|
LastMoving = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UpdateOnFootPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte LastStuckCount = 0;
|
||||||
|
private ulong LastStuckTime;
|
||||||
|
private void UpdateOnFootPosition(bool updatePosition = true, bool updateRotation = true, bool updateVelocity = true)
|
||||||
|
{
|
||||||
|
if (Character.Position.DistanceTo(Position) > 5f)
|
||||||
|
{
|
||||||
|
if (Util.GetTickCount64() - LastStuckTime < 1000)
|
||||||
|
{
|
||||||
|
LastStuckCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
++LastStuckCount;
|
||||||
|
|
||||||
|
if (LastStuckCount >= 5)
|
||||||
|
{
|
||||||
|
Character.Position = Position;
|
||||||
|
LastStuckCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LastStuckTime = Util.GetTickCount64();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatePosition)
|
||||||
|
{
|
||||||
|
float lerpValue = ((int)((Latency * 1000 / 2) + Main.MainNetworking.Latency * 1000 / 2)) * 2 / 50000f;
|
||||||
|
|
||||||
|
Vector2 biDimensionalPos = Vector2.Lerp(new Vector2(Character.Position.X, Character.Position.Y), new Vector2(Position.X + (Velocity.X / 5), Position.Y + (Velocity.Y / 5)), lerpValue);
|
||||||
|
float zPos = Util.Lerp(Character.Position.Z, Position.Z, 0.1f);
|
||||||
|
Character.PositionNoOffset = new Vector3(biDimensionalPos.X, biDimensionalPos.Y, zPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateRotation)
|
||||||
|
{
|
||||||
|
// You can find the ToQuaternion() for Rotation inside the VectorExtensions
|
||||||
|
Character.Quaternion = Quaternion.Lerp(Character.Quaternion, Rotation.ToQuaternion(), 0.10f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateVelocity)
|
||||||
|
{
|
||||||
|
Character.Velocity = Velocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
|
|
||||||
namespace CoopClient.Entities
|
namespace CoopClient.Entities.Player
|
||||||
{
|
{
|
||||||
public partial class EntitiesPed
|
public partial class EntitiesPlayer
|
||||||
{
|
{
|
||||||
#region -- VARIABLES --
|
#region -- VARIABLES --
|
||||||
private ulong VehicleStopTime { get; set; }
|
private ulong VehicleStopTime { get; set; }
|
||||||
@ -77,25 +76,6 @@ namespace CoopClient.Entities
|
|||||||
{
|
{
|
||||||
bool vehFound = false;
|
bool vehFound = false;
|
||||||
|
|
||||||
if (NPCVehHandle != 0)
|
|
||||||
{
|
|
||||||
lock (Main.NPCsVehicles)
|
|
||||||
{
|
|
||||||
if (Main.NPCsVehicles.ContainsKey(NPCVehHandle))
|
|
||||||
{
|
|
||||||
Vehicle targetVehicle = World.GetAllVehicles().First(x => x.Handle == Main.NPCsVehicles[NPCVehHandle]);
|
|
||||||
if (targetVehicle == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainVehicle = targetVehicle;
|
|
||||||
vehFound = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Vehicle targetVehicle = World.GetClosestVehicle(Position, 7f, new Model[] { CurrentVehicleModelHash });
|
Vehicle targetVehicle = World.GetClosestVehicle(Position, 7f, new Model[] { CurrentVehicleModelHash });
|
||||||
|
|
||||||
if (targetVehicle != null)
|
if (targetVehicle != null)
|
||||||
@ -106,7 +86,6 @@ namespace CoopClient.Entities
|
|||||||
vehFound = true;
|
vehFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!vehFound)
|
if (!vehFound)
|
||||||
{
|
{
|
||||||
@ -120,10 +99,6 @@ namespace CoopClient.Entities
|
|||||||
|
|
||||||
MainVehicle = World.CreateVehicle(vehicleModel, Position);
|
MainVehicle = World.CreateVehicle(vehicleModel, Position);
|
||||||
vehicleModel.MarkAsNoLongerNeeded();
|
vehicleModel.MarkAsNoLongerNeeded();
|
||||||
if (NPCVehHandle != 0)
|
|
||||||
{
|
|
||||||
Main.NPCsVehicles.Add(NPCVehHandle, MainVehicle.Handle);
|
|
||||||
}
|
|
||||||
MainVehicle.Quaternion = VehicleRotation;
|
MainVehicle.Quaternion = VehicleRotation;
|
||||||
|
|
||||||
if (MainVehicle.HasRoof)
|
if (MainVehicle.HasRoof)
|
@ -4,7 +4,8 @@ using System.Windows.Forms;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
using CoopClient.Entities;
|
using CoopClient.Entities.Player;
|
||||||
|
using CoopClient.Entities.NPC;
|
||||||
using CoopClient.Menus;
|
using CoopClient.Menus;
|
||||||
|
|
||||||
using GTA;
|
using GTA;
|
||||||
@ -38,7 +39,7 @@ namespace CoopClient
|
|||||||
|
|
||||||
internal static long LocalNetHandle = 0;
|
internal static long LocalNetHandle = 0;
|
||||||
internal static Dictionary<long, EntitiesPlayer> Players = null;
|
internal static Dictionary<long, EntitiesPlayer> Players = null;
|
||||||
internal static Dictionary<long, EntitiesPed> NPCs = null;
|
internal static Dictionary<long, EntitiesNPC> NPCs = null;
|
||||||
internal static Dictionary<long, int> NPCsVehicles = null;
|
internal static Dictionary<long, int> NPCsVehicles = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -72,7 +73,7 @@ namespace CoopClient
|
|||||||
#endif
|
#endif
|
||||||
MainChat = new Chat();
|
MainChat = new Chat();
|
||||||
Players = new Dictionary<long, EntitiesPlayer>();
|
Players = new Dictionary<long, EntitiesPlayer>();
|
||||||
NPCs = new Dictionary<long, EntitiesPed>();
|
NPCs = new Dictionary<long, EntitiesNPC>();
|
||||||
NPCsVehicles = new Dictionary<long, int>();
|
NPCsVehicles = new Dictionary<long, int>();
|
||||||
|
|
||||||
Tick += OnTick;
|
Tick += OnTick;
|
||||||
@ -240,7 +241,7 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
Players.Clear();
|
Players.Clear();
|
||||||
|
|
||||||
foreach (KeyValuePair<long, EntitiesPed> npc in NPCs)
|
foreach (KeyValuePair<long, EntitiesNPC> npc in NPCs)
|
||||||
{
|
{
|
||||||
npc.Value.Character?.CurrentVehicle?.Delete();
|
npc.Value.Character?.CurrentVehicle?.Delete();
|
||||||
npc.Value.Character?.Kill();
|
npc.Value.Character?.Kill();
|
||||||
@ -335,7 +336,7 @@ namespace CoopClient
|
|||||||
DebugSyncPed = Players[0];
|
DebugSyncPed = Players[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Util.GetTickCount64() - ArtificialLagCounter) < 350)
|
if ((Util.GetTickCount64() - ArtificialLagCounter) < 20)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using CoopClient.Entities;
|
using CoopClient.Entities.Player;
|
||||||
|
using CoopClient.Entities.NPC;
|
||||||
|
|
||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
|
|
||||||
@ -643,10 +644,10 @@ namespace CoopClient
|
|||||||
{
|
{
|
||||||
if (Main.NPCs.ContainsKey(packet.NetHandle))
|
if (Main.NPCs.ContainsKey(packet.NetHandle))
|
||||||
{
|
{
|
||||||
EntitiesPed npc = Main.NPCs[packet.NetHandle];
|
EntitiesNPC npc = Main.NPCs[packet.NetHandle];
|
||||||
|
|
||||||
// "if" this NPC has left a vehicle
|
// "if" this NPC has left a vehicle
|
||||||
npc.NPCVehHandle = 0;
|
npc.PlayerVehicleHandle = 0;
|
||||||
|
|
||||||
npc.ModelHash = packet.ModelHash;
|
npc.ModelHash = packet.ModelHash;
|
||||||
npc.Clothes = packet.Clothes;
|
npc.Clothes = packet.Clothes;
|
||||||
@ -670,7 +671,7 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Main.NPCs.Add(packet.NetHandle, new EntitiesPed()
|
Main.NPCs.Add(packet.NetHandle, new EntitiesNPC()
|
||||||
{
|
{
|
||||||
ModelHash = packet.ModelHash,
|
ModelHash = packet.ModelHash,
|
||||||
Clothes = packet.Clothes,
|
Clothes = packet.Clothes,
|
||||||
@ -702,9 +703,9 @@ namespace CoopClient
|
|||||||
{
|
{
|
||||||
if (Main.NPCs.ContainsKey(packet.NetHandle))
|
if (Main.NPCs.ContainsKey(packet.NetHandle))
|
||||||
{
|
{
|
||||||
EntitiesPed npc = Main.NPCs[packet.NetHandle];
|
EntitiesNPC npc = Main.NPCs[packet.NetHandle];
|
||||||
|
|
||||||
npc.NPCVehHandle = packet.VehHandle;
|
npc.PlayerVehicleHandle = packet.VehHandle;
|
||||||
|
|
||||||
npc.ModelHash = packet.ModelHash;
|
npc.ModelHash = packet.ModelHash;
|
||||||
npc.Clothes = packet.Clothes;
|
npc.Clothes = packet.Clothes;
|
||||||
@ -736,9 +737,9 @@ namespace CoopClient
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Main.NPCs.Add(packet.NetHandle, new EntitiesPed()
|
Main.NPCs.Add(packet.NetHandle, new EntitiesNPC()
|
||||||
{
|
{
|
||||||
NPCVehHandle = packet.VehHandle,
|
PlayerVehicleHandle = packet.VehHandle,
|
||||||
|
|
||||||
ModelHash = packet.ModelHash,
|
ModelHash = packet.ModelHash,
|
||||||
Clothes = packet.Clothes,
|
Clothes = packet.Clothes,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
using CoopClient.Entities;
|
using CoopClient.Entities.Player;
|
||||||
|
|
||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Native;
|
using GTA.Native;
|
||||||
|
Reference in New Issue
Block a user