using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Godot; #if TOOLS namespace Texty.addons.ClassExporter { [Tool] public class Plugin : EditorPlugin { private const string LoadTypesMenuItem = "Load types"; private const string ReloadTypesMenuItem = "Reload types"; private readonly List _types = new List(); public override void _EnterTree() { Connect("resource_saved", this, nameof(OnResourceSaved)); AddToolMenuItem(LoadTypesMenuItem, this, nameof(OnReloadTypes), false); AddToolMenuItem(ReloadTypesMenuItem, this, nameof(OnReloadTypes), true); RegisterTypes(); } public override void _ExitTree() { DeRegisterTypes(); RemoveToolMenuItem(LoadTypesMenuItem); RemoveToolMenuItem(ReloadTypesMenuItem); Disconnect("resource_saved", this, nameof(OnResourceSaved)); } // ReSharper disable once UnusedParameter.Local private void OnResourceSaved(Resource resource) { RegisterTypes(); } private void OnReloadTypes(bool reload) { if (reload) DeRegisterTypes(); RegisterTypes(); } private void RegisterTypes() { var assembly = Assembly.GetExecutingAssembly(); var newTypes = from type in assembly.GetTypes() where type.IsSubclassOf(typeof(Resource)) || type.IsSubclassOf(typeof(Node)) where !type.IsSubclassOf(typeof(EditorPlugin)) where !_types.Contains(type) select new RegistrableType(type); foreach (var type in newTypes) { GD.Print($"Exporting class {type.Name}: {type.Script.ResourcePath}"); AddCustomType(type.Name, type.Base, type.Script, null); _types.Add(type.Type); } } private void DeRegisterTypes() { _types.ForEach(type => RemoveCustomType(type.Name)); _types.Clear(); } private readonly struct RegistrableType { public RegistrableType(Type type) { Type = type; } public readonly Type Type; public CSharpScript Script { get { var components = (Type.FullName ?? "").Split('.'); var path = string.Join("/", components.Skip(1)) + ".cs"; return ResourceLoader.Load(path); } } public string Name => Type.Name; public string Base => Type.BaseType?.Name ?? ""; } } } #endif