Compare commits
No commits in common. "bd76fc1b251a05f03e0dc9fe032d6a82f931940a" and "ad2f527de5f3866155c9d27ebb877a985dd28de1" have entirely different histories.
bd76fc1b25
...
ad2f527de5
@ -69,7 +69,7 @@ namespace Nerfed.Editor
|
|||||||
|
|
||||||
ImGui.ShowDemoWindow();
|
ImGui.ShowDemoWindow();
|
||||||
|
|
||||||
EditorProjectGui.OnGui();
|
ProjectGui.OnGui();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +0,0 @@
|
|||||||
using System.Runtime.Loader;
|
|
||||||
|
|
||||||
namespace Nerfed.Editor.Project;
|
|
||||||
|
|
||||||
internal class EditorAssemblyLoadContext : AssemblyLoadContext
|
|
||||||
{
|
|
||||||
public EditorAssemblyLoadContext() : base(isCollectible: true) { }
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
using Nerfed.Runtime;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Nerfed.Editor.Project;
|
|
||||||
|
|
||||||
// https://github.com/godotengine/godot/blob/master/modules/mono/glue/GodotSharp/GodotPlugins/Main.c
|
|
||||||
// https://gitlab.com/robertk92/assemblyreloadtest/-/blob/main/AppContextTest/Program.cs
|
|
||||||
|
|
||||||
internal static class EditorAssemblyLoader
|
|
||||||
{
|
|
||||||
private sealed class EditorAssemblyLoadContextWrapper
|
|
||||||
{
|
|
||||||
private EditorAssemblyLoadContext assemblyLoadContext;
|
|
||||||
private readonly WeakReference weakReference;
|
|
||||||
|
|
||||||
private EditorAssemblyLoadContextWrapper(EditorAssemblyLoadContext assemblyLoadContext, WeakReference weakReference)
|
|
||||||
{
|
|
||||||
this.assemblyLoadContext = assemblyLoadContext;
|
|
||||||
this.weakReference = weakReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCollectible
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
// If assemblyLoadContext is null we already started unloading, so it was collectible.
|
|
||||||
get => assemblyLoadContext?.IsCollectible ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAlive
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
get => weakReference.IsAlive;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
public static (Assembly, EditorAssemblyLoadContextWrapper) CreateAndLoad(AssemblyName assemblyName)
|
|
||||||
{
|
|
||||||
EditorAssemblyLoadContext context = new EditorAssemblyLoadContext();
|
|
||||||
WeakReference reference = new WeakReference(context, trackResurrection: true);
|
|
||||||
EditorAssemblyLoadContextWrapper wrapper = new EditorAssemblyLoadContextWrapper(context, reference);
|
|
||||||
Assembly assembly = context.LoadFromAssemblyName(assemblyName);
|
|
||||||
return (assembly, wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
|
||||||
internal void Unload()
|
|
||||||
{
|
|
||||||
assemblyLoadContext?.Unload();
|
|
||||||
assemblyLoadContext = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (Assembly, EditorAssemblyLoadContextWrapper) Load(string assemblyFilePath)
|
|
||||||
{
|
|
||||||
string assemblyFileName = Path.GetFileNameWithoutExtension(assemblyFilePath);
|
|
||||||
|
|
||||||
AssemblyName assemblyName = new AssemblyName(assemblyFileName);
|
|
||||||
|
|
||||||
return EditorAssemblyLoadContextWrapper.CreateAndLoad(assemblyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool Unload(EditorAssemblyLoadContextWrapper assemblyLoadContextWrapper)
|
|
||||||
{
|
|
||||||
if (assemblyLoadContextWrapper == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!assemblyLoadContextWrapper.IsCollectible)
|
|
||||||
{
|
|
||||||
Log.Error($"{assemblyLoadContextWrapper} is not collectable!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
assemblyLoadContextWrapper.Unload();
|
|
||||||
|
|
||||||
GC.Collect();
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
|
|
||||||
TimeSpan timeout = TimeSpan.FromSeconds(30);
|
|
||||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
while (assemblyLoadContextWrapper.IsAlive)
|
|
||||||
{
|
|
||||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
|
|
||||||
if (!assemblyLoadContextWrapper.IsAlive)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopwatch.Elapsed.TotalSeconds % 10 == 0)
|
|
||||||
{
|
|
||||||
Log.Info("Tring to unload assembly...");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stopwatch.Elapsed >= timeout)
|
|
||||||
{
|
|
||||||
Log.Error("Failed to unload assembly!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Nerfed.Editor.Project;
|
namespace Nerfed.Editor.Project;
|
||||||
|
|
||||||
internal static class EditorProjectGui
|
internal static class ProjectGui
|
||||||
{
|
{
|
||||||
private static string projectDirectory = string.Empty;
|
private static string projectDirectory = string.Empty;
|
||||||
private static string projectName = string.Empty;
|
private static string projectName = string.Empty;
|
Loading…
x
Reference in New Issue
Block a user