// Copyright © Gamesmiths Guild. #if TOOLS using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace Gamesmiths.Forge.Godot.Editor.Statescript; /// /// Registry of available implementations. Resolver editors are discovered /// automatically via reflection. Any concrete subclass of in the executing assembly is /// registered and becomes available in node input property dropdowns. /// internal static class StatescriptResolverRegistry { private static readonly List> _factories = []; static StatescriptResolverRegistry() { Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes(); foreach (Type type in allTypes.Where( x => x.IsSubclassOf(typeof(NodeEditorProperty)) && !x.IsAbstract)) { Type captured = type; _factories.Add(() => (NodeEditorProperty)Activator.CreateInstance(captured)!); } } /// /// Gets factory functions for all resolver editors compatible with the given expected type. /// /// The type expected by the node input property. /// A list of compatible resolver editor factories. public static List> GetCompatibleFactories(Type expectedType) { return [.. _factories.Where(factory => IsCompatibleFactory(factory, expectedType))]; } public static int GetDefaultFactoryIndex(List> factories, bool isArray) { for (int i = 0; i < factories.Count; i++) { if (isArray) { if (GetResolverTypeId(factories[i]) == "ArrayVariable") { return i; } } else if (GetResolverTypeId(factories[i]) == "Variant") { return i; } } return 0; } public static string GetDisplayName(Func factory) { return UseTemporaryEditor(factory, static editor => editor.DisplayName); } public static string GetResolverTypeId(Func factory) { return UseTemporaryEditor(factory, static editor => editor.ResolverTypeId); } public static bool IsCompatibleFactory(Func factory, Type expectedType) { return UseTemporaryEditor(factory, editor => editor.IsCompatibleWith(expectedType)); } private static TResult UseTemporaryEditor( Func factory, Func selector) { NodeEditorProperty editor = factory(); try { return selector(editor); } finally { if (global::Godot.GodotObject.IsInstanceValid(editor)) { editor.Free(); } } } } #endif