Docs: EB-1 session log + DR-032; CLAUDE.md machines-can-die
Session log + DR-032 (structures reuse Health/DamageEvent, Destructible-not-PlacedStructure, fortress targeting, persistence v3, loss feedback; both adversarial reviews). CLAUDE.md: EB-1 build-gotcha bullet + persistence v3 floor-gate; net condensation of M7/inventory/UITK/juice reference bullets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -89,16 +89,17 @@ Long-form originals + the milestone each came from: `Docs/Vault/_Meta/CLAUDE_Bui
|
||||
- **`PlacedStructure{[GhostField] byte Type; int2 Cell (server-only); uint NextTick; uint LastProcessedTick}`** on an ownerless interpolated ghost. **Bake the two tick fields** (turret reuses `NextTick` as fire cooldown; they're the offline-catch-up linchpin). Only `Type` replicates (client derives `Cell` via `BaseGridMath.WorldToCell`). Data-driven `StructureCatalog` buffer. **Occupancy is DERIVED** by scanning live structure ghosts into a Temp `NativeHashSet<int2>`, never a mutable buffer on the baked `BaseAnchor`. See [[DR-014_M6_Build_Structures_Automation_Foundation]].
|
||||
- **Co-op placement atomicity:** commit the `StorageMath.Withdraw` + cell-reservation **in-place inside the RPC foreach** (only `Instantiate` goes through the ECB) so two same-tick requests for one cell can't both pass.
|
||||
- **Buildable turret = hitscan:** nearest living Husk in-region within Range, on `NextTick` cooldown appends a direct `DamageEvent{SourceNetworkId=-1}` → reuses `HealthApplyDamageSystem`. No projectile → no tunnelling.
|
||||
- **EB-1 machines can die ★ (DR-032):** structures (Turret/Wall/Pylon) bake `Health`(`[GhostField]`)+a `DamageEvent` buffer+a `Destructible` tag (NO `HitRadius`/NO `EffectiveCharacterStats` → clamp-to-0-then-die); `HealthApplyDamageSystem` destroys a `Destructible` at 0 (NOT bare `PlacedStructure` — M7 machines share it; occupancy auto-frees). `EnemyAISystem` fortress-targets the weighted-nearest of players+structures (snapshot ABOVE the early-return → an undefended base is razed; `EnemyAIMath.PickWeightedNearest`; `StructureAggroWeight` knob, <1 prefers structures, SQUARED). Loss VFX = proximity-gated `StructureFeedbackSystem` (`CombatFeedbackSystem` gated `!isStructure`). See [[DR-032_EB1_Machines_Can_Die]].
|
||||
- **Resource-gated ability tiers / buffs reuse `StatModifier`** (replace/clear-by-SourceId → bounded buffer; `StatRecomputeSystem` folds it into `EffectiveAbilityStats` both worlds). `GoalProgress{[GhostField] int Charge, Target}` rides the global CycleDirector ghost.
|
||||
- **M7 Automation (server-only; TRIMMED from the live build palette, code intact, not in the base loop) ★:** `Harvester`/`Conveyor`/`Fabricator` on `PlacedStructure`; server-only `MachineInput`/`MachineOutput` (NOT `[GhostField]`); Harvester→Conveyor→Fabricator plain server group; catch-up `ProductionMath.CyclesDue` (**lower-bound 0**, period-0 guarded); `RuntimePlacedTag` = player-built. See [[DR-020_M7_Automation_Production_Chains]] · [[DR-031_Base_Mining_Loop_Cohesion]].
|
||||
- **Per-player inventory + equipment + items ★:** harvest routes by node region (DR-031): **BASE node → shared `ResourceLedger` directly** (build currency; no `G`-friction), **Expedition/un-tagged → firing player's PERSONAL `InventorySlot`** (`[GhostField]` `OwnerSendType.All`, spill→ledger) — for BOTH the projectile (`ResourceHarvestSystem`) and melee (`MeleeComboSystem` server-only block, `Remaining` write-back for VFX); region via OPTIONAL `ComponentLookup<RegionTag>` (not a query column → no fixture-drop). `G`-key `InventoryDepositRequest` RPC deposits personal→ledger. Items = `ItemDatabase` blob (`ushort ItemId` subsumes `ResourceId`; ID-keyed; mods **INLINE on `ItemDefBlob` Mod0..3, NOT nested** — by-value `TryGetItem` reads nested empty). Equip via `EquipmentSlot` + event-driven `EquipSystem` (weapon→`AbilityRef.Id`; gear→`StatModifier`s by slot-`SourceId`, `RemoveBySourceId` strip; atomic). Session-only. See [[DR-026_Inventory_Equipment_Progression_Foundation]] · [[DR-027_Equipment_Slots_Phase1]].
|
||||
- **Disk persistence (`SaveData`, single-slot atomic JSON, versioned/additive) ★:** **born-correct load** (`CycleDirectorSpawnSystem` stages `PendingSave` AT SPAWN); host-only autosave; `BaseRestoreSystem` replays structures charge-free with REMAINING-tick cooldowns. See [[DR-019_Frontend_Menu_Settings_Saves_Build]].
|
||||
- **M7 Automation (server-only; TRIMMED from the live palette, code intact) ★:** `Harvester`/`Conveyor`/`Fabricator` on `PlacedStructure`; server-only `MachineInput`/`MachineOutput`; plain server group; catch-up `ProductionMath.CyclesDue` (**lower-bound 0**); `RuntimePlacedTag` = player-built. See [[DR-020_M7_Automation_Production_Chains]].
|
||||
- **Per-player inventory + equipment + items ★:** harvest routes by node region (DR-031): **BASE node → shared `ResourceLedger`** (build currency, no `G`-friction), **Expedition/un-tagged → PERSONAL `InventorySlot`** (`[GhostField]` `OwnerSendType.All`, spill→ledger) — BOTH projectile (`ResourceHarvestSystem`) + melee (`MeleeComboSystem` server block, `Remaining` write-back), region via OPTIONAL `ComponentLookup<RegionTag>` (not a query column → no fixture-drop). `G`-key `InventoryDepositRequest` deposits personal→ledger. Items = `ItemDatabase` blob (`ushort ItemId` subsumes `ResourceId`; mods INLINE on `ItemDefBlob`, NOT nested — by-value `TryGetItem` reads nested empty). Equip = event-driven `EquipSystem` (weapon→`AbilityRef.Id`; gear→`StatModifier`s by slot-`SourceId`). Session-only. See [[DR-026_Inventory_Equipment_Progression_Foundation]] · [[DR-027_Equipment_Slots_Phase1]].
|
||||
- **Disk persistence (`SaveData`, single-slot atomic JSON, versioned/additive) ★:** **born-correct load** (`CycleDirectorSpawnSystem` stages `PendingSave` AT SPAWN; `BaseRestoreSystem` replays structures charge-free, REMAINING-tick cooldowns, **EB-1 v3** per-structure HP set SAME-ECB born-correct). `SaveService.Load` = additive floor `[MinLoadableVersion=2, Current]` (old saves load; a missing field 0-defaults). See [[DR-019_Frontend_Menu_Settings_Saves_Build]] · [[DR-032_EB1_Machines_Can_Die]].
|
||||
|
||||
### Presentation / juice / VFX
|
||||
- **All juice/HUD = client-only managed `SystemBase` in `PresentationSystemGroup`** (once/frame, no rollback double-fire) that OBSERVES replicated state, never mutates the sim. Read ECS via `SystemAPI.Query` + `EntityManager.CompleteDependencyBeforeRO<T>()` — NOT a MonoBehaviour `LateUpdate` (job-safety throw). `Entity` is a stable client dict key for a ghost's lifetime — **prune the cache each frame** (a pruned enemy = a kill → death VFX); **never `DestroyEntity` a ghost from the client** (`GhostDespawnSystem` owns despawn). Hit-stop = a camera punch, **never `Time.timeScale`** (corrupts the sim).
|
||||
- **All juice/HUD = client-only observe-only `SystemBase` in `PresentationSystemGroup`** (once/frame, no rollback double-fire), never mutates the sim. Read ECS via `SystemAPI.Query` + `EntityManager.CompleteDependencyBeforeRO<T>()` — NOT MonoBehaviour `LateUpdate` (job-safety throw). `Entity` = a stable client dict key per ghost lifetime — **prune the cache each frame** (a pruned ghost = a kill/loss → death VFX); **never `DestroyEntity` a ghost client-side** (`GhostDespawnSystem` owns despawn). Hit-stop = camera punch, **never `Time.timeScale`**.
|
||||
- **Asset-free presentation:** procedural `AudioClip.Create` SFX; runtime `ParticleSystem` pool (Sprites/Default + HDR start color); code-built **UI Toolkit** HUD/menus. Edit a prefab asset's component in code via `PrefabUtility.LoadPrefabContents` → modify → **`SaveAsPrefabAsset(root, path)`** → `UnloadPrefabContents`. Watch **shared-material bleed** when re-tinting. ACES tonemapping needs URP color grading mode = HDR (`m_ColorGradingMode=1`).
|
||||
- **Prototype glue lives in `ProjectM.Client` as MonoBehaviours:** `PrototypeCameraRig` (player-following ARPG cam), `VFXConfig` (static `Instance` + prefab fields bridging authored VFX to `CombatFeedbackSystem`; keep a procedural fallback). A **static presentation bridge must reset on play-enter** via `[RuntimeInitializeOnLoadMethod(SubsystemRegistration)]` (statics survive fast-enter-playmode reloads → stale flash).
|
||||
- **UITK HUD + menus ★:** `MenuUi` owns the shared palette + factories + `PanelSettings`/`EventSystem` plumbing + `Round`/`Border` helpers; `HudUi`/`HudSystem` extend it. `HudSystem` = a `PresentationSystemGroup` observe-only `SystemBase` owning a runtime `UIDocument` (`sortingOrder 50`); builds the tree on the first frame `rootVisualElement != null`, root `pickingMode = Ignore` (only palette buttons opt back in). **Runtime UITK needs a `PanelSettings` WITH a `themeStyleSheet` AND an `EventSystem` + `InputSystemUIInputModule`** or buttons are silently dead. The **build palette** (lazy from the client `StructureCatalog`) drives click-to-place: green/red `BuildPreviewMath` ground-ghost, left-click → `BuildPlaceRequest` RPC, right-click/Esc cancel, `[`/`]`/R rotate, `Fire` suppressed. See [[DR-021_HUD_UITK_BuildPalette]].
|
||||
- **UITK HUD + menus ★:** `MenuUi` owns the palette/factories/`PanelSettings`/`EventSystem` plumbing; `HudSystem` = a `PresentationSystemGroup` observe-only `SystemBase` owning a runtime `UIDocument` (`sortingOrder 50`, root `pickingMode = Ignore`, tree built once `rootVisualElement != null`). **Runtime UITK needs `PanelSettings` WITH a `themeStyleSheet` AND an `EventSystem` + `InputSystemUIInputModule`** or buttons are silently dead. The build palette (lazy from the client `StructureCatalog`) drives click-to-place: green/red `BuildPreviewMath` ghost → `BuildPlaceRequest` RPC, right-click/Esc cancel, `[`/`]`/R rotate. See [[DR-021_HUD_UITK_BuildPalette]].
|
||||
- **Synty HUD skin via a build-safe `HudTheme` ★ (DR-024):** a runtime name-string `Resources.Load` of Synty sprites is **build-stripped** → use a curated `HudTheme : ScriptableObject` of serialized refs (`HudTheme.Get()` null-safe, flat fallback). `unityBackgroundImageTintColor` MULTIPLIES; don't set `unitySlice*` on 9-slice sprites (per-element ERROR); Synty sprites may import as **Multiple** → `LoadAssetAtPath<Sprite>` null. See [[DR-024_HUD_Synty_Skin_Theme]].
|
||||
|
||||
### Art import (HDRP store packs → URP)
|
||||
|
||||
Reference in New Issue
Block a user