Quellcode durchsuchen

Merge pull request #81783 from zaevi/fix-csharp-static-method

C#: make C# static methods accessible.
Rémi Verschelde vor 1 Jahr
Ursprung
Commit
ce0fa4c691

+ 14 - 0
modules/mono/csharp_script.cpp

@@ -2353,6 +2353,8 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> 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;

+ 1 - 0
modules/mono/csharp_script.h

@@ -199,6 +199,7 @@ public:
 	void get_script_method_list(List<MethodInfo> *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;
 

+ 32 - 2
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<IMethodSymbol>()
                 .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);
         }
 

+ 2 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs

@@ -29,6 +29,7 @@ namespace Godot.Bridge
         public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
         public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
         public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
+        public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> ScriptManagerBridge_CallStatic;
         public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> CSharpInstanceBridge_Call;
         public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Set;
         public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> 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,

+ 52 - 2
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<InvokeGodotClassStaticMethodDelegate>()(
+                            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<IntPtr, void*, int, void> addDefValFunc)

+ 1 - 0
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);

+ 2 - 0
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;