Execute behavior in editor mode #12

Closed
opened 2026-09-12 15:03:51 +02:00 by admin · 0 comments

ein toggle bei einem behavior object in einer scene (passender name fehlt mir noch):

  • wenn der toggle aktiviert ist, soll das behavior außerhalb des play modes trotzdem laufen (sprich immer)
  • das behavior ist natürlich nicht aktiv wenn die scene nicht geladen ist wo sich das behavior befindet (sprich genauso wie im play mode, nur ohne play mode)

Umgesetzt (2026-09-09). Der Schalter heisst Run in editor und steht im Inspector eines
Behavior-Objekts direkt unter Enabled. Ist er an, laeuft das Behavior weiter, waehrend das
Projekt nicht spielt (src/editor/EditorRun.ts, vom Editor neben der Play-Session getickt).

Die eine Entscheidung, die der Schalter erzwingt

Play arbeitet auf einer Wegwerf-Kopie — deshalb ist Spielen fuer das gespeicherte Projekt
gefahrlos. Ausserhalb von Play gibt es diese Kopie nicht, und damit stand die Frage im Raum, was
ein laufendes Behavior ueberhaupt anfassen darf. Entschieden wurde (Rueckfrage an den User) fuer
die Unity-Semantik (ExecuteInEditMode):

Was das Behavior bewegt oder schreibt, ist eine echte Aenderung am gespeicherten Modell.
Sie wird autosaved, die Panels zeigen sie — und Undo holt sie nicht zurueck.

Das macht den Schalter maechtig (ein Behavior kann Inhalt bauen oder anordnen) und ist genau der
Grund, warum er standardmaessig aus ist. Der E2E-Check haelt beide Haelften fest: der Server
liefert die verschobene Position aus, und nach zwei Undos ist der Schalter weg, die Bewegung nicht.

Was der Editor-Lauf bewusst nicht bekommt

Eingaben Tastatur und Maus bleiben beim Editor, sonst wuerde Tippen in einem Textfeld Behaviors ausloesen. On key …, On click und Is key down feuern hier nie; On start, On update, On timer und Kollisionen schon.
Container-Inhalt syncFromModel schreibt den Inhalt platzierter Container als normale Objekte aus (baking) und loescht dabei deren instanceEdits — im Editor waere das eine stille, irreversible Aenderung. Der Lauf instanziiert deshalb mit bakeContainers: false. Preis: ein Behavior innerhalb eines platzierten Containers laeuft ausserhalb von Play nicht.
ein zweites Leben Nur die Behaviors der geladenen Szene laufen, und nur im Edit-Modus. Play stoppt den Editor-Lauf — dort laeuft ohnehin jedes Behavior. Eine Exception im Graphen oder ein Stop game-Node beendet den Lauf und schreibt den Grund in die Notice-Zeile, statt ihn 60× pro Sekunde zu wiederholen.

Der zweite Punkt der Notiz faellt damit von selbst heraus: die Welt wird aus der aktiven Szene
gebaut, ein Behavior einer anderen Szene hat gar keine Entity. Beim Szenenwechsel wird der Lauf
neu aufgebaut oder verworfen.

Kein Save-Sturm

Ein Behavior, das jeden Frame etwas verschiebt, macht das Modell jeden Frame schmutzig — 60×
pro Sekunde speichern waere die naheliegende Katastrophe. Zwei Dinge verhindern das:

  • syncToModel() meldet jetzt, ob ueberhaupt geschrieben wurde ({structure, values} statt
    eines blossen boolean). Ein Behavior, das nur liest oder wartet, macht gar nichts schmutzig.
  • setSaveStatus('dirty') emittiert nur bei Wechsel, der Autosave-Timer wird also nicht jeden
    Frame neu gestellt. Gemessen: 2 Speicherungen in 2 Sekunden, nicht ~120.

Ein Darstellungsfehler, den erst der Screenshot gezeigt hat

schemaForAsset liefert fuer ein Behavior COMMON_PROPS + Typschema + Variablen. Der
Object-Inspector zeigte alles ausser enabled unter der Ueberschrift VARIABLES — der neue
Schalter landete also dort, wo nur steht, was das Behavior deklariert, und die Notiz „The
behavior declares no variables." verschwand fuer immer. Beides ist repariert: die Typschema-Zeilen
eines Behaviors stehen jetzt bei Enabled, die Sektion darunter fuehrt wieder nur die Variablen.
Aufgefallen ist es nur, weil ich mir den Screenshot angesehen habe — die Checks waren zufrieden.

Ein Messgeraet statt eines geratenen Offsets

Der erste Anlauf klickte die Checkbox ueber locate('Enabled').x + 55. Das trifft nur Zeilen,
deren Label in die 64-px-Spalte passt — Run in editor ist breiter und schiebt seine Checkbox
11 px nach rechts, also ging der Klick daneben und fuenf Checks fielen um. Neu ist deshalb
__gm.inspectorField(label): es liefert die Bildschirmmitte des Controls einer Inspector-
Zeile, gefunden ueber sein Label. Damit ist jeder kuenftige Inspector-Check unabhaengig von der
Labelbreite.

Belegt

Acht Unit-Tests (tests/editor/editor-run.test.ts, plus einer in container.test.ts fuer das
Nicht-Backen). Gegengeprueft: dreht man den Filter auf „alle Behaviors" und die Szenen-Bedingung
weg, fallen vier von sieben um; mit bakeContainers: true faellt der Container-Test.
Dazu zehn E2E-Checks in Modul 17:

PASS  a placed behavior does not run outside play mode until it is asked to
      – {"running":false,"time":0,"behaviors":[]} x=0
PASS  the inspector offers the switch on a behavior object, with Enabled and above the variables
      – {"enabledBox":{"x":1070,"y":221},"runBox":{"x":1081,"y":253},"variables":{…,"y":509.5}}
PASS  switching it on is an ordinary override on the object – {"runInEditor":true}
PASS  the behavior runs although Play was never pressed
      – {"running":true,"time":0.46,"behaviors":["er-logic"]} mode=edit
PASS  the owner drifts on, and the moved object is the stored one – x 48.33 → 108.32
PASS  what the behavior moved is saved, not just shown – stored x=308.31 (started at 0)
PASS  saving stays debounced while it runs, instead of once per frame – 2 saves in 2 s
PASS  taking the switch back stops the run and the object stands still – x=329.98
PASS  undo takes back the switch, never the movement it caused – overrides={} x=351.65, started at 0
PASS  the step leaves nothing of its own behind

Der Schritt baut sich seine eigene Kiste samt Behavior (On update → Move(owner)) statt den
Mover der Fixture zu nehmen — der laeuft ueber die Pfeiltasten, und die sieht der Editor-Lauf
absichtlich nie. Am Ende raeumt er alles wieder weg.

Screenshot 36-editor-run.


Übernommen aus todo-notes/done/execute-behavior-in-editor-mode.md beim Umzug auf das Issue-System (2026-09-12).

  • Angelegt: 2026-09-09 · ed455f1 — Note down three wishes for the game view
  • Abgeschlossen: 2026-09-09 · 8f31afa — Let a behavior run while the editor is open
  • Gemeldet von: admin
ein toggle bei einem behavior object in einer scene (passender name fehlt mir noch): - wenn der toggle aktiviert ist, soll das behavior außerhalb des play modes trotzdem laufen (sprich immer) - das behavior ist natürlich nicht aktiv wenn die scene nicht geladen ist wo sich das behavior befindet (sprich genauso wie im play mode, nur ohne play mode) --- **Umgesetzt (2026-09-09).** Der Schalter heisst **`Run in editor`** und steht im Inspector eines Behavior-Objekts direkt unter `Enabled`. Ist er an, laeuft das Behavior weiter, waehrend das Projekt *nicht* spielt (`src/editor/EditorRun.ts`, vom Editor neben der Play-Session getickt). ## Die eine Entscheidung, die der Schalter erzwingt Play arbeitet auf einer **Wegwerf-Kopie** — deshalb ist Spielen fuer das gespeicherte Projekt gefahrlos. Ausserhalb von Play gibt es diese Kopie nicht, und damit stand die Frage im Raum, was ein laufendes Behavior ueberhaupt anfassen darf. Entschieden wurde (Rueckfrage an den User) fuer die **Unity-Semantik** (`ExecuteInEditMode`): > Was das Behavior bewegt oder schreibt, ist eine **echte Aenderung am gespeicherten Modell**. > Sie wird autosaved, die Panels zeigen sie — und **Undo holt sie nicht zurueck**. Das macht den Schalter maechtig (ein Behavior kann Inhalt bauen oder anordnen) und ist genau der Grund, warum er **standardmaessig aus** ist. Der E2E-Check haelt beide Haelften fest: der Server liefert die verschobene Position aus, und nach zwei Undos ist der Schalter weg, die Bewegung nicht. ## Was der Editor-Lauf bewusst *nicht* bekommt | | | |---|---| | **Eingaben** | Tastatur und Maus bleiben beim Editor, sonst wuerde Tippen in einem Textfeld Behaviors ausloesen. `On key …`, `On click` und `Is key down` feuern hier nie; `On start`, `On update`, `On timer` und Kollisionen schon. | | **Container-Inhalt** | `syncFromModel` schreibt den Inhalt platzierter Container als normale Objekte aus (*baking*) und loescht dabei deren `instanceEdits` — im Editor waere das eine stille, irreversible Aenderung. Der Lauf instanziiert deshalb mit `bakeContainers: false`. **Preis:** ein Behavior *innerhalb* eines platzierten Containers laeuft ausserhalb von Play nicht. | | **ein zweites Leben** | Nur die Behaviors der **geladenen** Szene laufen, und nur im Edit-Modus. Play stoppt den Editor-Lauf — dort laeuft ohnehin jedes Behavior. Eine Exception im Graphen oder ein `Stop game`-Node beendet den Lauf und schreibt den Grund in die Notice-Zeile, statt ihn 60× pro Sekunde zu wiederholen. | Der zweite Punkt der Notiz faellt damit von selbst heraus: die Welt wird aus der aktiven Szene gebaut, ein Behavior einer anderen Szene hat gar keine Entity. Beim Szenenwechsel wird der Lauf neu aufgebaut oder verworfen. ## Kein Save-Sturm Ein Behavior, das jeden Frame etwas verschiebt, macht das Modell jeden Frame schmutzig — 60× pro Sekunde speichern waere die naheliegende Katastrophe. Zwei Dinge verhindern das: - `syncToModel()` meldet jetzt, **ob** ueberhaupt geschrieben wurde (`{structure, values}` statt eines blossen `boolean`). Ein Behavior, das nur liest oder wartet, macht gar nichts schmutzig. - `setSaveStatus('dirty')` emittiert nur bei **Wechsel**, der Autosave-Timer wird also nicht jeden Frame neu gestellt. Gemessen: **2 Speicherungen in 2 Sekunden**, nicht ~120. ## Ein Darstellungsfehler, den erst der Screenshot gezeigt hat `schemaForAsset` liefert fuer ein Behavior `COMMON_PROPS + Typschema + Variablen`. Der Object-Inspector zeigte alles ausser `enabled` unter der Ueberschrift **VARIABLES** — der neue Schalter landete also dort, wo nur steht, was das Behavior *deklariert*, und die Notiz „The behavior declares no variables." verschwand fuer immer. Beides ist repariert: die Typschema-Zeilen eines Behaviors stehen jetzt bei `Enabled`, die Sektion darunter fuehrt wieder nur die Variablen. Aufgefallen ist es nur, weil ich mir den Screenshot angesehen habe — die Checks waren zufrieden. ## Ein Messgeraet statt eines geratenen Offsets Der erste Anlauf klickte die Checkbox ueber `locate('Enabled').x + 55`. Das trifft nur Zeilen, deren Label in die 64-px-Spalte passt — `Run in editor` ist breiter und schiebt seine Checkbox 11 px nach rechts, also ging der Klick daneben und fuenf Checks fielen um. Neu ist deshalb `__gm.inspectorField(label)`: es liefert die Bildschirmmitte des **Controls** einer Inspector- Zeile, gefunden ueber sein Label. Damit ist jeder kuenftige Inspector-Check unabhaengig von der Labelbreite. ## Belegt Acht Unit-Tests (`tests/editor/editor-run.test.ts`, plus einer in `container.test.ts` fuer das Nicht-Backen). Gegengeprueft: dreht man den Filter auf „alle Behaviors" und die Szenen-Bedingung weg, fallen **vier von sieben** um; mit `bakeContainers: true` faellt der Container-Test. Dazu zehn E2E-Checks in Modul 17: ``` PASS a placed behavior does not run outside play mode until it is asked to – {"running":false,"time":0,"behaviors":[]} x=0 PASS the inspector offers the switch on a behavior object, with Enabled and above the variables – {"enabledBox":{"x":1070,"y":221},"runBox":{"x":1081,"y":253},"variables":{…,"y":509.5}} PASS switching it on is an ordinary override on the object – {"runInEditor":true} PASS the behavior runs although Play was never pressed – {"running":true,"time":0.46,"behaviors":["er-logic"]} mode=edit PASS the owner drifts on, and the moved object is the stored one – x 48.33 → 108.32 PASS what the behavior moved is saved, not just shown – stored x=308.31 (started at 0) PASS saving stays debounced while it runs, instead of once per frame – 2 saves in 2 s PASS taking the switch back stops the run and the object stands still – x=329.98 PASS undo takes back the switch, never the movement it caused – overrides={} x=351.65, started at 0 PASS the step leaves nothing of its own behind ``` Der Schritt baut sich seine eigene Kiste samt Behavior (`On update → Move(owner)`) statt den Mover der Fixture zu nehmen — der laeuft ueber die Pfeiltasten, und die sieht der Editor-Lauf absichtlich nie. Am Ende raeumt er alles wieder weg. Screenshot `36-editor-run`. --- *Übernommen aus `todo-notes/done/execute-behavior-in-editor-mode.md` beim Umzug auf das Issue-System (2026-09-12).* - **Angelegt:** 2026-09-09 · `ed455f1` — Note down three wishes for the game view - **Abgeschlossen:** 2026-09-09 · `8f31afa` — Let a behavior run while the editor is open - **Gemeldet von:** admin
admin added the todo-note label 2026-09-12 15:03:51 +02:00
admin closed this issue 2026-09-12 15:03:51 +02:00
admin added this to the Development project 2026-09-13 13:43:25 +02:00
admin moved this to Done in Development on 2026-09-13 13:44:24 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#12