#if TOOLS using System; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.Loader; using Godot; namespace GodotHostTest.AetherBind.Editor; /// /// Taken from https://github.com/godotengine/godot-proposals/issues/12294 /// public static class GodotScriptPathCache { // private static readonly ConcurrentDictionary TypeToPath = new(); private static readonly ConcurrentDictionary PathToType = new(); private static readonly Type GodotObject = typeof(GodotObject); private static readonly Type ScriptPathAttribute = typeof(ScriptPathAttribute); private static AssemblyLoadEventHandler? _assemblyLoadEventHandler; private static void InitializeIfNeeded() { if (_assemblyLoadEventHandler != null) return; Initialize(); AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly())! .Unloading += _ => { Deinitialize(); }; } private static void Initialize() { GD.Print($"Initializing {nameof(GodotScriptPathCache)}"); // TypeToPath.Clear(); PathToType.Clear(); _assemblyLoadEventHandler = (_, args) => CacheScriptsInAssembly(args.LoadedAssembly); AppDomain.CurrentDomain.AssemblyLoad += _assemblyLoadEventHandler; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) CacheScriptsInAssembly(assembly); return; void CacheScriptsInAssembly(Assembly assembly) { foreach (var type in assembly.GetTypes() .Where(t => t.IsClass) .Where(t => t.IsSubclassOf(GodotObject))) // get script path attribute if (type.GetCustomAttributes(ScriptPathAttribute, false).FirstOrDefault() is ScriptPathAttribute scriptPath) { // TypeToPath[type] = scriptPath.Path; PathToType[scriptPath.Path] = type; } } } private static void Deinitialize() { GD.Print($"Deinitializing {nameof(GodotScriptPathCache)}"); AppDomain.CurrentDomain.AssemblyLoad -= _assemblyLoadEventHandler; _assemblyLoadEventHandler = null; // TypeToPath.Clear(); PathToType.Clear(); } // public static bool TryGetScriptPath(Type type, [MaybeNullWhen(false)] out string path) // { // InitializeIfNeeded(); // return TypeToPath.TryGetValue(type, out path); // } // public static Script GetScriptFromType(Type type) // { // InitializeIfNeeded(); // return TryGetScriptPath(type, out string path) // ? GD.Load