You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-12 13:20:55 +00:00
C#/netcore: Add base desktop game export implementation
This base implementation is still very barebones but it defines the path for how exporting will work (at least when embedding the .NET runtime). Many manual steps are still needed, which should be automatized in the future. For example, in addition to the API assemblies, now you also need to copy the GodotPlugins assembly to each game project.
This commit is contained in:
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
using Godot.Bridge;
|
||||
using Godot.NativeInterop;
|
||||
|
||||
namespace GodotPlugins
|
||||
@@ -13,6 +14,7 @@ namespace GodotPlugins
|
||||
private static readonly List<AssemblyName> SharedAssemblies = new();
|
||||
private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
|
||||
private static Assembly? _editorApiAssembly;
|
||||
private static Assembly? _projectAssembly;
|
||||
|
||||
private static readonly AssemblyLoadContext MainLoadContext =
|
||||
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
|
||||
@@ -20,67 +22,59 @@ namespace GodotPlugins
|
||||
|
||||
// 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)
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
private static unsafe godot_bool InitializeFromEngine(godot_bool editorHint,
|
||||
PluginsCallbacks* pluginsCallbacks, ManagedCallbacks* managedCallbacks)
|
||||
{
|
||||
try
|
||||
{
|
||||
SharedAssemblies.Add(CoreApiAssembly.GetName());
|
||||
NativeLibrary.SetDllImportResolver(CoreApiAssembly, GodotDllImportResolver.OnResolveDllImport);
|
||||
|
||||
if (editorHint.ToBool())
|
||||
{
|
||||
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
|
||||
SharedAssemblies.Add(_editorApiAssembly.GetName());
|
||||
NativeLibrary.SetDllImportResolver(_editorApiAssembly, GodotDllImportResolver.OnResolveDllImport);
|
||||
}
|
||||
|
||||
NativeLibrary.SetDllImportResolver(CoreApiAssembly, OnResolveDllImport);
|
||||
|
||||
*pluginsCallbacks = new()
|
||||
{
|
||||
LoadProjectAssemblyCallback = &LoadProjectAssembly,
|
||||
LoadToolsAssemblyCallback = &LoadToolsAssembly,
|
||||
};
|
||||
|
||||
*managedCallbacks = Godot.Bridge.ManagedCallbacks.Create();
|
||||
*managedCallbacks = 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
|
||||
private 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)
|
||||
private static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_projectAssembly != null)
|
||||
return godot_bool.True; // Already loaded
|
||||
|
||||
string assemblyPath = new(nAssemblyPath);
|
||||
|
||||
var assembly = LoadPlugin(assemblyPath);
|
||||
_projectAssembly = 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 });
|
||||
ScriptManagerBridge.LookupScriptsInAssembly(_projectAssembly);
|
||||
|
||||
return godot_bool.True;
|
||||
}
|
||||
@@ -92,7 +86,7 @@ namespace GodotPlugins
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe IntPtr LoadToolsAssembly(char* nAssemblyPath)
|
||||
private static unsafe IntPtr LoadToolsAssembly(char* nAssemblyPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -103,7 +97,7 @@ namespace GodotPlugins
|
||||
|
||||
var assembly = LoadPlugin(assemblyPath);
|
||||
|
||||
NativeLibrary.SetDllImportResolver(assembly, OnResolveDllImport);
|
||||
NativeLibrary.SetDllImportResolver(assembly, GodotDllImportResolver.OnResolveDllImport);
|
||||
|
||||
var method = assembly.GetType("GodotTools.GodotSharpEditor")?
|
||||
.GetMethod("InternalCreateInstance",
|
||||
@@ -140,58 +134,5 @@ namespace GodotPlugins
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user