diff --git a/Client/Networking.cs b/Client/Networking.cs index 913eec5..544286b 100644 --- a/Client/Networking.cs +++ b/Client/Networking.cs @@ -230,6 +230,11 @@ namespace CoopClient packet.NetIncomingMessageToPacket(message); DecodeNativeCall((NativeCallPacket)packet); break; + case (byte)PacketTypes.NativeResponsePacket: + packet = new NativeResponsePacket(); + packet.NetIncomingMessageToPacket(message); + DecodeNativeResponse((NativeResponsePacket)packet); + break; case (byte)PacketTypes.ModPacket: packet = new ModPacket(); packet.NetIncomingMessageToPacket(message); @@ -464,6 +469,84 @@ namespace CoopClient Function.Call((Hash)packet.Hash, arguments.ToArray()); } + + private void DecodeNativeResponse(NativeResponsePacket packet) + { + List arguments = new List(); + Type typeOf = null; + + packet.Args.ForEach(arg => + { + typeOf = arg.GetType(); + if (typeOf == typeof(IntArgument)) + { + arguments.Add(((IntArgument)arg).Data); + } + else if (typeOf == typeof(BoolArgument)) + { + arguments.Add(((BoolArgument)arg).Data); + } + else if (typeOf == typeof(FloatArgument)) + { + arguments.Add(((FloatArgument)arg).Data); + } + else if (typeOf == typeof(StringArgument)) + { + arguments.Add(((StringArgument)arg).Data); + } + else if (typeOf == typeof(LVector3Argument)) + { + arguments.Add(((LVector3Argument)arg).Data.X); + arguments.Add(((LVector3Argument)arg).Data.Y); + arguments.Add(((LVector3Argument)arg).Data.Z); + } + else + { + GTA.UI.Notification.Show("[DecodeNativeCall][" + packet.Hash + "]: Type of argument not found!"); + return; + } + }); + + NativeArgument result = null; + + typeOf = packet.Type.GetType(); + if (typeOf == typeof(IntArgument)) + { + result = new IntArgument() { Data = Function.Call((Hash)packet.Hash, arguments.ToArray()) }; + } + else if (typeOf == typeof(BoolArgument)) + { + result = new BoolArgument() { Data = Function.Call((Hash)packet.Hash, arguments.ToArray()) }; + } + else if (typeOf == typeof(FloatArgument)) + { + result = new FloatArgument() { Data = Function.Call((Hash)packet.Hash, arguments.ToArray()) }; + } + else if (typeOf == typeof(StringArgument)) + { + result = new StringArgument() { Data = Function.Call((Hash)packet.Hash, arguments.ToArray()) }; + } + else if (typeOf == typeof(LVector3Argument)) + { + result = new LVector3Argument() { Data = Function.Call((Hash)packet.Hash, arguments.ToArray()).ToLVector() }; + } + else + { + GTA.UI.Notification.Show("[DecodeNativeCall][" + packet.Hash + "]: Type of argument not found!"); + return; + } + + NetOutgoingMessage outgoingMessage = Client.CreateMessage(); + new NativeResponsePacket() + { + Hash = 0, + Args = null, + Type = result, + ID = packet.ID + }.PacketToNetOutGoingMessage(outgoingMessage); + Client.SendMessage(outgoingMessage, NetDeliveryMethod.ReliableOrdered); + Client.FlushSendQueue(); + } #endregion // -- PLAYER -- #region -- NPC -- diff --git a/Client/Packets.cs b/Client/Packets.cs index ce45898..a202daf 100644 --- a/Client/Packets.cs +++ b/Client/Packets.cs @@ -129,6 +129,7 @@ namespace CoopClient FullSyncNpcVehPacket, ChatMessagePacket, NativeCallPacket, + NativeResponsePacket, ModPacket } @@ -721,6 +722,44 @@ namespace CoopClient } } + [ProtoContract] + class NativeResponsePacket : Packet + { + [ProtoMember(1)] + public ulong Hash { get; set; } + + [ProtoMember(2)] + public List Args { get; set; } + + [ProtoMember(3)] + public NativeArgument Type { get; set; } + + [ProtoMember(4)] + public long ID { get; set; } + + public override void PacketToNetOutGoingMessage(NetOutgoingMessage message) + { + message.Write((byte)PacketTypes.NativeResponsePacket); + + byte[] result = CoopSerializer.Serialize(this); + + message.Write(result.Length); + message.Write(result); + } + + public override void NetIncomingMessageToPacket(NetIncomingMessage message) + { + int len = message.ReadInt32(); + + NativeResponsePacket data = message.ReadBytes(len).Deserialize(); + + Hash = data.Hash; + Args = data.Args; + Type = data.Type; + ID = data.ID; + } + } + [ProtoContract] [ProtoInclude(1, typeof(IntArgument))] [ProtoInclude(2, typeof(BoolArgument))] diff --git a/Server/Client.cs b/Server/Client.cs index d8b8a41..ebdeb8e 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -11,6 +11,7 @@ namespace CoopServer public float Latency = 0.0f; public PlayerData Player; private readonly Dictionary CustomData = new(); + internal readonly Dictionary> Callbacks = new(); #region CUSTOMDATA FUNCTIONS public void SetData(string name, T data) @@ -108,6 +109,70 @@ namespace CoopServer } } + public void SendNativeResponse(Action callback, ulong hash, Type type, params object[] args) + { + try + { + NetConnection userConnection = Server.MainNetServer.Connections.Find(x => x.RemoteUniqueIdentifier == ID); + if (userConnection == null) + { + return; + } + + NativeArgument returnType = null; + Type typeOf = type; + if (typeOf == typeof(int)) + { + returnType = new IntArgument(); + } + else if (typeOf == typeof(bool)) + { + returnType = new BoolArgument(); + } + else if (typeOf == typeof(float)) + { + returnType = new FloatArgument(); + } + else if (typeOf == typeof(string)) + { + returnType = new StringArgument(); + } + else if (typeOf == typeof(LVector3)) + { + returnType = new LVector3Argument(); + } + else + { + return; + } + + List arguments = Util.ParseNativeArguments(args); + if (arguments == null) + { + return; + } + + long id = 0; + Callbacks.Add(id = Environment.TickCount64, callback); + + NativeResponsePacket packet = new() + { + Hash = hash, + Args = arguments, + Type = returnType, + ID = id + }; + + NetOutgoingMessage outgoingMessage = Server.MainNetServer.CreateMessage(); + packet.PacketToNetOutGoingMessage(outgoingMessage); + Server.MainNetServer.SendMessage(outgoingMessage, userConnection, NetDeliveryMethod.ReliableOrdered, 0); + } + catch (Exception e) + { + Logging.Error($">> {e.Message} <<>> {e.Source ?? string.Empty} <<>> {e.StackTrace ?? string.Empty} <<"); + } + } + public void SendModPacket(string mod, byte customID, byte[] bytes) { try diff --git a/Server/Packets.cs b/Server/Packets.cs index 54b6675..e5d5f66 100644 --- a/Server/Packets.cs +++ b/Server/Packets.cs @@ -72,6 +72,7 @@ namespace CoopServer FullSyncNpcVehPacket, ChatMessagePacket, NativeCallPacket, + NativeResponsePacket, ModPacket } @@ -636,6 +637,44 @@ namespace CoopServer } } + [ProtoContract] + class NativeResponsePacket : Packet + { + [ProtoMember(1)] + public ulong Hash { get; set; } + + [ProtoMember(2)] + public List Args { get; set; } + + [ProtoMember(3)] + public NativeArgument Type { get; set; } + + [ProtoMember(4)] + public long ID { get; set; } + + public override void PacketToNetOutGoingMessage(NetOutgoingMessage message) + { + message.Write((byte)PacketTypes.NativeResponsePacket); + + byte[] result = CoopSerializer.Serialize(this); + + message.Write(result.Length); + message.Write(result); + } + + public override void NetIncomingMessageToPacket(NetIncomingMessage message) + { + int len = message.ReadInt32(); + + NativeResponsePacket data = message.ReadBytes(len).Deserialize(); + + Hash = data.Hash; + Args = data.Args; + Type = data.Type; + ID = data.ID; + } + } + [ProtoContract] [ProtoInclude(1, typeof(IntArgument))] [ProtoInclude(2, typeof(BoolArgument))] diff --git a/Server/Server.cs b/Server/Server.cs index ea46ac7..1bbb580 100644 --- a/Server/Server.cs +++ b/Server/Server.cs @@ -352,6 +352,52 @@ namespace CoopServer message.SenderConnection.Disconnect("Npcs are not allowed!"); } break; + case (byte)PacketTypes.NativeResponsePacket: + { + try + { + packet = new NativeResponsePacket(); + packet.NetIncomingMessageToPacket(message); + NativeResponsePacket responsePacket = (NativeResponsePacket)packet; + + Client client = Clients.FirstOrDefault(x => x.ID == message.SenderConnection.RemoteUniqueIdentifier); + if (client != default(Client)) + { + if (client.Callbacks.ContainsKey(responsePacket.ID)) + { + object resp = null; + if (responsePacket.Type is IntArgument argument) + { + resp = argument.Data; + } + else if (responsePacket.Type is StringArgument argument1) + { + resp = argument1.Data; + } + else if (responsePacket.Type is FloatArgument argument2) + { + resp = argument2.Data; + } + else if (responsePacket.Type is BoolArgument argument3) + { + resp = argument3.Data; + } + else if (responsePacket.Type is LVector3Argument argument4) + { + resp = argument4.Data; + } + + client.Callbacks[responsePacket.ID].Invoke(resp); + client.Callbacks.Remove(responsePacket.ID); + } + } + } + catch (Exception e) + { + message.SenderConnection.Disconnect(e.Message); + } + } + break; case (byte)PacketTypes.ModPacket: if (MainSettings.ModsAllowed) { @@ -406,10 +452,12 @@ namespace CoopServer } break; case NetIncomingMessageType.ConnectionLatencyUpdated: - Client client = Clients.FirstOrDefault(x => x.ID == message.SenderConnection.RemoteUniqueIdentifier); - if (!client.Equals(default(Client))) { - client.Latency = message.ReadFloat(); + Client client = Clients.FirstOrDefault(x => x.ID == message.SenderConnection.RemoteUniqueIdentifier); + if (!client.Equals(default(Client))) + { + client.Latency = message.ReadFloat(); + } } break; case NetIncomingMessageType.ErrorMessage: