C#: make C# static methods accessible.

This commit is contained in:
Zae 2023-09-20 22:49:33 +08:00
parent 5f1e56ff26
commit 67e1373e5a
7 changed files with 104 additions and 4 deletions

View File

@ -2348,6 +2348,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 });
}
@ -2597,6 +2599,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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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,

View File

@ -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)

View File

@ -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);

View File

@ -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;