diff --git a/PorygonSharp/UserData/UserData.cs b/PorygonSharp/UserData/UserData.cs index 81b2e85..d6b4f88 100644 --- a/PorygonSharp/UserData/UserData.cs +++ b/PorygonSharp/UserData/UserData.cs @@ -121,17 +121,35 @@ namespace PorygonSharp.UserData private void RegisterFunction(MethodInfo method) { - var type = ScriptType.ScriptTypeHandler.GetFunctionScriptType(method); - if (type == IntPtr.Zero || !type.HasValue) - return; var fieldName = method.Name.ScriptHash(); - if (Fields.ContainsKey(fieldName)) - return; - var fieldData = new UserDataField(method); - var userDataField = CreateUserDataField(type.Value, fieldData.GetGetterPointer(), IntPtr.Zero); + if (Fields.TryGetValue(fieldName, out var f)) + { + if (!(f is UserDataFunctionField func)) + return; + + var methodPtr = func.MethodPtr; + var ret = ScriptType.ScriptTypeHandler.GetScriptType(method.ReturnType); + if (!ret.HasValue) return; + var parameters = method.GetParameters() + .Select(x => ScriptType.ScriptTypeHandler.GetScriptType(x.ParameterType)) + .ToArray(); + if (parameters.Any(x => !x.HasValue)) + return; + RegisterUserDataFunctionScriptTypeOption(methodPtr, ret.Value, + parameters.Select(x => x.Value).ToArray(), parameters.Length); + func.RegisterOption(method); + } + else + { + var type = ScriptType.ScriptTypeHandler.GetFunctionScriptType(method); + if (type == IntPtr.Zero || !type.HasValue) + return; + var fieldData = new UserDataFunctionField(method, type.Value); + var userDataField = CreateUserDataField(type.Value, fieldData.GetGetterPointer(), IntPtr.Zero); + RegisterUserDataField(Id, fieldName, userDataField); + Fields.Add(fieldName, fieldData); + } - RegisterUserDataField(Id, fieldName, userDataField); - Fields.Add(fieldName, fieldData); } private bool IsCastable(IntPtr scriptTypePtr, bool isExplicit) @@ -236,6 +254,9 @@ namespace PorygonSharp.UserData [DllImport("PorygonLang", EntryPoint = "AddUserdataBinaryOperation", CallingConvention = CallingConvention.Cdecl)] private static extern void AddUserdataBinaryOperation(uint id, byte kind, IntPtr operation); + [DllImport("PorygonLang", EntryPoint = "RegisterUserDataFunctionScriptTypeOption", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr RegisterUserDataFunctionScriptTypeOption(IntPtr existing, IntPtr returnType, + IntPtr[] parameters, int parameterCount); } } \ No newline at end of file diff --git a/PorygonSharp/UserData/UserDataField.cs b/PorygonSharp/UserData/UserDataField.cs index 80a9b55..c65ba1b 100644 --- a/PorygonSharp/UserData/UserDataField.cs +++ b/PorygonSharp/UserData/UserDataField.cs @@ -1,9 +1,7 @@ using System; -using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using PorygonSharp.EvalValues; -using PorygonSharp.Utilities; namespace PorygonSharp.UserData { @@ -11,11 +9,11 @@ namespace PorygonSharp.UserData { internal delegate IntPtr GetterDelegate(IntPtr ptr); internal delegate void SetterDelegate(IntPtr ptr, IntPtr val); - private delegate IntPtr CallerDelegate(IntPtr parent, IntPtr scriptOption, + protected delegate IntPtr CallerDelegate(IntPtr parent, IntPtr scriptOption, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]IntPtr[] parameters, int size); - private readonly GetterDelegate _getter; - private readonly SetterDelegate _setter; + protected GetterDelegate _getter; + protected readonly SetterDelegate _setter; public UserDataField(FieldInfo field) { @@ -58,30 +56,8 @@ namespace PorygonSharp.UserData }; } } - - public UserDataField(MethodInfo method) - { - var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray(); - _getter = ptr => - { - var func = new CallerDelegate((parent, scriptOptions, parameters, size) => - { - - var evaluatedParameters = new object[size]; - for (var i = 0; i < size; i++) - { - var eval = new EvalValue(parameters[i]); - evaluatedParameters[i] = Caster.Cast(eval, parameterTypes[i]); - } - - var parentObj = GCHandle.FromIntPtr(parent).Target; - var result = method.Invoke(parentObj, evaluatedParameters); - return EvalValueCreator.CreateValue(result).GetPointer(); - }); - var funcPtr = Marshal.GetFunctionPointerForDelegate(func); - return EvalValueCreator.FunctionEvalValue(funcPtr, ptr).GetPointer(); - }; - } + + protected UserDataField(){} public UserDataField(GetterDelegate getter, SetterDelegate setter) { diff --git a/PorygonSharp/UserData/UserDataFunctionField.cs b/PorygonSharp/UserData/UserDataFunctionField.cs new file mode 100644 index 0000000..9261294 --- /dev/null +++ b/PorygonSharp/UserData/UserDataFunctionField.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using PorygonSharp.EvalValues; +using PorygonSharp.Utilities; + +namespace PorygonSharp.UserData +{ + internal class UserDataFunctionField : UserDataField + { + public readonly IntPtr MethodPtr; + private readonly List _callers; + public UserDataFunctionField(MethodInfo method, IntPtr methodPtr) + { + _getter = ptr => + { + var funcPtr = Marshal.GetFunctionPointerForDelegate(_callers[0]); + var val = EvalValueCreator.FunctionEvalValue(funcPtr, ptr); + for (var i = 1; i < _callers.Count; i++) + { + funcPtr = Marshal.GetFunctionPointerForDelegate(_callers[i]); + RegisterFunctionEvalValueOption(val.GetPointer(), funcPtr, ptr); + } + return val.GetPointer(); + }; + MethodPtr = methodPtr; + _callers = new List(){CreateCaller(method)}; + } + + private CallerDelegate CreateCaller(MethodInfo method) + { + var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray(); + return (parent, scriptOptions, parameters, size) => + { + var evaluatedParameters = new object[size]; + for (var i = 0; i < size; i++) + { + var eval = new EvalValue(parameters[i]); + evaluatedParameters[i] = Caster.Cast(eval, parameterTypes[i]); + } + + var parentObj = GCHandle.FromIntPtr(parent).Target; + var result = method.Invoke(parentObj, evaluatedParameters); + return EvalValueCreator.CreateValue(result).GetPointer(); + }; + } + + internal void RegisterOption(MethodInfo method) + { + _callers.Add(CreateCaller(method)); + } + + [DllImport("PorygonLang", EntryPoint = "RegisterFunctionEvalValueOption",CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr RegisterFunctionEvalValueOption(IntPtr val, IntPtr func, IntPtr obj); + } +} \ No newline at end of file diff --git a/PorygonSharp/libPorygonLang.so b/PorygonSharp/libPorygonLang.so index 8df6851..7242a16 100755 Binary files a/PorygonSharp/libPorygonLang.so and b/PorygonSharp/libPorygonLang.so differ