A struct today declares its fields where it stands: on a struct variable or on a struct field. The same shape in two places is typed in twice, and nothing keeps the two in step. This issue adds a named, reusable shape.
Asset type "Struct"
Not placeable, created from the + menu, own group Structs in the asset panel.
Holds fields, each with a name, a kind and a default value. Every kind a struct field may have today is allowed, lists and other struct types included.
Edited in the inspector with the same rows as variables (+ Field, rename, remove, kind), and "Open" shows it in the Variables tab of #252. No canvas tab.
No cycles:Loot may not hold a Loot field, not even through another struct type, because its default would be endless. A list field is fine: it starts empty (and lists stay untyped here, see below).
Using it
Struct variable (behavior, Variables asset, and the fields of a struct asset): new row Type with "Own fields" or a struct asset. With a type, the fields come from the asset and cannot be changed at the variable. The values stay per variable, and a placed object may still override them.
Struct field inside a struct: the same choice.
Pack and Expand get a Type setting. With a type, their ports follow the asset by themselves. Without one they stay declared by hand as today.
When the asset changes
Field added: every value gets the field's default from the asset.
Field removed: it leaves every value, and ports of Pack/Expand with their edges.
Field renamed: one undo step renames it everywhere: in variables, defaults, overrides, and on Pack/Expand ports keeping their edges.
Kind changed or default changed: declarations follow. Values keep what fits the new kind.
Asset deleted: every place keeps the fields it last had, as its own fields. No value is lost, only the link.
Runtime
Values stay plain objects, the type does not travel with them. Equals, Index of, saving and loading stay as they are. No type check on edges in this step.
Existing "dynamic" structs
They stay and keep working, so existing projects run unchanged. A struct variable or struct field gets "Make struct type": it creates a struct asset from its current fields and values and links the place to it.
Not in this issue
Typed lists (a list whose items are one struct type, so + Item creates a Loot directly) get their own issue. Lists stay dynamic for now.
Done when
Unit tests: resolving shapes, cycle rule, add/remove/rename/kind change reaching every place, undo, load/save, fallback when the asset is deleted, "Make struct type".
e2e with the real mouse: create the asset, type a variable, rename a field and see it in the variable, the override and an Expand port with its edge.
Counter-checks that bite, and the wiki (new page Structs, plus Behaviors).
A struct today declares its fields where it stands: on a struct variable or on a struct field. The same shape in two places is typed in twice, and nothing keeps the two in step. This issue adds a named, reusable shape.
## Asset type "Struct"
- Not placeable, created from the `+` menu, own group *Structs* in the asset panel.
- Holds fields, each with a name, a kind and a **default value**. Every kind a struct field may have today is allowed, lists and other struct types included.
- Edited in the inspector with the same rows as variables (`+ Field`, rename, remove, kind), and "Open" shows it in the Variables tab of #252. No canvas tab.
- **No cycles:** `Loot` may not hold a `Loot` field, not even through another struct type, because its default would be endless. A *list* field is fine: it starts empty (and lists stay untyped here, see below).
## Using it
- **Struct variable** (behavior, Variables asset, and the fields of a struct asset): new row *Type* with "Own fields" or a struct asset. With a type, the fields come from the asset and cannot be changed at the variable. The values stay per variable, and a placed object may still override them.
- **Struct field inside a struct:** the same choice.
- **`Pack` and `Expand`** get a *Type* setting. With a type, their ports follow the asset by themselves. Without one they stay declared by hand as today.
## When the asset changes
- **Field added:** every value gets the field's default from the asset.
- **Field removed:** it leaves every value, and ports of `Pack`/`Expand` with their edges.
- **Field renamed:** one undo step renames it everywhere: in variables, defaults, overrides, and on `Pack`/`Expand` ports keeping their edges.
- **Kind changed or default changed:** declarations follow. Values keep what fits the new kind.
- **Asset deleted:** every place keeps the fields it last had, as its own fields. No value is lost, only the link.
## Runtime
Values stay plain objects, the type does not travel with them. `Equals`, `Index of`, saving and loading stay as they are. No type check on edges in this step.
## Existing "dynamic" structs
They stay and keep working, so existing projects run unchanged. A struct variable or struct field gets **"Make struct type"**: it creates a struct asset from its current fields and values and links the place to it.
## Not in this issue
Typed lists (a list whose items are one struct type, so `+ Item` creates a `Loot` directly) get their own issue. Lists stay dynamic for now.
## Done when
- Unit tests: resolving shapes, cycle rule, add/remove/rename/kind change reaching every place, undo, load/save, fallback when the asset is deleted, "Make struct type".
- e2e with the real mouse: create the asset, type a variable, rename a field and see it in the variable, the override and an `Expand` port with its edge.
- Counter-checks that bite, and the wiki (new page *Structs*, plus *Behaviors*).
admin
added this to the Development project 2026-09-27 22:17:14 +02:00
admin
moved this to Next in Development on 2026-09-27 22:17:54 +02:00
Asset type Struct (+ → Struct, group Structs): fields with name, kind and default value. "Open" shows them in the variables tab.
Struct variables and struct fields have a Type row: own fields, any Struct asset, or Make struct type. With a type the fields follow the asset and cannot be added, renamed or removed at the place. Values stay per variable, overrides on placed objects still work.
Pack / Expand have the setting Type. With a type their ports are the asset's fields (read-only).
A change to the asset reaches every typed place in one undo step: a new field comes with its default, a removed field goes along with its port, edge and typed value, a renamed field keeps its value everywhere (variables, overrides, ports with edges, nested types).
Cycles (Loot in Loot, also through another type) are refused and not offered.
Deleting the asset names how many places use it. Each place keeps its fields as its own afterwards.
Loading reshapes a stale copy to its type.
Differs from the plan
A changed default value only applies to new fields and newly typed places, existing values stay.
Removing a single field shows no warning (undo brings it back).
A field's kind cannot be changed in the editor at all, so that point does not apply.
Wiki: Structs, plus Behaviors, Architecture, Development.
Done in 61bbb96.
**What there is now**
- Asset type **Struct** (+ → Struct, group *Structs*): fields with name, kind and default value. "Open" shows them in the variables tab.
- Struct variables and struct fields have a **Type** row: own fields, any Struct asset, or **Make struct type**. With a type the fields follow the asset and cannot be added, renamed or removed at the place. Values stay per variable, overrides on placed objects still work.
- **Pack / Expand** have the setting **Type**. With a type their ports are the asset's fields (read-only).
- A change to the asset reaches every typed place in one undo step: a new field comes with its default, a removed field goes along with its port, edge and typed value, a renamed field keeps its value everywhere (variables, overrides, ports with edges, nested types).
- Cycles (Loot in Loot, also through another type) are refused and not offered.
- Deleting the asset names how many places use it. Each place keeps its fields as its own afterwards.
- Loading reshapes a stale copy to its type.
**Differs from the plan**
- A changed default value only applies to new fields and newly typed places, existing values stay.
- Removing a single field shows no warning (undo brings it back).
- A field's kind cannot be changed in the editor at all, so that point does not apply.
Typed lists are #254.
**Tests**
- `./check.sh`: 182 files, 2661 tests, CHECK EXIT 0
- e2e `GM_STEPS=1,4,21,22,54`: ALL PASSED, 176 checks (new module 54 with 14 checks, real mouse)
- 14 unit tests in `tests/core/struct-types.test.ts`
- Counter-probes all bite (unit: 4 / 8 / 1 failing tests, browser: 3 failing checks).
Wiki: [Structs](https://git.nockal.com/meleki/game-maker/wiki/Structs), plus Behaviors, Architecture, Development.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
A struct today declares its fields where it stands: on a struct variable or on a struct field. The same shape in two places is typed in twice, and nothing keeps the two in step. This issue adds a named, reusable shape.
Asset type "Struct"
+menu, own group Structs in the asset panel.+ Field, rename, remove, kind), and "Open" shows it in the Variables tab of #252. No canvas tab.Lootmay not hold aLootfield, not even through another struct type, because its default would be endless. A list field is fine: it starts empty (and lists stay untyped here, see below).Using it
PackandExpandget a Type setting. With a type, their ports follow the asset by themselves. Without one they stay declared by hand as today.When the asset changes
Pack/Expandwith their edges.Pack/Expandports keeping their edges.Runtime
Values stay plain objects, the type does not travel with them.
Equals,Index of, saving and loading stay as they are. No type check on edges in this step.Existing "dynamic" structs
They stay and keep working, so existing projects run unchanged. A struct variable or struct field gets "Make struct type": it creates a struct asset from its current fields and values and links the place to it.
Not in this issue
Typed lists (a list whose items are one struct type, so
+ Itemcreates aLootdirectly) get their own issue. Lists stay dynamic for now.Done when
Expandport with its edge.Done in
61bbb96.What there is now
Differs from the plan
Typed lists are #254.
Tests
./check.sh: 182 files, 2661 tests, CHECK EXIT 0GM_STEPS=1,4,21,22,54: ALL PASSED, 176 checks (new module 54 with 14 checks, real mouse)tests/core/struct-types.test.tsWiki: Structs, plus Behaviors, Architecture, Development.