Let a behavior run while the editor is open

A behavior object carries a "Run in editor" switch next to Enabled. When
it is on, the behavior ticks outside of Play and works on the saved model
directly - Unity semantics: what it moves is a real change, autosaved and
not undoable.

Input stays with the editor, so On key never fires while typing. The
editor run never bakes placed containers into the model, since that would
silently drop their instanceEdits.

syncToModel reports whether it wrote anything, and the dirty flag is only
raised on change - otherwise a behavior moving something every frame
would trigger ~60 saves a second.
This commit is contained in:
root committed 2026-09-09 17:13:07 +02:00
1 parent c74037b6e1
commit 8f31afac37
21 files changed
+718 -35

No files matched your search

+15 -1
View File
@@ -7,6 +7,7 @@ import { GameViewport } from '../viewport/GameViewport';
import { SceneViewport } from '../viewport/SceneViewport';
import { attachAutosave } from './autosave';
import { ContainerEditor } from './container/ContainerEditor';
import { EditorRun } from './EditorRun';
import { GraphEditor } from './graph/GraphEditor';
import { Inspector } from './inspector/Inspector';
import { AssetPanel } from './panels/AssetPanel';
@@ -47,6 +48,7 @@ export class Editor implements PlayHost {
/** Frame rate, refreshed twice a second; null until the first measurement. */
fps: number | null = null;
private readonly play: PlaySession;
private readonly editorRun: EditorRun;
private readonly projects: ProjectSession;
private readonly leftColumn: VStack;
private readonly inspector: Inspector;
@@ -76,6 +78,7 @@ export class Editor implements PlayHost {
this.hierarchy = new HierarchyPanel(state);
this.inspector = new Inspector(state);
this.play = new PlaySession(state, this);
this.editorRun = new EditorRun(state);
this.projects = new ProjectSession(state, store, () => {
if (this.play.isPlaying) this.play.stop();
});
@@ -164,7 +167,12 @@ export class Editor implements PlayHost {
)
this.showTab('container');
});
state.on('project', () => this.play.syncFromModel());
state.on('project', () => {
this.play.syncFromModel();
this.editorRun.invalidate();
});
state.on('load', () => this.editorRun.invalidate());
state.on('mode', () => this.editorRun.invalidate());
}
showTab(tab: CentreTab): void {
@@ -204,6 +212,7 @@ export class Editor implements PlayHost {
private tick(dt: number): void {
this.measureFps(dt);
this.play.tick(dt);
this.editorRun.tick(dt);
}
/** Refreshes the toolbar readout twice a second. */
@@ -221,4 +230,9 @@ export class Editor implements PlayHost {
worldSnapshot(): WorldSnapshot | null {
return this.play.snapshot();
}
/** What is running without Play, for the check scripts. */
editorRunInfo(): { running: boolean; time: number; behaviors: string[] } {
return this.editorRun.debugInfo();
}
}