Vehicle synchronization started (only NPC and Debug)

Not finished yet!
This commit is contained in:
EntenKoeniq
2021-07-10 09:41:17 +02:00
parent 7edb21087c
commit 2be5375a47
9 changed files with 417 additions and 30 deletions

View File

@ -1,6 +1,7 @@
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using GTA;
using GTA.Native;
@ -22,6 +23,8 @@ namespace CoopClient
private Dictionary<int, int> LastProps = new Dictionary<int, int>();
public Dictionary<int, int> Props { get; set; }
public Vector3 Position { get; set; }
#region -- ON FOOT --
public Vector3 Rotation { get; set; }
public Vector3 Velocity { get; set; }
public byte Speed { get; set; }
@ -34,9 +37,19 @@ namespace CoopClient
public bool IsShooting { get; set; }
public bool IsReloading { get; set; }
public int CurrentWeaponHash { get; set; }
#endregion
public Blip PedBlip;
#region -- VEHICLE --
public bool IsInVehicle { get; set; }
public int VehicleModelHash { get; set; }
public int VehicleSeatIndex { get; set; }
public Vehicle MainVehicle { get; set; }
public Vector3 VehiclePosition { get; set; }
public Quaternion VehicleRotation { get; set; }
#endregion
public void DisplayLocally(string username)
{
/*
@ -61,6 +74,12 @@ namespace CoopClient
#region NOT_IN_RANGE
if (!Game.Player.Character.IsInRange(Position, 250f))
{
if (MainVehicle != null && MainVehicle.Exists() && MainVehicle.PassengerCount <= 1)
{
MainVehicle.Delete();
MainVehicle = null;
}
if (Character != null && Character.Exists())
{
Character.Kill();
@ -121,7 +140,7 @@ namespace CoopClient
}
}
if (username != null && Character.IsInRange(Game.Player.Character.Position, 20f))
if (username != null && Character.IsVisible && Character.IsInRange(Game.Player.Character.Position, 20f))
{
float sizeOffset;
if (GameplayCamera.IsFirstPersonAimCamActive)
@ -190,6 +209,50 @@ namespace CoopClient
}
}
if (IsInVehicle)
{
DisplayInVehicle();
}
else
{
DisplayOnFoot();
}
#endregion
}
private void DisplayInVehicle()
{
if (MainVehicle == null || !MainVehicle.Exists() || MainVehicle.Model.Hash != VehicleModelHash)
{
List<Vehicle> vehs = World.GetNearbyVehicles(Character, 3f, new Model[] { VehicleModelHash }).OrderBy(v => (v.Position - Character.Position).Length()).Take(3).ToList();
if (vehs.Count == 0 || !vehs[0].IsSeatFree((VehicleSeat)VehicleSeatIndex))
{
MainVehicle = World.CreateVehicle(new Model(VehicleModelHash), VehiclePosition, VehicleRotation.Z);
}
else
{
MainVehicle = vehs[0];
}
}
if (!Character.IsInVehicle())
{
Character.Task.WarpIntoVehicle(MainVehicle, (VehicleSeat)VehicleSeatIndex);
Character.IsVisible = true;
}
MainVehicle.Position = VehiclePosition;
MainVehicle.Quaternion = VehicleRotation;
}
private void DisplayOnFoot()
{
if (Character.IsInVehicle())
{
Character.Task.LeaveVehicle();
}
if (IsJumping && !LastIsJumping)
{
Character.Task.Jump();
@ -262,7 +325,6 @@ namespace CoopClient
{
WalkTo();
}
#endregion
}
private void CreateCharacter(string username)
@ -272,6 +334,10 @@ namespace CoopClient
Character = World.CreatePed(new Model(ModelHash), Position, Rotation.Z);
Character.RelationshipGroup = Main.RelationshipGroup;
if (IsInVehicle)
{
Character.IsVisible = false;
}
Character.BlockPermanentEvents = true;
Character.CanRagdoll = false;
Character.IsInvincible = true;

View File

@ -36,6 +36,11 @@ namespace CoopClient.Entities
npc.Value.Character.Delete();
}
if (npc.Value.MainVehicle != null && npc.Value.MainVehicle.Exists() && npc.Value.MainVehicle.PassengerCount == 0)
{
npc.Value.MainVehicle.Delete();
}
Main.Npcs.Remove(npc.Key);
}
else

View File

@ -259,19 +259,25 @@ namespace CoopClient
DebugSyncPed = Players["DebugKey"];
}
if (!player.IsInVehicle() && DateTime.Now.Subtract(ArtificialLagCounter).TotalMilliseconds >= 300)
if (DateTime.Now.Subtract(ArtificialLagCounter).TotalMilliseconds < 300)
{
ArtificialLagCounter = DateTime.Now;
return;
}
byte? flags = Util.GetPedFlags(player, FullDebugSync, true);
ArtificialLagCounter = DateTime.Now;
if (FullDebugSync)
{
DebugSyncPed.ModelHash = player.Model.Hash;
DebugSyncPed.Props = Util.GetPedProps(player);
}
DebugSyncPed.Health = player.Health;
DebugSyncPed.Position = player.Position;
byte? flags = Util.GetPedFlags(player, FullDebugSync, true);
if (FullDebugSync)
{
DebugSyncPed.ModelHash = player.Model.Hash;
DebugSyncPed.Props = Util.GetPedProps(player);
}
DebugSyncPed.Health = player.Health;
DebugSyncPed.Position = player.Position;
if (!player.IsInVehicle())
{
DebugSyncPed.Rotation = player.Rotation;
DebugSyncPed.Velocity = player.Velocity;
DebugSyncPed.Speed = Util.GetPedSpeed(player);
@ -285,6 +291,16 @@ namespace CoopClient
DebugSyncPed.IsRagdoll = (flags.Value & (byte)PedDataFlags.IsRagdoll) > 0;
DebugSyncPed.IsOnFire = (flags.Value & (byte)PedDataFlags.IsOnFire) > 0;
}
else
{
Vehicle veh = player.CurrentVehicle;
DebugSyncPed.VehicleModelHash = veh.Model.Hash;
DebugSyncPed.VehicleSeatIndex = (int)player.SeatIndex;
DebugSyncPed.VehiclePosition = veh.Position;
DebugSyncPed.VehicleRotation = veh.Quaternion;
}
DebugSyncPed.IsInVehicle = (flags.Value & (byte)PedDataFlags.IsInVehicle) > 0;
if (DebugSyncPed.Character != null && DebugSyncPed.Character.Exists())
{
@ -292,6 +308,12 @@ namespace CoopClient
Function.Call(Hash.SET_ENTITY_NO_COLLISION_ENTITY, player.Handle, DebugSyncPed.Character.Handle, false);
}
if (DebugSyncPed.MainVehicle != null && DebugSyncPed.MainVehicle.Exists() && player.IsInVehicle())
{
Function.Call(Hash.SET_ENTITY_NO_COLLISION_ENTITY, DebugSyncPed.MainVehicle.Handle, player.CurrentVehicle.Handle, false);
Function.Call(Hash.SET_ENTITY_NO_COLLISION_ENTITY, player.CurrentVehicle.Handle, DebugSyncPed.MainVehicle.Handle, false);
}
FullDebugSync = !FullDebugSync;
}
}

View File

@ -222,6 +222,11 @@ namespace CoopClient
packet.NetIncomingMessageToPacket(message);
LightSyncPlayer((LightSyncPlayerPacket)packet);
break;
case (byte)PacketTypes.FullSyncNpcVehPacket:
packet = new FullSyncNpcVehPacket();
packet.NetIncomingMessageToPacket(message);
FullSyncNpcVeh((FullSyncNpcVehPacket)packet);
break;
case (byte)PacketTypes.ChatMessagePacket:
packet = new ChatMessagePacket();
packet.NetIncomingMessageToPacket(message);
@ -323,6 +328,7 @@ namespace CoopClient
npc.IsJumping = (packet.Flag.Value & (byte)PedDataFlags.IsJumping) > 0;
npc.IsRagdoll = (packet.Flag.Value & (byte)PedDataFlags.IsRagdoll) > 0;
npc.IsOnFire = (packet.Flag.Value & (byte)PedDataFlags.IsOnFire) > 0;
npc.IsInVehicle = (packet.Flag.Value & (byte)PedDataFlags.IsInVehicle) > 0;
}
else
{
@ -344,7 +350,8 @@ namespace CoopClient
IsReloading = (packet.Flag.Value & (byte)PedDataFlags.IsReloading) > 0,
IsJumping = (packet.Flag.Value & (byte)PedDataFlags.IsJumping) > 0,
IsRagdoll = (packet.Flag.Value & (byte)PedDataFlags.IsRagdoll) > 0,
IsOnFire = (packet.Flag.Value & (byte)PedDataFlags.IsOnFire) > 0
IsOnFire = (packet.Flag.Value & (byte)PedDataFlags.IsOnFire) > 0,
IsInVehicle = (packet.Flag.Value & (byte)PedDataFlags.IsInVehicle) > 0
});
}
}
@ -370,6 +377,42 @@ namespace CoopClient
player.IsOnFire = (packet.Flag.Value & (byte)PedDataFlags.IsOnFire) > 0;
}
}
private void FullSyncNpcVeh(FullSyncNpcVehPacket packet)
{
if (Main.Npcs.ContainsKey(packet.ID))
{
EntitiesNpc npc = Main.Npcs[packet.ID];
npc.LastUpdateReceived = Environment.TickCount;
npc.ModelHash = packet.ModelHash;
npc.Props = packet.Props;
npc.Health = packet.Health;
npc.Position = packet.Position.ToVector();
npc.VehicleModelHash = packet.VehModelHash;
npc.VehicleSeatIndex = packet.VehSeatIndex;
npc.VehiclePosition = packet.VehPosition.ToVector();
npc.VehicleRotation = packet.VehRotation.ToQuaternion();
npc.LastSyncWasFull = (packet.Flag.Value & (byte)PedDataFlags.LastSyncWasFull) > 0;
npc.IsInVehicle = (packet.Flag.Value & (byte)PedDataFlags.IsInVehicle) > 0;
}
else
{
Main.Npcs.Add(packet.ID, new EntitiesNpc()
{
LastUpdateReceived = Environment.TickCount,
ModelHash = packet.ModelHash,
Props = packet.Props,
Health = packet.Health,
Position = packet.Position.ToVector(),
VehicleModelHash = packet.VehModelHash,
VehicleSeatIndex = packet.VehSeatIndex,
VehiclePosition = packet.VehPosition.ToVector(),
VehicleRotation = packet.VehRotation.ToQuaternion(),
LastSyncWasFull = (packet.Flag.Value & (byte)PedDataFlags.LastSyncWasFull) > 0,
IsInVehicle = (packet.Flag.Value & (byte)PedDataFlags.IsInVehicle) > 0
});
}
}
#endregion
#region SEND
@ -423,20 +466,39 @@ namespace CoopClient
{
NetOutgoingMessage outgoingMessage = Client.CreateMessage();
new FullSyncNpcPacket()
if (!npc.IsInVehicle())
{
ID = Main.LocalPlayerID + npc.Handle,
ModelHash = npc.Model.Hash,
Props = Util.GetPedProps(npc),
Health = npc.Health,
Position = npc.Position.ToLVector(),
Rotation = npc.Rotation.ToLVector(),
Velocity = npc.Velocity.ToLVector(),
Speed = Util.GetPedSpeed(npc),
AimCoords = Util.GetPedAimCoords(npc, true).ToLVector(),
CurrentWeaponHash = (int)npc.Weapons.Current.Hash,
Flag = Util.GetPedFlags(npc, true)
}.PacketToNetOutGoingMessage(outgoingMessage);
new FullSyncNpcPacket()
{
ID = Main.LocalPlayerID + npc.Handle,
ModelHash = npc.Model.Hash,
Props = Util.GetPedProps(npc),
Health = npc.Health,
Position = npc.Position.ToLVector(),
Rotation = npc.Rotation.ToLVector(),
Velocity = npc.Velocity.ToLVector(),
Speed = Util.GetPedSpeed(npc),
AimCoords = Util.GetPedAimCoords(npc, true).ToLVector(),
CurrentWeaponHash = (int)npc.Weapons.Current.Hash,
Flag = Util.GetPedFlags(npc, true)
}.PacketToNetOutGoingMessage(outgoingMessage);
}
else
{
new FullSyncNpcVehPacket()
{
ID = Main.LocalPlayerID + npc.Handle,
ModelHash = npc.Model.Hash,
Props = Util.GetPedProps(npc),
Health = npc.Health,
Position = npc.Position.ToLVector(),
VehModelHash = npc.CurrentVehicle.Model.Hash,
VehSeatIndex = (int)npc.SeatIndex,
VehPosition = npc.CurrentVehicle.Position.ToLVector(),
VehRotation = npc.CurrentVehicle.Quaternion.ToLQuaternion(),
Flag = Util.GetPedFlags(npc, true)
}.PacketToNetOutGoingMessage(outgoingMessage);
}
Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered);
Client.FlushSendQueue();

View File

@ -21,6 +21,17 @@ namespace CoopClient
Z = vec.Z,
};
}
public static LQuaternion ToLQuaternion(this Quaternion vec)
{
return new LQuaternion()
{
X = vec.X,
Y = vec.Y,
Z = vec.Z,
W = vec.W
};
}
}
#endregion
@ -51,6 +62,37 @@ namespace CoopClient
public float Z { get; set; }
}
[ProtoContract]
public struct LQuaternion
{
#region CLIENT-ONLY
public Quaternion ToQuaternion()
{
return new Quaternion(X, Y, Z, W);
}
#endregion
public LQuaternion(float X, float Y, float Z, float W)
{
this.X = X;
this.Y = Y;
this.Z = Z;
this.W = W;
}
[ProtoMember(1)]
public float X { get; set; }
[ProtoMember(2)]
public float Y { get; set; }
[ProtoMember(3)]
public float Z { get; set; }
[ProtoMember(4)]
public float W { get; set; }
}
public enum ModVersion
{
V0_1_0
@ -64,6 +106,7 @@ namespace CoopClient
FullSyncPlayerPacket,
FullSyncNpcPacket,
LightSyncPlayerPacket,
FullSyncNpcVehPacket,
ChatMessagePacket
}
@ -76,7 +119,8 @@ namespace CoopClient
IsReloading = 1 << 3,
IsJumping = 1 << 4,
IsRagdoll = 1 << 5,
IsOnFire = 1 << 6
IsOnFire = 1 << 6,
IsInVehicle = 1 << 7
}
public interface IPacket
@ -383,6 +427,68 @@ namespace CoopClient
}
}
[ProtoContract]
public class FullSyncNpcVehPacket : Packet
{
[ProtoMember(1)]
public string ID { get; set; }
[ProtoMember(2)]
public int ModelHash { get; set; }
[ProtoMember(3)]
public Dictionary<int, int> Props { get; set; }
[ProtoMember(4)]
public int Health { get; set; }
[ProtoMember(5)]
public LVector3 Position { get; set; }
[ProtoMember(6)]
public int VehModelHash { get; set; }
[ProtoMember(7)]
public int VehSeatIndex { get; set; }
[ProtoMember(8)]
public LVector3 VehPosition { get; set; }
[ProtoMember(9)]
public LQuaternion VehRotation { get; set; }
[ProtoMember(10)]
public byte? Flag { get; set; } = 0;
public override void PacketToNetOutGoingMessage(NetOutgoingMessage message)
{
message.Write((byte)PacketTypes.FullSyncNpcVehPacket);
byte[] result = CoopSerializer.Serialize(this);
message.Write(result.Length);
message.Write(result);
}
public override void NetIncomingMessageToPacket(NetIncomingMessage message)
{
int len = message.ReadInt32();
FullSyncNpcVehPacket data = CoopSerializer.Deserialize<FullSyncNpcVehPacket>(message.ReadBytes(len));
ID = data.ID;
ModelHash = data.ModelHash;
Props = data.Props;
Health = data.Health;
Position = data.Position;
VehModelHash = data.VehModelHash;
VehSeatIndex = data.VehSeatIndex;
VehPosition = data.VehPosition;
VehRotation = data.VehRotation;
Flag = data.Flag;
}
}
[ProtoContract]
public class ChatMessagePacket : Packet
{

View File

@ -74,6 +74,11 @@ namespace CoopClient
flags |= (byte)PedDataFlags.IsOnFire;
}
if (ped.IsInVehicle())
{
flags |= (byte)PedDataFlags.IsInVehicle;
}
return flags;
}

View File

@ -32,6 +32,30 @@ namespace CoopServer
#endregion
}
[ProtoContract]
public struct LQuaternion
{
public LQuaternion(float X, float Y, float Z, float W)
{
this.X = X;
this.Y = Y;
this.Z = Z;
this.W = W;
}
[ProtoMember(1)]
public float X { get; set; }
[ProtoMember(2)]
public float Y { get; set; }
[ProtoMember(3)]
public float Z { get; set; }
[ProtoMember(4)]
public float W { get; set; }
}
public enum ModVersion
{
V0_1_0
@ -45,6 +69,7 @@ namespace CoopServer
FullSyncPlayerPacket,
FullSyncNpcPacket,
LightSyncPlayerPacket,
FullSyncNpcVehPacket,
ChatMessagePacket
}
@ -57,7 +82,8 @@ namespace CoopServer
IsReloading = 1 << 3,
IsJumping = 1 << 4,
IsRagdoll = 1 << 5,
IsOnFire = 1 << 6
IsOnFire = 1 << 6,
IsInVehicle = 1 << 7
}
public interface IPacket
@ -364,6 +390,68 @@ namespace CoopServer
}
}
[ProtoContract]
public class FullSyncNpcVehPacket : Packet
{
[ProtoMember(1)]
public string ID { get; set; }
[ProtoMember(2)]
public int ModelHash { get; set; }
[ProtoMember(3)]
public Dictionary<int, int> Props { get; set; }
[ProtoMember(4)]
public int Health { get; set; }
[ProtoMember(5)]
public LVector3 Position { get; set; }
[ProtoMember(6)]
public int VehModelHash { get; set; }
[ProtoMember(7)]
public int VehSeatIndex { get; set; }
[ProtoMember(8)]
public LVector3 VehPosition { get; set; }
[ProtoMember(9)]
public LQuaternion VehRotation { get; set; }
[ProtoMember(10)]
public byte? Flag { get; set; } = 0;
public override void PacketToNetOutGoingMessage(NetOutgoingMessage message)
{
message.Write((byte)PacketTypes.FullSyncNpcVehPacket);
byte[] result = CoopSerializer.Serialize(this);
message.Write(result.Length);
message.Write(result);
}
public override void NetIncomingMessageToPacket(NetIncomingMessage message)
{
int len = message.ReadInt32();
FullSyncNpcVehPacket data = CoopSerializer.Deserialize<FullSyncNpcVehPacket>(message.ReadBytes(len));
ID = data.ID;
ModelHash = data.ModelHash;
Props = data.Props;
Health = data.Health;
Position = data.Position;
VehModelHash = data.VehModelHash;
VehSeatIndex = data.VehSeatIndex;
VehPosition = data.VehPosition;
VehRotation = data.VehRotation;
Flag = data.Flag;
}
}
[ProtoContract]
public class ChatMessagePacket : Packet
{

View File

@ -229,6 +229,25 @@ namespace CoopServer
message.SenderConnection.Disconnect(e.Message);
}
break;
case (byte)PacketTypes.FullSyncNpcVehPacket:
if (MainSettings.NpcsAllowed)
{
try
{
packet = new FullSyncNpcVehPacket();
packet.NetIncomingMessageToPacket(message);
FullSyncNpcVeh(message.SenderConnection, (FullSyncNpcVehPacket)packet);
}
catch (Exception e)
{
message.SenderConnection.Disconnect(e.Message);
}
}
else
{
message.SenderConnection.Disconnect("Npcs are not allowed!");
}
break;
case (byte)PacketTypes.ChatMessagePacket:
try
{
@ -478,6 +497,19 @@ namespace CoopServer
MainNetServer.SendMessage(outgoingMessage, playerList, NetDeliveryMethod.ReliableOrdered, 0);
}
private static void FullSyncNpcVeh(NetConnection local, FullSyncNpcVehPacket packet)
{
List<NetConnection> playerList = GetAllInRange(packet.Position, 300f, local);
if (playerList.Count == 0)
{
return;
}
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
packet.PacketToNetOutGoingMessage(outgoingMessage);
MainNetServer.SendMessage(outgoingMessage, playerList, NetDeliveryMethod.ReliableOrdered, 0);
}
// Send a message to targets or all players
private static void SendChatMessage(ChatMessagePacket packet, List<NetConnection> targets = null)
{

View File

@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using System.Xml.Serialization;
namespace CoopServer
@ -9,7 +10,7 @@ namespace CoopServer
{
XmlSerializer ser = new(typeof(T));
string path = Directory.GetCurrentDirectory() + "\\" + file;
string path = AppContext.BaseDirectory + "\\" + file;
T settings;
if (File.Exists(path))