diff --git a/Behaviors.md b/Behaviors.md index 6a9c174..b825771 100644 --- a/Behaviors.md +++ b/Behaviors.md @@ -211,9 +211,16 @@ shown on the node and editable in the inspector. removing takes the edges hanging on it in *every* graph that calls the behavior. A call is a **call, not an inlining**: the nested graph runs in its own pulse cache with a fresh copy of its variable defaults, so values travel in and out through the ports and nothing else. That makes a - call repeatable and keeps a nested behavior free of hidden state — for state, use a behavior - object in the scene (see *Cross-object state* below). A behavior that would run itself raises an - error instead of looping; there is one start and one end node per behavior. + call repeatable and keeps a nested behavior free of hidden state. A behavior that would run + itself raises an error instead of looping; there is one start and one end node per behavior. +- **Keep state** (a checkbox on the calling node, off by default): the nested behavior then picks + up its variables and its local state machines where the last call **from this node, on this + object** left them. Two call nodes running the same behavior keep a state each, and so do two + objects running the same graph; a kept call inside a kept call has one per outer node. It follows + today's declarations: a variable added since starts at its default, a removed one is dropped, and + one whose kind changed starts over. The state lives as long as the object does in the run and is + never saved. For state shared between objects, use a Variables asset or a behavior object in the + scene (see *Cross-object state* below). Three ways in and out of a call: **drag** a behavior out of the asset panel onto the graph and it lands as a call where you let go; **double-click** a call node to open the graph it runs. The way down stays above the graph as a **breadcrumb** (`Game > Move > Other`): click a crumb to go diff --git a/Development.md b/Development.md index c417cbc..eae8a6d 100644 --- a/Development.md +++ b/Development.md @@ -14,7 +14,7 @@ npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output php tools/make-user.php [admin|user] # an account; every tool signs in (see Accounts) php tests/php/accounts.test.php # the API's account rules, no server needed (CI's gate job) -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1384 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1385 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/State-machines.md b/State-machines.md index 668ee52..79876ce 100644 --- a/State-machines.md +++ b/State-machines.md @@ -146,8 +146,9 @@ The rules, all of them worth knowing before wiring a graph on them: whose events keep moving the machine stops the run with an endless-loop error, like the step limit. - Who hears it follows the **scope**: a local machine is heard by the instance that moved it alone, a global one by **every** instance with a matching event node — which is the point of sharing a - state. A move a nested `Run behavior` makes to a *local* machine dies with the call and is not - reported; a move it makes to a global one is a move like any other. + state. A move a nested `Run behavior` makes to a *local* machine is not reported, and it dies + with the call unless the call node has **Keep state** on (see *Behaviors*); a move it makes to a + global one is a move like any other. ## The current state while playing @@ -162,7 +163,7 @@ gone the moment the run stops. Play repaints the tab the way it repaints the Beh **A local machine's current state is the behavior instance's own**, kept beside its variables (`NodeContext.states`, machine id → state id): two crates running the same behavior are in states of their own, and a behavior run through `Run behavior` starts in no state, as it starts -with fresh variables. A **global** one is kept for the run instead (`SharedState.states`, built +with fresh variables, unless the call keeps its state. A **global** one is kept for the run instead (`SharedState.states`, built once per run in `core/graph/sharedState.ts`) and every instance reads and moves that one — which bag a node touches is decided by the machine's scope, not by the node (`stateBag`). Neither survives a stop: both begin the next Play at the start state again, or in no state where there is