diff --git a/src/Godot.Bindings/Bridge/ClassDB/ClassDB.cs b/src/Godot.Bindings/Bridge/ClassDB/ClassDB.cs
index 85490ef..bdc5eec 100644
--- a/src/Godot.Bindings/Bridge/ClassDB/ClassDB.cs
+++ b/src/Godot.Bindings/Bridge/ClassDB/ClassDB.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Godot.NativeInterop;
@@ -23,7 +24,7 @@ public static class ClassDB
///
/// The type of the class.
/// The configuration function.
- public static void RegisterClass(Action configure) where T : GodotObject
+ public static void RegisterClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action configure) where T : GodotObject
{
RegisterClassCore(isVirtual: false, isAbstract: false, isExposed: true, isRuntime: false, configure);
}
@@ -35,7 +36,7 @@ public static void RegisterClass(Action configure
///
/// The type of the class.
/// The configuration function.
- public static void RegisterRuntimeClass(Action configure) where T : GodotObject
+ public static void RegisterRuntimeClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action configure) where T : GodotObject
{
RegisterClassCore(isVirtual: false, isAbstract: false, isExposed: true, isRuntime: true, configure);
}
@@ -47,7 +48,7 @@ public static void RegisterRuntimeClass(Action co
///
/// The type of the class.
/// The configuration function.
- public static void RegisterVirtualClass(Action configure) where T : GodotObject
+ public static void RegisterVirtualClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action configure) where T : GodotObject
{
RegisterClassCore(isVirtual: true, isAbstract: false, isExposed: true, isRuntime: false, configure);
}
@@ -59,7 +60,7 @@ public static void RegisterVirtualClass(Action co
///
/// The type of the class.
/// The configuration function.
- public static void RegisterAbstractClass(Action configure) where T : GodotObject
+ public static void RegisterAbstractClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action configure) where T : GodotObject
{
RegisterClassCore(isVirtual: false, isAbstract: true, isExposed: true, isRuntime: false, configure);
}
@@ -70,12 +71,12 @@ public static void RegisterAbstractClass(Action c
///
/// The type of the class.
/// The configuration function.
- public static void RegisterInternalClass(Action configure) where T : GodotObject
+ public static void RegisterInternalClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action configure) where T : GodotObject
{
RegisterClassCore(isVirtual: false, isAbstract: false, isExposed: false, isRuntime: false, configure);
}
- private unsafe static void RegisterClassCore(bool isVirtual, bool isAbstract, bool isExposed, bool isRuntime, Action configure) where T : GodotObject
+ private unsafe static void RegisterClassCore<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(bool isVirtual, bool isAbstract, bool isExposed, bool isRuntime, Action configure) where T : GodotObject
{
if (typeof(T).IsAbstract && !isAbstract)
{
@@ -152,7 +153,7 @@ private unsafe static void RegisterClassCore(bool isVirtual, bool isAbstract,
if (InteropUtils.RegisterVirtualOverridesHelpers.TryGetValue(godotNativeName, out var registerVirtualOverrides))
{
- registerVirtualOverrides(context);
+ registerVirtualOverrides(typeof(T), context);
}
}
@@ -412,7 +413,7 @@ private unsafe static void Free_Native(void* userData, void* instance)
if (!context.RegisteredVirtualMethodOverrides.TryGetValue(methodNameStr, out var virtualMethodInfo))
{
- throw new InvalidOperationException($"Virtual method '{methodNameStr}' has not been registered in class '{context.ClassName}'.");
+ return null;
}
return (delegate* unmanaged[Cdecl])Marshal.GetFunctionPointerForDelegate(virtualMethodInfo.Invoker.CallVirtualWithPtrArgs);
diff --git a/src/Godot.Bindings/NativeInterop/InteropUtils.cs b/src/Godot.Bindings/NativeInterop/InteropUtils.cs
index e2c98c0..5103075 100644
--- a/src/Godot.Bindings/NativeInterop/InteropUtils.cs
+++ b/src/Godot.Bindings/NativeInterop/InteropUtils.cs
@@ -1,14 +1,16 @@
using System;
using System.Collections.Frozen;
+using System.Diagnostics.CodeAnalysis;
using Godot.Bridge;
namespace Godot.NativeInterop;
-internal static partial class InteropUtils
+public static partial class InteropUtils
{
internal static FrozenDictionary> CreateHelpers { get; private set; }
- internal static FrozenDictionary> RegisterVirtualOverridesHelpers { get; private set; }
+ internal delegate void RegisterVirtualOverrideHelper([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type, ClassDBRegistrationContext context);
+ internal static FrozenDictionary RegisterVirtualOverridesHelpers { get; private set; }
static InteropUtils()
{
diff --git a/src/Godot.BindingsGenerator/BindingsDataCollectors/EngineClassesBindingsDataCollector.cs b/src/Godot.BindingsGenerator/BindingsDataCollectors/EngineClassesBindingsDataCollector.cs
index 6c142a8..b55d715 100644
--- a/src/Godot.BindingsGenerator/BindingsDataCollectors/EngineClassesBindingsDataCollector.cs
+++ b/src/Godot.BindingsGenerator/BindingsDataCollectors/EngineClassesBindingsDataCollector.cs
@@ -108,7 +108,7 @@ public override void Populate(BindingsData.CollectionContext context)
Body = MethodBody.Create(writer =>
{
writer.WriteLine($"var createHelpers = new global::System.Collections.Generic.Dictionary>(capacity: {context.Api.Classes.Length});");
- writer.WriteLine($"var registerVirtualOverridesHelpers = new global::System.Collections.Generic.Dictionary>(capacity: {context.Api.Classes.Length});");
+ writer.WriteLine($"var registerVirtualOverridesHelpers = new global::System.Collections.Generic.Dictionary(capacity: {context.Api.Classes.Length});");
foreach (var engineClass in context.Api.Classes)
{
@@ -303,6 +303,7 @@ private void PopulateEngineClassMethods(BindingsData.CollectionContext context,
IsNew = engineClass.Name != "Object",
Parameters =
{
+ new ParameterInfo("type", new TypeInfo("Type", "System")) { Attributes = ["[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)]"]},
new ParameterInfo("context", new TypeInfo("ClassDBRegistrationContext", "Godot.Bridge")),
},
Body = new RegisterVirtualOverrides(type, virtualMethods),
diff --git a/src/Godot.BindingsGenerator/BindingsGenerator/BindingsGenerator.cs b/src/Godot.BindingsGenerator/BindingsGenerator/BindingsGenerator.cs
index d840d06..f09fcf3 100644
--- a/src/Godot.BindingsGenerator/BindingsGenerator/BindingsGenerator.cs
+++ b/src/Godot.BindingsGenerator/BindingsGenerator/BindingsGenerator.cs
@@ -51,6 +51,10 @@ private static void GenerateCore(GodotApi api, string outputDirectoryPath, Bindi
using var streamWriter = new StreamWriter(stream);
using var writer = new IndentedTextWriter(streamWriter);
+ writer.WriteLine("using System.Diagnostics.CodeAnalysis;");
+ writer.WriteLine("using System.Reflection;");
+ writer.WriteLine();
+
writer.WriteLine($"namespace {type.Namespace};");
writer.WriteLine();
diff --git a/src/Godot.BindingsGenerator/MethodBodies/RegisterVirtualOverrides.cs b/src/Godot.BindingsGenerator/MethodBodies/RegisterVirtualOverrides.cs
index 17aa805..3459995 100644
--- a/src/Godot.BindingsGenerator/MethodBodies/RegisterVirtualOverrides.cs
+++ b/src/Godot.BindingsGenerator/MethodBodies/RegisterVirtualOverrides.cs
@@ -23,10 +23,14 @@ public override void Write(MethodBase owner, IndentedTextWriter writer)
{
if (_type.BaseType is not null)
{
- writer.WriteLine($"{_type.BaseType.FullNameWithGlobal}.RegisterVirtualOverrides(context);");
+ writer.WriteLine($"{_type.BaseType.FullNameWithGlobal}.RegisterVirtualOverrides(type, context);");
}
foreach (var (method, engineMethod) in _virtualMethods)
{
+ writer.WriteLine($"if (type.GetMethod(nameof(MethodName.{method.Name}), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) != null)");
+ writer.WriteLine('{');
+ writer.Indent++;
+
writer.Write($"context.BindVirtualMethodOverride(MethodName.{method.Name}, ");
writer.Write($"static ({_type.FullNameWithGlobal} __instance");
if (method.Parameters.Count > 0)
@@ -84,6 +88,8 @@ public override void Write(MethodBase owner, IndentedTextWriter writer)
writer.Indent--;
writer.WriteLine("});");
+ writer.Indent--;
+ writer.WriteLine('}');
}
}
}