2021-07-07 13:36:25 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
using GTA;
|
|
|
|
|
using GTA.Native;
|
|
|
|
|
using GTA.Math;
|
|
|
|
|
|
|
|
|
|
using LemonUI.Elements;
|
|
|
|
|
|
2021-12-27 10:15:52 +01:00
|
|
|
|
namespace CoopClient.Entities.Player
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
2021-12-15 00:25:31 +01:00
|
|
|
|
/// ?
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// </summary>
|
2021-12-27 10:15:52 +01:00
|
|
|
|
public partial class EntitiesPlayer
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
2021-12-27 10:15:52 +01:00
|
|
|
|
/// ?
|
2021-12-24 15:33:27 +01:00
|
|
|
|
/// </summary>
|
2021-12-27 10:15:52 +01:00
|
|
|
|
public string Username { get; set; } = "Player";
|
|
|
|
|
|
|
|
|
|
private bool AllDataAvailable = false;
|
|
|
|
|
internal bool LastSyncWasFull { get; set; } = false;
|
2021-12-24 15:33:27 +01:00
|
|
|
|
/// <summary>
|
2021-12-15 00:25:31 +01:00
|
|
|
|
/// Get the last update = TickCount64()
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// </summary>
|
2021-12-27 10:15:52 +01:00
|
|
|
|
public ulong LastUpdateReceived { get; set; }
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
2021-12-15 00:25:31 +01:00
|
|
|
|
/// Get the player latency
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// </summary>
|
2021-12-27 01:26:36 +01:00
|
|
|
|
public float Latency { get; internal set; }
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// ?
|
|
|
|
|
/// </summary>
|
2021-12-14 19:33:52 +01:00
|
|
|
|
public Ped Character { get; internal set; }
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
2021-12-15 00:25:31 +01:00
|
|
|
|
/// The latest character health (may not have been applied yet)
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// </summary>
|
2021-12-14 19:33:52 +01:00
|
|
|
|
public int Health { get; internal set; }
|
2021-07-07 13:36:25 +02:00
|
|
|
|
private int LastModelHash = 0;
|
2021-12-12 19:31:06 +01:00
|
|
|
|
private int CurrentModelHash = 0;
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
2021-12-15 00:25:31 +01:00
|
|
|
|
/// The latest character model hash (may not have been applied yet)
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// </summary>
|
2021-12-12 19:31:06 +01:00
|
|
|
|
public int ModelHash
|
|
|
|
|
{
|
2021-12-14 19:33:52 +01:00
|
|
|
|
get => CurrentModelHash;
|
|
|
|
|
internal set
|
2021-12-12 19:31:06 +01:00
|
|
|
|
{
|
|
|
|
|
LastModelHash = LastModelHash == 0 ? value : CurrentModelHash;
|
|
|
|
|
CurrentModelHash = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-16 22:05:40 +01:00
|
|
|
|
private Dictionary<byte, short> LastClothes = null;
|
|
|
|
|
internal Dictionary<byte, short> Clothes { get; set; }
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// <summary>
|
2021-12-15 00:25:31 +01:00
|
|
|
|
/// The latest character position (may not have been applied yet)
|
2021-11-28 23:35:37 +01:00
|
|
|
|
/// </summary>
|
2021-12-14 19:33:52 +01:00
|
|
|
|
public Vector3 Position { get; internal set; }
|
2022-03-20 09:21:41 +01:00
|
|
|
|
internal Vector3 Velocity { get; set; }
|
2021-12-15 00:25:31 +01:00
|
|
|
|
internal Blip PedBlip = null;
|
2021-12-15 03:31:57 +01:00
|
|
|
|
internal Vector3 AimCoords { get; set; }
|
2021-07-10 09:41:17 +02:00
|
|
|
|
|
2021-11-28 23:35:37 +01:00
|
|
|
|
internal void DisplayLocally(string username)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
|
|
|
|
// Check beforehand whether ped has all the required data
|
|
|
|
|
if (!AllDataAvailable)
|
|
|
|
|
{
|
|
|
|
|
if (!LastSyncWasFull)
|
|
|
|
|
{
|
2021-12-15 18:24:33 +01:00
|
|
|
|
if (Position != default)
|
2021-08-26 17:01:32 +02:00
|
|
|
|
{
|
|
|
|
|
if (PedBlip != null && PedBlip.Exists())
|
|
|
|
|
{
|
|
|
|
|
PedBlip.Position = Position;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PedBlip = World.CreateBlip(Position);
|
|
|
|
|
PedBlip.Color = BlipColor.White;
|
|
|
|
|
PedBlip.Scale = 0.8f;
|
|
|
|
|
PedBlip.Name = username;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AllDataAvailable = true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 21:19:26 +02:00
|
|
|
|
#region NOT_IN_RANGE
|
2021-12-27 01:26:36 +01:00
|
|
|
|
if (!Game.Player.Character.IsInRange(Position, 500f))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-09-26 22:27:49 +02:00
|
|
|
|
if (Character != null && Character.Exists())
|
|
|
|
|
{
|
|
|
|
|
Character.Kill();
|
|
|
|
|
Character.MarkAsNoLongerNeeded();
|
|
|
|
|
Character.Delete();
|
|
|
|
|
Character = null;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 21:19:26 +02:00
|
|
|
|
if (MainVehicle != null && MainVehicle.Exists() && MainVehicle.IsSeatFree(VehicleSeat.Driver) && MainVehicle.PassengerCount == 0)
|
2021-07-10 09:41:17 +02:00
|
|
|
|
{
|
2021-09-26 21:19:26 +02:00
|
|
|
|
MainVehicle.MarkAsNoLongerNeeded();
|
2021-07-10 09:41:17 +02:00
|
|
|
|
MainVehicle.Delete();
|
|
|
|
|
MainVehicle = null;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
if (username != null)
|
|
|
|
|
{
|
2021-08-26 17:01:32 +02:00
|
|
|
|
if (PedBlip != null && PedBlip.Exists())
|
|
|
|
|
{
|
|
|
|
|
PedBlip.Position = Position;
|
|
|
|
|
}
|
|
|
|
|
else
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
|
|
|
|
PedBlip = World.CreateBlip(Position);
|
|
|
|
|
PedBlip.Color = BlipColor.White;
|
|
|
|
|
PedBlip.Scale = 0.8f;
|
|
|
|
|
PedBlip.Name = username;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region IS_IN_RANGE
|
|
|
|
|
bool characterExist = Character != null && Character.Exists();
|
|
|
|
|
|
|
|
|
|
if (!characterExist)
|
|
|
|
|
{
|
2021-08-18 11:47:59 +02:00
|
|
|
|
if (!CreateCharacter(username))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
else if (LastSyncWasFull)
|
|
|
|
|
{
|
2021-12-12 19:31:06 +01:00
|
|
|
|
if (CurrentModelHash != LastModelHash)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-08-18 11:47:59 +02:00
|
|
|
|
Character.Kill();
|
|
|
|
|
Character.Delete();
|
|
|
|
|
|
|
|
|
|
if (!CreateCharacter(username))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-08-18 11:47:59 +02:00
|
|
|
|
return;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-16 22:26:45 +01:00
|
|
|
|
else if (!Clothes.Compare(LastClothes))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-12-16 22:05:40 +01:00
|
|
|
|
foreach (KeyValuePair<byte, short> cloth in Clothes)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-12-16 22:05:40 +01:00
|
|
|
|
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, Character.Handle, cloth.Key, cloth.Value, 0, 0);
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-16 22:05:40 +01:00
|
|
|
|
LastClothes = Clothes;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 09:41:17 +02:00
|
|
|
|
if (username != null && Character.IsVisible && Character.IsInRange(Game.Player.Character.Position, 20f))
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
|
|
|
|
float sizeOffset;
|
|
|
|
|
if (GameplayCamera.IsFirstPersonAimCamActive)
|
|
|
|
|
{
|
|
|
|
|
Vector3 targetPos = Character.Bones[Bone.IKHead].Position + new Vector3(0, 0, 0.10f) + (Character.Velocity / Game.FPS);
|
|
|
|
|
|
|
|
|
|
Function.Call(Hash.SET_DRAW_ORIGIN, targetPos.X, targetPos.Y, targetPos.Z, 0);
|
|
|
|
|
|
|
|
|
|
sizeOffset = Math.Max(1f - ((GameplayCamera.Position - Character.Position).Length() / 30f), 0.30f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Vector3 targetPos = Character.Bones[Bone.IKHead].Position + new Vector3(0, 0, 0.35f) + (Character.Velocity / Game.FPS);
|
|
|
|
|
|
|
|
|
|
Function.Call(Hash.SET_DRAW_ORIGIN, targetPos.X, targetPos.Y, targetPos.Z, 0);
|
|
|
|
|
|
|
|
|
|
sizeOffset = Math.Max(1f - ((GameplayCamera.Position - Character.Position).Length() / 25f), 0.25f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new ScaledText(new PointF(0, 0), username, 0.4f * sizeOffset, GTA.UI.Font.ChaletLondon)
|
|
|
|
|
{
|
|
|
|
|
Outline = true,
|
|
|
|
|
Alignment = GTA.UI.Alignment.Center
|
|
|
|
|
}.Draw();
|
|
|
|
|
|
|
|
|
|
Function.Call(Hash.CLEAR_DRAW_ORIGIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 09:41:17 +02:00
|
|
|
|
if (IsInVehicle)
|
|
|
|
|
{
|
|
|
|
|
DisplayInVehicle();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DisplayOnFoot();
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-18 11:47:59 +02:00
|
|
|
|
private bool CreateCharacter(string username)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-08-26 17:01:32 +02:00
|
|
|
|
if (PedBlip != null && PedBlip.Exists())
|
|
|
|
|
{
|
|
|
|
|
PedBlip.Delete();
|
|
|
|
|
PedBlip = null;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-12 19:31:06 +01:00
|
|
|
|
Model characterModel = CurrentModelHash.ModelRequest();
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
|
|
|
|
if (characterModel == null)
|
|
|
|
|
{
|
2021-12-12 22:00:06 +01:00
|
|
|
|
//GTA.UI.Notification.Show($"~r~(Character)Model ({CurrentModelHash}) cannot be loaded!");
|
2021-08-18 11:47:59 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Character = World.CreatePed(characterModel, Position, Rotation.Z);
|
2021-12-12 22:52:57 +01:00
|
|
|
|
characterModel.MarkAsNoLongerNeeded();
|
2021-12-27 10:15:52 +01:00
|
|
|
|
|
2021-07-07 13:36:25 +02:00
|
|
|
|
Character.RelationshipGroup = Main.RelationshipGroup;
|
2021-12-27 11:05:01 +01:00
|
|
|
|
Character.Health = Health;
|
2021-07-10 09:41:17 +02:00
|
|
|
|
if (IsInVehicle)
|
|
|
|
|
{
|
|
|
|
|
Character.IsVisible = false;
|
|
|
|
|
}
|
2021-07-07 13:36:25 +02:00
|
|
|
|
Character.BlockPermanentEvents = true;
|
|
|
|
|
Character.CanRagdoll = false;
|
|
|
|
|
Character.IsInvincible = true;
|
2021-12-27 11:05:01 +01:00
|
|
|
|
|
|
|
|
|
Character.CanSufferCriticalHits = false;
|
|
|
|
|
|
|
|
|
|
// Add a new blip for the ped
|
|
|
|
|
Character.AddBlip();
|
|
|
|
|
Character.AttachedBlip.Color = BlipColor.White;
|
|
|
|
|
Character.AttachedBlip.Scale = 0.8f;
|
|
|
|
|
Character.AttachedBlip.Name = username;
|
|
|
|
|
|
|
|
|
|
Function.Call(Hash.SET_PED_CAN_EVASIVE_DIVE, Character.Handle, false);
|
|
|
|
|
Function.Call(Hash.SET_PED_DROPS_WEAPONS_WHEN_DEAD, Character.Handle, false);
|
|
|
|
|
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED, Character.Handle, true);
|
2021-12-15 01:25:16 +01:00
|
|
|
|
Function.Call(Hash.SET_PED_CAN_BE_TARGETTED_BY_PLAYER, Character.Handle, Game.Player, true);
|
2021-12-27 11:05:01 +01:00
|
|
|
|
Function.Call(Hash.SET_PED_GET_OUT_UPSIDE_DOWN_VEHICLE, Character.Handle, false);
|
|
|
|
|
Function.Call(Hash.SET_PED_AS_ENEMY, Character.Handle, false);
|
|
|
|
|
Function.Call(Hash.SET_CAN_ATTACK_FRIENDLY, Character.Handle, true, true);
|
2021-07-07 13:36:25 +02:00
|
|
|
|
|
2021-12-16 22:05:40 +01:00
|
|
|
|
foreach (KeyValuePair<byte, short> cloth in Clothes)
|
2021-07-07 13:36:25 +02:00
|
|
|
|
{
|
2021-12-16 22:05:40 +01:00
|
|
|
|
Function.Call(Hash.SET_PED_COMPONENT_VARIATION, Character.Handle, cloth.Key, cloth.Value, 0, 0);
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
2021-08-18 11:47:59 +02:00
|
|
|
|
|
|
|
|
|
return true;
|
2021-07-07 13:36:25 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|