Map Updates

This commit is contained in:
2026-06-04 21:49:03 -07:00
parent 16b01bec38
commit 15bc1022ee
43 changed files with 4054 additions and 62 deletions
@@ -0,0 +1,63 @@
---
date: 2026-06-04
type: session
tags:
- session
- world-architecture
- economy
- building
- presentation
- art
- post-m8
permalink: gamevault/07-sessions/2026/2026-06-04-world-space-cohesion-pass
---
# Session 2026-06-04 — World-space cohesion pass
> Driven by `/dots-dev` (Feature track) under ultracode. Third log dated 2026-06-04 (after M8 + the Polish backlog pass).
## Goal
Make the flat-feeling world feel like **a more cohesive world** without editing the floor/terrain: non-flat feel
via props, **build out a base** (more placeable structures), and **destructible resource gathering + clearing out
areas**. Operator picked: balanced vertical slice · all-Synty recoloured Blight · clearing = juice + minor scrap ·
buildables = Walls + structural variety.
## Done
- **Clearing mechanic (net-new):** `BlightClutter` ownerless-interpolated ghost (RegionTag{Expedition}, [GhostField]
Remaining+Variant) + `ClutterFieldSpawner`. **Unified `ResourceHarvestSystem`** to sweep nodes + clutter in one
best-target loop (the double-destroy fix). `ExpeditionFieldSystem` scatters/clears clutter alongside the node field
(distinct seed). Client smash juice = new observe-only `WorldFeedbackSystem` + live-tunable `WorldFeelConfig`
(chip on `Remaining` decrease, shatter + camera punch on despawn, proximity-gated so region-transit stays silent).
- **Build out the base:** `StructureType.Wall=5`/`Pylon=6` (24 reserved for M7), generic `StructureAuthoring`, two
additive `StructureCatalog` rows, V/N build keys + editor hooks. `Wall.prefab` blocks the player (BoxCollider →
PhysicsCollider); `Pylon.prefab` cosmetic. `BuildPlaceSystem` untouched (already type-generic).
- **Visual cohesion:** `M_Aether_Wild`(orange)/`M_Aether_Ordered`(cyan) HDR-emissive materials; the 3 new ghosts
recoloured into the palette; the barren +1000 Blightfield became a 21-piece Synty rock/debris basin + 3 orange
wild-lights (classic-URP cosmetics in `Game.unity`, no subscene re-bake; relief via props, no terrain).
- **Validation:** EditMode **142/142** (5 harvest tests incl. overlap/fractional/same-tick-cleared). In-editor Play
(server+client) introspected via `execute_code`: baking, ghost registration, buildables (Ore 50→44, R1 collider),
clutter scatter (14+8 @ x≈1000), **0 errors**. A 4-lens adversarial-review Workflow (23 raised → 4 confirmed) caught
an immortal-shot-sink (sub-1.0 `ScrapPerHit` truncates to 0) + a same-tick-cleared passthrough — both fixed +
regression-tested before sign-off.
## Decisions
- [[DR-018_World_Space_Cohesion_Pass]] — clutter as a node-sibling on a unified sweep; byte-additive Wall/Pylon;
classic-URP Blightfield dressing; Aether-palette recolour. Builds on [[DR-013_M6_Aether_Cycle_Region_Split]] /
[[DR-014_M6_Build_Structures_Automation_Foundation]] / [[DR-015_The_Awakening_Engine_Fiction_Adoption]].
## Open / deferred
- Base-side cohesion accents (cyan lights / perimeter relief / re-enabled tiled ground) — deferred to avoid clashing
with the tuned SSAO/ACES look.
- Clearing as a spatial mechanic (gating / reveal nodes); build-palette HUD + ghost-preview; per-`Variant` clutter
meshes — all additive follow-ups.
- Eyeball the cohesion + Wall-blocks-player reads in a **focused** editor (mechanisms verified by value headless).
## Next
- A focused-editor play-through to tune the Blightfield basin density/lighting + the clutter/wall feel, then either
the base-side cohesion accents or fold clearing into a spatial mechanic — or proceed to M7 automation (the reserved
structure slots + tick fields are still the additive hook).
@@ -0,0 +1,133 @@
---
id: DR-018
title: World-space cohesion pass — destructible Blight clutter (clearing), buildable Wall/Pylon, Aether-palette Blightfield dressing
status: accepted
date: 2026-06-04
tags:
- decision
- netcode
- world-architecture
- economy
- building
- presentation
- art
- post-m8
permalink: gamevault/07-sessions/decisions/dr-018-world-space-cohesion-pass
---
# DR-018 — World-space cohesion pass
## Context
The operator asked for a **world-space pass** so the world "feels like a more cohesive world" instead of flat:
non-flat ground/foliage **without editing the terrain** (props on top only), **placing buildings / building out a
base**, and **destructible resource gathering + clearing out areas**. Recon (read-only swarm) found this is mostly a
**cohesion layer over the mature M8 foundation**, not greenfield: destructible `ResourceNode` harvesting already
existed ([[DR-013_M6_Aether_Cycle_Region_Split]]); the full grid-placement build pipeline existed but shipped only the
Turret ([[DR-014_M6_Build_Structures_Automation_Foundation]]); the world was a flat quad with ~60 clustered Synty
city props at the base and **only 4 lone pillars** at the +1000 Blightfield. The fiction ([[DR-015_The_Awakening_Engine_Fiction_Adoption]])
sets the duality: **cyan-ordered base sanctuary ↔ orange-red wild Blightfield**, Aether read by colour.
Four scope forks were resolved with the operator up front (intake `AskUserQuestion`): **balanced vertical slice**
(touch all three, foundation now / expand later) · **all-Synty recoloured** Blight (URP-native; not the HDRP
BefourStudios path) · **clearing = juice + minor scrap** (no hard gating) · **buildables = Walls + structural variety**
(cosmetic / player-blocking, NOT Husk-pathing-defensive). Hard constraints honoured: region offset (1000,0,0) +
GhostRelevancy, frozen 32×32 grid / save schema, byte ids (never enums) in Burst/RPC, static decor as collider-stripped
classic-URP cosmetics, Aether palette, predicted-loop server authority, **no terrain edit**.
## Decision
1. **Clearing = `BlightClutter`, a `ResourceNode` SIBLING harvested by a UNIFIED sweep.** New ownerless interpolated
ghost `BlightClutter { [GhostField] int Remaining; [GhostField] byte Variant; byte ScrapResourceId; float ScrapPerHit }`
(RegionTag{Expedition}, prefab duplicated from `ResourceNode.prefab` so the GhostAuthoring comes free). It deposits a
small Biomass "scrap" trickle and despawns at ≤0. **`ResourceHarvestSystem` was UNIFIED** to sweep nodes AND clutter
in ONE best-target loop — **a correctness requirement, not a convenience**: two separate sweep systems would each
`ecb.DestroyEntity` a projectile that overlaps a node AND a clutter piece → the documented "double DestroyEntity
throws at playback". `ExpeditionFieldSystem` scatters clutter from an OPTIONAL `ClutterFieldSpawner` singleton on the
same per-player-presence epoch edge as the node field (distinct seed `epoch*2+1`, round-robin Variant) and clears it
on the occupied→empty edge. Client smash juice = new **`WorldFeedbackSystem`** (observe-only managed `SystemBase` in
`PresentationSystemGroup`, mirrors `CombatFeedbackSystem`): edge-detects `Remaining` for a chip burst, despawn for a
shatter burst + camera punch, with a **proximity gate** (last-pos within ~40u of the local player) so the
region-transit relevancy-drop storm at +1000 stays silent off-camera. Knobs in live-tunable `WorldFeelConfig`.
2. **Buildables = byte-additive `Wall`(5)/`Pylon`(6).** `StructureType.Wall=5, Pylon=6` (24 stay RESERVED for M7
automation). A generic `StructureAuthoring{ byte Kind }` bakes only `PlacedStructure{Type=Kind}` (no `Turret`
component → `TurretFireSystem` ignores it). `StructureCatalogAuthoring` grew two additive rows; `BuildSendSystem`
grew dedicated **V=Wall / N=Pylon** keys + editor `PlaceWall`/`PlacePylon` hooks. **`BuildPlaceSystem` was NOT
touched** — it already resolves any catalog `Type` and stamps `PlacedStructure` + `RegionTag{Base}` generically.
`Wall.prefab` carries a static `BoxCollider` (baked → `PhysicsCollider` → the CC sweeps it → blocks the player);
`Pylon.prefab` has none (cosmetic beacon). Because `PlacedStructure.Type` is already a `[GhostField] byte`, adding
values 5/6 keeps the serializer identical → **no re-bake of existing ghosts**.
3. **Visual cohesion = Aether material pair + Blightfield basin (classic-URP cosmetics, no subscene re-bake).**
`M_Aether_Wild` (HDR orange emissive) + `M_Aether_Ordered` (HDR cyan emissive) URP/Lit assets; the three new ghosts
recoloured into the palette (Clutter→wild, Wall+Pylon→ordered). The barren +1000 Blightfield became a **21-piece
Synty rock/asteroid/debris basin + 3 orange wild-Aether point lights** under a `BlightfieldDecor` root in `Game.unity`
— deterministic ring/scatter at varied scale/height (the "non-flat" relief via props, **no terrain**), colliders
stripped (inert to the DOTS PhysicsWorld anyway, per the blessed `SyntyWorld` classic-URP pattern). Bulk authoring via
`execute_code` (PrefabUtility) for determinism + speed.
## Consequences
- **Validated.** EditMode **142/142** green (rewrote/added 5 `ResourceHarvestSystem` tests incl. node+clutter overlap,
fractional-yield, and same-tick-cleared consumption; existing 134 unaffected). **In-editor Play (server+client over
IPC), driven via `execute_code` world-introspection:** baking clean (catalog = Turret/Wall/Pylon with valid prefab
refs + correct costs; `ClutterFieldSpawner` baked); buildables end-to-end (built Wall@(16,16)+Pylon@(18,16), Ore 50→44,
Type GhostField replicated, Cell stays server-only=0 on client); **R1** confirmed (client Wall entity has
`PhysicsCollider`, Pylon doesn't); clutter scatter end-to-end (14 clutter + 8 nodes spawned + replicated at x≈1000,
round-robin variants); **R2** clear (the edited Bursted `ExpeditionFieldSystem` ran; **0 errors** all session, only the
pre-existing unfocused-editor Server-Tick-Batching warnings). Decor verified by VALUE (21 renderers, 0 broken shaders,
x∈[977,1020], correct HDR emission) — not just a screenshot.
- **Adversarial review** (4-lens Workflow → verify) raised 23, confirmed 4 (3 were one root issue). **Fixed before
sign-off:** an **immortal-shot-sink**`int amount = (int)YieldPerHit` truncates a sub-1.0 per-hit value to 0, so the
projectile is consumed, nothing deposits, and the target never depletes; reachable only because
`BlightClutterAuthoring.ScrapPerHit` was `[Min(0f)]` (the node sibling is `[Min(1f)]`). Hardened with `[Min(1f)]` +
`math.max(1, (int)…)` in the system. Plus a low **same-tick-cleared passthrough** — a 2nd projectile whose only target
a sibling already cleared this tick now still consumes (an `overlappedCleared` branch) so "a hit always spends the
shot." Both regression-tested. The 19 refuted were correct-by-design (the `ghostId==0` relevancy skip, Temp-ECB
no-dispose matching sibling spawn systems, the proximity gate vs. atomic-teleport transit, observe-only audit).
- **No new asmdefs.** New code under `…/Economy/` (`BlightClutter`, `ClutterFieldSpawner` + authorings), `…/Building/`
(`StructureType.Wall/Pylon`, `StructureAuthoring`, catalog rows), `…/Client/Presentation/` (`WorldFeedbackSystem`,
`WorldFeelConfig`), `…/Client/Building/` (BuildSendSystem keys). New assets: `BlightClutter`/`Wall`/`Pylon` prefabs,
`M_Aether_Wild`/`M_Aether_Ordered` materials, `Gameplay.unity` (clutter spawner + catalog rows), `Game.unity`
(BlightfieldDecor). Reuses the runtime-ghost recipe / region split / GhostRelevancy / swept-hit / RPC-build /
StatModifier-free-economy patterns verbatim. Orthogonal to + additive over M8; does not touch the M7 automation slots.
## Open / deferred (defaulted, tunable)
- **Base-side cohesion**: this layer dressed the Blightfield (the barren gap); the cyan-ordered base still reads via the
existing city props + the new cyan-recoloured Wall/Pylon. A deliberate base accent (cyan lights, perimeter relief,
re-enabled tiled ground) was deferred to avoid clashing with the tuned SSAO/ACES look.
- **Clearing as a spatial mechanic**: shipped as juice + scrap only (no gating); making cleared cells buildable or
reveal hidden nodes (the "functional gating" fork) is a follow-up.
- **More buildables / build-palette HUD**: dedicated V/N keys for now (matches the B/U idiom); a selectable build palette
+ ghost-preview is polish.
- **Clutter visual variety**: `Variant` is replicated + round-robined but the prefab is single-mesh; per-variant meshes
are a follow-up (additive, no schema change).
- **Focused-editor Play confirmed (2026-06-04, same day):** the Wall **stops the player CC dead at the collider face**
(drove +X, X 2.50→**3.257**, server==client, no tunnel); the **Blightfield reads as an orange-wild rock basin** vs the
cyan base (real player-view game-camera screenshots); the **clutter-clear loop works end-to-end** (BIO 0→6→10, clutter
14→13 shatter replicated to the client); node harvest AETHER 0→30 (R2 clear on the re-edited system). Console clean.
Remaining is only **feel-tuning** (basin density/lighting) + the base-side accents — not correctness.
## Build gotchas recorded this session
- **A unified sweep is REQUIRED, not optional, when two target types share one projectile pass** — separate sweep
systems each `DestroyEntity` an overlapping projectile → double-destroy at ECB playback. One best-target loop over the
combined set + a shared destroyed-bitset is the correct shape.
- **Float per-hit yield truncated to an int that ALSO gates despawn is an immortal-sink footgun**: a sub-1.0 value →
`(int)`=0 → no deposit AND no decrement, yet the projectile is still consumed. Guard with `[Min(1f)]` on the authoring
AND `math.max(1, (int)…)` in the consumer (the node path was already `[Min(1f)]`; the new clutter path wasn't).
- **Unfocused-editor Play validation is feasible via `execute_code` world-introspection** even when the Play transition
stalls: identify worlds by `world.Name`, query/instantiate/mutate via the live `EntityManager`, drive client editor
hooks (`BuildSendSystem.PlaceWall`) + deposit into the ledger to exercise end-to-end paths, and read errors-only from
the console (the tick-batching warning spam is benign). Keep the session short (unfocused can dispose netcode worlds).
- **Editing a Bursted ISystem's BODY (not its query set) is low R2 risk** — the stale-binary hazard is tied to query-set
changes on an unfocused editor; a `math.max`/loop-reorder edit that leaves the SystemAPI query set unchanged is safe.
- **`manage_prefabs modify_contents component_properties` sets a `byte` field fine** (verified Pylon.Kind=6) — the
silent-drop gotcha is enum/Vector3, not byte. Still verify via `execute_code`.
Builds on + reuses [[DR-013_M6_Aether_Cycle_Region_Split]] (region split, GhostRelevancy, swept-hit, runtime-ghost),
[[DR-014_M6_Build_Structures_Automation_Foundation]] (build pipeline, structure ghost, frozen grid/schema),
[[DR-015_The_Awakening_Engine_Fiction_Adoption]] (Aether palette), and the client-presentation pattern from
[[DR-009_GameFeel_Identity_FirstBlood]]. Serves the cohesive-world + persistent-base pillars in [[Pillars]].