Let each variable of a behavior choose whether calls keep it (#229)
The first version of #229 put a Keep state switch on the Run behavior node. The user wanted it where the variable is declared instead. Whether a value lives on belongs to the variable, not to every call site. - The node switch keepState is gone again. RunBehavior, CallResult and nested.ts are back to what they were before #229. - BehaviorAsset.keptVariables lists the kept names. It lives on the asset and not in PropertyDef, because that is the schema of every inspector row. - A variable added from now on starts with Keep on. Variables in existing projects start with Keep off, so old projects run unchanged. - SetVariableKeptCommand flips the switch as one undo step. Add, remove and rename carry the list along. Loading drops names that are not declared. - The interpreter keeps only the listed variables, per Run behavior node and per object as before. The others start at their defaults. - Local state machines in a called behavior start empty on every call again, as before #229. Global and scene machines are unchanged. - The inspector shows a Keep button in each variable row of a behavior. Its state is part of the asset signature, so a click redraws the row. Without that the button kept its old look until the inspector was reopened. Found: the project Garden of Sacrifices still has keepState = true on the call Player -> Character Movement. It is ignored now. Direction there predates the switch, so Keep is off until set by hand. Tests: - ./check.sh: 163 files, 2392 tests, CHECK EXIT 0 (before 2388) - tests/core/keep-state.test.ts rewritten, 15 tests - e2e 19: ALL PASSED, 35 checks. 19c-ii now clicks the Keep button of a new variable: on when added, off by a click, on again, off after undo. - Counter-checks, each fails its own test: keep list ignored (2), states kept (1), new variable not kept (8), rename drops the list (1), no Keep button (e2e 19c-ii). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7c70245c79
commit
454d202109
14 files changed
+333
-149
No files matched your search
+21
-1
@@ -29,13 +29,33 @@ export interface SceneAsset extends AssetBase {
|
||||
objects: SceneObject[];
|
||||
}
|
||||
|
||||
/** `variables` is this asset's own property schema; `props` holds their default values. */
|
||||
/**
|
||||
* `variables` is this asset's own property schema; `props` holds their default values.
|
||||
*
|
||||
* `keptVariables` names the variables a `Run behavior` call hands on to the next call from the same
|
||||
* node on the same object (#229); the others start at their default every call. Absent keeps none,
|
||||
* so a project from before the switch runs as it did – a variable added since starts out kept.
|
||||
*/
|
||||
export interface BehaviorAsset extends AssetBase {
|
||||
type: 'behavior';
|
||||
variables: PropertyDef[];
|
||||
keptVariables?: string[];
|
||||
graph: Graph;
|
||||
}
|
||||
|
||||
/** Whether a call of this behavior hands `key` on to the next call (#229). */
|
||||
export function isKeptVariable(asset: BehaviorAsset, key: string): boolean {
|
||||
return asset.keptVariables?.includes(key) === true;
|
||||
}
|
||||
|
||||
/** Writes the switch for one variable; an empty list is dropped rather than stored. */
|
||||
export function setKeptVariable(asset: BehaviorAsset, key: string, on: boolean): void {
|
||||
const rest = (asset.keptVariables ?? []).filter((k) => k !== key);
|
||||
const next = on ? [...rest, key] : rest;
|
||||
if (next.length > 0) asset.keptVariables = next;
|
||||
else delete asset.keptVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Declarations shared by the whole run: a `Variables` node naming this asset reads and writes one
|
||||
* value per key, however many graphs point at it. Nothing is placed, so nothing overrides it –
|
||||
|
||||
@@ -5,14 +5,19 @@ import { findAssetOf, type Project } from './Project';
|
||||
|
||||
/**
|
||||
* What a graph may see of the project around it. A behavior's `defaults` are its variable values;
|
||||
* every call copies them, so a nested behavior never carries state from one call to the next.
|
||||
* every call starts from a copy of them, except for the variables it keeps (#229).
|
||||
*/
|
||||
export function graphLookup(project: Project): GraphLookup {
|
||||
return {
|
||||
behavior: (assetId) => {
|
||||
const asset = findAssetOf(project, assetId, 'behavior');
|
||||
if (!asset) return null;
|
||||
return { name: asset.name, graph: asset.graph, defaults: resolveAssetProps(project, asset) };
|
||||
return {
|
||||
name: asset.name,
|
||||
graph: asset.graph,
|
||||
defaults: resolveAssetProps(project, asset),
|
||||
kept: asset.keptVariables ?? [],
|
||||
};
|
||||
},
|
||||
machine: (assetId) => {
|
||||
const asset = findAssetOf(project, assetId, 'statemachine');
|
||||
|
||||
Reference in new issue
Block a user