Skip to content

Commit

Permalink
Only register actually overridden virtual methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Beliar83 committed Aug 16, 2024
1 parent b84c5d2 commit e465187
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 12 deletions.
17 changes: 9 additions & 8 deletions src/Godot.Bindings/Bridge/ClassDB/ClassDB.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -23,7 +24,7 @@ public static class ClassDB
/// </summary>
/// <typeparam name="T">The type of the class.</typeparam>
/// <param name="configure">The configuration function.</param>
public static void RegisterClass<T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
public static void RegisterClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
{
RegisterClassCore<T>(isVirtual: false, isAbstract: false, isExposed: true, isRuntime: false, configure);
}
Expand All @@ -35,7 +36,7 @@ public static void RegisterClass<T>(Action<ClassDBRegistrationContext> configure
/// </summary>
/// <typeparam name="T">The type of the class.</typeparam>
/// <param name="configure">The configuration function.</param>
public static void RegisterRuntimeClass<T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
public static void RegisterRuntimeClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
{
RegisterClassCore<T>(isVirtual: false, isAbstract: false, isExposed: true, isRuntime: true, configure);
}
Expand All @@ -47,7 +48,7 @@ public static void RegisterRuntimeClass<T>(Action<ClassDBRegistrationContext> co
/// </summary>
/// <typeparam name="T">The type of the class.</typeparam>
/// <param name="configure">The configuration function.</param>
public static void RegisterVirtualClass<T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
public static void RegisterVirtualClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
{
RegisterClassCore<T>(isVirtual: true, isAbstract: false, isExposed: true, isRuntime: false, configure);
}
Expand All @@ -59,7 +60,7 @@ public static void RegisterVirtualClass<T>(Action<ClassDBRegistrationContext> co
/// </summary>
/// <typeparam name="T">The type of the class.</typeparam>
/// <param name="configure">The configuration function.</param>
public static void RegisterAbstractClass<T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
public static void RegisterAbstractClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
{
RegisterClassCore<T>(isVirtual: false, isAbstract: true, isExposed: true, isRuntime: false, configure);
}
Expand All @@ -70,12 +71,12 @@ public static void RegisterAbstractClass<T>(Action<ClassDBRegistrationContext> c
/// </summary>
/// <typeparam name="T">The type of the class.</typeparam>
/// <param name="configure">The configuration function.</param>
public static void RegisterInternalClass<T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
public static void RegisterInternalClass<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(Action<ClassDBRegistrationContext> configure) where T : GodotObject
{
RegisterClassCore<T>(isVirtual: false, isAbstract: false, isExposed: false, isRuntime: false, configure);
}

private unsafe static void RegisterClassCore<T>(bool isVirtual, bool isAbstract, bool isExposed, bool isRuntime, Action<ClassDBRegistrationContext> configure) where T : GodotObject
private unsafe static void RegisterClassCore<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] T>(bool isVirtual, bool isAbstract, bool isExposed, bool isRuntime, Action<ClassDBRegistrationContext> configure) where T : GodotObject
{
if (typeof(T).IsAbstract && !isAbstract)
{
Expand Down Expand Up @@ -152,7 +153,7 @@ private unsafe static void RegisterClassCore<T>(bool isVirtual, bool isAbstract,

if (InteropUtils.RegisterVirtualOverridesHelpers.TryGetValue(godotNativeName, out var registerVirtualOverrides))
{
registerVirtualOverrides(context);
registerVirtualOverrides(typeof(T), context);
}
}

Expand Down Expand Up @@ -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]<void*, void**, void*, void>)Marshal.GetFunctionPointerForDelegate(virtualMethodInfo.Invoker.CallVirtualWithPtrArgs);
Expand Down
6 changes: 4 additions & 2 deletions src/Godot.Bindings/NativeInterop/InteropUtils.cs
Original file line number Diff line number Diff line change
@@ -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<StringName, Func<nint, GodotObject>> CreateHelpers { get; private set; }

internal static FrozenDictionary<StringName, Action<ClassDBRegistrationContext>> RegisterVirtualOverridesHelpers { get; private set; }
internal delegate void RegisterVirtualOverrideHelper([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type, ClassDBRegistrationContext context);
internal static FrozenDictionary<StringName, RegisterVirtualOverrideHelper> RegisterVirtualOverridesHelpers { get; private set; }

static InteropUtils()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<StringName, global::System.Func<nint, global::Godot.GodotObject>>(capacity: {context.Api.Classes.Length});");
writer.WriteLine($"var registerVirtualOverridesHelpers = new global::System.Collections.Generic.Dictionary<StringName, global::System.Action<global::Godot.Bridge.ClassDBRegistrationContext>>(capacity: {context.Api.Classes.Length});");
writer.WriteLine($"var registerVirtualOverridesHelpers = new global::System.Collections.Generic.Dictionary<StringName, RegisterVirtualOverrideHelper>(capacity: {context.Api.Classes.Length});");
foreach (var engineClass in context.Api.Classes)
{
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -84,6 +88,8 @@ public override void Write(MethodBase owner, IndentedTextWriter writer)

writer.Indent--;
writer.WriteLine("});");
writer.Indent--;
writer.WriteLine('}');
}
}
}

0 comments on commit e465187

Please sign in to comment.