using Newtonsoft.Json; using System.Runtime.InteropServices; namespace RageCoop.Core.Scripting { public unsafe delegate void CustomEventHandlerDelegate(int hash, byte* data, int cbData); /// /// public class CustomEventReceivedArgs : EventArgs { /// /// The event hash /// public int Hash { get; set; } /// /// Supported types: byte, short, ushort, int, uint, long, ulong, float, bool, string, Vector3, Quaternion /// public object[] Args { get; set; } internal object Tag { get; set; } } public unsafe class CustomEventHandler { // Make sure the handler doesn't get GC'd static List _handlers = new(); [ThreadStatic] static object _tag; public CustomEventHandler() { lock (_handlers) { _handlers.Add(this); } } public CustomEventHandler(IntPtr func) : this() { FunctionPtr = (ulong)func; Module = (ulong)SHVDN.Core.CurrentModule; } [JsonIgnore] private CustomEventHandlerDelegate _managedHandler; // Used to keep GC reference [JsonProperty] public ulong FunctionPtr { get; private set; } [JsonProperty] public ulong Module { get; private set; } /// /// /// /// /// /// /// Only works when using public void Invoke(int hash, byte* data, int cbData, object tag = null) { _tag = tag; ((delegate* unmanaged)FunctionPtr)(hash, data, cbData); _tag = null; } public static implicit operator CustomEventHandler(CustomEventHandlerDelegate handler) => new(Marshal.GetFunctionPointerForDelegate(handler)) { _managedHandler = handler }; public static implicit operator CustomEventHandler(Action handler) { return new CustomEventHandlerDelegate((hash, data, cbData) => { var reader = GetReader(data, cbData); var arg = new CustomEventReceivedArgs { Hash = hash, Args = CustomEvents.ReadObjects(reader), Tag = _tag }; handler(arg); }); } } }