EditorPlugin: панель и команда меню
Полный пример с чтением открытого уровня и симметричной очисткой.
Пример добавляет панель Scene audit и пункт Docs scene audit в меню инструментов проекта. Кнопка и меню читают корень открытой редактируемой иерархии и число его непосредственных детей. Содержимое уровня не меняется.
Файлы плагина
Создайте asset://addons/docs_scene_audit/. Сохраните следующий код как SceneAuditPlugin.cs, конфигурацию — как plugin.cfg в том же каталоге:
using Reckfell;
[Tool]
public partial class SceneAuditPlugin : EditorPlugin
{
private const string MenuName = "Docs scene audit";
private EditorDock? _dock;
private Button? _button;
private Label? _status;
private int _calls;
public override void _EnterTree()
{
_dock = new EditorDock { Name = "DocsSceneAuditDock", Title = "Scene audit", DefaultSlot = EditorDock.DockSlot.LeftUl };
var layout = new VBoxContainer { Name = "Layout" }; _dock.AddChild(layout);
_button = new Button { Name = "Inspect", Text = "Inspect current level" }; layout.AddChild(_button);
_status = new Label { Name = "Status", Text = "No request" }; layout.AddChild(_status);
_button.Pressed += InspectLevel;
AddDock(_dock);
AddToolMenuItem(MenuName, Callable.From(InspectLevel));
}
private void InspectLevel()
{
Entity? root = EditorInterface.Singleton.GetEditedSceneRoot();
_calls++;
_status!.Text = root is null ? "No level open" : $"Calls: {_calls}; children: {root.GetChildCount()}";
}
public override void _ExitTree()
{
RemoveToolMenuItem(MenuName);
if (_button is not null) _button.Pressed -= InspectLevel;
if (_dock is not null) { RemoveDock(_dock); _dock.QueueFree(); }
_dock = null; _button = null; _status = null;
}
}[plugin]
name="Docs scene audit"
description="Read-only current-level inspection example"
author="Reckfell documentation"
version="1.0.0"
script="SceneAuditPlugin.cs"Соберите C#-проект, затем включите дополнение: установка. [Tool] нужен для выполнения в редакторе, а partial — для генерации обвязки SDK.
Проверьте действие
Откройте уровень с одним дочерним объектом. Нажмите Inspect current level: статус должен стать Calls: 1; children: 1. Команда Docs scene audit вызывает тот же обработчик и увеличивает Calls до 2. Если открытой иерархии нет, показывается No level open вместо обращения к пустой ссылке.
GetEditedSceneRoot() относится к редактируемому содержимому, а не к GetTree().CurrentScene запущенной игры. При редактировании префаба этот API тоже возвращает корень редактируемой иерархии; имя файла не превращает его в отдельный тип Entity.
Почему очистка симметрична
AddDock() регистрирует EditorDock. При отключении сначала удаляется команда меню и подписка кнопки, затем RemoveDock() снимает регистрацию, а QueueFree() освобождает панель и её детей. Снятие регистрации само по себе не освобождает созданный объект.
Включите, отключите и снова включите плагин. Должны остаться одна панель, одна команда и один вызов на нажатие. Не храните C#-ссылку на панель как доказательство, что её нативный объект ещё существует после отключения.
DefaultSlot задаёт начальное размещение. Пользовательский сохранённый layout может влиять на реальное положение; не обещайте всегда одну и ту же физическую колонку. Пример не принуждает пользовательский layout каждый кадр.
Выполнены включение по имени каталога, чтение тестового уровня, программные сигналы кнопки/меню, отключение, освобождение и повторное включение без дублей. Физические клики, оформление, сохранённые layout, изменяющие сцену команды и экспорт не проверялись.