Keep items a running game puts into a typed list
A typed global list lost the items the game had added to it. The item showed up in the inspector for a moment and then was gone again. - Since #254 the project hands out a typed list as a fresh copy each time, with the `$struct` marks stripped. - While a game runs, every change to the project runs `adoptDeclarations`. It took a declared value over when it differed from the last one it had seen, compared with `!==`. - The fresh copy never equals the last one by identity. So the empty list from the project overwrote the live list on every project change, for example when the game writes something back to the scene. - The comparison now uses `sameValue`. A real edit to the variable during a run still reaches the game. Tests: - ./check.sh: CHECK EXIT 0 - New unit test in scope.test.ts, red without the fix. - e2e 55i: a graph appends to a typed global list, then another asset changes during the run. With the fix {"filled":2,"afterEdit":2}, without it afterEdit is 1 and the check fails. - GM_STEPS=1,55: ALL PASSED, 26 checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b0d0868f55
commit
e1d3c0cadb
4 files changed
+85
-5
No files matched your search
@@ -5,6 +5,7 @@
|
||||
* rename on the asset reaches both; "Make struct type" turns a list's items into an asset. In a run
|
||||
* `Add item` with a type takes an item of that list and a Pack of it, and turns a number away. A
|
||||
* typed item's asset field is drawn as the asset picker its type declares, not as the text it holds.
|
||||
* A shared typed list keeps what a run added to it when the document changes during the run.
|
||||
*
|
||||
* Everything it adds carries a `tl55` id or is an asset it made, and goes again at the end.
|
||||
*/
|
||||
@@ -305,15 +306,76 @@ export async function typedLists(t) {
|
||||
JSON.stringify(logged),
|
||||
);
|
||||
|
||||
// 55i. A shared typed list the run has added to keeps the item when the document changes while
|
||||
// the run is on: its declaration is a fresh copy each time, which is no edit of it.
|
||||
const fillGraph = {
|
||||
nodes: [
|
||||
node('tl55-f-start', 'OnStart', -400, 0),
|
||||
node('tl55-f-get', 'Variables', -400, 160, { variablesAsset: 'tl55-save' }, [
|
||||
{ key: 'inv', kind: 'list' },
|
||||
]),
|
||||
node('tl55-f-pack', 'PackStruct', -400, 320, { structType: LOOT, Name: 'Bow', Amount: 2 }, fields),
|
||||
node('tl55-f-add', 'AddItem', -200, 160, { structType: LOOT }),
|
||||
node('tl55-f-set', 'Variables', 0, 0, { variablesAsset: 'tl55-save' }, [
|
||||
{ key: 'inv', kind: 'list', write: true },
|
||||
]),
|
||||
],
|
||||
edges: [
|
||||
edge('tl55-f-e1', 'tl55-f-start', 'exec', 'tl55-f-set', 'exec'),
|
||||
edge('tl55-f-e2', 'tl55-f-get', 'inv', 'tl55-f-add', 'list'),
|
||||
edge('tl55-f-e3', 'tl55-f-pack', 'value', 'tl55-f-add', 'value'),
|
||||
edge('tl55-f-e4', 'tl55-f-add', 'result', 'tl55-f-set', 'inv'),
|
||||
],
|
||||
};
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
const scene = __gm.state.activeScene;
|
||||
const inv = [{ Name: 'Gem', Amount: 4, [${JSON.stringify(MARK)}]: '${LOOT}' }];
|
||||
p.assets.push({
|
||||
id: 'tl55-save',
|
||||
type: 'variables',
|
||||
name: 'Save 55',
|
||||
props: { inv },
|
||||
variables: [{ key: 'inv', label: 'inv', kind: 'list', itemType: '${LOOT}', default: [] }],
|
||||
});
|
||||
p.assets.push({
|
||||
id: 'tl55-filler',
|
||||
type: 'behavior',
|
||||
name: 'Filler 55',
|
||||
props: { enabled: true, runInEditor: false },
|
||||
variables: [],
|
||||
graph: ${JSON.stringify(fillGraph)},
|
||||
});
|
||||
${MAKE_OBJECT}
|
||||
scene.objects.push(make('tl55-fill-obj', 'tl55-filler', '', 440, 'Filler 55'));
|
||||
`);
|
||||
const held = async () => ((await json('__gm.world()'))?.shared?.variables?.['tl55-save']?.inv ?? []).length;
|
||||
await t.play();
|
||||
await sleep(400);
|
||||
await t.clickToolbar('pause');
|
||||
await sleep(150);
|
||||
const filled = await held();
|
||||
// Any edit while the run is on – here one on another asset – brings the declarations in again.
|
||||
await mutate(`__gm.state.project.assets.find((a) => a.id === '${LOOT}').props.Amount = 7`);
|
||||
await sleep(150);
|
||||
const afterEdit = await held();
|
||||
await stop();
|
||||
check(
|
||||
'a shared typed list keeps the item the run added when the document changes during the run',
|
||||
filled === 2 && afterEdit === 2,
|
||||
JSON.stringify({ filled, afterEdit }),
|
||||
);
|
||||
|
||||
// Clean up.
|
||||
await evaluate('__gm.state.select(null)');
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
const scene = __gm.state.activeScene;
|
||||
scene.objects = scene.objects.filter((o) => o.id !== 'tl55-obj');
|
||||
scene.objects = scene.objects.filter((o) => o.id !== 'tl55-obj' && o.id !== 'tl55-fill-obj');
|
||||
const made = ${JSON.stringify(made?.id ?? '')};
|
||||
p.assets = p.assets.filter(
|
||||
(a) => a.id !== 'tl55-chest' && a.id !== '${LOOT}' && a.id !== '${DROP}' && a.id !== made,
|
||||
(a) =>
|
||||
!['tl55-chest', 'tl55-save', 'tl55-filler', '${LOOT}', '${DROP}', made].includes(a.id),
|
||||
);
|
||||
`);
|
||||
}
|
||||
Reference in new issue
Block a user