| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | using System; | 
					
						
							|  |  |  | using System.Collections.Generic; | 
					
						
							|  |  |  | using System.IO; | 
					
						
							|  |  |  | using System.Reflection; | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  | using System.Runtime.CompilerServices; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | using System.Runtime.InteropServices; | 
					
						
							|  |  |  | using System.Runtime.Loader; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | using Godot.Bridge; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | using Godot.NativeInterop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace GodotPlugins | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     public static class Main | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |         // IMPORTANT: | 
					
						
							|  |  |  |         // Keeping strong references to the AssemblyLoadContext (our PluginLoadContext) prevents | 
					
						
							|  |  |  |         // it from being unloaded. To avoid issues, we wrap the reference in this class, and mark | 
					
						
							|  |  |  |         // all the methods that access it as non-inlineable. This way we prevent local references | 
					
						
							|  |  |  |         // (either real or introduced by the JIT) to escape the scope of these methods due to | 
					
						
							|  |  |  |         // inlining, which could keep the AssemblyLoadContext alive while trying to unload. | 
					
						
							|  |  |  |         private sealed class PluginLoadContextWrapper | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             private PluginLoadContext? _pluginLoadContext; | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |             private readonly WeakReference _weakReference; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             private PluginLoadContextWrapper(PluginLoadContext pluginLoadContext, WeakReference weakReference) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 _pluginLoadContext = pluginLoadContext; | 
					
						
							|  |  |  |                 _weakReference = weakReference; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             public string? AssemblyLoadedPath | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 [MethodImpl(MethodImplOptions.NoInlining)] | 
					
						
							|  |  |  |                 get => _pluginLoadContext?.AssemblyLoadedPath; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |             public bool IsCollectible | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 [MethodImpl(MethodImplOptions.NoInlining)] | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                 // if _pluginLoadContext is null we already started unloading, so it was collectible | 
					
						
							|  |  |  |                 get => _pluginLoadContext?.IsCollectible ?? true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             public bool IsAlive | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 [MethodImpl(MethodImplOptions.NoInlining)] | 
					
						
							|  |  |  |                 get => _weakReference.IsAlive; | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |             [MethodImpl(MethodImplOptions.NoInlining)] | 
					
						
							|  |  |  |             public static (Assembly, PluginLoadContextWrapper) CreateAndLoadFromAssemblyName( | 
					
						
							|  |  |  |                 AssemblyName assemblyName, | 
					
						
							|  |  |  |                 string pluginPath, | 
					
						
							|  |  |  |                 ICollection<string> sharedAssemblies, | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 AssemblyLoadContext mainLoadContext, | 
					
						
							|  |  |  |                 bool isCollectible | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |             ) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                 var context = new PluginLoadContext(pluginPath, sharedAssemblies, mainLoadContext, isCollectible); | 
					
						
							|  |  |  |                 var reference = new WeakReference(context, trackResurrection: true); | 
					
						
							|  |  |  |                 var wrapper = new PluginLoadContextWrapper(context, reference); | 
					
						
							|  |  |  |                 var assembly = context.LoadFromAssemblyName(assemblyName); | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 return (assembly, wrapper); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             [MethodImpl(MethodImplOptions.NoInlining)] | 
					
						
							|  |  |  |             internal void Unload() | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 _pluginLoadContext?.Unload(); | 
					
						
							|  |  |  |                 _pluginLoadContext = null; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         private static readonly List<AssemblyName> SharedAssemblies = new(); | 
					
						
							| 
									
										
										
										
											2022-12-07 16:16:51 +01:00
										 |  |  |         private static readonly Assembly CoreApiAssembly = typeof(global::Godot.GodotObject).Assembly; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         private static Assembly? _editorApiAssembly; | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |         private static PluginLoadContextWrapper? _projectLoadContext; | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |         private static bool _editorHint = false; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         private static readonly AssemblyLoadContext MainLoadContext = | 
					
						
							|  |  |  |             AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ?? | 
					
						
							|  |  |  |             AssemblyLoadContext.Default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:52 +01:00
										 |  |  |         private static DllImportResolver? _dllImportResolver; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         // Right now we do it this way for simplicity as hot-reload is disabled. It will need to be changed later. | 
					
						
							|  |  |  |         [UnmanagedCallersOnly] | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         // ReSharper disable once UnusedMember.Local | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:52 +01:00
										 |  |  |         private static unsafe godot_bool InitializeFromEngine(IntPtr godotDllHandle, godot_bool editorHint, | 
					
						
							| 
									
										
										
										
											2022-08-05 03:32:59 +02:00
										 |  |  |             PluginsCallbacks* pluginsCallbacks, ManagedCallbacks* managedCallbacks, | 
					
						
							|  |  |  |             IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             try | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 _editorHint = editorHint.ToBool(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:52 +01:00
										 |  |  |                 _dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |                 SharedAssemblies.Add(CoreApiAssembly.GetName()); | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:52 +01:00
										 |  |  |                 NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 AlcReloadCfg.Configure(alcReloadEnabled: _editorHint); | 
					
						
							| 
									
										
										
										
											2022-08-05 03:32:59 +02:00
										 |  |  |                 NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize); | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 if (_editorHint) | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |                 { | 
					
						
							|  |  |  |                     _editorApiAssembly = Assembly.Load("GodotSharpEditor"); | 
					
						
							|  |  |  |                     SharedAssemblies.Add(_editorApiAssembly.GetName()); | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:52 +01:00
										 |  |  |                     NativeLibrary.SetDllImportResolver(_editorApiAssembly, _dllImportResolver); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 *pluginsCallbacks = new() | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     LoadProjectAssemblyCallback = &LoadProjectAssembly, | 
					
						
							|  |  |  |                     LoadToolsAssemblyCallback = &LoadToolsAssembly, | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                     UnloadProjectPluginCallback = &UnloadProjectPlugin, | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |                 }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 *managedCallbacks = ManagedCallbacks.Create(); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return godot_bool.True; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             catch (Exception e) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Console.Error.WriteLine(e); | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 return godot_bool.False; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         [StructLayout(LayoutKind.Sequential)] | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         private struct PluginsCallbacks | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |             public unsafe delegate* unmanaged<char*, godot_string*, godot_bool> LoadProjectAssemblyCallback; | 
					
						
							| 
									
										
										
										
											2022-08-05 03:32:59 +02:00
										 |  |  |             public unsafe delegate* unmanaged<char*, IntPtr, int, IntPtr> LoadToolsAssemblyCallback; | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |             public unsafe delegate* unmanaged<godot_bool> UnloadProjectPluginCallback; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         [UnmanagedCallersOnly] | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |         private static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath, godot_string* outLoadedAssemblyPath) | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             try | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 if (_projectLoadContext != null) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                     return godot_bool.True; // Already loaded | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 string assemblyPath = new(nAssemblyPath); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 (var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath, isCollectible: _editorHint); | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath; | 
					
						
							|  |  |  |                 *outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 ScriptManagerBridge.LookupScriptsInAssembly(projectAssembly); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 return godot_bool.True; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             catch (Exception e) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Console.Error.WriteLine(e); | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 return godot_bool.False; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         [UnmanagedCallersOnly] | 
					
						
							| 
									
										
										
										
											2022-08-05 03:32:59 +02:00
										 |  |  |         private static unsafe IntPtr LoadToolsAssembly(char* nAssemblyPath, | 
					
						
							|  |  |  |             IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             try | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 string assemblyPath = new(nAssemblyPath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (_editorApiAssembly == null) | 
					
						
							| 
									
										
										
										
											2022-08-24 13:54:47 +02:00
										 |  |  |                     throw new InvalidOperationException("The Godot editor API assembly is not loaded."); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                 var (assembly, _) = LoadPlugin(assemblyPath, isCollectible: false); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:52 +01:00
										 |  |  |                 NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!); | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 var method = assembly.GetType("GodotTools.GodotSharpEditor")? | 
					
						
							|  |  |  |                     .GetMethod("InternalCreateInstance", | 
					
						
							|  |  |  |                         BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (method == null) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     throw new MissingMethodException("GodotTools.GodotSharpEditor", | 
					
						
							|  |  |  |                         "InternalCreateInstance"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-05 03:32:59 +02:00
										 |  |  |                 return (IntPtr?)method | 
					
						
							|  |  |  |                            .Invoke(null, new object[] { unmanagedCallbacks, unmanagedCallbacksSize }) | 
					
						
							|  |  |  |                        ?? IntPtr.Zero; | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             catch (Exception e) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Console.Error.WriteLine(e); | 
					
						
							|  |  |  |                 return IntPtr.Zero; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |         private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath, bool isCollectible) | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             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); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |             return PluginLoadContextWrapper.CreateAndLoadFromAssemblyName( | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext, isCollectible); | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         [UnmanagedCallersOnly] | 
					
						
							|  |  |  |         private static godot_bool UnloadProjectPlugin() | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             try | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return UnloadPlugin(ref _projectLoadContext).ToGodotBool(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             catch (Exception e) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 Console.Error.WriteLine(e); | 
					
						
							|  |  |  |                 return godot_bool.False; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         private static bool UnloadPlugin(ref PluginLoadContextWrapper? pluginLoadContext) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             try | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (pluginLoadContext == null) | 
					
						
							|  |  |  |                     return true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-16 23:55:54 +02:00
										 |  |  |                 if (!pluginLoadContext.IsCollectible) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     Console.Error.WriteLine("Cannot unload a non-collectible assembly load context."); | 
					
						
							|  |  |  |                     return false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 Console.WriteLine("Unloading assembly load context..."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 pluginLoadContext.Unload(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 int startTimeMs = Environment.TickCount; | 
					
						
							|  |  |  |                 bool takingTooLong = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                 while (pluginLoadContext.IsAlive) | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 { | 
					
						
							|  |  |  |                     GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); | 
					
						
							|  |  |  |                     GC.WaitForPendingFinalizers(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                     if (!pluginLoadContext.IsAlive) | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                         break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     int elapsedTimeMs = Environment.TickCount - startTimeMs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                     if (!takingTooLong && elapsedTimeMs >= 200) | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                     { | 
					
						
							|  |  |  |                         takingTooLong = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         // TODO: How to log from GodotPlugins? (delegate pointer?) | 
					
						
							|  |  |  |                         Console.Error.WriteLine("Assembly unloading is taking longer than expected..."); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                     else if (elapsedTimeMs >= 1000) | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                     { | 
					
						
							|  |  |  |                         // TODO: How to log from GodotPlugins? (delegate pointer?) | 
					
						
							|  |  |  |                         Console.Error.WriteLine( | 
					
						
							|  |  |  |                             "Failed to unload assemblies. Possible causes: Strong GC handles, running threads, etc."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         return false; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 Console.WriteLine("Assembly load context unloaded successfully."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-31 11:53:16 +02:00
										 |  |  |                 pluginLoadContext = null; | 
					
						
							| 
									
										
										
										
											2022-05-28 04:56:46 +02:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             catch (Exception e) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // TODO: How to log exceptions from GodotPlugins? (delegate pointer?) | 
					
						
							|  |  |  |                 Console.Error.WriteLine(e); | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-09-12 20:23:05 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |