World Generation Memberships
Explains world generation memberships, placement occurrences, ordering pins, validation, and removal behavior.
World generation uses child-owned memberships for its reusable content.
ZoneAsset.Worldsdeclares the worlds that collect a zone.WorldGenBiomeAsset.Zonesdeclares the zones that collect a biome.CaveTypeAsset.CaveConfigsdeclares the cave configurations that collect a cave type.CoverAsset.Biomesdeclares cover placements in biomes.PrefabPatternAsset.Biomesdeclares prefab placements in biomes.UniquePrefabAsset.Zonesdeclares unique prefab placements in zones.WorldGenLayerAsset.Biomesdeclares static and dynamic layer placements in biomes.
Worlds compose the registered worldgen assets directly. Prefabs use the asset store, and image masks use their explicit resource paths. World-specific content directories are no longer required.
Remove the retired ContentConfig and PrefabStore properties from world assets. These properties are absent from the canonical schema and produce a diagnostic directing authors to remove them. The legacy provider ID remains compatible.
A same-key Parent: "super" overlay inherits an omitted SeedName. Explicit seed names override it. Different-key zones and biomes still require their own seed name. Cave nodes retain their anonymous-node rules; name new cave graphs explicitly. Preserve converted labels and indices when moving or renaming assets.
Noise payloads inherit omitted scalars, references, and nested properties. Explicit arrays replace the inherited sequence, preserving order and duplicates. Singular inputs remain distinct from arrays.
Membership arrays are inherited replacement fields. They do not append to the parent array.
Asset names and folders
Each asset key is its filename without .json. Keys must be unique within their asset type, regardless of folder or case.
Use a descriptive name. Add a qualifier only when another asset of that type needs the same name.
Prefix biome keys with their Type: Tile_ or Custom_.
For example, Tile_Cold_Kelp is a Tile biome. Custom_Cold_Kelp_Patch is its Custom patch.
Keep existing qualifiers, including _Patch and River_, after the prefix.
Keep the biome's SeedName unchanged. Biome-mask rules and interpolation names use seed names, not asset keys.
Capitalize each word and use single underscores between words. Repeated world and zone prefixes are unnecessary.
Folders give context for filesystem navigation. Converted biomes sit under their zone.
Dependencies used by one biome sit under that biome within its zone.
Dependencies shared by several biomes sit at the zone's shared level.
Dependencies used by several zones sit under Shared.
Cave folders also group nodes by their cave family and branch.
Layers sit under Layers/Static or Layers/Dynamic, then under the zone folder of their biomes.
Layers used by biomes in several zones sit under Shared.
A layer folder with more than 20 assets groups them by material family, such as Rock or Soil.
A layer name describes its blocks. A static layer name also gives its height band, such as Dirt_Cold_Between_110_And_180.
Moving an asset between folders does not change its key. Renaming a file requires updates to its asset references.
Keep SeedName, SeedIndex, Seed, Order, Rank, and ConvertedPin unchanged when you rename converted content.
These fields preserve generation identity. Folder names and asset keys do not supply that identity.
The converter records every old identity, final key, and output path in naming.tsv.
It records collision choices in collisions.tsv and shared representatives in deduplication.tsv.
Membership order
Order and Rank are converter-only placement values. ConvertedPin marks only the adjacent value.
Runtime classifies each value with these rules.
- An absent value with no true marker is native.
- A present value with no true marker is ignored. Runtime logs a WARNING and treats the item as native.
- A present nonnegative value with a true marker is pinned.
- A missing or negative value with a true marker is invalid. Runtime logs a WARNING and skips the item.
Runtime trusts a true marker as an assertion. It does not store hidden converter provenance.
Collision is the only runtime pin check. A unique unused pin enters the converted partition and can shift later identities.
The converter rejects ConvertedPin entries it did not emit. Runtime honors a collision-free pin because it cannot disprove the marker.
The repository has no separate converter-provenance report or CI fingerprint. Review converted pins against the committed asset content and collision diagnostics.
Pinned memberships precede native memberships. Pinned items sort by their value. Native items sort by canonical exact child key.
Tile and Custom biome memberships share one duplicate Order domain. Build still constructs all Tile biomes before all Custom biomes.
Color claims are collected per world and parsed RGB value. Pinned claims sort by Rank, then native claims sort by zone key.
Unique rules use one world sequence. Native rules sort by zone key, then by their physical row index.
Cave seed names
Write CaveTypeAsset.SeedName as a plain name, such as "SeedName": "Copper".
The build adds JSON string quotes and escapes before it appends the name to the cave seed.
This rule applies to converted and native cave types. Preserve SeedName after a Name change to keep generation unchanged.
CaveNodeAsset.SeedName uses its text directly. It does not add JSON string quotes.
If a node has no SeedName, the build assigns its name from the world counter.
Cover and prefab placements
Add a cover in Server/WorldGen/Covers. Add its target biomes in Biomes.
Each membership contains the cover blocks, weights, offsets, substrate, density, height condition, and noise mask.
Add a prefab pattern in Server/WorldGen/PrefabPatterns. Add its target biomes in Biomes.
Each membership contains its weighted Prefabs, optional Environment, and optional MaskCacheKey.
The pattern retains the common placement algorithm, transforms, and conditions.
Add a unique prefab in Server/WorldGen/UniquePrefabs. Add its target zones in Zones.
Each membership contains Name, Category, weighted Prefabs, and the unique placement Config.
The config contains the anchor, rotations, offsets, masks, and placement limits.
These three arrays can repeat a parent. Each row declares a separate placement occurrence.
Converted occurrences use the parent key, child key, and pinned Order as their identity.
Native occurrences use the parent key, child key, and physical membership index.
Order controls placement order. SeedIndex preserves the legacy seed fragment.
Runtime honors both fields only with ConvertedPin: true. Both values must be nonnegative.
Unmarked values log WG-MEMBER-NATIVE-ORDER and are ignored. Incomplete pins log WG-MEMBER-PIN-INVALID and are skipped.
Pinned occurrences sort by Order. Native occurrences follow in canonical child-key order, then physical membership order.
Native seed fragments include the exact child key and physical membership index.
They do not use converted numeric seed indices.
An Order collision logs WG-MEMBER-ORDER-COLLISION. A SeedIndex collision logs WG-MEMBER-SEED-COLLISION.
Either collision refuses a build that reaches that parent collection. Both diagnostics use WARNING.
Missing parents and case mismatches use the existing membership diagnostics below.
Repeated placement parents are valid and do not trigger WG-MEMBER-DUPLICATE.
The membership snapshot collects cover and pattern occurrences by biome, and unique prefab occurrences by zone. Reloading either new asset type uses the same coalesced generator rebuild as other world generation assets. A failed replacement keeps the installed generator.
Biome IDs and the cave counter do not change when these collections are composed.
World unique-zone rules and climate graph rules retain their existing ownership.
A unique climate Name must identify an active built zone.
For example, this cover adds one placement to an existing biome.
{
"Biomes": [
{
"Biome": "Tile_MyBiome",
"Blocks": [{ "SeedIndex": 0, "Block": "Rock_Stone", "Weight": 1, "Offset": 0 }],
"Density": 0.1
}
]
}The asset filename supplies the cover key. Native memberships do not need Order, SeedIndex, or ConvertedPin.
The block entry uses its own local index.
Biome layers
Add a layer in Server/WorldGen/Layers. Set Type to Static or Dynamic. Add its target biomes in Biomes.
The layer payload sits at the asset root. It contains Entries, DirectEntry, NoiseMask, and Environment.
A dynamic layer also contains Offset and OffsetNoise.
Each membership contains Biome and the optional Order, SeedIndex, and ConvertedPin fields.
The biome keeps Layers.Default and Layers.Environment. These fields apply where no layer entry applies.
The retired Layers.Static and Layers.Dynamic arrays log WG-BIOME-FIELD-RETIRED.
Static and dynamic layers use separate Order domains.
Pinned layers sort by Order. Native layers follow in canonical layer-key order, then physical membership order.
Each occurrence builds its own layer from the biome seed. Runtime does not share built layers between biomes.
A pinned layer appends -<SeedIndex> to the .LayerContainer seed of the biome.
The layer key does not enter that seed. A rename or move of a converted layer does not change generation.
A native layer seed includes the exact layer key and physical membership index. A rename of a native layer changes its seed.
A layer can list the same biome more than once. Each row declares a separate layer occurrence. The membership snapshot collects layer occurrences by biome. Reloading a layer uses the same coalesced generator rebuild as other world generation assets.
For example, this static layer adds stone between Y 0 and Y 10 to an existing biome.
{
"Type": "Static",
"Entries": [
{
"SeedIndex": 0,
"Blocks": { "Entries": [{ "SeedIndex": 0, "Block": "Rock_Stone" }] },
"Min": 0,
"Max": 10
}
],
"Biomes": [{ "Biome": "Tile_MyBiome" }]
}The asset filename supplies the layer key. A native membership does not need Order, SeedIndex, or ConvertedPin.
Zone color claims
Each ZoneAsset.Worlds entry can contain Colors and UniqueZones.
An ordinary Colors row claims one six-digit RGB color. A Rank pins its legacy row position only when ConvertedPin is true.
Each moved UniqueZones rule belongs to its zone and world membership. ParentColors contains raw RGB colors, not asset keys.
The default Radius is 1. The default Padding is 0.
A complete membership with no color claims or unique rules is a valid dormant candidate.
Validation severity and diagnostics
Every diagnostic in this section uses WARNING. User content never creates a Sentry-eligible SEVERE record.
Generated converter output treats every listed condition as a hard acceptance failure.
Retired world fields
WG-WORLD-FIELD-RETIRED: WorldGenWorldAsset '<world>' field '<field>' is retired. Remove ContentConfig and PrefabStore. Prefabs use the asset store; masks use explicit resource paths.The retired properties are detected during decoding, including inherited overlays. The candidate build refuses the affected world until the properties are removed.
Other worlds rebuild independently. Reload keeps the installed generator.
Retired biome layer fields
WG-BIOME-FIELD-RETIRED: WorldGenBiomeAsset '<biome>' field 'Layers.<field>' is retired. Move each layer into a WorldGenLayerAsset under WorldGen/Layers that lists this biome in Biomes.Runtime detects Layers.Static and Layers.Dynamic during decoding. The canonical schema does not contain these fields.
A biome that inherits these fields from its parent also reports the diagnostic.
The biome build fails until the fields are removed. The candidate build refuses each world that reaches the biome.
Reload keeps the installed generator.
Native membership order
WG-MEMBER-NATIVE-ORDER: <surface> child '<child>' parent '<parent>' sets converter-only Order without ConvertedPin. Order is ignored and the membership is ordered as native.Runtime keeps the membership and ignores Order.
Invalid membership pin
WG-MEMBER-PIN-INVALID: <surface> child '<child>' parent '<parent>' has ConvertedPin without a nonnegative Order. Membership is skipped.Runtime skips the membership.
Duplicate membership
WG-MEMBER-DUPLICATE: <surface> child '<child>' declares parent '<parent>' more than once. All duplicate memberships are skipped.Runtime skips every record for the child and parent pair.
Membership order collision
WG-MEMBER-ORDER-COLLISION: <surface> parent '<parent>' has converter Order <order> on children '<first>' and '<second>'. The parent collection is invalid.Runtime refuses a world build that reaches this parent.
Missing membership parent
WG-MEMBER-MISSING-PARENT: <surface> child '<child>' references missing parent '<parent>'. Membership is skipped.Runtime keeps the child asset loaded and skips the membership.
Membership key case collision
WG-MEMBER-CASE-COLLISION: <surface> key '<authored>' differs only by case from canonical key '<canonical>'. Membership is skipped.Runtime skips the membership.
Native color rank
WG-COLOR-NATIVE-RANK: Zone '<zone>' world '<world>' color '<color>' sets converter-only Rank without ConvertedPin. Rank is ignored and the claim is ordered as native.Runtime keeps the claim and ignores Rank.
Invalid color pin
WG-COLOR-PIN-INVALID: Zone '<zone>' world '<world>' color '<color>' has ConvertedPin without a nonnegative Rank. Claim is skipped.Runtime skips the claim.
Duplicate color claim
WG-COLOR-DUPLICATE: World '<world>' zone '<zone>' claims color '<color>' more than once. The membership is skipped.Runtime skips the complete zone and world membership. This also skips its other claims and unique rules.
Color rank collision
WG-COLOR-RANK-COLLISION: World '<world>' color '<color>' has converter Rank <rank> on zones '<first>' and '<second>'. The color mapping is invalid.Runtime refuses the world build.
Unclaimed emitted color
WG-COLOR-UNCLAIMED: World '<world>' selected mask emits color '<color>' but no active zone claims it. Generator build is refused to preserve legacy behavior.Runtime refuses the candidate generator. Reload keeps the installed generator.
Native unique rule rank
WG-UNIQUE-NATIVE-RANK: Zone '<zone>' world '<world>' unique rule <index> sets converter-only Rank without ConvertedPin. Rank is ignored and the rule is ordered as native.Runtime keeps the rule and ignores Rank.
Invalid unique rule pin
WG-UNIQUE-PIN-INVALID: Zone '<zone>' world '<world>' unique rule <index> has ConvertedPin without a nonnegative Rank. Rule is skipped.Runtime skips the rule.
Duplicate unique rule
WG-UNIQUE-DUPLICATE: Zone '<zone>' world '<world>' repeats the same unique-placement rule. All exact duplicates are skipped.Runtime skips every exact duplicate row.
Unique rule rank collision
WG-UNIQUE-RANK-COLLISION: World '<world>' has converter unique-rule Rank <rank> on '<first>' and '<second>'. The unique-rule sequence is invalid.Runtime refuses the world build.
Native cave type reaches an anonymous node
WG-CAVE-NATIVE-ANONYMOUS: CaveType '<type>' membership in CaveConfig '<config>' reaches anonymous CaveNode '<node>'. Membership is skipped. Copy the graph with explicit SeedName values or use a new named graph.Runtime skips the native cave type membership and builds the base configuration.
Native zone reaches an anonymous node
WG-ZONE-NATIVE-ANONYMOUS: Zone '<zone>' membership in world '<world>' reaches anonymous CaveNode '<node>'. Membership is skipped. Copy the cave closure with explicit SeedName values.Runtime skips the native zone membership and builds the base world.
Skipping the membership also removes all color claims from that zone.
A color claimed only there then triggers WG-COLOR-UNCLAIMED and refuses the candidate build.
Invalid color
WG-COLOR-INVALID: Zone '<zone>' world '<world>' field '<field>' has invalid six-digit color '<value>'. Containing row is skipped.Runtime accepts only #[0-9A-Fa-f]{6}. A bad ParentColors element uses its indexed field name.
Runtime compares parsed 24-bit RGB values. The converter writes accepted colors in lowercase.
Editor references
The asset schema exposes World as a WorldGenWorldAsset reference.
The asset schema exposes Zone as a ZoneAsset reference.
Cave configurations are created automatically from ZoneAsset.CaveConfig and CaveTypeAsset.CaveConfigs.
These fields use nonempty, case-sensitive names. They do not require files in Server/WorldGen/CaveConfigs.
A zone configuration with no cave types generates no caves. Reloading either asset type rebuilds the configurations.
Editors offer exact canonical keys for world and zone references. Runtime still validates authored values after effective asset resolution.
A missing world or zone parent does not unload the child asset. Runtime logs WG-MEMBER-MISSING-PARENT and skips that membership.
A case-only world or zone key mismatch does not select the canonical asset. Runtime logs WG-MEMBER-CASE-COLLISION and skips that membership.
ConvertedPin is visible serialized data, not trusted provenance. Authoring it opts into fixed-stack behavior.
Membership removal and staleness
Containment removal uses an ordinary same-key child override. The higher-priority child sets Parent: "super" and supplies a complete membership array.
The complete array omits the unwanted parent. An empty array removes the child's only membership.
This operation applies to all membership arrays, including CoverAsset.Biomes, PrefabPatternAsset.Biomes, UniquePrefabAsset.Zones, and WorldGenLayerAsset.Biomes.
To remove one repeated occurrence, omit only that row. Preserve the other rows and their converted pins.
An explicitly present child array replaces inherited builder state. Membership arrays never use append inheritance.
A removal overlay freezes the complete array that existed when the overlay was authored.
A later lower-priority base addition is silently hidden by that overlay. Rebase the overlay to include the new membership.
Pack priority selects one effective same-key child. Two same-key removal packs do not commute.
Distinct child keys still compose after effective-key resolution. Their memberships use deterministic collection order.
Removing a zone world membership removes its color claims and unique rules together.
An emitted color with no remaining claimant refuses the candidate build. Reload keeps the installed generator.
A same-key biome override changes the payload and every membership occurrence.
Create a qualified variant to change one occurrence. Remove that parent from the base asset and assign it to the variant.
Use the same reassignment pattern for shared zones and cave types.
Mod set compatibility
Install world generation mods before creating a world, then keep that mod set fixed.
The composition contract preserves local identities for converted content. It does not preserve spatial patterns after mod set changes.
Adding or removing a world generation mod in an existing world intentionally disrupts zone patterns.
Runtime trusts ConvertedPin: true. A unique unused pin can shift later converted IDs, positions, and cave counters.
Runtime ignores native Order or Rank values without that marker and logs a WARNING.
A same-key removal overlay hides later lower-priority membership additions until the overlay is rebased.
A native ordinary claim grows the color array. Selection uses the hash modulo the new array length.
This can redistribute existing cells between converted zones. Colors without a native claim remain unchanged.
A unique rule's output Color installs an exclusive one-zone mapping at the later provider stage.
That exclusive mapping replaces any ordinary mapping for the same color, matching legacy behavior.
