diff --git a/code/client/clrcore-v2/Attributes.cs b/code/client/clrcore-v2/Attributes.cs index c7faa66c28..dc681e19b1 100644 --- a/code/client/clrcore-v2/Attributes.cs +++ b/code/client/clrcore-v2/Attributes.cs @@ -116,6 +116,32 @@ public EventHandlerAttribute(string name, Binding binding = Binding.All) Binding = binding; } } + +#if !IS_FXSERVER + /// + /// Register this method to listen for the given when this is loaded + /// if is specified this will use a raw NUI callback instead + /// + /// Only works on inherited class methods +#else + /// Does nothing on server side + [EditorBrowsable(EditorBrowsableState.Never)] +#endif + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class NuiCallbackAttribute : Attribute + { + public string CallbackName { get; } + public bool IsRawCallback { get; } + public NuiCallbackAttribute(string callbackName, bool isRawCallback = false) + { + CallbackName = callbackName; + if (isRawCallback) + { + throw new NotImplementedException("Raw Nui Callbacks are not currently implemented"); + } + IsRawCallback = isRawCallback; + } + } /// /// Register this method to listen for the given when this is loaded diff --git a/code/client/clrcore-v2/BaseScript.cs b/code/client/clrcore-v2/BaseScript.cs index cc604661ec..7e38edac56 100644 --- a/code/client/clrcore-v2/BaseScript.cs +++ b/code/client/clrcore-v2/BaseScript.cs @@ -34,6 +34,8 @@ protected event Func Tick } private readonly List> m_commands = new List>(); + + private readonly Dictionary m_nuiCallbacks = new Dictionary(); #if REMOTE_FUNCTION_ENABLED private readonly List m_persistentFunctions = new List(); @@ -100,6 +102,9 @@ internal void Initialize() case KeyMapAttribute keyMap: RegisterKeyMap(keyMap.Command, keyMap.Description, keyMap.InputMapper, keyMap.InputParameter, Func.CreateCommand(this, method, keyMap.RemapParameters)); break; + case NuiCallbackAttribute nuiCallback: + RegisterNuiCallback(nuiCallback.CallbackName, Func.Create(this, method)); + break; #endif case ExportAttribute export: Exports.Add(export.Export, Func.Create(this, method), export.Binding); @@ -140,6 +145,11 @@ public void Enable() ReferenceFunctionManager.SetDelegate(m_commands[i].Key, m_commands[i].Value); } + foreach (var nuiCallback in m_nuiCallbacks) + { + Native.CoreNatives.RegisterNuiCallback(nuiCallback.Key, nuiCallback.Value); + } + EventHandlers.Enable(); Exports.Enable(); @@ -171,6 +181,11 @@ public void Disable() { ReferenceFunctionManager.SetDelegate(m_commands[i].Key, (_0, _1) => null); } + + foreach (var nuiCallback in m_nuiCallbacks) + { + Native.CoreNatives.RemoveNuiCallback(nuiCallback.Key); + } EventHandlers.Disable(); Exports.Disable(); @@ -283,7 +298,90 @@ internal void RegisterKeyMap(string command, string description, string inputMap m_commands.Add(new KeyValuePair(ReferenceFunctionManager.CreateCommand(command, dynFunc, false), dynFunc)); #endif } + + #endregion + + #region NUI Callback registration + + internal void RegisterNuiCallback(string callbackName, DynFunc dynFunc) + { +#if IS_FXSERVER + throw new NotImplementedException(); +#endif + m_nuiCallbacks.Add(callbackName, dynFunc); + Native.CoreNatives.RegisterNuiCallback(callbackName, dynFunc); + } + + /// + /// Registers the NUI callback and binds it to the the + /// + /// the NUI callback to add + /// The function to bind the callback to, the callback will be invoked with an ExpandoObject containing the data and a +#if IS_FXSERVER + /// Does nothing on server side + [EditorBrowsable(EditorBrowsableState.Never)] +#endif + public void RegisterNuiCallback(string callbackName, Delegate delegateFn) + { +#if IS_FXSERVER + throw new NotImplementedException(); +#endif + DynFunc dynFunc = Func.Create(delegateFn); + m_nuiCallbacks.Add(callbackName, dynFunc); + Native.CoreNatives.RegisterNuiCallback(callbackName, dynFunc); + } + + /// + /// Unregisters the NUI callback from the + /// + /// the NUI callback to remove +#if IS_FXSERVER + /// Does nothing on server side + [EditorBrowsable(EditorBrowsableState.Never)] +#endif + public void UnregisterNuiCallback(string callbackName) + { +#if IS_FXSERVER + throw new NotImplementedException(); +#endif + m_nuiCallbacks.Remove(callbackName); + Native.CoreNatives.RemoveNuiCallback(callbackName); + } + + /// + /// Registers a NUI callback to the specified + /// + /// the event that the callback will bind to + /// The function to bind the callback to, the callback will be invoked with an ExpandoObject containing the data and a +#if IS_FXSERVER + /// Does nothing on server side + [EditorBrowsable(EditorBrowsableState.Never)] +#endif + public static void AddNuiCallback(string callbackName, Delegate delegateFn) + { +#if IS_FXSERVER + throw new NotImplementedException(); +#endif + Native.CoreNatives.RegisterNuiCallback(callbackName, delegateFn); + } + /// + /// Removes the NUI callback for the specified + /// + /// the callback event that will be removed +#if IS_FXSERVER + /// Does nothing on server side + [EditorBrowsable(EditorBrowsableState.Never)] +#endif + public static void RemoveNuiCallback(string callbackName) + { +#if IS_FXSERVER + throw new NotImplementedException(); +#else + Native.CoreNatives.RemoveNuiCallback(callbackName); +#endif + } + #endregion #region Script loading diff --git a/code/client/clrcore-v2/Native/Native.cs b/code/client/clrcore-v2/Native/Native.cs index c9a00f995b..69f4b2d54c 100644 --- a/code/client/clrcore-v2/Native/Native.cs +++ b/code/client/clrcore-v2/Native/Native.cs @@ -15,6 +15,8 @@ internal static class CoreNatives private static UIntPtr s_0x637f4c75; private static UIntPtr s_0x8d50e33a; private static UIntPtr s_0x91310870; + private static UIntPtr s_registerNuiCallback; // 0xc59b980c + private static UIntPtr s_unregisterRawNuiCallback; // 0x7fb46432 #if IS_FXSERVER private static UIntPtr s_0x2f7a49e6; private static UIntPtr s_0x70b35890; @@ -34,12 +36,23 @@ internal static unsafe void RegisterResourceAsEventHandler(CString eventName) } [SecuritySafeCritical] - internal static unsafe void RegisterCommand(CString commandName, InFunc handler, bool restricted) + internal static unsafe void RegisterNuiCallback(CString callbackName, InFunc handler) { - fixed (byte* p_commandName = commandName?.value, p_handler = &handler.value[0]) + fixed (byte* p_callbackType = callbackName?.value, p_handler = &handler.value[0]) { - ulong* __data = stackalloc ulong[] { (ulong)p_commandName, (ulong)p_handler, N64.Val(restricted) }; - ScriptContext.InvokeNative(ref s_0x5fa79b0f, 0x5fa79b0f, __data, 3); // REGISTER_COMMAND + ulong* __data = stackalloc ulong[] { (ulong)p_callbackType, (ulong)p_handler }; + ScriptContext.InvokeNative(ref s_registerNuiCallback, 0xc59b980c, __data, 2); // REGISTER_NUI_CALLBACK + } + } + + + [SecuritySafeCritical] + internal static unsafe void RemoveNuiCallback(CString callbackName) + { + fixed (byte* p_callbackType = callbackName?.value) + { + ulong* __data = stackalloc ulong[] { (ulong)p_callbackType }; + ScriptContext.InvokeNative(ref s_unregisterRawNuiCallback, 0x7fb46432, __data, 1); // UNREGISTER_RAW_NUI_CALLBACK } } @@ -55,6 +68,16 @@ public static unsafe void RegisterKeyMapping(CString commandString, CString desc ScriptContext.InvokeNative(ref s_0xd7664fd1, 0xd7664fd1, __data, 4); } } + + [SecuritySafeCritical] + internal static unsafe void RegisterCommand(CString commandName, InFunc handler, bool restricted) + { + fixed (byte* p_commandName = commandName?.value, p_handler = &handler.value[0]) + { + ulong* __data = stackalloc ulong[] { (ulong)p_commandName, (ulong)p_handler, N64.Val(restricted) }; + ScriptContext.InvokeNative(ref s_0x5fa79b0f, 0x5fa79b0f, __data, 3); // REGISTER_COMMAND + } + } [SecuritySafeCritical] internal static unsafe object GetStateBagValue(CString bagName, CString key)