Keep behavior variables private to their own graph (#257)
A behavior often needs working state such as a timer or a counter. Until now every variable showed up on each placed object and in the Properties menu, so the inspector filled up with values nobody should touch. A private variable works like any other inside its graph but is not offered anywhere outside. - Each behavior variable gets a lock switch next to Keep. It starts off, so existing projects stay as they are (`privateVariables`). - A placed object shows no private variable, neither in the inspector nor while the game runs. If all are private, it says so. - Switching a variable to private drops its overrides on every placed object in one undo step. Switching back does not restore them. - A running game does not write a private value back as an override, and a project change during the run does not reset it. - `+ Property` no longer offers private variables. A port that names one by hand still reads and writes it without a warning. - The default value of a private variable is read-only in the asset inspector. Its shape (name, fields, type, delete) stays editable. - Keep is now a pin icon instead of a word. With the lock added, the header of a list variable had no room left and the lock covered `+ Item`. Not done: the animation track picker still offers private variables. Tests: ./check.sh -> 186 files, 2711 tests, CHECK EXIT 0. e2e 1,19,20,21,56 -> ALL PASSED, 119 checks. New module 56 has 7 checks with a real mouse. Counter-checks fail as expected: unit without the write-back filter, the sync guard, dropping overrides or loading the flag. Browser with all variables on the object, an unfiltered menu, or no value lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cf6565d108
commit
e8b3ac0a3b
16 files changed
+455
-49
No files matched your search
+10
-3
@@ -1,6 +1,6 @@
|
||||
import { ENTITY_HANDLE, isHandleEnabled, type PointerState, worldMatrixOf } from '../core/graph';
|
||||
import { newId } from '../core/ids';
|
||||
import type { Asset, TilemapAsset } from '../core/model/Asset';
|
||||
import { type Asset, isPrivateVariable, type TilemapAsset } from '../core/model/Asset';
|
||||
import { withoutObjects } from '../core/graph/liveObjects';
|
||||
import { bagWithoutItemTypes, type PropertyBag, sameValue, type Vec2 } from '../core/model/Properties';
|
||||
import { isPlaceableType } from '../core/model/AssetTypes';
|
||||
@@ -252,8 +252,11 @@ export class World {
|
||||
const resolved = bagWithoutItemTypes(resolveSceneObjectProps(this.project, asset, object));
|
||||
for (const key of Object.keys(entity.props)) if (!(key in resolved)) delete entity.props[key];
|
||||
// The scene only ever got the objects' empty places, so a value that differs by them alone stays.
|
||||
for (const [key, value] of Object.entries(resolved))
|
||||
// A private value never reaches the scene, so the scene's is only where it starts.
|
||||
for (const [key, value] of Object.entries(resolved)) {
|
||||
if (isPrivateVariable(asset, key) && key in entity.props) continue;
|
||||
if (!sameValue(value, withoutObjects(entity.props[key]))) entity.props[key] = value;
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -322,9 +325,13 @@ export class World {
|
||||
const moved = p.x !== entity.x || p.y !== entity.y || p.z !== entity.z;
|
||||
const base = bagWithoutItemTypes(resolveSceneObjectProps(this.project, asset, object));
|
||||
// What a run holds of an object stays in the run; the scene gets the empty one.
|
||||
// A private variable (#257) has no override to hold its value: that stays in the run.
|
||||
const drifted = Object.keys(entity.props).filter(
|
||||
(k) =>
|
||||
k in base && base[k] !== entity.props[k] && !sameValue(base[k], withoutObjects(entity.props[k])),
|
||||
k in base &&
|
||||
!isPrivateVariable(asset, k) &&
|
||||
base[k] !== entity.props[k] &&
|
||||
!sameValue(base[k], withoutObjects(entity.props[k])),
|
||||
);
|
||||
if (!moved && drifted.length === 0) continue;
|
||||
// Only now, because a ref for resolved content costs a resolve of its own – and because a
|
||||
|
||||
Reference in new issue
Block a user