diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b41f2155f8d..26c684f769a 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2353,6 +2353,8 @@ void CSharpScript::update_script_class_info(Ref p_script) { mi.arguments.push_back(arg_info); } + mi.flags = (uint32_t)method_info_dict["flags"]; + p_script->methods.set(push_index++, CSharpMethodInfo{ name, mi }); } @@ -2602,6 +2604,18 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const { return MethodInfo(); } +Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + ERR_FAIL_COND_V(!valid, Variant()); + + Variant ret; + bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CallStatic(this, &p_method, p_args, p_argcount, &r_error, &ret); + if (ok) { + return ret; + } + + return Script::callp(p_method, p_args, p_argcount, r_error); +} + Error CSharpScript::reload(bool p_keep_state) { if (!reload_invalidated) { return OK; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 33862016a45..fd9e281e63f 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -199,6 +199,7 @@ public: void get_script_method_list(List *p_list) const override; bool has_method(const StringName &p_method) const override; MethodInfo get_method_info(const StringName &p_method) const override; + Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; int get_member_line(const StringName &p_member) const override; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs index 5ea0ca53c3c..7b643914bbf 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs @@ -125,7 +125,7 @@ namespace Godot.SourceGenerators var members = symbol.GetMembers(); var methodSymbols = members - .Where(s => !s.IsStatic && s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared) + .Where(s => s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared) .Cast() .Where(m => m.MethodKind == MethodKind.Ordinary); @@ -221,6 +221,29 @@ namespace Godot.SourceGenerators source.Append(" }\n"); } + // Generate InvokeGodotClassStaticMethod + + var godotClassStaticMethods = godotClassMethods.Where(m => m.Method.IsStatic).ToArray(); + + if (godotClassStaticMethods.Length > 0) + { + source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n"); + source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); + source.Append(" internal new static bool InvokeGodotClassStaticMethod(in godot_string_name method, "); + source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n"); + + foreach (var method in godotClassStaticMethods) + { + GenerateMethodInvoker(method, source); + } + + source.Append(" ret = default;\n"); + source.Append(" return false;\n"); + source.Append(" }\n"); + + source.Append("#pragma warning restore CS0109\n"); + } + // Generate HasGodotClassMethod if (distinctMethodNames.Length > 0) @@ -356,7 +379,14 @@ namespace Godot.SourceGenerators arguments = null; } - return new MethodInfo(method.Method.Name, returnVal, MethodFlags.Default, arguments, + MethodFlags flags = MethodFlags.Default; + + if (method.Method.IsStatic) + { + flags |= MethodFlags.Static; + } + + return new MethodInfo(method.Method.Name, returnVal, flags, arguments, defaultArguments: null); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs index 109643c2d40..5d6583b404f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs @@ -29,6 +29,7 @@ namespace Godot.Bridge public delegate* unmanaged ScriptManagerBridge_SwapGCHandleForType; public delegate* unmanaged, void> ScriptManagerBridge_GetPropertyInfoList; public delegate* unmanaged, void> ScriptManagerBridge_GetPropertyDefaultValues; + public delegate* unmanaged ScriptManagerBridge_CallStatic; public delegate* unmanaged CSharpInstanceBridge_Call; public delegate* unmanaged CSharpInstanceBridge_Set; public delegate* unmanaged CSharpInstanceBridge_Get; @@ -70,6 +71,7 @@ namespace Godot.Bridge ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType, ScriptManagerBridge_GetPropertyInfoList = &ScriptManagerBridge.GetPropertyInfoList, ScriptManagerBridge_GetPropertyDefaultValues = &ScriptManagerBridge.GetPropertyDefaultValues, + ScriptManagerBridge_CallStatic = &ScriptManagerBridge.CallStatic, CSharpInstanceBridge_Call = &CSharpInstanceBridge.Call, CSharpInstanceBridge_Set = &CSharpInstanceBridge.Set, CSharpInstanceBridge_Get = &CSharpInstanceBridge.Get, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs index 0fe4bcdfce0..1a7d2d9075e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs @@ -90,7 +90,7 @@ namespace Godot.Bridge internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName, IntPtr godotObject) { - // TODO: Optimize with source generators and delegate pointers + // TODO: Optimize with source generators and delegate pointers. try { @@ -124,7 +124,7 @@ namespace Godot.Bridge IntPtr godotObject, godot_variant** args, int argCount) { - // TODO: Optimize with source generators and delegate pointers + // TODO: Optimize with source generators and delegate pointers. try { @@ -677,6 +677,8 @@ namespace Godot.Bridge methodInfo.Add("params", methodParams); + methodInfo.Add("flags", (int)method.Flags); + methods.Add(methodInfo); } } @@ -958,6 +960,54 @@ namespace Godot.Bridge public godot_variant Value; // Not owned } + private delegate bool InvokeGodotClassStaticMethodDelegate(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret); + + [UnmanagedCallersOnly] + internal static unsafe godot_bool CallStatic(IntPtr scriptPtr, godot_string_name* method, + godot_variant** args, int argCount, godot_variant_call_error* refCallError, godot_variant* ret) + { + // TODO: Optimize with source generators and delegate pointers. + + try + { + Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr); + + Type? top = scriptType; + Type native = GodotObject.InternalGetClassNativeBase(top); + + while (top != null && top != native) + { + var invokeGodotClassStaticMethod = top.GetMethod( + "InvokeGodotClassStaticMethod", + BindingFlags.DeclaredOnly | BindingFlags.Static | + BindingFlags.NonPublic | BindingFlags.Public); + + if (invokeGodotClassStaticMethod != null) + { + var invoked = invokeGodotClassStaticMethod.CreateDelegate()( + CustomUnsafe.AsRef(method), new NativeVariantPtrArgs(args, argCount), out godot_variant retValue); + if (invoked) + { + *ret = retValue; + return godot_bool.True; + } + } + + top = top.BaseType; + } + } + catch (Exception e) + { + ExceptionUtils.LogException(e); + *ret = default; + return godot_bool.False; + } + + *ret = default; + (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD; + return godot_bool.False; + } + [UnmanagedCallersOnly] internal static unsafe void GetPropertyDefaultValues(IntPtr scriptPtr, delegate* unmanaged addDefValFunc) diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index 8fdf163b26d..5a1f90fa1de 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -70,6 +70,7 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) { CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType); CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyInfoList); CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyDefaultValues); + CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CallStatic); CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call); CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set); CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index f604e4d681a..6ddc688ea04 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -95,6 +95,7 @@ struct ManagedCallbacks { using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool); using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add); using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add); + using FuncScriptManagerBridge_CallStatic = bool(GD_CLR_STDCALL *)(const CSharpScript *, const StringName *, const Variant **, int32_t, Callable::CallError *, Variant *); using FuncCSharpInstanceBridge_Call = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, Callable::CallError *, Variant *); using FuncCSharpInstanceBridge_Set = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant *); using FuncCSharpInstanceBridge_Get = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, Variant *); @@ -130,6 +131,7 @@ struct ManagedCallbacks { FuncScriptManagerBridge_SwapGCHandleForType ScriptManagerBridge_SwapGCHandleForType; FuncScriptManagerBridge_GetPropertyInfoList ScriptManagerBridge_GetPropertyInfoList; FuncScriptManagerBridge_GetPropertyDefaultValues ScriptManagerBridge_GetPropertyDefaultValues; + FuncScriptManagerBridge_CallStatic ScriptManagerBridge_CallStatic; FuncCSharpInstanceBridge_Call CSharpInstanceBridge_Call; FuncCSharpInstanceBridge_Set CSharpInstanceBridge_Set; FuncCSharpInstanceBridge_Get CSharpInstanceBridge_Get;