Editor API
Namespace GodotECS.Editor, plus the plugin entry point (global class). Editor tooling: debugger dock, entity inspector backend, AABB gizmos, and the bake button. See Editor tools for workflows.
plugin
csharp
[Tool]
public partial class plugin : EditorPlugin
{
public override void _EnterTree();
public override void _ExitTree();
}Compiled only with TOOLS. _EnterTree() adds an EntityDebuggerDock { Name = "ECS Debugger" } to DockSlot.LeftUr; _ExitTree() removes and frees it. Registered via addons/godotecs/plugin.cfg (name="GodotECS", version="0.1.0", script="plugin.cs").
EntityDebuggerDock
csharp
public partial class EntityDebuggerDock : Control
{
public const int TimingCapacity = 120;
public bool Paused { get; private set; }
public bool StepPending { get; }
public World CurrentWorld { get; private set; }
public int TimingCount { get; }
public EntityDebuggerDock();
public void RegisterTiming(float ms);
public void ClearTimings();
public float AverageMs();
public float[] GetTimingsOrdered();
public void SetPaused(bool paused);
public void TogglePause();
public void RequestStep();
public bool ConsumeStep();
public World[] GetWorlds();
public void SelectWorld(int index);
public static ulong ComputeHash(World w);
public void RefreshNow();
public override void _Ready();
public override void _Process(double delta);
}TimingCapacity— ring-buffer size (120 samples).- Constructor sets
CurrentWorld = World.Default. RegisterTiming(float ms)— pushes a sample; negative/NaN/infinite values are stored as0. Redraws the graph when in the tree.ClearTimings()— empties the buffer.AverageMs()— mean over stored samples (0when empty).GetTimingsOrdered()— oldest-first copy of the stored samples.SetPaused(bool)— setsPausedand updates the pause button label ("Riprendi"/"Pausa").TogglePause()flips it.RequestStep()— arms the one-shot step flag (StepPending);ConsumeStep()returnsfalsewhen disarmed, else disarms and returnstrue.GetWorlds()—{ World.Default, World.Preview }.SelectWorld(int index)— switchesCurrentWorld(out-of-range ignored, keeps selection) and refreshes.ComputeHash(World w)—Snapshot.Hash(w).RefreshNow()— no-op until_Ready()built the UI or whenCurrentWorldis null. Otherwise updates the info label (World / Tick / Live / Query(All)count,-1on query failure), the hash label (Snapshot.Save+HashBytes,err <Exception>on failure), the timing label, and the graph._Ready()— builds the UI (world selector, labels, graph, pause/step/refresh buttons) and refreshes._Process(double delta)— recordsdelta * 1000ms when unpaused and refreshes every 0.5 s.
TimingGraph
Nested inside EntityDebuggerDock (sealed partial class TimingGraph : Control, constructed with its owning dock). Custom _Draw(): dark background rect, one green bar per stored sample scaled to 1.2 × max, and a yellow horizontal line at the average. No public members beyond the constructor.
EntityInspector
csharp
public partial class EntityInspector : Node
{
public void RegisterMapping(int multimeshInstanceId, int instanceIndex, Entity entity);
public bool TryGetEntity(int multimeshInstanceId, int instanceIndex, out Entity entity);
public bool UnregisterMapping(int multimeshInstanceId, int instanceIndex);
public void ClearMappings();
public int MappingCount { get; }
public Godot.Collections.Dictionary Inspect(World world, Entity entity);
public Godot.Collections.Dictionary InspectWith<T>(World world, Entity entity)
where T : struct, IComponentData;
}- Mapping key packs both ids:
(long)(uint)multimeshInstanceId << 32 | (uint)instanceIndex.TryGetEntityreturnsfalseon miss;UnregisterMappingreturns whether an entry was removed. Inspect(World world, Entity entity)—Dictionarywithworld(name),tick(int),index,version,alive,liveCount. Null world →World.Default.InspectWith<T>(World world, Entity entity)—Inspectplushas_<TypeName>(bool) and, when present,data_<TypeName>(ToString()of the component orerr:<Exception>).
EcsGizmos
csharp
public partial class EcsGizmos : Node3D
{
public bool ShowGizmos { get; set; }
public int BoxCount { get; }
public override void _Ready();
public void AddBox(in GodotECS.Math.Aabb box);
public void SetBoxes(IEnumerable<GodotECS.Math.Aabb> boxes);
public void ClearBoxes();
public override void _Process(double delta);
public void Rebuild();
}ShowGizmos— master toggle, defaulttrue.BoxCount— queued box count.AddBoxappends,SetBoxesreplaces (null → empty),ClearBoxesempties; all mark the mesh dirty.Rebuild()— recreates the internalImmediateMesh/MeshInstance3Dnodes if missing, clears surfaces, and emits 12 line edges per box (unshaded green, shadow-casting off). No-op other than clearing the dirty flag when empty or hidden._Process(double)— hides the mesh node whenShowGizmosisfalseor the node is off-tree; otherwise shows it and rebuilds only when dirty.
BakeTool
csharp
public partial class BakeTool : VBoxContainer
{
public string LastStatus { get; private set; }
public override void _Ready();
public bool TryBake();
public bool TryBake(Node root);
}LastStatus— starts"idle"; mirrored to the status label.TryBake()— reflects overGodotECS.Authoring.Bakerfor a zero-parameter staticBakeAll/Bake/BakeWorld/BakeActiveScene; invokes the first found, statusbaked:<name>(orbake-failed:<name>+ warning when it returnsfalse).TryBake(Node root)— with non-null root prefers staticBakeSubtreeInto(World.Preview, root)→ statusbaked-subtree:<n>, elseBakeSubtree(root)→baked-subtree; with null root falls back toTryBake().- Failure modes (all return
false, warn, leave scenes untouched): Baker type absent →baker-missing; no known entry point →baker-no-entrypoint; exception →bake-error.