Files
MovementTests/addons/forge/editor/statescript/StatescriptResolverRegistry.cs
Minimata e09714cf83
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 27s
Create tag and build when new code gets to main / Export (push) Successful in 7m25s
update forge
2026-05-17 00:06:44 +02:00

97 lines
2.6 KiB
C#

// Copyright © Gamesmiths Guild.
#if TOOLS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Gamesmiths.Forge.Godot.Editor.Statescript;
/// <summary>
/// Registry of available <see cref="NodeEditorProperty"/> implementations. Resolver editors are discovered
/// automatically via reflection. Any concrete subclass of <see cref="NodeEditorProperty"/> in the executing assembly is
/// registered and becomes available in node input property dropdowns.
/// </summary>
internal static class StatescriptResolverRegistry
{
private static readonly List<Func<NodeEditorProperty>> _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)!);
}
}
/// <summary>
/// Gets factory functions for all resolver editors compatible with the given expected type.
/// </summary>
/// <param name="expectedType">The type expected by the node input property.</param>
/// <returns>A list of compatible resolver editor factories.</returns>
public static List<Func<NodeEditorProperty>> GetCompatibleFactories(Type expectedType)
{
return [.. _factories.Where(factory => IsCompatibleFactory(factory, expectedType))];
}
public static int GetDefaultFactoryIndex(List<Func<NodeEditorProperty>> 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<NodeEditorProperty> factory)
{
return UseTemporaryEditor(factory, static editor => editor.DisplayName);
}
public static string GetResolverTypeId(Func<NodeEditorProperty> factory)
{
return UseTemporaryEditor(factory, static editor => editor.ResolverTypeId);
}
public static bool IsCompatibleFactory(Func<NodeEditorProperty> factory, Type expectedType)
{
return UseTemporaryEditor(factory, editor => editor.IsCompatibleWith(expectedType));
}
private static TResult UseTemporaryEditor<TResult>(
Func<NodeEditorProperty> factory,
Func<NodeEditorProperty, TResult> selector)
{
NodeEditorProperty editor = factory();
try
{
return selector(editor);
}
finally
{
if (global::Godot.GodotObject.IsInstanceValid(editor))
{
editor.Free();
}
}
}
}
#endif