using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using Godot; using OwofGames.GodotLume; namespace GodotHostTest.GodotDI; public static class ScopeTypesAndNames { private static readonly ConcurrentDictionary TypeToQualifiedName = new(); private static readonly ConcurrentDictionary QualifiedNameToType = new(); private static readonly ConcurrentDictionary QualifiedNameToSimpleName = new(); private static readonly Type RootScopeType = typeof(RootScope); private static AssemblyLoadEventHandler? _assemblyLoadEventHandler; private static void InitializeIfNeeded() { if (_assemblyLoadEventHandler != null) return; Initialize(); System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly())! .Unloading += _ => { Deinitialize(); }; } private static void Initialize() { GD.Print($"Initializing {nameof(ScopeTypesAndNames)}"); TypeToQualifiedName.Clear(); QualifiedNameToType.Clear(); QualifiedNameToSimpleName.Clear(); _assemblyLoadEventHandler = (sender, 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 == RootScopeType || t.IsSubclassOf(RootScopeType))) { if (type.AssemblyQualifiedName == null) { GD.PrintErr("Assembly qualified name of {type} is null"); continue; } TypeToQualifiedName[type] = type.AssemblyQualifiedName; QualifiedNameToType[type.AssemblyQualifiedName] = type; QualifiedNameToSimpleName[type.AssemblyQualifiedName] = type.Name; } } } private static void Deinitialize() { GD.Print($"Deinitializing {nameof(ScopeTypesAndNames)}"); AppDomain.CurrentDomain.AssemblyLoad -= _assemblyLoadEventHandler; _assemblyLoadEventHandler = null; TypeToQualifiedName.Clear(); QualifiedNameToType.Clear(); QualifiedNameToSimpleName.Clear(); } public static IEnumerable GetQualifiedNames() { InitializeIfNeeded(); return from p in TypeToQualifiedName orderby p.Key == RootScopeType ? 0 : 1 select p.Value; } public static Type GetType(string qualifiedName) { InitializeIfNeeded(); return QualifiedNameToType[qualifiedName]; } public static string GetSimpleNameFromQualifiedName(string qualifiedName) { InitializeIfNeeded(); return QualifiedNameToSimpleName[qualifiedName]; } }