Skip to content

Commit

Permalink
Initial draft: use a custom lookup (baked by a dictionary) to handle …
Browse files Browse the repository at this point in the history
…InvokeGodotClassMethod and HasGodotClassMethod
  • Loading branch information
roookeee committed Mar 24, 2024
1 parent fe01776 commit 0ae33cc
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 174 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Godot;
using Godot.NativeInterop;
using Godot.Bridge;

partial class Methods
{
Expand Down Expand Up @@ -28,34 +29,46 @@ public new class MethodName : global::Godot.GodotObject.MethodName {
return methods;
}
#pragma warning restore CS0109
/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret)
{
if (method == MethodName.MethodWithOverload && args.Count == 0) {
MethodWithOverload();

public new static readonly FunctionRegistry<Methods> Registry = new FunctionRegistry<Methods>()
.Register(global::Godot.GodotObject.Registry)
.Register(MethodName.MethodWithOverload, 0, (Methods instance, NativeVariantPtrArgs args, out godot_variant ret) =>
{
instance.MethodWithOverload();
ret = default;
return true;
}
if (method == MethodName.MethodWithOverload && args.Count == 1) {
MethodWithOverload(global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[0]));
})
.Register(MethodName.MethodWithOverload, 1, (Methods instance, NativeVariantPtrArgs args, out godot_variant ret) =>
{
instance.MethodWithOverload(global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[0]));
ret = default;
return true;
}
if (method == MethodName.MethodWithOverload && args.Count == 2) {
MethodWithOverload(global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[0]), global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[1]));
})
.Register(MethodName.MethodWithOverload, 2, (Methods instance, NativeVariantPtrArgs args, out godot_variant ret) =>
{
instance.MethodWithOverload(global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[0]), global::Godot.NativeInterop.VariantUtils.ConvertTo<int>(args[1]));
ret = default;
return true;
})
.Compile();

/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret)
{
if (Registry.TryGetFunction(in method, args.Count, out var scriptFunction))
{
return scriptFunction(this, args, out ret);
}
return base.InvokeGodotClassMethod(method, args, out ret);

ret = new godot_variant();
return false;
}

/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool HasGodotClassMethod(in godot_string_name method)
{
if (method == MethodName.MethodWithOverload) {
return true;
}
return base.HasGodotClassMethod(method);
return Registry.ContainsFunction(method);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Godot;
using Godot.NativeInterop;
using Godot.Bridge;

partial struct OuterClass
{
Expand Down Expand Up @@ -28,25 +29,35 @@ public new class MethodName : global::Godot.RefCounted.MethodName {
return methods;
}
#pragma warning restore CS0109

public new static readonly FunctionRegistry<NestedClass> Registry = new FunctionRegistry<NestedClass>()
.Register(global::Godot.RefCounted.Registry)
.Register(MethodName._Get, 1, (NestedClass instance, NativeVariantPtrArgs args, out godot_variant ret) =>
{
var callRet = instance._Get(global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(args[0]));
ret = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(callRet);
return true;
})
.Compile();

/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret)
{
if (method == MethodName._Get && args.Count == 1) {
var callRet = _Get(global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(args[0]));
ret = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Variant>(callRet);
return true;
if (Registry.TryGetFunction(in method, args.Count, out var scriptFunction))
{
return scriptFunction(this, args, out ret);
}
return base.InvokeGodotClassMethod(method, args, out ret);

ret = new godot_variant();
return false;
}

/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool HasGodotClassMethod(in godot_string_name method)
{
if (method == MethodName._Get) {
return true;
}
return base.HasGodotClassMethod(method);
return Registry.ContainsFunction(method);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Godot;
using Godot.NativeInterop;
using Godot.Bridge;

partial class ScriptBoilerplate
{
Expand Down Expand Up @@ -31,32 +32,40 @@ public new class MethodName : global::Godot.Node.MethodName {
return methods;
}
#pragma warning restore CS0109
/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret)
{
if (method == MethodName._Process && args.Count == 1) {
_Process(global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(args[0]));

public new static readonly FunctionRegistry<ScriptBoilerplate> Registry = new FunctionRegistry<ScriptBoilerplate>()
.Register(global::Godot.Node.Registry)
.Register(MethodName._Process, 1, (ScriptBoilerplate instance, NativeVariantPtrArgs args, out godot_variant ret) =>
{
instance._Process(global::Godot.NativeInterop.VariantUtils.ConvertTo<double>(args[0]));
ret = default;
return true;
}
if (method == MethodName.Bazz && args.Count == 1) {
var callRet = Bazz(global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(args[0]));
})
.Register(MethodName.Bazz, 1, (ScriptBoilerplate instance, NativeVariantPtrArgs args, out godot_variant ret) =>
{
var callRet = instance.Bazz(global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.StringName>(args[0]));
ret = global::Godot.NativeInterop.VariantUtils.CreateFrom<int>(callRet);
return true;
})
.Compile();

/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool InvokeGodotClassMethod(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret)
{
if (Registry.TryGetFunction(in method, args.Count, out var scriptFunction))
{
return scriptFunction(this, args, out ret);
}
return base.InvokeGodotClassMethod(method, args, out ret);

ret = new godot_variant();
return false;
}

/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
protected override bool HasGodotClassMethod(in godot_string_name method)
{
if (method == MethodName._Process) {
return true;
}
else if (method == MethodName.Bazz) {
return true;
}
return base.HasGodotClassMethod(method);
return Registry.ContainsFunction(method);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ INamedTypeSymbol symbol

source.Append("using Godot;\n");
source.Append("using Godot.NativeInterop;\n");
source.Append("using Godot.Bridge;\n");

source.Append("\n");

if (hasNamespace)
Expand Down Expand Up @@ -201,25 +203,37 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType)
source.Append(" }\n");
}

source.Append("#pragma warning restore CS0109\n");
source.Append("#pragma warning restore CS0109\n\n");

// Generate InvokeGodotClassMethod

if (godotClassMethods.Length > 0)
// TODO: why where static methods in here? does excluding them here break stuff? c++ codegen filters by is_virtual and static methods can't be virtual in C#
var godotClassNonStaticMethods = godotClassMethods.Where(m => !m.Method.IsStatic).ToArray();
if (godotClassNonStaticMethods.Length > 0)
{
source.Append(" /// <inheritdoc/>\n");
source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
source.Append(" public new static readonly FunctionRegistry<").Append(symbol.NameWithTypeParameters())
.Append("> Registry = ")
.Append("new FunctionRegistry<").Append(symbol.NameWithTypeParameters()).Append(">()");
source.Append("\n .Register(").Append(symbol.BaseType.FullQualifiedNameIncludeGlobal()).Append(".Registry)");

foreach (var method in godotClassMethods)
foreach (var method in godotClassNonStaticMethods)
{
GenerateMethodInvoker(method, source);
GenerateRegistryEntry(symbol.NameWithTypeParameters(), method, source);
}

source.Append(" return base.InvokeGodotClassMethod(method, args, out ret);\n");
source.Append("\n .Compile();\n\n");

source.Append(" }\n");
source.Append(" /// <inheritdoc/>\n");
source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
source.Append(" if (Registry.TryGetFunction(in method, args.Count, out var scriptFunction))\n");
source.Append(" {\n");
source.Append(" return scriptFunction(this, args, out ret);\n");
source.Append(" }\n\n");
source.Append(" ret = new godot_variant();\n");
source.Append(" return false;\n");
source.Append(" }\n\n");
}

// Generate InvokeGodotClassStaticMethod
Expand Down Expand Up @@ -252,16 +266,7 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType)
source.Append(" /// <inheritdoc/>\n");
source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");

bool isFirstEntry = true;
foreach (string methodName in distinctMethodNames)
{
GenerateHasMethodEntry(methodName, source, isFirstEntry);
isFirstEntry = false;
}

source.Append(" return base.HasGodotClassMethod(method);\n");

source.Append(" return Registry.ContainsFunction(method);\n");
source.Append(" }\n");
}

Expand Down Expand Up @@ -410,20 +415,6 @@ private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, IType
PropertyHint.None, string.Empty, propUsage, className, exported: false);
}

private static void GenerateHasMethodEntry(
string methodName,
StringBuilder source,
bool isFirstEntry
)
{
source.Append(" ");
if (!isFirstEntry)
source.Append("else ");
source.Append("if (method == MethodName.");
source.Append(methodName);
source.Append(") {\n return true;\n }\n");
}

private static void GenerateMethodInvoker(
GodotMethodData method,
StringBuilder source
Expand Down Expand Up @@ -474,5 +465,60 @@ StringBuilder source

source.Append(" }\n");
}

private static void GenerateRegistryEntry(
string type,
GodotMethodData method,
StringBuilder source
)
{
string methodName = method.Method.Name;

source.Append("\n .Register(MethodName.")
.Append(methodName)
.Append(", ")
.Append(method.ParamTypes.Length)
.Append(", ")
.Append($"({type} instance, NativeVariantPtrArgs args, out godot_variant ret) => \n")
.Append(" {\n");

if (method.RetType != null)
source.Append(" var callRet = ");
else
source.Append(" ");

source.Append("instance.").Append(methodName);
source.Append("(");

for (int i = 0; i < method.ParamTypes.Length; i++)
{
if (i != 0)
source.Append(", ");

source.AppendNativeVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"),
method.ParamTypeSymbols[i], method.ParamTypes[i]);
}

source.Append(");\n");

if (method.RetType != null)
{
source.Append(" ret = ");

source.AppendManagedToNativeVariantExpr("callRet",
method.RetType.Value.TypeSymbol, method.RetType.Value.MarshalType);
source.Append(";\n");

source.Append(" return true;\n");
}
else
{
source.Append(" ret = default;\n");
source.Append(" return true;\n");
}

source.Append(" })");

}
}
}

0 comments on commit 0ae33cc

Please sign in to comment.