Merge pull request #67511 from neikeq/issue-66060
C#: Load assemblies as collectible only in the Godot editor
This commit is contained in:
commit
c3af45791c
3 changed files with 32 additions and 10 deletions
|
@ -710,6 +710,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
// We disable collectible assemblies in the game player, because the limitations cause
|
||||||
|
// issues with mocking libraries. As such, we can only reload assemblies in the editor.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Currently, this reloads all scripts, including those whose class is not part of the
|
// Currently, this reloads all scripts, including those whose class is not part of the
|
||||||
// assembly load context being unloaded. As such, we unnecessarily reload GodotTools.
|
// assembly load context being unloaded. As such, we unnecessarily reload GodotTools.
|
||||||
|
|
|
@ -28,17 +28,24 @@ namespace GodotPlugins
|
||||||
get => _pluginLoadContext?.AssemblyLoadedPath;
|
get => _pluginLoadContext?.AssemblyLoadedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsCollectible
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
get => _pluginLoadContext?.IsCollectible ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public static (Assembly, PluginLoadContextWrapper) CreateAndLoadFromAssemblyName(
|
public static (Assembly, PluginLoadContextWrapper) CreateAndLoadFromAssemblyName(
|
||||||
AssemblyName assemblyName,
|
AssemblyName assemblyName,
|
||||||
string pluginPath,
|
string pluginPath,
|
||||||
ICollection<string> sharedAssemblies,
|
ICollection<string> sharedAssemblies,
|
||||||
AssemblyLoadContext mainLoadContext
|
AssemblyLoadContext mainLoadContext,
|
||||||
|
bool isCollectible
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var wrapper = new PluginLoadContextWrapper();
|
var wrapper = new PluginLoadContextWrapper();
|
||||||
wrapper._pluginLoadContext = new PluginLoadContext(
|
wrapper._pluginLoadContext = new PluginLoadContext(
|
||||||
pluginPath, sharedAssemblies, mainLoadContext);
|
pluginPath, sharedAssemblies, mainLoadContext, isCollectible);
|
||||||
var assembly = wrapper._pluginLoadContext.LoadFromAssemblyName(assemblyName);
|
var assembly = wrapper._pluginLoadContext.LoadFromAssemblyName(assemblyName);
|
||||||
return (assembly, wrapper);
|
return (assembly, wrapper);
|
||||||
}
|
}
|
||||||
|
@ -61,6 +68,7 @@ namespace GodotPlugins
|
||||||
private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
|
private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
|
||||||
private static Assembly? _editorApiAssembly;
|
private static Assembly? _editorApiAssembly;
|
||||||
private static PluginLoadContextWrapper? _projectLoadContext;
|
private static PluginLoadContextWrapper? _projectLoadContext;
|
||||||
|
private static bool _editorHint = false;
|
||||||
|
|
||||||
private static readonly AssemblyLoadContext MainLoadContext =
|
private static readonly AssemblyLoadContext MainLoadContext =
|
||||||
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
|
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
|
||||||
|
@ -77,15 +85,17 @@ namespace GodotPlugins
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_editorHint = editorHint.ToBool();
|
||||||
|
|
||||||
_dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
|
_dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
|
||||||
|
|
||||||
SharedAssemblies.Add(CoreApiAssembly.GetName());
|
SharedAssemblies.Add(CoreApiAssembly.GetName());
|
||||||
NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver);
|
NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver);
|
||||||
|
|
||||||
AlcReloadCfg.Configure(alcReloadEnabled: editorHint.ToBool());
|
AlcReloadCfg.Configure(alcReloadEnabled: _editorHint);
|
||||||
NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
|
NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
|
||||||
|
|
||||||
if (editorHint.ToBool())
|
if (_editorHint)
|
||||||
{
|
{
|
||||||
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
|
_editorApiAssembly = Assembly.Load("GodotSharpEditor");
|
||||||
SharedAssemblies.Add(_editorApiAssembly.GetName());
|
SharedAssemblies.Add(_editorApiAssembly.GetName());
|
||||||
|
@ -128,7 +138,7 @@ namespace GodotPlugins
|
||||||
|
|
||||||
string assemblyPath = new(nAssemblyPath);
|
string assemblyPath = new(nAssemblyPath);
|
||||||
|
|
||||||
(var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath);
|
(var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath, isCollectible: _editorHint);
|
||||||
|
|
||||||
string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath;
|
string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath;
|
||||||
*outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath);
|
*outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath);
|
||||||
|
@ -155,7 +165,7 @@ namespace GodotPlugins
|
||||||
if (_editorApiAssembly == null)
|
if (_editorApiAssembly == null)
|
||||||
throw new InvalidOperationException("The Godot editor API assembly is not loaded.");
|
throw new InvalidOperationException("The Godot editor API assembly is not loaded.");
|
||||||
|
|
||||||
var (assembly, _) = LoadPlugin(assemblyPath);
|
var (assembly, _) = LoadPlugin(assemblyPath, isCollectible: _editorHint);
|
||||||
|
|
||||||
NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!);
|
NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!);
|
||||||
|
|
||||||
|
@ -180,7 +190,7 @@ namespace GodotPlugins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath)
|
private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath, bool isCollectible)
|
||||||
{
|
{
|
||||||
string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
||||||
|
|
||||||
|
@ -194,7 +204,7 @@ namespace GodotPlugins
|
||||||
}
|
}
|
||||||
|
|
||||||
return PluginLoadContextWrapper.CreateAndLoadFromAssemblyName(
|
return PluginLoadContextWrapper.CreateAndLoadFromAssemblyName(
|
||||||
new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext);
|
new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext, isCollectible);
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
@ -218,6 +228,12 @@ namespace GodotPlugins
|
||||||
if (pluginLoadContext == null)
|
if (pluginLoadContext == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (!pluginLoadContext.IsCollectible)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Cannot unload a non-collectible assembly load context.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine("Unloading assembly load context...");
|
Console.WriteLine("Unloading assembly load context...");
|
||||||
|
|
||||||
var alcWeakReference = pluginLoadContext.CreateWeakReference();
|
var alcWeakReference = pluginLoadContext.CreateWeakReference();
|
||||||
|
|
|
@ -15,8 +15,8 @@ namespace GodotPlugins
|
||||||
public string? AssemblyLoadedPath { get; private set; }
|
public string? AssemblyLoadedPath { get; private set; }
|
||||||
|
|
||||||
public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies,
|
public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies,
|
||||||
AssemblyLoadContext mainLoadContext)
|
AssemblyLoadContext mainLoadContext, bool isCollectible)
|
||||||
: base(isCollectible: true)
|
: base(isCollectible)
|
||||||
{
|
{
|
||||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||||
_sharedAssemblies = sharedAssemblies;
|
_sharedAssemblies = sharedAssemblies;
|
||||||
|
|
Loading…
Reference in a new issue