KROYSDOCS
HomeWhat's newv0.1.0
MANUAL / Extend the editor / Commands and menus

Commands and menus

A command is an action with a label, an optional shortcut, menu path, toolbar button and enabled state. Wrap scene edits in a transaction to make the whole command one undo step.

Capabilitycommands
Permissionsscene.read, scene.write
SampleCommandWithUndo
01

Register a command

Host.AddCommand(options, execute, isEnabled, isChecked) adds a command. Its editor id is <plugin id>.<Id>, so other plugins and automation can run it with Host.Execute.

OptionEffect
MenuA path under Tools › Plugins ("Arrange", "Level/Lights")
ShortcutA key chord such as "Ctrl+Shift+R"; users can rebind it in Help › Keyboard Shortcuts
ToolbarA button on the viewport's plugin toolbar (bottom left)
IconA Lucide icon name for the menu, palette and toolbar
Description, KeywordsShown and searched in the command palette

isEnabled greys the command out (for example until two entities are selected); isChecked shows a tick for toggles.

ArrangePlugin.cs
public sealed class ArrangePlugin : EditorPlugin
{
    public override void OnLoad()
    {
        // The editor command id is "<plugin id>.ArrangeInRow".
        Host.AddCommand(
            new CommandOptions("ArrangeInRow", "Arrange in Row")
            {
                Menu = "Arrange",                 // Tools > Plugins > Arrange > Arrange in Row
                Icon = "align-horizontal-distribute-center",
                Shortcut = "Ctrl+Shift+R",
                Toolbar = true,                   // the viewport's plugin toolbar
                Keywords = "align distribute row",
            },
            ArrangeInRow,
            isEnabled: () => !Host.IsPlaying && Host.Document is not null && Host.Selection.Count >= 2);
    }

    private void ArrangeInRow()
    {
        World scene = Host.Document!;
        IReadOnlyList<Entity> selection = Host.Selection;
        Vector3 start = scene.GetTransform(selection[0]).Position;
        using (Host.Transaction("Arrange in Row"))   // Ctrl+Z undoes the whole row
        {
            for (int index = 0; index < selection.Count; ++index)
            {
                Transform transform = scene.GetTransform(selection[index]);
                transform.Position = start + new Vector3(index * 2.0f, 0.0f, 0.0f);
                scene.SetTransform(selection[index], transform);
            }
        }
    }
}
02

Edit the scene with undo

Host.Document is the scene being edited (null while Play runs or without a scene) and Host.Selection the selected entities. Reading needs permission scene.read, writing scene.write. Each write is undoable on its own; inside using (Host.Transaction("Label")) all writes become one undo step named Label.

03

Run long work in the background

Host.RunTask(name, run, complete) runs run on a worker thread with progress and cancel in the Tasks panel, then calls complete on the main thread. Never touch the scene or the UI from the worker; hand results back with the completion or Host.Post.

SceneStats.cs
public sealed class SceneStats : EditorPlugin
{
    public override void OnLoad()
    {
        Host.AddCommand(new CommandOptions("Count", "Count Entities") { Menu = "Stats" }, () =>
        {
            int count = Host.Document?.Entities.Count ?? 0;
            Host.Notify(Severity.Info, "Scene", $"{count} entities, {Host.Selection.Count} selected");
        });

        // Slow work on a worker thread, with progress in the Tasks panel; the completion runs on the main thread.
        Host.AddCommand(new CommandOptions("Scan", "Scan Content") { Menu = "Stats" }, () =>
            Host.RunTask("Scan content", progress =>
            {
                string[] files = Directory.GetFiles(Host.ContentFolder, "*", SearchOption.AllDirectories);
                progress.Report(1.0f, $"{files.Length} files");
            }, (succeeded, message) => Host.Log($"scan finished: {message}")));
    }

    public override void OnUnload() => Host.Log("Stats unloading (registrations are removed for you)");
}

KroysEngine 0.1.0 documentation, built from the engine repository by Tools/BuildDocsSite.py.