diff --git a/Architecture.md b/Architecture.md index 9bda02b..d9d72db 100644 --- a/Architecture.md +++ b/Architecture.md @@ -89,7 +89,8 @@ src/core/graph/ graph model, NodeRegistry/NodeContext/values (a travellin portTypes (#207: ports of one node that carry the same value, and the type their inputs agree on), savedValues (#166: the SaveArea a run reads persistent Variables assets from and writes them to, and restoring a save through today's declaration), stateMachine (the State node, a machine's states, the ports they become), variablePorts, propertyPorts, - lookup (what a node may look up: behaviors, state machines), keyRepeat; nodes/{events,flow,data,action,variable}/.ts + typedValues (#271: what fits a struct type, and a written variable held to its declaration), + lookup (what a node may look up: behaviors, state machines, struct types, what a variable declares), keyRepeat; nodes/{events,flow,data,action,variable}/.ts src/core/particles/ nodes (the catalogue), compile (a graph → one function per output), emission (which particles are alive at a second — a pure rule, no state) src/core/store/ serialize (untrusted JSON → Project), projectPlugins (which plugins a project switches on, read off the raw diff --git a/Development.md b/Development.md index 4e36b75..53e399d 100644 --- a/Development.md +++ b/Development.md @@ -18,7 +18,7 @@ php tests/php/accounts.test.php # the API's accoun # has and the web server's container has not (SKIP there) php tests/php/snapshots.test.php # the snapshot store (#231), the same way php tests/php/releases.test.php # the release store (#266), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1603 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1606 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/Structs.md b/Structs.md index c4fbcca..7183bd1 100644 --- a/Structs.md +++ b/Structs.md @@ -116,6 +116,16 @@ In a **mixed** list, every struct item has a **Type** row of its own, as does a such an item. Pick a struct asset there, and that one item takes on its fields and follows it, while the other items stay as they are. **Own fields** turns it back. +### A typed List node + +The `List` node, a constant list, has a **Type** setting too. Pick a struct asset there, and its +items take on the type exactly as a typed list variable's do: what they hold under the same name +stays, every other field starts at the default, **+ Item** adds one of the type, and the field +names are fixed. A list holding anything but structs refuses the type, with a line in the console. +**None** makes it a mixed list again: the items keep their values but no longer follow the asset, +since a node's list has no Type row per item. A `For each` over a typed `List` offers **Split into +Loot fields** for its `item`, like one over a typed list variable. + ### When the asset changes Typed items follow their asset like every other place of that type — the table above applies to @@ -125,7 +135,7 @@ the overrides of placed objects and in lists nested inside other items, in one u ## Deleting a struct asset The delete dialog counts the structs, the typed lists and the nodes that use it (`Pack`/`Expand` -with the type, and every split output). +and `List` with the type, and every split output). After deleting, each of them **keeps the fields it last had**, now as its own fields — no value is lost, only the link. A Type row reads **Own fields** again, an Items row **Mixed**. @@ -135,11 +145,25 @@ A struct value is the same plain bundle of fields, with or without a type: the t with the value, so `Equals`, `Index of`, saving and loading treat it as before. Edges do not check the type either — any struct fits any struct port. -The places that check are **Add item** and **Set item**, each with its **Type** setting. With a -type they take a value only if it is a struct with **exactly** the type's field names — none -missing, none more. Anything else is not added or set: the list comes out as it went in, and the -console names the value and the type. An item taken out of a typed list, and a `Pack` with the same -type, always fit. Without a type (or with one that was deleted) both take anything, as before. +The places that check are **Add item** and **Set item** with their **Type** setting, and every +**variable with a type** that a graph writes: + +- **Add item** and **Set item** with a type take a value only if it is a struct with **exactly** + the type's field names — none missing, none more. Anything else is not added or set: the list + comes out as it went in, and the console names the value and the type. An item taken out of a + typed list, and a `Pack` with the same type, always fit. Without a type (or with one that was + deleted) both take anything, as before. +- **A typed list** keeps, of what is written into it, only the items that fit its type by the same + rule. Every other item is left out and named in the console, one line each; the rest of the list + is written. This holds for a list variable, for a typed list field inside a struct variable, and + for the lists inside typed items, at any depth. +- **A struct variable with a type** takes a struct whose fields are all fields of the type. It may + leave some out: those keep their value, as in any struct variable, so a `Pack` of one field still + sets just that field. A struct bringing a field the type does not have, or a value that is no + struct at all, is not written, and the console says so. + +Writing means the `Variables` node, on a behavior's own variables and on a Variables asset's alike, +and the `Properties` node setting a behavior variable of the object it is handed. ## Under the hood @@ -158,7 +182,14 @@ struct item with a type of its own in a mixed list holds the same key. No field since field names never start with `$`. The same sync brings every marked item into shape, wherever it sits. A run never sees the key: it is taken out where values enter the game (`withoutItemTypes` in `src/core/model/Properties.ts`), which is why `Add item` and `Set item` can -compare field names exactly. +compare field names exactly. A typed `List` node keeps the marks in its setting, and its output +drops them the same way. + +What a written variable is held to comes from its declaration, not from the value. When a +`Variables` or `Properties` node is resolved, `GraphLookup.variableTyping` hands each port that +writes a variable its item type, its struct type and the typed fields inside it (`typingOf` in +`structTypes.ts`); `writeDeclared` in `src/core/graph/typedValues.ts` holds the written value to +that. A run resolves each node once, so this costs nothing per frame beyond the check itself. A typed item keeps a field's value as plain JSON, the way a declared struct does: an asset id or a texture id is a text, a color a number. What kind a field is comes from the type, so the item rows