mirror of
https://github.com/godotengine/godot.git
synced 2024-11-22 12:12:28 +00:00
Merge pull request #67987 from neikeq/dotnet-more-static-marshaling
C#: Reflection-less delegate callables and nested generic Godot collections
This commit is contained in:
commit
256c0079b0
@ -188,14 +188,14 @@ namespace Godot.SourceGenerators
|
||||
if (godotClassMethods.Length > 0)
|
||||
{
|
||||
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
|
||||
source.Append("NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n {\n");
|
||||
source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
|
||||
|
||||
foreach (var method in godotClassMethods)
|
||||
{
|
||||
GenerateMethodInvoker(method, source);
|
||||
}
|
||||
|
||||
source.Append(" return base.InvokeGodotClassMethod(method, args, argCount, out ret);\n");
|
||||
source.Append(" return base.InvokeGodotClassMethod(method, args, out ret);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
@ -364,7 +364,7 @@ namespace Godot.SourceGenerators
|
||||
|
||||
source.Append(" if (method == MethodName.");
|
||||
source.Append(methodName);
|
||||
source.Append(" && argCount == ");
|
||||
source.Append(" && args.Count == ");
|
||||
source.Append(method.ParamTypes.Length);
|
||||
source.Append(") {\n");
|
||||
|
||||
|
@ -167,6 +167,7 @@ namespace Godot.SourceGenerators
|
||||
Common.ReportSignalDelegateSignatureMustReturnVoid(context, signalDelegateSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -257,14 +258,14 @@ namespace Godot.SourceGenerators
|
||||
{
|
||||
source.Append(
|
||||
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
|
||||
source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
|
||||
source.Append("NativeVariantPtrArgs args)\n {\n");
|
||||
|
||||
foreach (var signal in godotSignalDelegates)
|
||||
{
|
||||
GenerateSignalEventInvoker(signal, source);
|
||||
}
|
||||
|
||||
source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
|
||||
source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
@ -404,7 +405,7 @@ namespace Godot.SourceGenerators
|
||||
|
||||
source.Append(" if (signal == SignalName.");
|
||||
source.Append(signalName);
|
||||
source.Append(" && argCount == ");
|
||||
source.Append(" && args.Count == ");
|
||||
source.Append(invokeMethodData.ParamTypes.Length);
|
||||
source.Append(") {\n");
|
||||
source.Append(" backing_");
|
||||
|
@ -1614,7 +1614,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||
|
||||
output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
|
||||
<< " bool " CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(in godot_string_name method, "
|
||||
<< "NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n"
|
||||
<< "NativeVariantPtrArgs args, out godot_variant ret)\n"
|
||||
<< INDENT1 "{\n";
|
||||
|
||||
for (const MethodInterface &imethod : itype.methods) {
|
||||
@ -1630,7 +1630,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||
// We check both native names (snake_case) and proxy names (PascalCase)
|
||||
output << INDENT2 "if ((method == " << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name
|
||||
<< " || method == MethodName." << imethod.proxy_name
|
||||
<< ") && argCount == " << itos(imethod.arguments.size())
|
||||
<< ") && args.Count == " << itos(imethod.arguments.size())
|
||||
<< " && " << CS_METHOD_HAS_GODOT_CLASS_METHOD << "((godot_string_name)"
|
||||
<< CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name << ".NativeValue))\n"
|
||||
<< INDENT2 "{\n";
|
||||
@ -1682,7 +1682,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
||||
}
|
||||
|
||||
if (is_derived_type) {
|
||||
output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, argCount, out ret);\n";
|
||||
output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, out ret);\n";
|
||||
} else {
|
||||
output << INDENT2 "ret = default;\n"
|
||||
<< INDENT2 "return false;\n";
|
||||
@ -2200,6 +2200,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
||||
|
||||
Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output) {
|
||||
String arguments_sig;
|
||||
String delegate_type_params;
|
||||
|
||||
if (!p_isignal.arguments.is_empty()) {
|
||||
delegate_type_params += "<";
|
||||
}
|
||||
|
||||
// Retrieve information from the arguments
|
||||
const ArgumentInterface &first = p_isignal.arguments.front()->get();
|
||||
@ -2220,11 +2225,18 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
||||
|
||||
if (&iarg != &first) {
|
||||
arguments_sig += ", ";
|
||||
delegate_type_params += ", ";
|
||||
}
|
||||
|
||||
arguments_sig += arg_type->cs_type;
|
||||
arguments_sig += " ";
|
||||
arguments_sig += iarg.name;
|
||||
|
||||
delegate_type_params += arg_type->cs_type;
|
||||
}
|
||||
|
||||
if (!p_isignal.arguments.is_empty()) {
|
||||
delegate_type_params += ">";
|
||||
}
|
||||
|
||||
// Generate signal
|
||||
@ -2248,15 +2260,46 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
||||
p_output.append("\")]");
|
||||
}
|
||||
|
||||
String delegate_name = p_isignal.proxy_name;
|
||||
delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
|
||||
bool is_parameterless = p_isignal.arguments.size() == 0;
|
||||
|
||||
// Generate delegate
|
||||
p_output.append(MEMBER_BEGIN "public delegate void ");
|
||||
p_output.append(delegate_name);
|
||||
p_output.append("(");
|
||||
p_output.append(arguments_sig);
|
||||
p_output.append(");\n");
|
||||
// Delegate name is [SignalName]EventHandler
|
||||
String delegate_name = is_parameterless ? "Action" : p_isignal.proxy_name + "EventHandler";
|
||||
|
||||
if (!is_parameterless) {
|
||||
// Generate delegate
|
||||
p_output.append(MEMBER_BEGIN "public delegate void ");
|
||||
p_output.append(delegate_name);
|
||||
p_output.append("(");
|
||||
p_output.append(arguments_sig);
|
||||
p_output.append(");\n");
|
||||
|
||||
// Generate Callable trampoline for the delegate
|
||||
p_output << MEMBER_BEGIN "private static unsafe void " << p_isignal.proxy_name << "Trampoline"
|
||||
<< "(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)\n"
|
||||
<< INDENT1 "{\n"
|
||||
<< INDENT2 "Callable.ThrowIfArgCountMismatch(args, " << itos(p_isignal.arguments.size()) << ");\n"
|
||||
<< INDENT2 "((" << delegate_name << ")delegateObj)(";
|
||||
|
||||
int idx = 0;
|
||||
for (const ArgumentInterface &iarg : p_isignal.arguments) {
|
||||
const TypeInterface *arg_type = _get_type_or_null(iarg.type);
|
||||
ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
|
||||
|
||||
if (idx != 0) {
|
||||
p_output << ",";
|
||||
}
|
||||
|
||||
// TODO: We don't need to use VariantConversionCallbacks. We have the type information so we can use [cs_variant_to_managed] and [cs_managed_to_variant].
|
||||
p_output << "\n" INDENT3 "VariantConversionCallbacks.GetToManagedCallback<"
|
||||
<< arg_type->cs_type << ">()(args[" << itos(idx) << "])";
|
||||
|
||||
idx++;
|
||||
}
|
||||
|
||||
p_output << ");\n"
|
||||
<< INDENT2 "ret = default;\n"
|
||||
<< INDENT1 "}\n";
|
||||
}
|
||||
|
||||
if (p_isignal.method_doc && p_isignal.method_doc->description.size()) {
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype);
|
||||
@ -2292,6 +2335,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
||||
p_output.append("static ");
|
||||
}
|
||||
|
||||
if (!is_parameterless) {
|
||||
// `unsafe` is needed for taking the trampoline's function pointer
|
||||
p_output << "unsafe ";
|
||||
}
|
||||
|
||||
p_output.append("event ");
|
||||
p_output.append(delegate_name);
|
||||
p_output.append(" ");
|
||||
@ -2304,8 +2352,13 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
||||
p_output.append("add => Connect(SignalName.");
|
||||
}
|
||||
|
||||
p_output.append(p_isignal.proxy_name);
|
||||
p_output.append(", new Callable(value));\n");
|
||||
if (is_parameterless) {
|
||||
// Delegate type is Action. No need for custom trampoline.
|
||||
p_output << p_isignal.proxy_name << ", Callable.From(value));\n";
|
||||
} else {
|
||||
p_output << p_isignal.proxy_name
|
||||
<< ", Callable.CreateWithUnsafeTrampoline(value, &" << p_isignal.proxy_name << "Trampoline));\n";
|
||||
}
|
||||
|
||||
if (p_itype.is_singleton) {
|
||||
p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(SignalName.");
|
||||
@ -2313,8 +2366,14 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
|
||||
p_output.append(INDENT2 "remove => Disconnect(SignalName.");
|
||||
}
|
||||
|
||||
p_output.append(p_isignal.proxy_name);
|
||||
p_output.append(", new Callable(value));\n");
|
||||
if (is_parameterless) {
|
||||
// Delegate type is Action. No need for custom trampoline.
|
||||
p_output << p_isignal.proxy_name << ", Callable.From(value));\n";
|
||||
} else {
|
||||
p_output << p_isignal.proxy_name
|
||||
<< ", Callable.CreateWithUnsafeTrampoline(value, &" << p_isignal.proxy_name << "Trampoline));\n";
|
||||
}
|
||||
|
||||
p_output.append(CLOSE_BLOCK_L1);
|
||||
}
|
||||
|
||||
|
@ -489,25 +489,37 @@ namespace Godot.Collections
|
||||
ICollection<T>,
|
||||
IEnumerable<T>
|
||||
{
|
||||
private static godot_variant ToVariantFunc(in Array<T> godotArray) =>
|
||||
VariantUtils.CreateFromArray(godotArray);
|
||||
|
||||
private static Array<T> FromVariantFunc(in godot_variant variant) =>
|
||||
VariantUtils.ConvertToArrayObject<T>(variant);
|
||||
|
||||
// ReSharper disable StaticMemberInGenericType
|
||||
// Warning is about unique static fields being created for each generic type combination:
|
||||
// https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
|
||||
// In our case this is exactly what we want.
|
||||
|
||||
private static unsafe delegate* managed<in T, godot_variant> _convertToVariantCallback;
|
||||
private static unsafe delegate* managed<in godot_variant, T> _convertToManagedCallback;
|
||||
private static readonly unsafe delegate* managed<in T, godot_variant> ConvertToVariantCallback;
|
||||
private static readonly unsafe delegate* managed<in godot_variant, T> ConvertToManagedCallback;
|
||||
|
||||
// ReSharper restore StaticMemberInGenericType
|
||||
|
||||
static unsafe Array()
|
||||
{
|
||||
_convertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
|
||||
_convertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
|
||||
VariantConversionCallbacks.GenericConversionCallbacks[typeof(Array<T>)] =
|
||||
(
|
||||
(IntPtr)(delegate* managed<in Array<T>, godot_variant>)&ToVariantFunc,
|
||||
(IntPtr)(delegate* managed<in godot_variant, Array<T>>)&FromVariantFunc
|
||||
);
|
||||
|
||||
ConvertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
|
||||
ConvertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
|
||||
}
|
||||
|
||||
private static unsafe void ValidateVariantConversionCallbacks()
|
||||
{
|
||||
if (_convertToVariantCallback == null || _convertToManagedCallback == null)
|
||||
if (ConvertToVariantCallback == null || ConvertToManagedCallback == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
|
||||
@ -653,7 +665,7 @@ namespace Godot.Collections
|
||||
get
|
||||
{
|
||||
_underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
|
||||
return _convertToManagedCallback(borrowElem);
|
||||
return ConvertToManagedCallback(borrowElem);
|
||||
}
|
||||
set
|
||||
{
|
||||
@ -663,7 +675,7 @@ namespace Godot.Collections
|
||||
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
|
||||
godot_variant* itemPtr = &ptrw[index];
|
||||
(*itemPtr).Dispose();
|
||||
*itemPtr = _convertToVariantCallback(value);
|
||||
*itemPtr = ConvertToVariantCallback(value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,7 +687,7 @@ namespace Godot.Collections
|
||||
/// <returns>The index of the item, or -1 if not found.</returns>
|
||||
public unsafe int IndexOf(T item)
|
||||
{
|
||||
using var variantValue = _convertToVariantCallback(item);
|
||||
using var variantValue = ConvertToVariantCallback(item);
|
||||
var self = (godot_array)_underlyingArray.NativeValue;
|
||||
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
|
||||
}
|
||||
@ -693,7 +705,7 @@ namespace Godot.Collections
|
||||
if (index < 0 || index > Count)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
using var variantValue = _convertToVariantCallback(item);
|
||||
using var variantValue = ConvertToVariantCallback(item);
|
||||
var self = (godot_array)_underlyingArray.NativeValue;
|
||||
NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
|
||||
}
|
||||
@ -726,7 +738,7 @@ namespace Godot.Collections
|
||||
/// <returns>The new size after adding the item.</returns>
|
||||
public unsafe void Add(T item)
|
||||
{
|
||||
using var variantValue = _convertToVariantCallback(item);
|
||||
using var variantValue = ConvertToVariantCallback(item);
|
||||
var self = (godot_array)_underlyingArray.NativeValue;
|
||||
_ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
|
||||
}
|
||||
|
@ -22,8 +22,7 @@ namespace Godot.Bridge
|
||||
}
|
||||
|
||||
bool methodInvoked = godotObject.InvokeGodotClassMethod(CustomUnsafe.AsRef(method),
|
||||
new NativeVariantPtrArgs(args),
|
||||
argCount, out godot_variant retValue);
|
||||
new NativeVariantPtrArgs(args, argCount), out godot_variant retValue);
|
||||
|
||||
if (!methodInvoked)
|
||||
{
|
||||
@ -102,7 +101,7 @@ namespace Godot.Bridge
|
||||
return godot_bool.False;
|
||||
}
|
||||
|
||||
*outRet = Marshaling.ConvertManagedObjectToVariant(ret);
|
||||
*outRet = ret.CopyNativeVariant();
|
||||
return godot_bool.True;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -9,7 +9,7 @@ namespace Godot.Bridge
|
||||
{
|
||||
// @formatter:off
|
||||
public delegate* unmanaged<IntPtr, godot_variant**, int, godot_bool*, void> SignalAwaiter_SignalCallback;
|
||||
public delegate* unmanaged<IntPtr, godot_variant**, uint, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
|
||||
public delegate* unmanaged<IntPtr, void*, godot_variant**, int, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
|
||||
public delegate* unmanaged<IntPtr, godot_array*, godot_bool> DelegateUtils_TrySerializeDelegateWithGCHandle;
|
||||
public delegate* unmanaged<godot_array*, IntPtr*, godot_bool> DelegateUtils_TryDeserializeDelegateWithGCHandle;
|
||||
|
@ -339,7 +339,7 @@ namespace Godot.Bridge
|
||||
*outOwnerIsNull = godot_bool.False;
|
||||
|
||||
owner.RaiseGodotClassSignalCallbacks(CustomUnsafe.AsRef(eventSignalName),
|
||||
new NativeVariantPtrArgs(args), argCount);
|
||||
new NativeVariantPtrArgs(args, argCount));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -26,11 +26,12 @@ namespace Godot
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public readonly struct Callable
|
||||
public readonly partial struct Callable
|
||||
{
|
||||
private readonly Object _target;
|
||||
private readonly StringName _method;
|
||||
private readonly Delegate _delegate;
|
||||
private readonly unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> _trampoline;
|
||||
|
||||
/// <summary>
|
||||
/// Object that contains the method.
|
||||
@ -48,10 +49,10 @@ namespace Godot
|
||||
public Delegate Delegate => _delegate;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="Delegate"/> to a <see cref="Callable"/>.
|
||||
/// Trampoline function pointer for dynamically invoking <see cref="Callable.Delegate"/>.
|
||||
/// </summary>
|
||||
/// <param name="delegate">The delegate to convert.</param>
|
||||
public static implicit operator Callable(Delegate @delegate) => new Callable(@delegate);
|
||||
public unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> Trampoline
|
||||
=> _trampoline;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="Callable"/> for the method called <paramref name="method"/>
|
||||
@ -59,22 +60,21 @@ namespace Godot
|
||||
/// </summary>
|
||||
/// <param name="target">Object that contains the method.</param>
|
||||
/// <param name="method">Name of the method that will be called.</param>
|
||||
public Callable(Object target, StringName method)
|
||||
public unsafe Callable(Object target, StringName method)
|
||||
{
|
||||
_target = target;
|
||||
_method = method;
|
||||
_delegate = null;
|
||||
_trampoline = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="Callable"/> for the given <paramref name="delegate"/>.
|
||||
/// </summary>
|
||||
/// <param name="delegate">Delegate method that will be called.</param>
|
||||
public Callable(Delegate @delegate)
|
||||
private unsafe Callable(Delegate @delegate,
|
||||
delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
|
||||
{
|
||||
_target = @delegate?.Target as Object;
|
||||
_method = null;
|
||||
_delegate = @delegate;
|
||||
_trampoline = trampoline;
|
||||
}
|
||||
|
||||
private const int VarArgsSpanThreshold = 5;
|
||||
@ -149,5 +149,59 @@ namespace Godot
|
||||
NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Constructs a new <see cref="Callable"/> using the <paramref name="trampoline"/>
|
||||
/// function pointer to dynamically invoke the given <paramref name="delegate"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The parameters passed to the <paramref name="trampoline"/> function are:
|
||||
/// </para>
|
||||
/// <list type="number">
|
||||
/// <item>
|
||||
/// <term>delegateObj</term>
|
||||
/// <description>The given <paramref name="delegate"/>, upcast to <see cref="object"/>.</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>args</term>
|
||||
/// <description>Array of <see cref="godot_variant"/> arguments.</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>ret</term>
|
||||
/// <description>Return value of type <see cref="godot_variant"/>.</description>
|
||||
/// </item>
|
||||
///</list>
|
||||
/// <para>
|
||||
/// The delegate should be downcast to a more specific delegate type before invoking.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Usage example:
|
||||
///
|
||||
/// <code>
|
||||
/// static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
/// {
|
||||
/// if (args.Count != 1)
|
||||
/// throw new ArgumentException($"Callable expected {1} arguments but received {args.Count}.");
|
||||
///
|
||||
/// TResult res = ((Func<int, string>)delegateObj)(
|
||||
/// VariantConversionCallbacks.GetToManagedCallback<int>()(args[0])
|
||||
/// );
|
||||
///
|
||||
/// ret = VariantConversionCallbacks.GetToVariantCallback<string>()(res);
|
||||
/// }
|
||||
///
|
||||
/// var callable = Callable.CreateWithUnsafeTrampoline((int num) => "foo" + num.ToString(), &Trampoline);
|
||||
/// var res = (string)callable.Call(10);
|
||||
/// Console.WriteLine(res);
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <param name="delegate">Delegate method that will be called.</param>
|
||||
/// <param name="trampoline">Trampoline function pointer for invoking the delegate.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe Callable CreateWithUnsafeTrampoline(Delegate @delegate,
|
||||
delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
|
||||
=> new(@delegate, trampoline);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,480 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace Godot;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public readonly partial struct Callable
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void ThrowIfArgCountMismatch(NativeVariantPtrArgs args, int countExpected,
|
||||
[CallerArgumentExpression("args")] string? paramName = null)
|
||||
{
|
||||
if (countExpected != args.Count)
|
||||
ThrowArgCountMismatch(countExpected, args.Count, paramName);
|
||||
|
||||
static void ThrowArgCountMismatch(int countExpected, int countReceived, string? paramName)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Invalid argument count for invoking callable." +
|
||||
$" Expected {countExpected} arguments, received {countReceived}.",
|
||||
paramName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="Callable"/> for the given <paramref name="action"/>.
|
||||
/// </summary>
|
||||
/// <param name="action">Action method that will be called.</param>
|
||||
public static unsafe Callable From(
|
||||
Action action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 0);
|
||||
|
||||
((Action)delegateObj)();
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0>(
|
||||
Action<T0> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 1);
|
||||
|
||||
((Action<T0>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1>(
|
||||
Action<T0, T1> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 2);
|
||||
|
||||
((Action<T0, T1>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2>(
|
||||
Action<T0, T1, T2> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 3);
|
||||
|
||||
((Action<T0, T1, T2>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3>(
|
||||
Action<T0, T1, T2, T3> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 4);
|
||||
|
||||
((Action<T0, T1, T2, T3>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4>(
|
||||
Action<T0, T1, T2, T3, T4> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 5);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5>(
|
||||
Action<T0, T1, T2, T3, T4, T5> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 6);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6>(
|
||||
Action<T0, T1, T2, T3, T4, T5, T6> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 7);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5, T6>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7>(
|
||||
Action<T0, T1, T2, T3, T4, T5, T6, T7> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 8);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5, T6, T7>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From(Action)"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8>(
|
||||
Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> action
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 9);
|
||||
|
||||
((Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
|
||||
);
|
||||
|
||||
ret = default;
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(action, &Trampoline);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new <see cref="Callable"/> for the given <paramref name="func"/>.
|
||||
/// </summary>
|
||||
/// <param name="func">Action method that will be called.</param>
|
||||
public static unsafe Callable From<TResult>(
|
||||
Func<TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 0);
|
||||
|
||||
TResult res = ((Func<TResult>)delegateObj)();
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, TResult>(
|
||||
Func<T0, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 1);
|
||||
|
||||
TResult res = ((Func<T0, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, TResult>(
|
||||
Func<T0, T1, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 2);
|
||||
|
||||
TResult res = ((Func<T0, T1, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, TResult>(
|
||||
Func<T0, T1, T2, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 3);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, TResult>(
|
||||
Func<T0, T1, T2, T3, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 4);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, TResult>(
|
||||
Func<T0, T1, T2, T3, T4, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 5);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, TResult>(
|
||||
Func<T0, T1, T2, T3, T4, T5, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 6);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, TResult>(
|
||||
Func<T0, T1, T2, T3, T4, T5, T6, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 7);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, TResult>(
|
||||
Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 8);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="From{TResult}(Func{TResult})"/>
|
||||
public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
|
||||
Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult> func
|
||||
)
|
||||
{
|
||||
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
|
||||
{
|
||||
ThrowIfArgCountMismatch(args, 9);
|
||||
|
||||
TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>)delegateObj)(
|
||||
VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
|
||||
VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
|
||||
);
|
||||
|
||||
ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
|
||||
}
|
||||
|
||||
return CreateWithUnsafeTrampoline(func, &Trampoline);
|
||||
}
|
||||
}
|
@ -30,33 +30,23 @@ namespace Godot
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
|
||||
godot_variant* outRet)
|
||||
internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, void* trampoline,
|
||||
godot_variant** args, int argc, godot_variant* outRet)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: Optimize
|
||||
if (trampoline == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(trampoline),
|
||||
"Cannot dynamically invoke delegate because the trampoline is null.");
|
||||
}
|
||||
|
||||
var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
|
||||
var managedArgs = new object?[argc];
|
||||
var trampolineFn = (delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void>)trampoline;
|
||||
|
||||
var parameterInfos = @delegate.Method.GetParameters();
|
||||
var paramsLength = parameterInfos.Length;
|
||||
trampolineFn(@delegate, new NativeVariantPtrArgs(args, argc), out godot_variant ret);
|
||||
|
||||
if (argc != paramsLength)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The delegate expects {paramsLength} arguments, but received {argc}.");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < argc; i++)
|
||||
{
|
||||
managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
|
||||
*args[i], parameterInfos[i].ParameterType);
|
||||
}
|
||||
|
||||
object? invokeRet = @delegate.DynamicInvoke(managedArgs);
|
||||
|
||||
*outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet);
|
||||
*outRet = ret;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -356,35 +356,47 @@ namespace Godot.Collections
|
||||
IDictionary<TKey, TValue>,
|
||||
IReadOnlyDictionary<TKey, TValue>
|
||||
{
|
||||
private static godot_variant ToVariantFunc(in Dictionary<TKey, TValue> godotDictionary) =>
|
||||
VariantUtils.CreateFromDictionary(godotDictionary);
|
||||
|
||||
private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) =>
|
||||
VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant);
|
||||
|
||||
// ReSharper disable StaticMemberInGenericType
|
||||
// Warning is about unique static fields being created for each generic type combination:
|
||||
// https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
|
||||
// In our case this is exactly what we want.
|
||||
|
||||
private static unsafe delegate* managed<in TKey, godot_variant> _convertKeyToVariantCallback;
|
||||
private static unsafe delegate* managed<in godot_variant, TKey> _convertKeyToManagedCallback;
|
||||
private static unsafe delegate* managed<in TValue, godot_variant> _convertValueToVariantCallback;
|
||||
private static unsafe delegate* managed<in godot_variant, TValue> _convertValueToManagedCallback;
|
||||
private static readonly unsafe delegate* managed<in TKey, godot_variant> ConvertKeyToVariantCallback;
|
||||
private static readonly unsafe delegate* managed<in godot_variant, TKey> ConvertKeyToManagedCallback;
|
||||
private static readonly unsafe delegate* managed<in TValue, godot_variant> ConvertValueToVariantCallback;
|
||||
private static readonly unsafe delegate* managed<in godot_variant, TValue> ConvertValueToManagedCallback;
|
||||
|
||||
// ReSharper restore StaticMemberInGenericType
|
||||
|
||||
static unsafe Dictionary()
|
||||
{
|
||||
_convertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
|
||||
_convertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
|
||||
_convertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
|
||||
_convertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
|
||||
VariantConversionCallbacks.GenericConversionCallbacks[typeof(Dictionary<TKey, TValue>)] =
|
||||
(
|
||||
(IntPtr)(delegate* managed<in Dictionary<TKey, TValue>, godot_variant>)&ToVariantFunc,
|
||||
(IntPtr)(delegate* managed<in godot_variant, Dictionary<TKey, TValue>>)&FromVariantFunc
|
||||
);
|
||||
|
||||
ConvertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
|
||||
ConvertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
|
||||
ConvertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
|
||||
ConvertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
|
||||
}
|
||||
|
||||
private static unsafe void ValidateVariantConversionCallbacks()
|
||||
{
|
||||
if (_convertKeyToVariantCallback == null || _convertKeyToManagedCallback == null)
|
||||
if (ConvertKeyToVariantCallback == null || ConvertKeyToManagedCallback == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'.");
|
||||
}
|
||||
|
||||
if (_convertValueToVariantCallback == null || _convertValueToManagedCallback == null)
|
||||
if (ConvertValueToVariantCallback == null || ConvertValueToManagedCallback == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
|
||||
@ -473,14 +485,14 @@ namespace Godot.Collections
|
||||
{
|
||||
get
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
|
||||
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
|
||||
variantKey, out godot_variant value).ToBool())
|
||||
{
|
||||
using (value)
|
||||
return _convertValueToManagedCallback(value);
|
||||
return ConvertValueToManagedCallback(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -489,8 +501,8 @@ namespace Godot.Collections
|
||||
}
|
||||
set
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(key);
|
||||
using var variantValue = _convertValueToVariantCallback(value);
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
using var variantValue = ConvertValueToVariantCallback(value);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
NativeFuncs.godotsharp_dictionary_set_value(ref self,
|
||||
variantKey, variantValue);
|
||||
@ -539,8 +551,8 @@ namespace Godot.Collections
|
||||
using (value)
|
||||
{
|
||||
return new KeyValuePair<TKey, TValue>(
|
||||
_convertKeyToManagedCallback(key),
|
||||
_convertValueToManagedCallback(value));
|
||||
ConvertKeyToManagedCallback(key),
|
||||
ConvertValueToManagedCallback(value));
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,13 +564,13 @@ namespace Godot.Collections
|
||||
/// <param name="value">The object to add.</param>
|
||||
public unsafe void Add(TKey key, TValue value)
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
|
||||
if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
|
||||
throw new ArgumentException("An element with the same key already exists.", nameof(key));
|
||||
|
||||
using var variantValue = _convertValueToVariantCallback(value);
|
||||
using var variantValue = ConvertValueToVariantCallback(value);
|
||||
NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
|
||||
}
|
||||
|
||||
@ -569,7 +581,7 @@ namespace Godot.Collections
|
||||
/// <returns>Whether or not this dictionary contains the given key.</returns>
|
||||
public unsafe bool ContainsKey(TKey key)
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
|
||||
}
|
||||
@ -580,7 +592,7 @@ namespace Godot.Collections
|
||||
/// <param name="key">The key of the element to remove.</param>
|
||||
public unsafe bool Remove(TKey key)
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
|
||||
}
|
||||
@ -593,13 +605,13 @@ namespace Godot.Collections
|
||||
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
|
||||
public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
|
||||
variantKey, out godot_variant retValue).ToBool();
|
||||
|
||||
using (retValue)
|
||||
value = found ? _convertValueToManagedCallback(retValue) : default;
|
||||
value = found ? ConvertValueToManagedCallback(retValue) : default;
|
||||
|
||||
return found;
|
||||
}
|
||||
@ -625,7 +637,7 @@ namespace Godot.Collections
|
||||
|
||||
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(item.Key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(item.Key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
|
||||
variantKey, out godot_variant retValue).ToBool();
|
||||
@ -635,7 +647,7 @@ namespace Godot.Collections
|
||||
if (!found)
|
||||
return false;
|
||||
|
||||
using var variantValue = _convertValueToVariantCallback(item.Value);
|
||||
using var variantValue = ConvertValueToVariantCallback(item.Value);
|
||||
return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
|
||||
}
|
||||
}
|
||||
@ -670,7 +682,7 @@ namespace Godot.Collections
|
||||
|
||||
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
using var variantKey = _convertKeyToVariantCallback(item.Key);
|
||||
using var variantKey = ConvertKeyToVariantCallback(item.Key);
|
||||
var self = (godot_dictionary)_underlyingDict.NativeValue;
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
|
||||
variantKey, out godot_variant retValue).ToBool();
|
||||
@ -680,7 +692,7 @@ namespace Godot.Collections
|
||||
if (!found)
|
||||
return false;
|
||||
|
||||
using var variantValue = _convertValueToVariantCallback(item.Value);
|
||||
using var variantValue = ConvertValueToVariantCallback(item.Value);
|
||||
if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
|
||||
{
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(
|
||||
@ -717,6 +729,7 @@ namespace Godot.Collections
|
||||
public static implicit operator Variant(Dictionary<TKey, TValue> from) => Variant.CreateFrom(from);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator Dictionary<TKey, TValue>(Variant from) => from.AsGodotDictionary<TKey, TValue>();
|
||||
public static explicit operator Dictionary<TKey, TValue>(Variant from) =>
|
||||
from.AsGodotDictionary<TKey, TValue>();
|
||||
}
|
||||
}
|
||||
|
@ -721,10 +721,19 @@ namespace Godot.NativeInterop
|
||||
if (p_managed_callable.Delegate != null)
|
||||
{
|
||||
var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate);
|
||||
IntPtr objectPtr = p_managed_callable.Target != null ? Object.GetPtr(p_managed_callable.Target) : IntPtr.Zero;
|
||||
NativeFuncs.godotsharp_callable_new_with_delegate(
|
||||
GCHandle.ToIntPtr(gcHandle), objectPtr, out godot_callable callable);
|
||||
return callable;
|
||||
|
||||
IntPtr objectPtr = p_managed_callable.Target != null ?
|
||||
Object.GetPtr(p_managed_callable.Target) :
|
||||
IntPtr.Zero;
|
||||
|
||||
unsafe
|
||||
{
|
||||
NativeFuncs.godotsharp_callable_new_with_delegate(
|
||||
GCHandle.ToIntPtr(gcHandle), (IntPtr)p_managed_callable.Trampoline,
|
||||
objectPtr, out godot_callable callable);
|
||||
|
||||
return callable;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -748,19 +757,22 @@ namespace Godot.NativeInterop
|
||||
public static Callable ConvertCallableToManaged(in godot_callable p_callable)
|
||||
{
|
||||
if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(p_callable,
|
||||
out IntPtr delegateGCHandle, out IntPtr godotObject,
|
||||
out godot_string_name name).ToBool())
|
||||
out IntPtr delegateGCHandle, out IntPtr trampoline,
|
||||
out IntPtr godotObject, out godot_string_name name).ToBool())
|
||||
{
|
||||
if (delegateGCHandle != IntPtr.Zero)
|
||||
{
|
||||
return new Callable((Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Callable(
|
||||
InteropUtils.UnmanagedGetManaged(godotObject),
|
||||
StringName.CreateTakingOwnershipOfDisposableValue(name));
|
||||
unsafe
|
||||
{
|
||||
return Callable.CreateWithUnsafeTrampoline(
|
||||
(Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target,
|
||||
(delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void>)trampoline);
|
||||
}
|
||||
}
|
||||
|
||||
return new Callable(
|
||||
InteropUtils.UnmanagedGetManaged(godotObject),
|
||||
StringName.CreateTakingOwnershipOfDisposableValue(name));
|
||||
}
|
||||
|
||||
// Some other unsupported callable
|
||||
|
@ -141,11 +141,11 @@ namespace Godot.NativeInterop
|
||||
public static partial void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest,
|
||||
in godot_string p_element);
|
||||
|
||||
public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_object,
|
||||
out godot_callable r_callable);
|
||||
public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_trampoline,
|
||||
IntPtr p_object, out godot_callable r_callable);
|
||||
|
||||
internal static partial godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable,
|
||||
out IntPtr r_delegate_handle, out IntPtr r_object, out godot_string_name r_name);
|
||||
out IntPtr r_delegate_handle, out IntPtr r_trampoline, out IntPtr r_object, out godot_string_name r_name);
|
||||
|
||||
internal static partial godot_variant godotsharp_callable_call(in godot_callable p_callable,
|
||||
godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
|
||||
|
@ -8,8 +8,22 @@ namespace Godot.NativeInterop
|
||||
public unsafe ref struct NativeVariantPtrArgs
|
||||
{
|
||||
private godot_variant** _args;
|
||||
private int _argc;
|
||||
|
||||
internal NativeVariantPtrArgs(godot_variant** args) => _args = args;
|
||||
internal NativeVariantPtrArgs(godot_variant** args, int argc)
|
||||
{
|
||||
_args = args;
|
||||
_argc = argc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of arguments.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _argc;
|
||||
}
|
||||
|
||||
public ref godot_variant this[int index]
|
||||
{
|
||||
|
@ -1,10 +1,15 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Godot.NativeInterop;
|
||||
|
||||
// TODO: Change VariantConversionCallbacks<T>. Store the callback in a static field for quick repeated access, instead of checking every time.
|
||||
internal static unsafe class VariantConversionCallbacks
|
||||
{
|
||||
internal static System.Collections.Generic.Dictionary<Type, (IntPtr ToVariant, IntPtr FromVariant)>
|
||||
GenericConversionCallbacks = new();
|
||||
|
||||
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
|
||||
internal static delegate*<in T, godot_variant> GetToVariantCallback<T>()
|
||||
{
|
||||
@ -502,6 +507,26 @@ internal static unsafe class VariantConversionCallbacks
|
||||
&FromVariant;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
|
||||
// We could make the Godot collections implement an interface and use IsAssignableFrom instead.
|
||||
// Or we could just skip the check and always look for a conversion callback for the type.
|
||||
if (typeOfT.IsGenericType)
|
||||
{
|
||||
var genericTypeDef = typeOfT.GetGenericTypeDefinition();
|
||||
|
||||
if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
|
||||
genericTypeDef == typeof(Godot.Collections.Array<>))
|
||||
{
|
||||
RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
|
||||
|
||||
if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
|
||||
{
|
||||
return (delegate*<in T, godot_variant>)genericConversion.ToVariant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1005,6 +1030,26 @@ internal static unsafe class VariantConversionCallbacks
|
||||
&ToVariant;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
|
||||
// We could make the Godot collections implement an interface and use IsAssignableFrom instead.
|
||||
// Or we could just skip the check and always look for a conversion callback for the type.
|
||||
if (typeOfT.IsGenericType)
|
||||
{
|
||||
var genericTypeDef = typeOfT.GetGenericTypeDefinition();
|
||||
|
||||
if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
|
||||
genericTypeDef == typeof(Godot.Collections.Array<>))
|
||||
{
|
||||
RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
|
||||
|
||||
if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
|
||||
{
|
||||
return (delegate*<in godot_variant, T>)genericConversion.FromVariant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper restore RedundantCast
|
||||
|
||||
return null;
|
||||
|
@ -202,7 +202,7 @@ namespace Godot
|
||||
|
||||
// ReSharper disable once VirtualMemberNeverOverridden.Global
|
||||
protected internal virtual void RaiseGodotClassSignalCallbacks(in godot_string_name signal,
|
||||
NativeVariantPtrArgs args, int argCount)
|
||||
NativeVariantPtrArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,7 @@
|
||||
<Compile Include="Core\AABB.cs" />
|
||||
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
|
||||
<Compile Include="Core\Bridge\MethodInfo.cs" />
|
||||
<Compile Include="Core\Callable.generics.cs" />
|
||||
<Compile Include="Core\CustomGCHandle.cs" />
|
||||
<Compile Include="Core\Array.cs" />
|
||||
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
|
||||
|
@ -447,15 +447,16 @@ void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String
|
||||
r_dest->append(*p_element);
|
||||
}
|
||||
|
||||
void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, const Object *p_object, Callable *r_callable) {
|
||||
void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, void *p_trampoline,
|
||||
const Object *p_object, Callable *r_callable) {
|
||||
// TODO: Use pooling for ManagedCallable instances.
|
||||
ObjectID objid = p_object ? p_object->get_instance_id() : ObjectID();
|
||||
CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle, objid));
|
||||
CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle, p_trampoline, objid));
|
||||
memnew_placement(r_callable, Callable(managed_callable));
|
||||
}
|
||||
|
||||
bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
|
||||
GCHandleIntPtr *r_delegate_handle, Object **r_object, StringName *r_name) {
|
||||
GCHandleIntPtr *r_delegate_handle, void **r_trampoline, Object **r_object, StringName *r_name) {
|
||||
if (p_callable->is_custom()) {
|
||||
CallableCustom *custom = p_callable->get_custom();
|
||||
CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
|
||||
@ -463,18 +464,21 @@ bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
|
||||
if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
|
||||
ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
|
||||
*r_delegate_handle = managed_callable->get_delegate();
|
||||
*r_trampoline = managed_callable->get_trampoline();
|
||||
*r_object = nullptr;
|
||||
memnew_placement(r_name, StringName());
|
||||
return true;
|
||||
} else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
|
||||
SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
|
||||
*r_delegate_handle = { nullptr };
|
||||
*r_trampoline = nullptr;
|
||||
*r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object());
|
||||
memnew_placement(r_name, StringName(signal_awaiter_callable->get_signal()));
|
||||
return true;
|
||||
} else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
|
||||
EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
|
||||
*r_delegate_handle = { nullptr };
|
||||
*r_trampoline = nullptr;
|
||||
*r_object = ObjectDB::get_instance(event_signal_callable->get_object());
|
||||
memnew_placement(r_name, StringName(event_signal_callable->get_signal()));
|
||||
return true;
|
||||
@ -482,11 +486,13 @@ bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
|
||||
|
||||
// Some other CallableCustom. We only support ManagedCallable.
|
||||
*r_delegate_handle = { nullptr };
|
||||
*r_trampoline = nullptr;
|
||||
*r_object = nullptr;
|
||||
memnew_placement(r_name, StringName());
|
||||
return false;
|
||||
} else {
|
||||
*r_delegate_handle = { nullptr };
|
||||
*r_trampoline = nullptr;
|
||||
*r_object = ObjectDB::get_instance(p_callable->get_object_id());
|
||||
memnew_placement(r_name, StringName(p_callable->get_method()));
|
||||
return true;
|
||||
|
@ -92,7 +92,7 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
|
||||
ERR_FAIL_COND(delegate_handle.value == nullptr);
|
||||
|
||||
GDMonoCache::managed_callbacks.DelegateUtils_InvokeWithVariantArgs(
|
||||
delegate_handle, p_arguments, p_argcount, &r_return_value);
|
||||
delegate_handle, trampoline, p_arguments, p_argcount, &r_return_value);
|
||||
|
||||
r_call_error.error = Callable::CallError::CALL_OK;
|
||||
}
|
||||
@ -106,7 +106,8 @@ void ManagedCallable::release_delegate_handle() {
|
||||
|
||||
// Why you do this clang-format...
|
||||
/* clang-format off */
|
||||
ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id) : delegate_handle(p_delegate_handle), object_id(p_object_id) {
|
||||
ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle, void *p_trampoline, ObjectID p_object_id) :
|
||||
delegate_handle(p_delegate_handle), trampoline(p_trampoline), object_id(p_object_id) {
|
||||
#ifdef GD_MONO_HOT_RELOAD
|
||||
{
|
||||
MutexLock lock(instances_mutex);
|
||||
|
@ -40,6 +40,7 @@
|
||||
class ManagedCallable : public CallableCustom {
|
||||
friend class CSharpLanguage;
|
||||
GCHandleIntPtr delegate_handle;
|
||||
void *trampoline = nullptr;
|
||||
ObjectID object_id;
|
||||
|
||||
#ifdef GD_MONO_HOT_RELOAD
|
||||
@ -58,6 +59,7 @@ public:
|
||||
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||
|
||||
_FORCE_INLINE_ GCHandleIntPtr get_delegate() const { return delegate_handle; }
|
||||
_FORCE_INLINE_ void *get_trampoline() const { return trampoline; }
|
||||
|
||||
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
|
||||
@ -67,7 +69,7 @@ public:
|
||||
|
||||
void release_delegate_handle();
|
||||
|
||||
ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id);
|
||||
ManagedCallable(GCHandleIntPtr p_delegate_handle, void *p_trampoline, ObjectID p_object_id);
|
||||
~ManagedCallable();
|
||||
};
|
||||
|
||||
|
@ -74,7 +74,7 @@ struct ManagedCallbacks {
|
||||
using Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add = void(GD_CLR_STDCALL *)(CSharpScript *p_script, void *p_def_vals, int32_t p_count);
|
||||
|
||||
using FuncSignalAwaiter_SignalCallback = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, int32_t, bool *);
|
||||
using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, uint32_t, const Variant *);
|
||||
using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, void *, const Variant **, int32_t, const Variant *);
|
||||
using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr);
|
||||
using FuncDelegateUtils_TrySerializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const Array *);
|
||||
using FuncDelegateUtils_TryDeserializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(const Array *, GCHandleIntPtr *);
|
||||
|
Loading…
Reference in New Issue
Block a user