You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-26 15:46:23 +00:00
C#: Begin move to .NET Core
We're targeting .NET 5 for now to make development easier while .NET 6 is not yet released. TEMPORARY REGRESSIONS --------------------- Assembly unloading is not implemented yet. As such, many Godot resources are leaked at exit. This will be re-implemented later together with assembly hot-reloading.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<LangVersion>9</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<!-- To generate the .runtimeconfig.json file-->
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GodotSharp\GodotSharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
197
modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
Normal file
197
modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace GodotPlugins
|
||||
{
|
||||
public static class Main
|
||||
{
|
||||
private static readonly List<AssemblyName> SharedAssemblies = new();
|
||||
private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
|
||||
private static Assembly? _editorApiAssembly;
|
||||
|
||||
private static readonly AssemblyLoadContext MainLoadContext =
|
||||
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
|
||||
AssemblyLoadContext.Default;
|
||||
|
||||
// Right now we do it this way for simplicity as hot-reload is disabled. It will need to be changed later.
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool Initialize(godot_bool editorHint,
|
||||
PluginsCallbacks* pluginsCallbacks, Godot.Bridge.ManagedCallbacks* managedCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
SharedAssemblies.Add(CoreApiAssembly.GetName());
|
||||
|
||||
if (editorHint.ToBool())
|
||||
{
|
||||
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
|
||||
SharedAssemblies.Add(_editorApiAssembly.GetName());
|
||||
}
|
||||
|
||||
NativeLibrary.SetDllImportResolver(CoreApiAssembly, OnResolveDllImport);
|
||||
|
||||
*pluginsCallbacks = new()
|
||||
{
|
||||
LoadProjectAssemblyCallback = &LoadProjectAssembly,
|
||||
LoadToolsAssemblyCallback = &LoadToolsAssembly,
|
||||
};
|
||||
|
||||
*managedCallbacks = Godot.Bridge.ManagedCallbacks.Create();
|
||||
|
||||
return godot_bool.True;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine(e);
|
||||
*pluginsCallbacks = default;
|
||||
*managedCallbacks = default;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct PluginsCallbacks
|
||||
{
|
||||
public unsafe delegate* unmanaged<char*, godot_bool> LoadProjectAssemblyCallback;
|
||||
public unsafe delegate* unmanaged<char*, IntPtr> LoadToolsAssemblyCallback;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string assemblyPath = new(nAssemblyPath);
|
||||
|
||||
var assembly = LoadPlugin(assemblyPath);
|
||||
|
||||
var method = CoreApiAssembly.GetType("Godot.Bridge.ScriptManagerBridge")?
|
||||
.GetMethod("LookupScriptsInAssembly",
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
throw new MissingMethodException("Godot.Bridge.ScriptManagerBridge",
|
||||
"LookupScriptsInAssembly");
|
||||
}
|
||||
|
||||
method.Invoke(null, new object[] { assembly });
|
||||
|
||||
return godot_bool.True;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe IntPtr LoadToolsAssembly(char* nAssemblyPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string assemblyPath = new(nAssemblyPath);
|
||||
|
||||
if (_editorApiAssembly == null)
|
||||
throw new InvalidOperationException("The Godot editor API assembly is not loaded");
|
||||
|
||||
var assembly = LoadPlugin(assemblyPath);
|
||||
|
||||
NativeLibrary.SetDllImportResolver(assembly, OnResolveDllImport);
|
||||
|
||||
var method = assembly.GetType("GodotTools.GodotSharpEditor")?
|
||||
.GetMethod("InternalCreateInstance",
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
throw new MissingMethodException("GodotTools.GodotSharpEditor",
|
||||
"InternalCreateInstance");
|
||||
}
|
||||
|
||||
return (IntPtr?)method.Invoke(null, null) ?? IntPtr.Zero;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine(e);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private static Assembly LoadPlugin(string assemblyPath)
|
||||
{
|
||||
string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
||||
|
||||
var sharedAssemblies = new List<string>();
|
||||
|
||||
foreach (var sharedAssembly in SharedAssemblies)
|
||||
{
|
||||
string? sharedAssemblyName = sharedAssembly.Name;
|
||||
if (sharedAssemblyName != null)
|
||||
sharedAssemblies.Add(sharedAssemblyName);
|
||||
}
|
||||
|
||||
var loadContext = new PluginLoadContext(assemblyPath, sharedAssemblies, MainLoadContext);
|
||||
return loadContext.LoadFromAssemblyName(new AssemblyName(assemblyName));
|
||||
}
|
||||
|
||||
public static IntPtr OnResolveDllImport(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||
{
|
||||
if (libraryName == "__Internal")
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return Win32.GetModuleHandle(IntPtr.Zero);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return Linux.dlopen(IntPtr.Zero, Linux.RTLD_LAZY);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return MacOS.dlopen(IntPtr.Zero, MacOS.RTLD_LAZY);
|
||||
}
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
private static class MacOS
|
||||
{
|
||||
private const string SystemLibrary = "/usr/lib/libSystem.dylib";
|
||||
|
||||
public const int RTLD_LAZY = 1;
|
||||
|
||||
[DllImport(SystemLibrary)]
|
||||
public static extern IntPtr dlopen(IntPtr path, int mode);
|
||||
}
|
||||
|
||||
private static class Linux
|
||||
{
|
||||
// libdl.so was resulting in DllNotFoundException, for some reason...
|
||||
// libcoreclr.so should work with both CoreCLR and the .NET Core version of Mono.
|
||||
private const string SystemLibrary = "libcoreclr.so";
|
||||
|
||||
public const int RTLD_LAZY = 1;
|
||||
|
||||
[DllImport(SystemLibrary)]
|
||||
public static extern IntPtr dlopen(IntPtr path, int mode);
|
||||
}
|
||||
|
||||
private static class Win32
|
||||
{
|
||||
private const string SystemLibrary = "Kernel32.dll";
|
||||
|
||||
[DllImport(SystemLibrary)]
|
||||
public static extern IntPtr GetModuleHandle(IntPtr lpModuleName);
|
||||
}
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace GodotPlugins
|
||||
{
|
||||
public class PluginLoadContext : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
private readonly ICollection<string> _sharedAssemblies;
|
||||
private readonly AssemblyLoadContext _mainLoadContext;
|
||||
|
||||
public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies,
|
||||
AssemblyLoadContext mainLoadContext)
|
||||
{
|
||||
Console.WriteLine(pluginPath);
|
||||
Console.Out.Flush();
|
||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
_sharedAssemblies = sharedAssemblies;
|
||||
_mainLoadContext = mainLoadContext;
|
||||
}
|
||||
|
||||
protected override Assembly? Load(AssemblyName assemblyName)
|
||||
{
|
||||
if (assemblyName.Name == null)
|
||||
return null;
|
||||
|
||||
if (_sharedAssemblies.Contains(assemblyName.Name))
|
||||
return _mainLoadContext.LoadFromAssemblyName(assemblyName);
|
||||
|
||||
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
|
||||
if (assemblyPath != null)
|
||||
{
|
||||
// Load in memory to prevent locking the file
|
||||
using var assemblyFile = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
string pdbPath = Path.ChangeExtension(assemblyPath, ".pdb");
|
||||
|
||||
if (File.Exists(pdbPath))
|
||||
{
|
||||
using var pdbFile = File.Open(pdbPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
return LoadFromStream(assemblyFile, pdbFile);
|
||||
}
|
||||
|
||||
return LoadFromStream(assemblyFile);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
|
||||
{
|
||||
string? libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
|
||||
if (libraryPath != null)
|
||||
return LoadUnmanagedDllFromPath(libraryPath);
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "GodotSharp\Go
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpEditor", "GodotSharpEditor\GodotSharpEditor.csproj", "{8FBEC238-D944-4074-8548-B3B524305905}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotPlugins", "GodotPlugins\GodotPlugins.csproj", "{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -18,5 +20,9 @@ Global
|
||||
{8FBEC238-D944-4074-8548-B3B524305905}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Godot.Collections
|
||||
public Array Duplicate(bool deep = false)
|
||||
{
|
||||
godot_array newArray;
|
||||
NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep, out newArray);
|
||||
NativeFuncs.godotsharp_array_duplicate(ref NativeValue, deep.ToGodotBool(), out newArray);
|
||||
return CreateTakingOwnershipOfDisposableValue(newArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,118 +6,167 @@ namespace Godot.Bridge
|
||||
{
|
||||
internal static class CSharpInstanceBridge
|
||||
{
|
||||
private static unsafe void Call(IntPtr godotObjectGCHandle, godot_string_name* method,
|
||||
godot_variant** args, int argCount, godot_variant_call_error* ref_callError, godot_variant* r_ret)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool Call(IntPtr godotObjectGCHandle, godot_string_name* method,
|
||||
godot_variant** args, int argCount, godot_variant_call_error* refCallError, godot_variant* ret)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (godotObject == null)
|
||||
try
|
||||
{
|
||||
*r_ret = default;
|
||||
(*ref_callError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
|
||||
return;
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (godotObject == null)
|
||||
{
|
||||
*ret = default;
|
||||
(*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
|
||||
using godot_string dest = default;
|
||||
NativeFuncs.godotsharp_string_name_as_string(&dest, method);
|
||||
string methodStr = Marshaling.mono_string_from_godot(dest);
|
||||
|
||||
bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant retValue);
|
||||
|
||||
if (!methodInvoked)
|
||||
{
|
||||
*ret = default;
|
||||
// This is important, as it tells Object::call that no method was called.
|
||||
// Otherwise, it would prevent Object::call from calling native methods.
|
||||
(*refCallError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
|
||||
*ret = retValue;
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
||||
using godot_string dest = default;
|
||||
NativeFuncs.godotsharp_string_name_as_string(&dest, method);
|
||||
string methodStr = Marshaling.mono_string_from_godot(dest);
|
||||
|
||||
bool methodInvoked = godotObject.InternalGodotScriptCall(methodStr, args, argCount, out godot_variant outRet);
|
||||
|
||||
if (!methodInvoked)
|
||||
catch (Exception e)
|
||||
{
|
||||
*r_ret = default;
|
||||
// This is important, as it tells Object::call that no method was called.
|
||||
// Otherwise, it would prevent Object::call from calling native methods.
|
||||
(*ref_callError).error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
|
||||
return;
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
*ret = default;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
|
||||
*r_ret = outRet;
|
||||
}
|
||||
|
||||
private static unsafe bool Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
try
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (godotObject == null)
|
||||
throw new InvalidOperationException();
|
||||
if (godotObject == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
|
||||
NativeFuncs.godotsharp_string_name_new_copy(name));
|
||||
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
|
||||
NativeFuncs.godotsharp_string_name_new_copy(name));
|
||||
|
||||
if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value))
|
||||
return true;
|
||||
if (godotObject.InternalGodotScriptSetFieldOrPropViaReflection(nameManaged.ToString(), value))
|
||||
return true.ToGodotBool();
|
||||
|
||||
object valueManaged = Marshaling.variant_to_mono_object(value);
|
||||
object valueManaged = Marshaling.variant_to_mono_object(value);
|
||||
|
||||
return godotObject._Set(nameManaged, valueManaged);
|
||||
return godotObject._Set(nameManaged, valueManaged).ToGodotBool();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe bool Get(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* r_retValue)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool Get(IntPtr godotObjectGCHandle, godot_string_name* name,
|
||||
godot_variant* outRet)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (godotObject == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
|
||||
NativeFuncs.godotsharp_string_name_new_copy(name));
|
||||
|
||||
if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
|
||||
out godot_variant outRet))
|
||||
try
|
||||
{
|
||||
*r_retValue = outRet;
|
||||
return true;
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (godotObject == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
|
||||
NativeFuncs.godotsharp_string_name_new_copy(name));
|
||||
|
||||
if (godotObject.InternalGodotScriptGetFieldOrPropViaReflection(nameManaged.ToString(),
|
||||
out godot_variant outRetValue))
|
||||
{
|
||||
*outRet = outRetValue;
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
||||
object ret = godotObject._Get(nameManaged);
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
*outRet = default;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
|
||||
*outRet = Marshaling.mono_object_to_variant(ret);
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
||||
object ret = godotObject._Get(nameManaged);
|
||||
|
||||
if (ret == null)
|
||||
catch (Exception e)
|
||||
{
|
||||
*r_retValue = default;
|
||||
return false;
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
*outRet = default;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
|
||||
*r_retValue = Marshaling.mono_object_to_variant(ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CallDispose(IntPtr godotObjectGCHandle, bool okIfNull)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void CallDispose(IntPtr godotObjectGCHandle, godot_bool okIfNull)
|
||||
{
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
try
|
||||
{
|
||||
var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (okIfNull)
|
||||
godotObject?.Dispose();
|
||||
else
|
||||
godotObject!.Dispose();
|
||||
if (okIfNull.ToBool())
|
||||
godotObject?.Dispose();
|
||||
else
|
||||
godotObject!.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void CallToString(IntPtr godotObjectGCHandle, godot_string* r_res, bool* r_valid)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void CallToString(IntPtr godotObjectGCHandle, godot_string* outRes, godot_bool* outValid)
|
||||
{
|
||||
var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (self == null)
|
||||
try
|
||||
{
|
||||
*r_res = default;
|
||||
*r_valid = false;
|
||||
return;
|
||||
var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
|
||||
|
||||
if (self == null)
|
||||
{
|
||||
*outRes = default;
|
||||
*outValid = false.ToGodotBool();
|
||||
return;
|
||||
}
|
||||
|
||||
var resultStr = self.ToString();
|
||||
|
||||
if (resultStr == null)
|
||||
{
|
||||
*outRes = default;
|
||||
*outValid = false.ToGodotBool();
|
||||
return;
|
||||
}
|
||||
|
||||
*outRes = Marshaling.mono_string_to_godot(resultStr);
|
||||
*outValid = true.ToGodotBool();
|
||||
}
|
||||
|
||||
var resultStr = self.ToString();
|
||||
|
||||
if (resultStr == null)
|
||||
catch (Exception e)
|
||||
{
|
||||
*r_res = default;
|
||||
*r_valid = false;
|
||||
return;
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
*outRes = default;
|
||||
*outValid = false.ToGodotBool();
|
||||
}
|
||||
|
||||
*r_res = Marshaling.mono_string_to_godot(resultStr);
|
||||
*r_valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace Godot.Bridge
|
||||
{
|
||||
internal static class GCHandleBridge
|
||||
{
|
||||
private static void FreeGCHandle(IntPtr gcHandlePtr)
|
||||
=> GCHandle.FromIntPtr(gcHandlePtr).Free();
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FreeGCHandle(IntPtr gcHandlePtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
GCHandle.FromIntPtr(gcHandlePtr).Free();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace Godot.Bridge
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe struct ManagedCallbacks
|
||||
{
|
||||
// @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, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
|
||||
public delegate* unmanaged<void> ScriptManagerBridge_FrameCallback;
|
||||
public delegate* unmanaged<godot_string_name*, IntPtr, IntPtr> ScriptManagerBridge_CreateManagedForGodotObjectBinding;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, godot_variant**, int, godot_bool> ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
|
||||
public delegate* unmanaged<IntPtr, godot_string_name*, void> ScriptManagerBridge_GetScriptNativeName;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, void> ScriptManagerBridge_SetGodotObjectPtr;
|
||||
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_bool*, void> ScriptManagerBridge_RaiseEventSignal;
|
||||
public delegate* unmanaged<IntPtr, godot_dictionary*, void> ScriptManagerBridge_GetScriptSignalList;
|
||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_HasScriptSignal;
|
||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool, godot_bool> ScriptManagerBridge_HasMethodUnknownParams;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> ScriptManagerBridge_ScriptIsOrInherits;
|
||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_AddScriptBridge;
|
||||
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
|
||||
public delegate* unmanaged<IntPtr, godot_bool*, godot_dictionary*, void> ScriptManagerBridge_UpdateScriptClassInfo;
|
||||
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
|
||||
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> CSharpInstanceBridge_Call;
|
||||
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Set;
|
||||
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Get;
|
||||
public delegate* unmanaged<IntPtr, godot_bool, void> CSharpInstanceBridge_CallDispose;
|
||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, void> CSharpInstanceBridge_CallToString;
|
||||
public delegate* unmanaged<IntPtr, void> GCHandleBridge_FreeGCHandle;
|
||||
public delegate* unmanaged<void> DebuggingUtils_InstallTraceListener;
|
||||
public delegate* unmanaged<void> Dispatcher_InitializeDefaultGodotTaskScheduler;
|
||||
// @formatter:on
|
||||
|
||||
public static ManagedCallbacks Create()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
// @formatter:off
|
||||
SignalAwaiter_SignalCallback = &SignalAwaiter.SignalCallback,
|
||||
DelegateUtils_InvokeWithVariantArgs = &DelegateUtils.InvokeWithVariantArgs,
|
||||
DelegateUtils_DelegateEquals = &DelegateUtils.DelegateEquals,
|
||||
ScriptManagerBridge_FrameCallback = &ScriptManagerBridge.FrameCallback,
|
||||
ScriptManagerBridge_CreateManagedForGodotObjectBinding = &ScriptManagerBridge.CreateManagedForGodotObjectBinding,
|
||||
ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance = &ScriptManagerBridge.CreateManagedForGodotObjectScriptInstance,
|
||||
ScriptManagerBridge_GetScriptNativeName = &ScriptManagerBridge.GetScriptNativeName,
|
||||
ScriptManagerBridge_SetGodotObjectPtr = &ScriptManagerBridge.SetGodotObjectPtr,
|
||||
ScriptManagerBridge_RaiseEventSignal = &ScriptManagerBridge.RaiseEventSignal,
|
||||
ScriptManagerBridge_GetScriptSignalList = &ScriptManagerBridge.GetScriptSignalList,
|
||||
ScriptManagerBridge_HasScriptSignal = &ScriptManagerBridge.HasScriptSignal,
|
||||
ScriptManagerBridge_HasMethodUnknownParams = &ScriptManagerBridge.HasMethodUnknownParams,
|
||||
ScriptManagerBridge_ScriptIsOrInherits = &ScriptManagerBridge.ScriptIsOrInherits,
|
||||
ScriptManagerBridge_AddScriptBridge = &ScriptManagerBridge.AddScriptBridge,
|
||||
ScriptManagerBridge_RemoveScriptBridge = &ScriptManagerBridge.RemoveScriptBridge,
|
||||
ScriptManagerBridge_UpdateScriptClassInfo = &ScriptManagerBridge.UpdateScriptClassInfo,
|
||||
ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType,
|
||||
CSharpInstanceBridge_Call = &CSharpInstanceBridge.Call,
|
||||
CSharpInstanceBridge_Set = &CSharpInstanceBridge.Set,
|
||||
CSharpInstanceBridge_Get = &CSharpInstanceBridge.Get,
|
||||
CSharpInstanceBridge_CallDispose = &CSharpInstanceBridge.CallDispose,
|
||||
CSharpInstanceBridge_CallToString = &CSharpInstanceBridge.CallToString,
|
||||
GCHandleBridge_FreeGCHandle = &GCHandleBridge.FreeGCHandle,
|
||||
DebuggingUtils_InstallTraceListener = &DebuggingUtils.InstallTraceListener,
|
||||
Dispatcher_InitializeDefaultGodotTaskScheduler = &Dispatcher.InitializeDefaultGodotTaskScheduler,
|
||||
// @formatter:on
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,99 +27,150 @@ namespace Godot.Bridge
|
||||
}
|
||||
};
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FrameCallback()
|
||||
{
|
||||
Dispatcher.DefaultGodotTaskScheduler?.Activate();
|
||||
try
|
||||
{
|
||||
Dispatcher.DefaultGodotTaskScheduler?.Activate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName,
|
||||
IntPtr godotObject)
|
||||
{
|
||||
Type nativeType = TypeGetProxyClass(nativeTypeName);
|
||||
var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
|
||||
try
|
||||
{
|
||||
Type nativeType = TypeGetProxyClass(nativeTypeName);
|
||||
var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
|
||||
|
||||
obj.NativePtr = godotObject;
|
||||
obj.NativePtr = godotObject;
|
||||
|
||||
var ctor = nativeType.GetConstructor(
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null, Type.EmptyTypes, null);
|
||||
_ = ctor!.Invoke(obj, null);
|
||||
var ctor = nativeType.GetConstructor(
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
|
||||
null, Type.EmptyTypes, null);
|
||||
_ = ctor!.Invoke(obj, null);
|
||||
|
||||
return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
|
||||
return GCHandle.ToIntPtr(GCHandle.Alloc(obj));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe void CreateManagedForGodotObjectScriptInstance(IntPtr scriptPtr, IntPtr godotObject,
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool CreateManagedForGodotObjectScriptInstance(IntPtr scriptPtr,
|
||||
IntPtr godotObject,
|
||||
godot_variant** args, int argCount)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
Type scriptType = _scriptBridgeMap[scriptPtr];
|
||||
var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
|
||||
|
||||
obj.NativePtr = godotObject;
|
||||
|
||||
var ctor = scriptType
|
||||
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.Where(c => c.GetParameters().Length == argCount)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (ctor == null)
|
||||
try
|
||||
{
|
||||
if (argCount == 0)
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
Type scriptType = _scriptBridgeMap[scriptPtr];
|
||||
var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
|
||||
|
||||
obj.NativePtr = godotObject;
|
||||
|
||||
var ctor = scriptType
|
||||
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.Where(c => c.GetParameters().Length == argCount)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (ctor == null)
|
||||
{
|
||||
throw new MissingMemberException(
|
||||
$"Cannot create script instance. The class '{scriptType.FullName}' does not define a parameterless constructor.");
|
||||
if (argCount == 0)
|
||||
{
|
||||
throw new MissingMemberException(
|
||||
$"Cannot create script instance. The class '{scriptType.FullName}' does not define a parameterless constructor.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MissingMemberException(
|
||||
$"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
var parameters = ctor.GetParameters();
|
||||
int paramCount = parameters.Length;
|
||||
|
||||
object[] invokeParams = new object[paramCount];
|
||||
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
{
|
||||
throw new MissingMemberException(
|
||||
$"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
|
||||
invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
|
||||
args[i], parameters[i].ParameterType);
|
||||
}
|
||||
|
||||
ctor.Invoke(obj, invokeParams);
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
||||
var parameters = ctor.GetParameters();
|
||||
int paramCount = parameters.Length;
|
||||
|
||||
object[] invokeParams = new object[paramCount];
|
||||
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
catch (Exception e)
|
||||
{
|
||||
invokeParams[i] = Marshaling.variant_to_mono_object_of_type(
|
||||
args[i], parameters[i].ParameterType);
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
|
||||
ctor.Invoke(obj, invokeParams);
|
||||
}
|
||||
|
||||
private static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_name* r_res)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_name* outRes)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
try
|
||||
{
|
||||
*r_res = default;
|
||||
return;
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
{
|
||||
*outRes = default;
|
||||
return;
|
||||
}
|
||||
|
||||
var native = Object.InternalGetClassNativeBase(scriptType);
|
||||
|
||||
var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
|
||||
BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
if (field == null)
|
||||
{
|
||||
*outRes = default;
|
||||
return;
|
||||
}
|
||||
|
||||
var nativeName = (StringName)field.GetValue(null);
|
||||
|
||||
if (nativeName == null)
|
||||
{
|
||||
*outRes = default;
|
||||
return;
|
||||
}
|
||||
|
||||
*outRes = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue);
|
||||
}
|
||||
|
||||
var native = Object.InternalGetClassNativeBase(scriptType);
|
||||
|
||||
var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
|
||||
BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
if (field == null)
|
||||
catch (Exception e)
|
||||
{
|
||||
*r_res = default;
|
||||
return;
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
*outRes = default;
|
||||
}
|
||||
|
||||
var nativeName = (StringName)field.GetValue(null);
|
||||
|
||||
*r_res = NativeFuncs.godotsharp_string_name_new_copy(nativeName.NativeValue);
|
||||
}
|
||||
|
||||
private static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
|
||||
{
|
||||
var target = (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
|
||||
if (target != null)
|
||||
target.NativePtr = newPtr;
|
||||
try
|
||||
{
|
||||
var target = (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
|
||||
if (target != null)
|
||||
target.NativePtr = newPtr;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe Type TypeGetProxyClass(godot_string_name* nativeTypeName)
|
||||
@@ -152,7 +203,9 @@ namespace Godot.Bridge
|
||||
return wrapperType;
|
||||
}
|
||||
|
||||
internal static void LookupScriptsInAssembly(Assembly assembly)
|
||||
// Called from GodotPlugins
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
private static void LookupScriptsInAssembly(Assembly assembly)
|
||||
{
|
||||
static void LookupScriptForClass(Type type)
|
||||
{
|
||||
@@ -208,294 +261,398 @@ namespace Godot.Bridge
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void RaiseEventSignal(IntPtr ownerGCHandlePtr,
|
||||
godot_string_name* eventSignalName, godot_variant** args, int argCount, bool* r_ownerIsNull)
|
||||
godot_string_name* eventSignalName, godot_variant** args, int argCount, godot_bool* outOwnerIsNull)
|
||||
{
|
||||
var owner = (Object)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
|
||||
|
||||
if (owner == null)
|
||||
try
|
||||
{
|
||||
*r_ownerIsNull = true;
|
||||
return;
|
||||
var owner = (Object)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
|
||||
|
||||
if (owner == null)
|
||||
{
|
||||
*outOwnerIsNull = true.ToGodotBool();
|
||||
return;
|
||||
}
|
||||
|
||||
*outOwnerIsNull = false.ToGodotBool();
|
||||
|
||||
owner.InternalRaiseEventSignal(eventSignalName, args, argCount);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
*outOwnerIsNull = false.ToGodotBool();
|
||||
}
|
||||
|
||||
*r_ownerIsNull = false;
|
||||
|
||||
owner.InternalRaiseEventSignal(eventSignalName, args, argCount);
|
||||
}
|
||||
|
||||
internal static unsafe void GetScriptSignalList(IntPtr scriptPtr, godot_dictionary* r_retSignals)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void GetScriptSignalList(IntPtr scriptPtr, godot_dictionary* outRetSignals)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
using var signals = new Dictionary();
|
||||
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
try
|
||||
{
|
||||
// Legacy signals
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
using var signals = new Dictionary();
|
||||
|
||||
foreach (var signalDelegate in top
|
||||
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
|
||||
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
|
||||
{
|
||||
var invokeMethod = signalDelegate.GetMethod("Invoke");
|
||||
|
||||
if (invokeMethod == null)
|
||||
throw new MissingMethodException(signalDelegate.FullName, "Invoke");
|
||||
|
||||
var signalParams = new Collections.Array();
|
||||
|
||||
foreach (var parameters in invokeMethod.GetParameters())
|
||||
{
|
||||
var paramType = Marshaling.managed_to_variant_type(
|
||||
parameters.ParameterType, out bool nilIsVariant);
|
||||
signalParams.Add(new Dictionary()
|
||||
{
|
||||
{ "name", parameters.Name },
|
||||
{ "type", paramType },
|
||||
{ "nil_is_variant", nilIsVariant }
|
||||
});
|
||||
}
|
||||
|
||||
signals.Add(signalDelegate.Name, signalParams);
|
||||
}
|
||||
|
||||
// Event signals
|
||||
|
||||
var foundEventSignals = top.GetEvents(
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
||||
.Select(ev => ev.Name);
|
||||
|
||||
var fields = top.GetFields(
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
foreach (var eventSignalField in fields
|
||||
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
|
||||
.Where(f => foundEventSignals.Contains(f.Name)))
|
||||
{
|
||||
var delegateType = eventSignalField.FieldType;
|
||||
var invokeMethod = delegateType.GetMethod("Invoke");
|
||||
|
||||
if (invokeMethod == null)
|
||||
throw new MissingMethodException(delegateType.FullName, "Invoke");
|
||||
|
||||
var signalParams = new Collections.Array();
|
||||
|
||||
foreach (var parameters in invokeMethod.GetParameters())
|
||||
{
|
||||
var paramType = Marshaling.managed_to_variant_type(
|
||||
parameters.ParameterType, out bool nilIsVariant);
|
||||
signalParams.Add(new Dictionary()
|
||||
{
|
||||
{ "name", parameters.Name },
|
||||
{ "type", paramType },
|
||||
{ "nil_is_variant", nilIsVariant }
|
||||
});
|
||||
}
|
||||
|
||||
signals.Add(eventSignalField.Name, signalParams);
|
||||
}
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
*r_retSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue);
|
||||
}
|
||||
|
||||
internal static unsafe bool HasScriptSignal(IntPtr scriptPtr, godot_string* signalName)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
using var signals = new Dictionary();
|
||||
|
||||
string signalNameStr = Marshaling.mono_string_from_godot(*signalName);
|
||||
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
{
|
||||
// Legacy signals
|
||||
|
||||
if (top
|
||||
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
|
||||
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
||||
.Any(signalDelegate => signalDelegate.Name == signalNameStr)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Event signals
|
||||
|
||||
if (top.GetEvents(
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
||||
.Any(eventSignal => eventSignal.Name == signalNameStr)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static unsafe bool HasMethodUnknownParams(IntPtr scriptPtr, godot_string* method, bool deep)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
return false;
|
||||
|
||||
string methodStr = Marshaling.mono_string_from_godot(*method);
|
||||
|
||||
if (deep)
|
||||
{
|
||||
Type top = scriptType;
|
||||
Type native = Object.InternalGetClassNativeBase(scriptType);
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
{
|
||||
var methodInfo = top.GetMethod(methodStr,
|
||||
// Legacy signals
|
||||
|
||||
foreach (var signalDelegate in top
|
||||
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
|
||||
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any()))
|
||||
{
|
||||
var invokeMethod = signalDelegate.GetMethod("Invoke");
|
||||
|
||||
if (invokeMethod == null)
|
||||
throw new MissingMethodException(signalDelegate.FullName, "Invoke");
|
||||
|
||||
var signalParams = new Collections.Array();
|
||||
|
||||
foreach (var parameters in invokeMethod.GetParameters())
|
||||
{
|
||||
var paramType = Marshaling.managed_to_variant_type(
|
||||
parameters.ParameterType, out bool nilIsVariant);
|
||||
signalParams.Add(new Dictionary()
|
||||
{
|
||||
{ "name", parameters.Name },
|
||||
{ "type", paramType },
|
||||
{ "nil_is_variant", nilIsVariant }
|
||||
});
|
||||
}
|
||||
|
||||
signals.Add(signalDelegate.Name, signalParams);
|
||||
}
|
||||
|
||||
// Event signals
|
||||
|
||||
var foundEventSignals = top.GetEvents(
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
||||
.Select(ev => ev.Name);
|
||||
|
||||
var fields = top.GetFields(
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (methodInfo != null)
|
||||
return true;
|
||||
foreach (var eventSignalField in fields
|
||||
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
|
||||
.Where(f => foundEventSignals.Contains(f.Name)))
|
||||
{
|
||||
var delegateType = eventSignalField.FieldType;
|
||||
var invokeMethod = delegateType.GetMethod("Invoke");
|
||||
|
||||
if (invokeMethod == null)
|
||||
throw new MissingMethodException(delegateType.FullName, "Invoke");
|
||||
|
||||
var signalParams = new Collections.Array();
|
||||
|
||||
foreach (var parameters in invokeMethod.GetParameters())
|
||||
{
|
||||
var paramType = Marshaling.managed_to_variant_type(
|
||||
parameters.ParameterType, out bool nilIsVariant);
|
||||
signalParams.Add(new Dictionary()
|
||||
{
|
||||
{ "name", parameters.Name },
|
||||
{ "type", paramType },
|
||||
{ "nil_is_variant", nilIsVariant }
|
||||
});
|
||||
}
|
||||
|
||||
signals.Add(eventSignalField.Name, signalParams);
|
||||
}
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
return false;
|
||||
*outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy(signals.NativeValue);
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
var methodInfo = scriptType.GetMethod(methodStr, BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public);
|
||||
return methodInfo != null;
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
*outRetSignals = NativeFuncs.godotsharp_dictionary_new();
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool HasScriptSignal(IntPtr scriptPtr, godot_string* signalName)
|
||||
{
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
return false;
|
||||
try
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
using var signals = new Dictionary();
|
||||
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
|
||||
return false;
|
||||
string signalNameStr = Marshaling.mono_string_from_godot(*signalName);
|
||||
|
||||
return scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType);
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
{
|
||||
// Legacy signals
|
||||
|
||||
if (top
|
||||
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
|
||||
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
||||
.Any(signalDelegate => signalDelegate.Name == signalNameStr)
|
||||
)
|
||||
{
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
||||
// Event signals
|
||||
|
||||
if (top.GetEvents(
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
||||
.Any(eventSignal => eventSignal.Name == signalNameStr)
|
||||
)
|
||||
{
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
internal static unsafe bool AddScriptBridge(IntPtr scriptPtr, godot_string* scriptPath)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool HasMethodUnknownParams(IntPtr scriptPtr, godot_string* method,
|
||||
godot_bool deep)
|
||||
{
|
||||
string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath);
|
||||
try
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
return false.ToGodotBool();
|
||||
|
||||
if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
|
||||
return false;
|
||||
string methodStr = Marshaling.mono_string_from_godot(*method);
|
||||
|
||||
_scriptBridgeMap.Add(scriptPtr, lookupInfo.ScriptType);
|
||||
if (deep.ToBool())
|
||||
{
|
||||
Type top = scriptType;
|
||||
Type native = Object.InternalGetClassNativeBase(scriptType);
|
||||
|
||||
return true;
|
||||
while (top != null && top != native)
|
||||
{
|
||||
var methodInfo = top.GetMethod(methodStr,
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (methodInfo != null)
|
||||
return true.ToGodotBool();
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
top = native;
|
||||
Type typeOfSystemObject = typeof(System.Object);
|
||||
while (top != null && top != typeOfSystemObject)
|
||||
{
|
||||
bool found = top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public)
|
||||
.Where(m => m.GetCustomAttributes(false).OfType<GodotMethodAttribute>()
|
||||
.Where(a => a.MethodName == methodStr)
|
||||
.Any())
|
||||
.Any();
|
||||
|
||||
if (found)
|
||||
return true.ToGodotBool();
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
else
|
||||
{
|
||||
var methodInfo = scriptType.GetMethod(methodStr, BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public);
|
||||
return (methodInfo != null).ToGodotBool();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static godot_bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
return false.ToGodotBool();
|
||||
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
|
||||
return false.ToGodotBool();
|
||||
|
||||
return (scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType)).ToGodotBool();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool AddScriptBridge(IntPtr scriptPtr, godot_string* scriptPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
string scriptPathStr = Marshaling.mono_string_from_godot(*scriptPath);
|
||||
|
||||
if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
|
||||
return false.ToGodotBool();
|
||||
|
||||
_scriptBridgeMap.Add(scriptPtr, lookupInfo.ScriptType);
|
||||
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void AddScriptBridgeWithType(IntPtr scriptPtr, Type scriptType)
|
||||
=> _scriptBridgeMap.Add(scriptPtr, scriptType);
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void RemoveScriptBridge(IntPtr scriptPtr)
|
||||
=> _scriptBridgeMap.Remove(scriptPtr);
|
||||
|
||||
internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, bool* r_tool,
|
||||
godot_dictionary* r_rpcFunctionsDest)
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var scriptType = _scriptBridgeMap[scriptPtr];
|
||||
|
||||
*r_tool = scriptType.GetCustomAttributes(inherit: false)
|
||||
.OfType<ToolAttribute>()
|
||||
.Any();
|
||||
|
||||
if (!*r_tool && scriptType.IsNested)
|
||||
try
|
||||
{
|
||||
*r_tool = scriptType.DeclaringType?.GetCustomAttributes(inherit: false)
|
||||
.OfType<ToolAttribute>()
|
||||
.Any() ?? false;
|
||||
_scriptBridgeMap.Remove(scriptPtr);
|
||||
}
|
||||
|
||||
if (!*r_tool && scriptType.Assembly.GetName().Name == "GodotTools")
|
||||
*r_tool = true;
|
||||
|
||||
// RPC functions
|
||||
|
||||
Dictionary<string, Dictionary> rpcFunctions = new();
|
||||
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
catch (Exception e)
|
||||
{
|
||||
foreach (var method in top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
if (method.IsStatic)
|
||||
continue;
|
||||
|
||||
string methodName = method.Name;
|
||||
|
||||
if (rpcFunctions.ContainsKey(methodName))
|
||||
continue;
|
||||
|
||||
var rpcAttr = method.GetCustomAttributes(inherit: false)
|
||||
.OfType<RPCAttribute>().FirstOrDefault();
|
||||
|
||||
if (rpcAttr == null)
|
||||
continue;
|
||||
|
||||
var rpcConfig = new Dictionary();
|
||||
|
||||
rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
|
||||
rpcConfig["call_local"] = rpcAttr.CallLocal;
|
||||
rpcConfig["transfer_mode"] = (long)rpcAttr.TransferMode;
|
||||
rpcConfig["channel"] = rpcAttr.TransferChannel;
|
||||
|
||||
rpcFunctions.Add(methodName, rpcConfig);
|
||||
}
|
||||
|
||||
top = top.BaseType;
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
}
|
||||
|
||||
*r_rpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue);
|
||||
}
|
||||
|
||||
internal static unsafe bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* r_newGCHandlePtr,
|
||||
bool createWeak)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, godot_bool* outTool,
|
||||
godot_dictionary* outRpcFunctionsDest)
|
||||
{
|
||||
var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
|
||||
|
||||
object target = oldGCHandle.Target;
|
||||
|
||||
if (target == null)
|
||||
try
|
||||
{
|
||||
oldGCHandle.Free();
|
||||
*r_newGCHandlePtr = IntPtr.Zero;
|
||||
return false; // Called after the managed side was collected, so nothing to do here
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var scriptType = _scriptBridgeMap[scriptPtr];
|
||||
|
||||
*outTool = scriptType.GetCustomAttributes(inherit: false)
|
||||
.OfType<ToolAttribute>()
|
||||
.Any().ToGodotBool();
|
||||
|
||||
if (!(*outTool).ToBool() && scriptType.IsNested)
|
||||
{
|
||||
*outTool = (scriptType.DeclaringType?.GetCustomAttributes(inherit: false)
|
||||
.OfType<ToolAttribute>()
|
||||
.Any() ?? false).ToGodotBool();
|
||||
}
|
||||
|
||||
if (!(*outTool).ToBool() && scriptType.Assembly.GetName().Name == "GodotTools")
|
||||
*outTool = true.ToGodotBool();
|
||||
|
||||
// RPC functions
|
||||
|
||||
Dictionary<string, Dictionary> rpcFunctions = new();
|
||||
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
{
|
||||
foreach (var method in top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
||||
BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
if (method.IsStatic)
|
||||
continue;
|
||||
|
||||
string methodName = method.Name;
|
||||
|
||||
if (rpcFunctions.ContainsKey(methodName))
|
||||
continue;
|
||||
|
||||
var rpcAttr = method.GetCustomAttributes(inherit: false)
|
||||
.OfType<RPCAttribute>().FirstOrDefault();
|
||||
|
||||
if (rpcAttr == null)
|
||||
continue;
|
||||
|
||||
var rpcConfig = new Dictionary();
|
||||
|
||||
rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
|
||||
rpcConfig["call_local"] = rpcAttr.CallLocal;
|
||||
rpcConfig["transfer_mode"] = (long)rpcAttr.TransferMode;
|
||||
rpcConfig["channel"] = rpcAttr.TransferChannel;
|
||||
|
||||
rpcFunctions.Add(methodName, rpcConfig);
|
||||
}
|
||||
|
||||
top = top.BaseType;
|
||||
}
|
||||
|
||||
*outRpcFunctionsDest =
|
||||
NativeFuncs.godotsharp_dictionary_new_copy(((Dictionary)rpcFunctions).NativeValue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
*outTool = false.ToGodotBool();
|
||||
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
|
||||
}
|
||||
}
|
||||
|
||||
// Release the current weak handle and replace it with a strong handle.
|
||||
var newGCHandle = GCHandle.Alloc(target, createWeak ? GCHandleType.Weak : GCHandleType.Normal);
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe godot_bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* outNewGCHandlePtr,
|
||||
godot_bool createWeak)
|
||||
{
|
||||
try
|
||||
{
|
||||
var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
|
||||
|
||||
oldGCHandle.Free();
|
||||
*r_newGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
|
||||
return true;
|
||||
object target = oldGCHandle.Target;
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
oldGCHandle.Free();
|
||||
*outNewGCHandlePtr = IntPtr.Zero;
|
||||
return false.ToGodotBool(); // Called after the managed side was collected, so nothing to do here
|
||||
}
|
||||
|
||||
// Release the current weak handle and replace it with a strong handle.
|
||||
var newGCHandle = GCHandle.Alloc(target,
|
||||
createWeak.ToBool() ? GCHandleType.Weak : GCHandleType.Normal);
|
||||
|
||||
oldGCHandle.Free();
|
||||
*outNewGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
*outNewGCHandlePtr = IntPtr.Zero;
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
@@ -19,13 +21,23 @@ namespace Godot
|
||||
sb.Append(" ");
|
||||
}
|
||||
|
||||
public static void InstallTraceListener()
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void InstallTraceListener()
|
||||
{
|
||||
Trace.Listeners.Clear();
|
||||
Trace.Listeners.Add(new GodotTraceListener());
|
||||
try
|
||||
{
|
||||
Trace.Listeners.Clear();
|
||||
Trace.Listeners.Add(new GodotTraceListener());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
ExceptionUtils.PushError("Failed to install 'System.Diagnostics.Trace' listener.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl)
|
||||
public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber,
|
||||
out string methodDecl)
|
||||
{
|
||||
fileName = frame.GetFileName();
|
||||
fileLineNumber = frame.GetFileLineNumber();
|
||||
|
||||
@@ -11,38 +11,56 @@ namespace Godot
|
||||
{
|
||||
internal static class DelegateUtils
|
||||
{
|
||||
internal static bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static godot_bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
|
||||
{
|
||||
var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target;
|
||||
var @delegateB = (Delegate)GCHandle.FromIntPtr(delegateGCHandleB).Target;
|
||||
return @delegateA == @delegateB;
|
||||
try
|
||||
{
|
||||
var @delegateA = (Delegate)GCHandle.FromIntPtr(delegateGCHandleA).Target;
|
||||
var @delegateB = (Delegate)GCHandle.FromIntPtr(delegateGCHandleB).Target;
|
||||
return (@delegateA == @delegateB).ToGodotBool();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
return false.ToGodotBool();
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
|
||||
godot_variant* ret)
|
||||
godot_variant* outRet)
|
||||
{
|
||||
// TODO: Optimize
|
||||
var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target;
|
||||
var managedArgs = new object[argc];
|
||||
|
||||
var parameterInfos = @delegate.Method.GetParameters();
|
||||
var paramsLength = parameterInfos.Length;
|
||||
|
||||
if (argc != paramsLength)
|
||||
try
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The delegate expects {paramsLength} arguments, but received {argc}.");
|
||||
}
|
||||
// TODO: Optimize
|
||||
var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target;
|
||||
var managedArgs = new object[argc];
|
||||
|
||||
for (uint i = 0; i < argc; i++)
|
||||
var parameterInfos = @delegate!.Method.GetParameters();
|
||||
var paramsLength = parameterInfos.Length;
|
||||
|
||||
if (argc != paramsLength)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"The delegate expects {paramsLength} arguments, but received {argc}.");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < argc; i++)
|
||||
{
|
||||
managedArgs[i] = Marshaling.variant_to_mono_object_of_type(
|
||||
args[i], parameterInfos[i].ParameterType);
|
||||
}
|
||||
|
||||
object invokeRet = @delegate.DynamicInvoke(managedArgs);
|
||||
|
||||
*outRet = Marshaling.mono_object_to_variant(invokeRet);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
managedArgs[i] = Marshaling.variant_to_mono_object_of_type(
|
||||
args[i], parameterInfos[i].ParameterType);
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
*outRet = default;
|
||||
}
|
||||
|
||||
object invokeRet = @delegate.DynamicInvoke(managedArgs);
|
||||
|
||||
*ret = Marshaling.mono_object_to_variant(invokeRet);
|
||||
}
|
||||
|
||||
// TODO: Check if we should be using BindingFlags.DeclaredOnly (would give better reflection performance).
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Godot.Collections
|
||||
public Dictionary Duplicate(bool deep = false)
|
||||
{
|
||||
godot_dictionary newDictionary;
|
||||
NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep, out newDictionary);
|
||||
NativeFuncs.godotsharp_dictionary_duplicate(ref NativeValue, deep.ToGodotBool(), out newDictionary);
|
||||
return CreateTakingOwnershipOfDisposableValue(newDictionary);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace Godot.Collections
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
|
||||
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref NativeValue, &variantKey,
|
||||
out godot_variant value))
|
||||
out godot_variant value).ToBool())
|
||||
{
|
||||
using (value)
|
||||
return Marshaling.variant_to_mono_object(&value);
|
||||
@@ -165,7 +165,7 @@ namespace Godot.Collections
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
|
||||
|
||||
if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey))
|
||||
if (NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool())
|
||||
throw new ArgumentException("An element with the same key already exists", nameof(key));
|
||||
|
||||
using godot_variant variantValue = Marshaling.mono_object_to_variant(value);
|
||||
@@ -185,7 +185,7 @@ namespace Godot.Collections
|
||||
public unsafe bool Contains(object key)
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
|
||||
return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey);
|
||||
return NativeFuncs.godotsharp_dictionary_contains_key(ref NativeValue, &variantKey).ToBool();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -432,7 +432,7 @@ namespace Godot.Collections
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
|
||||
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
|
||||
&variantKey, out godot_variant value))
|
||||
&variantKey, out godot_variant value).ToBool())
|
||||
{
|
||||
using (value)
|
||||
return (TValue)Marshaling.variant_to_mono_object_of_type(&value, TypeOfValues);
|
||||
@@ -513,7 +513,7 @@ namespace Godot.Collections
|
||||
public unsafe bool Remove(TKey key)
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey);
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey).ToBool();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -526,7 +526,7 @@ namespace Godot.Collections
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(key);
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
|
||||
&variantKey, out godot_variant retValue);
|
||||
&variantKey, out godot_variant retValue).ToBool();
|
||||
|
||||
using (retValue)
|
||||
{
|
||||
@@ -566,7 +566,7 @@ namespace Godot.Collections
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key);
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
|
||||
&variantKey, out godot_variant retValue);
|
||||
&variantKey, out godot_variant retValue).ToBool();
|
||||
|
||||
using (retValue)
|
||||
{
|
||||
@@ -574,7 +574,7 @@ namespace Godot.Collections
|
||||
return false;
|
||||
|
||||
using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value);
|
||||
return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue);
|
||||
return NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,7 +610,7 @@ namespace Godot.Collections
|
||||
{
|
||||
using godot_variant variantKey = Marshaling.mono_object_to_variant(item.Key);
|
||||
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref _underlyingDict.NativeValue,
|
||||
&variantKey, out godot_variant retValue);
|
||||
&variantKey, out godot_variant retValue).ToBool();
|
||||
|
||||
using (retValue)
|
||||
{
|
||||
@@ -618,8 +618,11 @@ namespace Godot.Collections
|
||||
return false;
|
||||
|
||||
using godot_variant variantValue = Marshaling.mono_object_to_variant(item.Value);
|
||||
if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue))
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(ref _underlyingDict.NativeValue, &variantKey);
|
||||
if (NativeFuncs.godotsharp_variant_equals(&variantValue, &retValue).ToBool())
|
||||
{
|
||||
return NativeFuncs.godotsharp_dictionary_remove_key(
|
||||
ref _underlyingDict.NativeValue, &variantKey).ToBool();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace Godot
|
||||
{
|
||||
public static class Dispatcher
|
||||
{
|
||||
internal static GodotTaskScheduler DefaultGodotTaskScheduler;
|
||||
|
||||
private static void InitializeDefaultGodotTaskScheduler()
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void InitializeDefaultGodotTaskScheduler()
|
||||
{
|
||||
DefaultGodotTaskScheduler = new GodotTaskScheduler();
|
||||
try
|
||||
{
|
||||
DefaultGodotTaskScheduler = new GodotTaskScheduler();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugUnhandledException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
|
||||
|
||||
@@ -24,14 +24,16 @@ namespace Godot
|
||||
if (nativeBase)
|
||||
{
|
||||
// Native type
|
||||
var field = typeOfT.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
|
||||
BindingFlags.Public | BindingFlags.NonPublic);
|
||||
var field = typeOfT.GetField("NativeName",
|
||||
BindingFlags.DeclaredOnly | BindingFlags.Static |
|
||||
BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
var nativeName = (StringName)field!.GetValue(null);
|
||||
godot_string_name nativeNameAux = nativeName.NativeValue;
|
||||
godot_array inputAux = array.NativeValue;
|
||||
godot_array filteredArray;
|
||||
godotsharp_array_filter_godot_objects_by_native(&nativeNameAux, &inputAux, &filteredArray);
|
||||
NativeFuncs.godotsharp_array_filter_godot_objects_by_native(
|
||||
&nativeNameAux, &inputAux, &filteredArray);
|
||||
return Array<T>.CreateTakingOwnershipOfDisposableValue(filteredArray);
|
||||
}
|
||||
else
|
||||
@@ -39,7 +41,7 @@ namespace Godot
|
||||
// Custom derived type
|
||||
godot_array inputAux = array.NativeValue;
|
||||
godot_array filteredArray;
|
||||
godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray);
|
||||
NativeFuncs.godotsharp_array_filter_godot_objects_by_non_native(&inputAux, &filteredArray);
|
||||
|
||||
var filteredArrayWrapped = Array.CreateTakingOwnershipOfDisposableValue(filteredArray);
|
||||
|
||||
@@ -62,13 +64,5 @@ namespace Godot
|
||||
return resWrapped;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern unsafe void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name,
|
||||
godot_array* p_input, godot_array* r_output);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal extern unsafe void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input,
|
||||
godot_array* r_output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Godot
|
||||
{
|
||||
using var varBytes = Marshaling.mono_array_to_PackedByteArray(bytes);
|
||||
using godot_variant ret = default;
|
||||
NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects, &ret);
|
||||
NativeFuncs.godotsharp_bytes2var(&varBytes, allowObjects.ToGodotBool(), &ret);
|
||||
return Marshaling.variant_to_mono_object(&ret);
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ namespace Godot
|
||||
{
|
||||
using var variant = Marshaling.mono_object_to_variant(var);
|
||||
using godot_packed_byte_array varBytes = default;
|
||||
NativeFuncs.godotsharp_var2bytes(&variant, fullObjects, &varBytes);
|
||||
NativeFuncs.godotsharp_var2bytes(&variant, fullObjects.ToGodotBool(), &varBytes);
|
||||
using (varBytes)
|
||||
return Marshaling.PackedByteArray_to_mono_array(&varBytes);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
|
||||
namespace Godot.NativeInterop
|
||||
{
|
||||
internal static class ExceptionUtils
|
||||
{
|
||||
public static void PushError(string message)
|
||||
{
|
||||
GD.PushError(message);
|
||||
}
|
||||
|
||||
private static void OnExceptionLoggerException(Exception loggerException, Exception exceptionToLog)
|
||||
{
|
||||
// This better not throw
|
||||
PushError("Exception thrown when trying to log another exception...");
|
||||
PushError("Exception:");
|
||||
PushError(exceptionToLog.ToString());
|
||||
PushError("Logger exception:");
|
||||
PushError(loggerException.ToString());
|
||||
}
|
||||
|
||||
public static void DebugPrintUnhandledException(Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO Not implemented (debug_print_unhandled_exception)
|
||||
GD.PushError(e.ToString());
|
||||
}
|
||||
catch (Exception unexpected)
|
||||
{
|
||||
OnExceptionLoggerException(unexpected, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DebugSendUnhandledExceptionError(Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO Not implemented (debug_send_unhandled_exception_error)
|
||||
GD.PushError(e.ToString());
|
||||
}
|
||||
catch (Exception unexpected)
|
||||
{
|
||||
OnExceptionLoggerException(unexpected, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DebugUnhandledException(Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO Not implemented (debug_unhandled_exception)
|
||||
GD.PushError(e.ToString());
|
||||
}
|
||||
catch (Exception unexpected)
|
||||
{
|
||||
OnExceptionLoggerException(unexpected, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrintUnhandledException(Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO Not implemented (print_unhandled_exception)
|
||||
GD.PushError(e.ToString());
|
||||
}
|
||||
catch (Exception unexpected)
|
||||
{
|
||||
OnExceptionLoggerException(unexpected, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,36 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#if REAL_T_IS_DOUBLE
|
||||
using real_t = System.Double;
|
||||
#else
|
||||
using real_t = System.Single;
|
||||
|
||||
#endif
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Godot.NativeInterop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public struct godot_bool
|
||||
internal static class GodotBoolExtensions
|
||||
{
|
||||
public byte _value;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe godot_bool ToGodotBool(this bool @bool)
|
||||
{
|
||||
return *(godot_bool*)&@bool;
|
||||
}
|
||||
|
||||
public unsafe godot_bool(bool value) => _value = *(byte*)&value;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe bool ToBool(this godot_bool godotBool)
|
||||
{
|
||||
return *(bool*)&godotBool;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe implicit operator bool(godot_bool godotBool) => *(bool*)&godotBool._value;
|
||||
public static implicit operator godot_bool(bool @bool) => new godot_bool(@bool);
|
||||
// Apparently a struct with a byte is not blittable? It crashes when calling a UnmanagedCallersOnly function ptr.
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public enum godot_bool : byte
|
||||
{
|
||||
True = 1,
|
||||
False = 0
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
||||
@@ -16,13 +16,14 @@ namespace Godot.NativeInterop
|
||||
return null;
|
||||
|
||||
IntPtr gcHandlePtr;
|
||||
bool has_cs_script_instance = false;
|
||||
godot_bool has_cs_script_instance = false.ToGodotBool();
|
||||
|
||||
// First try to get the tied managed instance from a CSharpInstance script instance
|
||||
|
||||
unsafe
|
||||
{
|
||||
gcHandlePtr = unmanaged_get_script_instance_managed(unmanaged, &has_cs_script_instance);
|
||||
gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed(
|
||||
unmanaged, &has_cs_script_instance);
|
||||
}
|
||||
|
||||
if (gcHandlePtr != IntPtr.Zero)
|
||||
@@ -30,12 +31,12 @@ namespace Godot.NativeInterop
|
||||
|
||||
// Otherwise, if the object has a CSharpInstance script instance, return null
|
||||
|
||||
if (has_cs_script_instance)
|
||||
if (has_cs_script_instance.ToBool())
|
||||
return null;
|
||||
|
||||
// If it doesn't have a CSharpInstance script instance, try with native instance bindings
|
||||
|
||||
gcHandlePtr = unmanaged_get_instance_binding_managed(unmanaged);
|
||||
gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_instance_binding_managed(unmanaged);
|
||||
|
||||
object target = gcHandlePtr != IntPtr.Zero ? GCHandle.FromIntPtr(gcHandlePtr).Target : null;
|
||||
|
||||
@@ -44,22 +45,12 @@ namespace Godot.NativeInterop
|
||||
|
||||
// If the native instance binding GC handle target was collected, create a new one
|
||||
|
||||
gcHandlePtr = unmanaged_instance_binding_create_managed(unmanaged, gcHandlePtr);
|
||||
gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_instance_binding_create_managed(
|
||||
unmanaged, gcHandlePtr);
|
||||
|
||||
return gcHandlePtr != IntPtr.Zero ? (Object)GCHandle.FromIntPtr(gcHandlePtr).Target : null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern unsafe IntPtr unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
|
||||
bool* r_has_cs_script_instance);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern IntPtr unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern IntPtr unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
|
||||
IntPtr oldGCHandlePtr);
|
||||
|
||||
public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged,
|
||||
StringName nativeName, bool refCounted, Type type, Type nativeType)
|
||||
{
|
||||
@@ -70,30 +61,22 @@ namespace Godot.NativeInterop
|
||||
unsafe
|
||||
{
|
||||
godot_string_name nativeNameAux = nativeName.NativeValue;
|
||||
internal_tie_native_managed_to_unmanaged(GCHandle.ToIntPtr(gcHandle), unmanaged,
|
||||
&nativeNameAux, refCounted);
|
||||
NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged(
|
||||
GCHandle.ToIntPtr(gcHandle), unmanaged, &nativeNameAux, refCounted.ToGodotBool());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPtr scriptPtr = internal_new_csharp_script();
|
||||
IntPtr scriptPtr = NativeFuncs.godotsharp_internal_new_csharp_script();
|
||||
|
||||
ScriptManagerBridge.AddScriptBridgeWithType(scriptPtr, type);
|
||||
|
||||
// IMPORTANT: This must be called after AddScriptWithTypeBridge
|
||||
internal_tie_user_managed_to_unmanaged(GCHandle.ToIntPtr(gcHandle), unmanaged,
|
||||
scriptPtr, refCounted);
|
||||
NativeFuncs.godotsharp_internal_tie_user_managed_to_unmanaged(
|
||||
GCHandle.ToIntPtr(gcHandle), unmanaged, scriptPtr, refCounted.ToGodotBool());
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern unsafe void internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
|
||||
IntPtr unmanaged, godot_string_name* nativeName, bool refCounted);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern void internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
|
||||
IntPtr unmanaged, IntPtr scriptPtr, bool refCounted);
|
||||
|
||||
public static void TieManagedToUnmanagedWithPreSetup(Object managed, IntPtr unmanaged,
|
||||
Type type, Type nativeType)
|
||||
{
|
||||
@@ -101,16 +84,10 @@ namespace Godot.NativeInterop
|
||||
return;
|
||||
|
||||
var strongGCHandle = GCHandle.Alloc(managed, GCHandleType.Normal);
|
||||
internal_tie_managed_to_unmanaged_with_pre_setup(GCHandle.ToIntPtr(strongGCHandle), unmanaged);
|
||||
NativeFuncs.godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
|
||||
GCHandle.ToIntPtr(strongGCHandle), unmanaged);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern void internal_tie_managed_to_unmanaged_with_pre_setup(
|
||||
IntPtr gcHandleIntPtr, IntPtr unmanaged);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern IntPtr internal_new_csharp_script();
|
||||
|
||||
public static unsafe Object EngineGetSingleton(string name)
|
||||
{
|
||||
using godot_string src = Marshaling.mono_string_to_godot(name);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
@@ -420,44 +421,18 @@ namespace Godot.NativeInterop
|
||||
if (genericTypeDefinition == typeof(System.Collections.Generic.Dictionary<,>))
|
||||
{
|
||||
// TODO: Validate key and value types are compatible with Variant
|
||||
#if NET
|
||||
Collections.IGenericGodotDictionary genericGodotDictionary =
|
||||
IDictionaryToGenericGodotDictionary((dynamic)p_obj);
|
||||
#else
|
||||
var genericArguments = type.GetGenericArguments();
|
||||
var godotDict = new Collections.Dictionary();
|
||||
|
||||
// With .NET Standard we need a package reference for Microsoft.CSharp in order to
|
||||
// use dynamic, so we have this workaround for now until we switch to .NET 5/6.
|
||||
var method = typeof(Marshaling).GetMethod(nameof(IDictionaryToGenericGodotDictionary),
|
||||
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)!
|
||||
.MakeGenericMethod(genericArguments[0], genericArguments[1]);
|
||||
foreach (KeyValuePair<object, object> entry in (IDictionary)p_obj)
|
||||
godotDict.Add(entry.Key, entry.Value);
|
||||
|
||||
var genericGodotDictionary = (Collections.IGenericGodotDictionary)method
|
||||
.Invoke(null, new[] { p_obj });
|
||||
#endif
|
||||
|
||||
var godotDict = genericGodotDictionary.UnderlyingDictionary;
|
||||
if (godotDict == null)
|
||||
return new godot_variant();
|
||||
return VariantUtils.CreateFromDictionary(godotDict.NativeValue);
|
||||
}
|
||||
|
||||
if (genericTypeDefinition == typeof(System.Collections.Generic.List<>))
|
||||
{
|
||||
// TODO: Validate element type is compatible with Variant
|
||||
#if NET
|
||||
var nativeGodotArray =
|
||||
(godot_array)mono_array_to_Array(System.Runtime.InteropServices.CollectionsMarshal.AsSpan((dynamic)p_obj));
|
||||
#else
|
||||
// With .NET Standard we need a package reference for Microsoft.CSharp in order to
|
||||
// use dynamic, so we have this workaround for now until we switch to .NET 5/6.
|
||||
// Also CollectionsMarshal.AsSpan is not available with .NET Standard.
|
||||
|
||||
var collection = (System.Collections.ICollection)p_obj;
|
||||
var array = new object[collection.Count];
|
||||
collection.CopyTo(array, 0);
|
||||
var nativeGodotArray = mono_array_to_Array(array);
|
||||
#endif
|
||||
var nativeGodotArray = mono_array_to_Array((IList)p_obj);
|
||||
return VariantUtils.CreateFromArray(&nativeGodotArray);
|
||||
}
|
||||
}
|
||||
@@ -478,9 +453,6 @@ namespace Godot.NativeInterop
|
||||
}
|
||||
}
|
||||
|
||||
private static Collections.Dictionary<TKey, TValue> IDictionaryToGenericGodotDictionary<TKey, TValue>
|
||||
(IDictionary<TKey, TValue> dictionary) => new(dictionary);
|
||||
|
||||
public static unsafe string variant_to_mono_string(godot_variant* p_var)
|
||||
{
|
||||
switch ((*p_var)._type)
|
||||
@@ -855,7 +827,7 @@ namespace Godot.NativeInterop
|
||||
switch ((*p_var)._type)
|
||||
{
|
||||
case Variant.Type.Bool:
|
||||
return (bool)(*p_var)._data._bool;
|
||||
return (*p_var)._data._bool.ToBool();
|
||||
case Variant.Type.Int:
|
||||
return (*p_var)._data._int;
|
||||
case Variant.Type.Float:
|
||||
@@ -1058,7 +1030,7 @@ namespace Godot.NativeInterop
|
||||
godot_string_name name;
|
||||
|
||||
if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(
|
||||
p_callable, &delegateGCHandle, &godotObject, &name))
|
||||
p_callable, &delegateGCHandle, &godotObject, &name).ToBool())
|
||||
{
|
||||
if (delegateGCHandle != IntPtr.Zero)
|
||||
{
|
||||
@@ -1141,15 +1113,37 @@ namespace Godot.NativeInterop
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static godot_array mono_array_to_Array(Span<object> p_array)
|
||||
public static godot_array mono_array_to_Array(object[] p_array)
|
||||
{
|
||||
if (p_array.IsEmpty)
|
||||
int length = p_array.Length;
|
||||
|
||||
if (length == 0)
|
||||
return NativeFuncs.godotsharp_array_new();
|
||||
|
||||
using var array = new Collections.Array();
|
||||
array.Resize(p_array.Length);
|
||||
array.Resize(length);
|
||||
|
||||
for (int i = 0; i < p_array.Length; i++)
|
||||
for (int i = 0; i < length; i++)
|
||||
array[i] = p_array[i];
|
||||
|
||||
godot_array src = array.NativeValue;
|
||||
unsafe
|
||||
{
|
||||
return NativeFuncs.godotsharp_array_new_copy(&src);
|
||||
}
|
||||
}
|
||||
|
||||
public static godot_array mono_array_to_Array(IList p_array)
|
||||
{
|
||||
int length = p_array.Count;
|
||||
|
||||
if (length == 0)
|
||||
return NativeFuncs.godotsharp_array_new();
|
||||
|
||||
using var array = new Collections.Array();
|
||||
array.Resize(length);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
array[i] = p_array[i];
|
||||
|
||||
godot_array src = array.NativeValue;
|
||||
|
||||
@@ -20,21 +20,62 @@ namespace Godot.NativeInterop
|
||||
public static extern IntPtr godotsharp_method_bind_get_method(ref godot_string_name p_classname,
|
||||
char* p_methodname);
|
||||
|
||||
#if NET
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(ref godot_string_name p_classname);
|
||||
#else
|
||||
// Workaround until we switch to .NET 5/6
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_get_class_constructor(ref godot_string_name p_classname);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_invoke_class_constructor(IntPtr p_creation_func);
|
||||
#endif
|
||||
public static extern delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(
|
||||
ref godot_string_name p_classname);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_engine_get_singleton(godot_string* p_name);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_object_disposed(IntPtr ptr);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, godot_bool isFinalizer);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj,
|
||||
godot_string_name* eventSignal);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source,
|
||||
ref godot_string_name signal,
|
||||
IntPtr target, IntPtr awaiterHandlePtr);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
|
||||
IntPtr unmanaged, godot_string_name* nativeName, godot_bool refCounted);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
|
||||
IntPtr unmanaged, IntPtr scriptPtr, godot_bool refCounted);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
|
||||
IntPtr gcHandleIntPtr, IntPtr unmanaged);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
|
||||
godot_bool* r_has_cs_script_instance);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
|
||||
IntPtr oldGCHandlePtr);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern IntPtr godotsharp_internal_new_csharp_script();
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_array_filter_godot_objects_by_native(godot_string_name* p_native_name,
|
||||
godot_array* p_input, godot_array* r_output);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_array_filter_godot_objects_by_non_native(godot_array* p_input,
|
||||
godot_array* r_output);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_ref_destroy(ref godot_ref p_instance);
|
||||
|
||||
@@ -509,12 +550,12 @@ namespace Godot.NativeInterop
|
||||
public static extern int godotsharp_node_path_get_subname_count(ref godot_node_path p_self);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern bool godotsharp_node_path_is_absolute(ref godot_node_path p_self);
|
||||
public static extern godot_bool godotsharp_node_path_is_absolute(ref godot_node_path p_self);
|
||||
|
||||
// GD, etc
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, bool p_allow_objects,
|
||||
public static extern void godotsharp_bytes2var(godot_packed_byte_array* p_bytes, godot_bool p_allow_objects,
|
||||
godot_variant* r_ret);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
@@ -578,7 +619,7 @@ namespace Godot.NativeInterop
|
||||
public static extern void godotsharp_str2var(godot_string* p_str, godot_variant* r_ret);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_var2bytes(godot_variant* what, bool fullObjects,
|
||||
public static extern void godotsharp_var2bytes(godot_variant* what, godot_bool fullObjects,
|
||||
godot_packed_byte_array* bytes);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
|
||||
@@ -8,46 +8,46 @@ namespace Godot.NativeInterop
|
||||
public static class VariantUtils
|
||||
{
|
||||
public static godot_variant CreateFromRID(RID from)
|
||||
=> new() {_type = Variant.Type.Rid, _data = {_m_rid = from}};
|
||||
=> new() { _type = Variant.Type.Rid, _data = { _m_rid = from } };
|
||||
|
||||
public static godot_variant CreateFromBool(bool from)
|
||||
=> new() {_type = Variant.Type.Bool, _data = {_bool = from}};
|
||||
=> new() { _type = Variant.Type.Bool, _data = { _bool = from.ToGodotBool() } };
|
||||
|
||||
public static godot_variant CreateFromInt(long from)
|
||||
=> new() {_type = Variant.Type.Int, _data = {_int = from}};
|
||||
=> new() { _type = Variant.Type.Int, _data = { _int = from } };
|
||||
|
||||
public static godot_variant CreateFromInt(ulong from)
|
||||
=> new() {_type = Variant.Type.Int, _data = {_int = (long)from}};
|
||||
=> new() { _type = Variant.Type.Int, _data = { _int = (long)from } };
|
||||
|
||||
public static godot_variant CreateFromFloat(double from)
|
||||
=> new() {_type = Variant.Type.Float, _data = {_float = from}};
|
||||
=> new() { _type = Variant.Type.Float, _data = { _float = from } };
|
||||
|
||||
public static godot_variant CreateFromVector2(Vector2 from)
|
||||
=> new() {_type = Variant.Type.Vector2, _data = {_m_vector2 = from}};
|
||||
=> new() { _type = Variant.Type.Vector2, _data = { _m_vector2 = from } };
|
||||
|
||||
public static godot_variant CreateFromVector2i(Vector2i from)
|
||||
=> new() {_type = Variant.Type.Vector2i, _data = {_m_vector2i = from}};
|
||||
=> new() { _type = Variant.Type.Vector2i, _data = { _m_vector2i = from } };
|
||||
|
||||
public static godot_variant CreateFromVector3(Vector3 from)
|
||||
=> new() {_type = Variant.Type.Vector3, _data = {_m_vector3 = from}};
|
||||
=> new() { _type = Variant.Type.Vector3, _data = { _m_vector3 = from } };
|
||||
|
||||
public static godot_variant CreateFromVector3i(Vector3i from)
|
||||
=> new() {_type = Variant.Type.Vector3i, _data = {_m_vector3i = from}};
|
||||
=> new() { _type = Variant.Type.Vector3i, _data = { _m_vector3i = from } };
|
||||
|
||||
public static godot_variant CreateFromRect2(Rect2 from)
|
||||
=> new() {_type = Variant.Type.Rect2, _data = {_m_rect2 = from}};
|
||||
=> new() { _type = Variant.Type.Rect2, _data = { _m_rect2 = from } };
|
||||
|
||||
public static godot_variant CreateFromRect2i(Rect2i from)
|
||||
=> new() {_type = Variant.Type.Rect2i, _data = {_m_rect2i = from}};
|
||||
=> new() { _type = Variant.Type.Rect2i, _data = { _m_rect2i = from } };
|
||||
|
||||
public static godot_variant CreateFromQuaternion(Quaternion from)
|
||||
=> new() {_type = Variant.Type.Quaternion, _data = {_m_quaternion = from}};
|
||||
=> new() { _type = Variant.Type.Quaternion, _data = { _m_quaternion = from } };
|
||||
|
||||
public static godot_variant CreateFromColor(Color from)
|
||||
=> new() {_type = Variant.Type.Color, _data = {_m_color = from}};
|
||||
=> new() { _type = Variant.Type.Color, _data = { _m_color = from } };
|
||||
|
||||
public static godot_variant CreateFromPlane(Plane from)
|
||||
=> new() {_type = Variant.Type.Plane, _data = {_m_plane = from}};
|
||||
=> new() { _type = Variant.Type.Plane, _data = { _m_plane = from } };
|
||||
|
||||
public static unsafe godot_variant CreateFromTransform2D(Transform2D from)
|
||||
{
|
||||
@@ -100,15 +100,15 @@ namespace Godot.NativeInterop
|
||||
|
||||
// Explicit name to make it very clear
|
||||
public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from)
|
||||
=> new() {_type = Variant.Type.Callable, _data = {_m_callable = from}};
|
||||
=> new() { _type = Variant.Type.Callable, _data = { _m_callable = from } };
|
||||
|
||||
// Explicit name to make it very clear
|
||||
public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from)
|
||||
=> new() {_type = Variant.Type.Signal, _data = {_m_signal = from}};
|
||||
=> new() { _type = Variant.Type.Signal, _data = { _m_signal = from } };
|
||||
|
||||
// Explicit name to make it very clear
|
||||
public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from)
|
||||
=> new() {_type = Variant.Type.String, _data = {_m_string = from}};
|
||||
=> new() { _type = Variant.Type.String, _data = { _m_string = from } };
|
||||
|
||||
public static unsafe godot_variant CreateFromPackedByteArray(godot_packed_byte_array* from)
|
||||
{
|
||||
@@ -223,61 +223,97 @@ namespace Godot.NativeInterop
|
||||
// We avoid the internal call if the stored type is the same we want.
|
||||
|
||||
public static unsafe bool ConvertToBool(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Bool ? (*p_var)._data._bool : NativeFuncs.godotsharp_variant_as_bool(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Bool ?
|
||||
(*p_var)._data._bool.ToBool() :
|
||||
NativeFuncs.godotsharp_variant_as_bool(p_var).ToBool();
|
||||
|
||||
public static unsafe char ConvertToChar(godot_variant* p_var)
|
||||
=> (char)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (char)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe sbyte ConvertToInt8(godot_variant* p_var)
|
||||
=> (sbyte)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (sbyte)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe Int16 ConvertToInt16(godot_variant* p_var)
|
||||
=> (Int16)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (Int16)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe Int32 ConvertToInt32(godot_variant* p_var)
|
||||
=> (Int32)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (Int32)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe Int64 ConvertToInt64(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var);
|
||||
|
||||
public static unsafe byte ConvertToUInt8(godot_variant* p_var)
|
||||
=> (byte)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (byte)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe UInt16 ConvertToUInt16(godot_variant* p_var)
|
||||
=> (UInt16)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (UInt16)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe UInt32 ConvertToUInt32(godot_variant* p_var)
|
||||
=> (UInt32)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (UInt32)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe UInt64 ConvertToUInt64(godot_variant* p_var)
|
||||
=> (UInt64)((*p_var)._type == Variant.Type.Int ? (*p_var)._data._int : NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
=> (UInt64)((*p_var)._type == Variant.Type.Int ?
|
||||
(*p_var)._data._int :
|
||||
NativeFuncs.godotsharp_variant_as_int(p_var));
|
||||
|
||||
public static unsafe float ConvertToFloat32(godot_variant* p_var)
|
||||
=> (float)((*p_var)._type == Variant.Type.Float ? (*p_var)._data._float : NativeFuncs.godotsharp_variant_as_float(p_var));
|
||||
=> (float)((*p_var)._type == Variant.Type.Float ?
|
||||
(*p_var)._data._float :
|
||||
NativeFuncs.godotsharp_variant_as_float(p_var));
|
||||
|
||||
public static unsafe double ConvertToFloat64(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Float ? (*p_var)._data._float : NativeFuncs.godotsharp_variant_as_float(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Float ?
|
||||
(*p_var)._data._float :
|
||||
NativeFuncs.godotsharp_variant_as_float(p_var);
|
||||
|
||||
public static unsafe Vector2 ConvertToVector2(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Vector2 ? (*p_var)._data._m_vector2 : NativeFuncs.godotsharp_variant_as_vector2(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Vector2 ?
|
||||
(*p_var)._data._m_vector2 :
|
||||
NativeFuncs.godotsharp_variant_as_vector2(p_var);
|
||||
|
||||
public static unsafe Vector2i ConvertToVector2i(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Vector2i ? (*p_var)._data._m_vector2i : NativeFuncs.godotsharp_variant_as_vector2i(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Vector2i ?
|
||||
(*p_var)._data._m_vector2i :
|
||||
NativeFuncs.godotsharp_variant_as_vector2i(p_var);
|
||||
|
||||
public static unsafe Rect2 ConvertToRect2(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Rect2 ? (*p_var)._data._m_rect2 : NativeFuncs.godotsharp_variant_as_rect2(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Rect2 ?
|
||||
(*p_var)._data._m_rect2 :
|
||||
NativeFuncs.godotsharp_variant_as_rect2(p_var);
|
||||
|
||||
public static unsafe Rect2i ConvertToRect2i(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Rect2i ? (*p_var)._data._m_rect2i : NativeFuncs.godotsharp_variant_as_rect2i(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Rect2i ?
|
||||
(*p_var)._data._m_rect2i :
|
||||
NativeFuncs.godotsharp_variant_as_rect2i(p_var);
|
||||
|
||||
public static unsafe Transform2D ConvertToTransform2D(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Transform2d ? *(*p_var)._data._transform2d : NativeFuncs.godotsharp_variant_as_transform2d(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Transform2d ?
|
||||
*(*p_var)._data._transform2d :
|
||||
NativeFuncs.godotsharp_variant_as_transform2d(p_var);
|
||||
|
||||
public static unsafe Vector3 ConvertToVector3(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Vector3 ? (*p_var)._data._m_vector3 : NativeFuncs.godotsharp_variant_as_vector3(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Vector3 ?
|
||||
(*p_var)._data._m_vector3 :
|
||||
NativeFuncs.godotsharp_variant_as_vector3(p_var);
|
||||
|
||||
public static unsafe Vector3i ConvertToVector3i(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Vector3i ? (*p_var)._data._m_vector3i : NativeFuncs.godotsharp_variant_as_vector3i(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Vector3i ?
|
||||
(*p_var)._data._m_vector3i :
|
||||
NativeFuncs.godotsharp_variant_as_vector3i(p_var);
|
||||
|
||||
public static unsafe Vector4 ConvertToVector4(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Vector4 ? *(*p_var)._data._vector4 : NativeFuncs.godotsharp_variant_as_vector4(p_var);
|
||||
@@ -286,31 +322,45 @@ namespace Godot.NativeInterop
|
||||
=> (*p_var)._type == Variant.Type.Vector4i ? *(*p_var)._data._vector4i : NativeFuncs.godotsharp_variant_as_vector4i(p_var);
|
||||
|
||||
public static unsafe Basis ConvertToBasis(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Basis ? *(*p_var)._data._basis : NativeFuncs.godotsharp_variant_as_basis(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Basis ?
|
||||
*(*p_var)._data._basis :
|
||||
NativeFuncs.godotsharp_variant_as_basis(p_var);
|
||||
|
||||
public static unsafe Quaternion ConvertToQuaternion(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Quaternion ? (*p_var)._data._m_quaternion : NativeFuncs.godotsharp_variant_as_quaternion(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Quaternion ?
|
||||
(*p_var)._data._m_quaternion :
|
||||
NativeFuncs.godotsharp_variant_as_quaternion(p_var);
|
||||
|
||||
public static unsafe Transform3D ConvertToTransform3D(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Transform3d ? *(*p_var)._data._transform3d : NativeFuncs.godotsharp_variant_as_transform3d(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Transform3d ?
|
||||
*(*p_var)._data._transform3d :
|
||||
NativeFuncs.godotsharp_variant_as_transform3d(p_var);
|
||||
|
||||
public static unsafe Projection ConvertToProjection(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Projection ? *(*p_var)._data._projection : NativeFuncs.godotsharp_variant_as_projection(p_var);
|
||||
|
||||
public static unsafe AABB ConvertToAABB(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Aabb ? *(*p_var)._data._aabb : NativeFuncs.godotsharp_variant_as_aabb(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Aabb ?
|
||||
*(*p_var)._data._aabb :
|
||||
NativeFuncs.godotsharp_variant_as_aabb(p_var);
|
||||
|
||||
public static unsafe Color ConvertToColor(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Color ? (*p_var)._data._m_color : NativeFuncs.godotsharp_variant_as_color(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Color ?
|
||||
(*p_var)._data._m_color :
|
||||
NativeFuncs.godotsharp_variant_as_color(p_var);
|
||||
|
||||
public static unsafe Plane ConvertToPlane(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Plane ? (*p_var)._data._m_plane : NativeFuncs.godotsharp_variant_as_plane(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Plane ?
|
||||
(*p_var)._data._m_plane :
|
||||
NativeFuncs.godotsharp_variant_as_plane(p_var);
|
||||
|
||||
public static unsafe IntPtr ConvertToGodotObject(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Object ? (*p_var)._data._m_obj_data.obj : IntPtr.Zero;
|
||||
|
||||
public static unsafe RID ConvertToRID(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.Rid ? (*p_var)._data._m_rid : NativeFuncs.godotsharp_variant_as_rid(p_var);
|
||||
=> (*p_var)._type == Variant.Type.Rid ?
|
||||
(*p_var)._data._m_rid :
|
||||
NativeFuncs.godotsharp_variant_as_rid(p_var);
|
||||
|
||||
public static unsafe godot_string_name ConvertToStringName(godot_variant* p_var)
|
||||
=> (*p_var)._type == Variant.Type.StringName ?
|
||||
|
||||
@@ -263,7 +263,7 @@ namespace Godot
|
||||
/// <returns>If the <see cref="NodePath"/> is an absolute path.</returns>
|
||||
public bool IsAbsolute()
|
||||
{
|
||||
return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue);
|
||||
return NativeFuncs.godotsharp_node_path_is_absolute(ref NativeValue).ToBool();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,14 +21,11 @@ namespace Godot
|
||||
{
|
||||
if (NativePtr == IntPtr.Zero)
|
||||
{
|
||||
#if NET
|
||||
unsafe
|
||||
{
|
||||
NativePtr = NativeCtor();
|
||||
}
|
||||
#else
|
||||
NativePtr = _gd__invoke_class_constructor(NativeCtor);
|
||||
#endif
|
||||
|
||||
InteropUtils.TieManagedToUnmanaged(this, NativePtr,
|
||||
NativeName, refCounted: false, GetType(), _cachedType);
|
||||
}
|
||||
@@ -58,7 +55,7 @@ namespace Godot
|
||||
{
|
||||
using var eventSignalName = new StringName(eventSignal.Name);
|
||||
godot_string_name eventSignalNameAux = eventSignalName.NativeValue;
|
||||
godot_icall_Object_ConnectEventSignal(NativePtr, &eventSignalNameAux);
|
||||
NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, &eventSignalNameAux);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,14 +111,14 @@ namespace Godot
|
||||
if (MemoryOwn)
|
||||
{
|
||||
MemoryOwn = false;
|
||||
godot_icall_RefCounted_Disposed(NativePtr, !disposing);
|
||||
NativeFuncs.godotsharp_internal_refcounted_disposed(NativePtr, (!disposing).ToGodotBool());
|
||||
}
|
||||
else
|
||||
{
|
||||
godot_icall_Object_Disposed(NativePtr);
|
||||
NativeFuncs.godotsharp_internal_object_disposed(NativePtr);
|
||||
}
|
||||
|
||||
this.NativePtr = IntPtr.Zero;
|
||||
NativePtr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
@@ -391,7 +388,6 @@ namespace Godot
|
||||
return methodBind;
|
||||
}
|
||||
|
||||
#if NET
|
||||
internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type)
|
||||
{
|
||||
// for some reason the '??' operator doesn't support 'delegate*'
|
||||
@@ -402,30 +398,5 @@ namespace Godot
|
||||
|
||||
return nativeConstructor;
|
||||
}
|
||||
#else
|
||||
internal static IntPtr ClassDB_get_constructor(StringName type)
|
||||
{
|
||||
// for some reason the '??' operator doesn't support 'delegate*'
|
||||
var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(ref type.NativeValue);
|
||||
|
||||
if (nativeConstructor == IntPtr.Zero)
|
||||
throw new NativeConstructorNotFoundException(type);
|
||||
|
||||
return nativeConstructor;
|
||||
}
|
||||
|
||||
internal static IntPtr _gd__invoke_class_constructor(IntPtr ctorFuncPtr)
|
||||
=> NativeFuncs.godotsharp_invoke_class_constructor(ctorFuncPtr);
|
||||
#endif
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void godot_icall_Object_Disposed(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void godot_icall_RefCounted_Disposed(IntPtr ptr, bool isFinalizer);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern unsafe void godot_icall_Object_ConnectEventSignal(IntPtr obj,
|
||||
godot_string_name* eventSignal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
@@ -13,14 +12,10 @@ namespace Godot
|
||||
|
||||
public SignalAwaiter(Object source, StringName signal, Object target)
|
||||
{
|
||||
godot_icall_SignalAwaiter_connect(Object.GetPtr(source), ref signal.NativeValue,
|
||||
NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), ref signal.NativeValue,
|
||||
Object.GetPtr(target), GCHandle.ToIntPtr(GCHandle.Alloc(this)));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, ref godot_string_name signal,
|
||||
IntPtr target, IntPtr awaiterHandlePtr);
|
||||
|
||||
public bool IsCompleted => _completed;
|
||||
|
||||
public void OnCompleted(Action action)
|
||||
@@ -32,30 +27,38 @@ namespace Godot
|
||||
|
||||
public IAwaiter<object[]> GetAwaiter() => this;
|
||||
|
||||
internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr,
|
||||
godot_variant** args, int argCount,
|
||||
bool* r_awaiterIsNull)
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr, godot_variant** args, int argCount,
|
||||
godot_bool* outAwaiterIsNull)
|
||||
{
|
||||
var awaiter = (SignalAwaiter)GCHandle.FromIntPtr(awaiterGCHandlePtr).Target;
|
||||
|
||||
if (awaiter == null)
|
||||
try
|
||||
{
|
||||
*r_awaiterIsNull = true;
|
||||
return;
|
||||
var awaiter = (SignalAwaiter)GCHandle.FromIntPtr(awaiterGCHandlePtr).Target;
|
||||
|
||||
if (awaiter == null)
|
||||
{
|
||||
*outAwaiterIsNull = true.ToGodotBool();
|
||||
return;
|
||||
}
|
||||
|
||||
*outAwaiterIsNull = false.ToGodotBool();
|
||||
|
||||
awaiter._completed = true;
|
||||
|
||||
object[] signalArgs = new object[argCount];
|
||||
|
||||
for (int i = 0; i < argCount; i++)
|
||||
signalArgs[i] = Marshaling.variant_to_mono_object(args[i]);
|
||||
|
||||
awaiter._result = signalArgs;
|
||||
|
||||
awaiter._action?.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
||||
*outAwaiterIsNull = false.ToGodotBool();
|
||||
}
|
||||
|
||||
*r_awaiterIsNull = false;
|
||||
|
||||
awaiter._completed = true;
|
||||
|
||||
object[] signalArgs = new object[argCount];
|
||||
|
||||
for (int i = 0; i < argCount; i++)
|
||||
signalArgs[i] = Marshaling.variant_to_mono_object(args[i]);
|
||||
|
||||
awaiter._result = signalArgs;
|
||||
|
||||
awaiter._action?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<OutputPath>bin/$(Configuration)</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<RootNamespace>Godot</RootNamespace>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@@ -34,6 +34,7 @@
|
||||
<Compile Include="Core\Basis.cs" />
|
||||
<Compile Include="Core\Bridge\CSharpInstanceBridge.cs" />
|
||||
<Compile Include="Core\Bridge\GCHandleBridge.cs" />
|
||||
<Compile Include="Core\Bridge\ManagedCallbacks.cs" />
|
||||
<Compile Include="Core\Bridge\ScriptManagerBridge.cs" />
|
||||
<Compile Include="Core\Callable.cs" />
|
||||
<Compile Include="Core\Color.cs" />
|
||||
@@ -58,6 +59,7 @@
|
||||
<Compile Include="Core\MarshalUtils.cs" />
|
||||
<Compile Include="Core\Mathf.cs" />
|
||||
<Compile Include="Core\MathfEx.cs" />
|
||||
<Compile Include="Core\NativeInterop\ExceptionUtils.cs" />
|
||||
<Compile Include="Core\NativeInterop\InteropUtils.cs" />
|
||||
<Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
|
||||
<Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("GodotSharpEditor")]
|
||||
[assembly: InternalsVisibleTo("GodotPlugins")]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<OutputPath>bin/$(Configuration)</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<RootNamespace>Godot</RootNamespace>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
|
||||
<EnableDefaultItems>false</EnableDefaultItems>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
Reference in New Issue
Block a user