using GTA; using GTA.Math; using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; namespace RageCoop.Core.Scripting { /// /// Describes how the event should be sent or processed /// public enum CustomEventFlags : byte { None = 0, /// /// Data will be encrypted and decrypted on target client /// Encrypted = 1, /// /// Event will be queued and fired in script thread, specify this flag if your handler will call native functions. /// Queued = 2 } /// /// Struct to identify different event using hash /// public struct CustomEventHash { private static readonly MD5 Hasher = MD5.Create(); private static readonly Dictionary Hashed = new Dictionary(); /// /// Hash value /// public int Hash; /// /// Create from hash /// /// public static implicit operator CustomEventHash(int hash) { return new CustomEventHash { Hash = hash }; } /// /// Create from string /// /// public static implicit operator CustomEventHash(string name) { return new CustomEventHash { Hash = FromString(name) }; } /// /// Get a Int32 hash of a string. /// /// /// /// /// The exception is thrown when the name did not match a previously computed one and /// the hash was the same. /// public static int FromString(string s) { var hash = BitConverter.ToInt32(Hasher.ComputeHash(Encoding.UTF8.GetBytes(s)), 0); lock (Hashed) { if (Hashed.TryGetValue(hash, out var name)) { if (name != s) throw new ArgumentException( $"Hashed value has collision with another name:{name}, hashed value:{hash}"); return hash; } Hashed.Add(hash, s); return hash; } } /// /// To int /// /// public static implicit operator int(CustomEventHash h) { return h.Hash; } } /// /// public static partial class CustomEvents { internal static readonly CustomEventHash OnPlayerDied = "RageCoop.OnPlayerDied"; internal static readonly CustomEventHash SetWeather = "RageCoop.SetWeather"; internal static readonly CustomEventHash OnPedDeleted = "RageCoop.OnPedDeleted"; internal static readonly CustomEventHash OnVehicleDeleted = "RageCoop.OnVehicleDeleted"; internal static readonly CustomEventHash SetAutoRespawn = "RageCoop.SetAutoRespawn"; internal static readonly CustomEventHash SetDisplayNameTag = "RageCoop.SetDisplayNameTag"; internal static readonly CustomEventHash NativeCall = "RageCoop.NativeCall"; internal static readonly CustomEventHash NativeResponse = "RageCoop.NativeResponse"; internal static readonly CustomEventHash AllResourcesSent = "RageCoop.AllResourcesSent"; internal static readonly CustomEventHash ServerPropSync = "RageCoop.ServerPropSync"; internal static readonly CustomEventHash ServerBlipSync = "RageCoop.ServerBlipSync"; internal static readonly CustomEventHash SetEntity = "RageCoop.SetEntity"; internal static readonly CustomEventHash DeleteServerProp = "RageCoop.DeleteServerProp"; internal static readonly CustomEventHash UpdatePedBlip = "RageCoop.UpdatePedBlip"; internal static readonly CustomEventHash DeleteEntity = "RageCoop.DeleteEntity"; internal static readonly CustomEventHash DeleteServerBlip = "RageCoop.DeleteServerBlip"; internal static readonly CustomEventHash CreateVehicle = "RageCoop.CreateVehicle"; internal static readonly CustomEventHash WeatherTimeSync = "RageCoop.WeatherTimeSync"; internal static readonly CustomEventHash IsHost = "RageCoop.IsHost"; #region TYPE CONSTANTS public const byte T_BYTE = 1; public const byte T_SHORT = 2; public const byte T_USHORT = 3; public const byte T_INT = 4; public const byte T_UINT = 5; public const byte T_LONG = 6; public const byte T_ULONG = 7; public const byte T_FLOAT = 8; public const byte T_BOOL = 9; public const byte T_STR = 10; public const byte T_VEC3 = 11; public const byte T_QUAT = 12; public const byte T_MODEL = 13; public const byte T_VEC2 = 14; public const byte T_BYTEARR = 15; public const byte T_ID_PROP = 50; public const byte T_ID_PED = 51; public const byte T_ID_VEH = 52; public const byte T_ID_BLIP = 60; #endregion public static void WriteObjects(WriteBuffer b, params object[] objs) { b.WriteVal(objs.Length); foreach(var obj in objs) { switch (obj) { case byte value: b.WriteVal(T_BYTE); b.WriteVal(value); break; case short value: b.WriteVal(T_SHORT); b.WriteVal(value); break; case ushort value: b.WriteVal(T_USHORT); b.WriteVal(value); break; case int value: b.WriteVal(T_INT); b.WriteVal(value); break; case uint value: b.WriteVal(T_UINT); b.WriteVal(value); break; case long value: b.WriteVal(T_LONG); b.WriteVal(value); break; case ulong value: b.WriteVal(T_ULONG); b.WriteVal(value); break; case float value: b.WriteVal(T_FLOAT); b.WriteVal(value); break; case bool value: b.WriteVal(T_BOOL); b.WriteVal(value); break; case string value: b.WriteVal(T_STR); b.Write(value); break; case Vector2 value: b.WriteVal(T_VEC2); b.Write(ref value); break; case Vector3 value: b.WriteVal(T_VEC3); b.Write(ref value); break; case Quaternion value: b.WriteVal(T_QUAT); b.Write(ref value); break; case Model value: b.WriteVal(T_MODEL); b.WriteVal(value); break; case byte[] value: b.WriteVal(T_BYTEARR); b.WriteArray(value); break; case Tuple value: b.WriteVal(value.Item1); b.Write(new ReadOnlySpan(value.Item2)); break; default: throw new Exception("Unsupported object type: " + obj.GetType()); } } } public static object[] ReadObjects(ReadBuffer r) { var Args = new object[r.ReadVal()]; for (var i = 0; i < Args.Length; i++) { var type = r.ReadVal(); switch (type) { case T_BYTE: Args[i] = r.ReadVal(); break; case T_SHORT: Args[i] = r.ReadVal(); break; case T_USHORT: Args[i] = r.ReadVal(); break; case T_INT: Args[i] = r.ReadVal(); break; case T_UINT: Args[i] = r.ReadVal(); break; case T_LONG: Args[i] = r.ReadVal(); break; case T_ULONG: Args[i] = r.ReadVal(); break; case T_FLOAT: Args[i] = r.ReadVal(); break; case T_BOOL: Args[i] = r.ReadVal(); break; case T_STR: r.Read(out string str); Args[i] = str; break; case T_VEC3: r.Read(out Vector3 vec); Args[i] = vec; break; case T_QUAT: r.Read(out Quaternion quat); Args[i] = quat; break; case T_MODEL: Args[i] = r.ReadVal(); break; case T_VEC2: r.Read(out Vector2 vec2); Args[i] = vec2; break; case T_BYTEARR: Args[i] = r.ReadArray(); break; case T_ID_BLIP: case T_ID_PED: case T_ID_PROP: case T_ID_VEH: Args[i] = IdToHandle(type,r.ReadVal()); break; default: throw new InvalidOperationException($"Unexpected type: {type}"); } } return Args; } [LibraryImport("RageCoop.Client.dll")] public static partial int IdToHandle(byte type,int id); } }