Docs: DR-027 equipment slots (Phase 1) + session log
DR-027 records the architecture (reuse AbilityRef/StatModifier; event-driven server-only equip supersedes DR-026's per-tick sketch), the 7 validated decisions, the inline-mod + reserved-SourceId fixes, and the MaxHealth-gear / session-only notes. Folds the equipment pointer into CLAUDE.md's inventory bullet net-zero (39925 bytes, >1KB headroom) by trimming the persistence/M7/ability-tier bullets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
---
|
||||
date: 2026-06-08
|
||||
type: session
|
||||
tags:
|
||||
- session
|
||||
- equipment
|
||||
- items
|
||||
- abilities
|
||||
- statmodifier
|
||||
- netcode
|
||||
- ultracode
|
||||
permalink: gamevault/07-sessions/2026/2026-06-08-equipment-slots-phase1
|
||||
---
|
||||
|
||||
# Session 2026-06-08 — Equipment slots (Phase 1)
|
||||
|
||||
> Driven by `/dots-dev` in **ultracode**, continuing from the Phase 0 inventory slice (committed earlier today,
|
||||
> [[DR-026_Inventory_Equipment_Progression_Foundation]]). Operator: *"Continue with the next phase."*
|
||||
|
||||
## Decision & design
|
||||
|
||||
Architecture + the 7 decisions live in [[DR-027_Equipment_Slots_Phase1]]. Per the recorded
|
||||
[[validate-netcode-design-before-coding]] preference, a 4-lens adversarial review ran BEFORE any code (netcode/
|
||||
prediction · determinism-Burst · architecture-scope · test → synthesis). Verdict **GO_WITH_CHANGES** — all
|
||||
architectural decisions confirmed, two data-layer blockers caught with clean fixes:
|
||||
|
||||
- **Blocker (EQ2):** a nested `BlobArray<ItemModSpec>` inside `ItemDefBlob` would read EMPTY — `TryGetItem` returns
|
||||
the def BY VALUE and copying a struct containing a BlobArray breaks its relative-offset pointer. **Fix:** 4 inline
|
||||
`ItemModSpec` slots (copy-safe, Burst-trivial). The `ItemDatabaseBlobTests` second-item read-back is the guard.
|
||||
- **Blocker (EQ3):** a vague "per-slot SourceId range" would collide with the flat sentinel namespace and the
|
||||
Target-filtered strip would orphan a gear item's other-target mods. **Fix:** reserved `Tuning.EquipSourceIdBase`
|
||||
(one sentinel per slot, disjoint from upgrade/debug/pickup) + target-agnostic `TimedModifierUtil.RemoveBySourceId`.
|
||||
- Plus: atomic equip-over-occupied (check bag room before withdraw — no item loss); `EquipmentSlot` index-as-slot
|
||||
(drop the redundant Slot field); event-driven (supersedes DR-026's per-tick "sync" sketch); mandatory player re-bake.
|
||||
|
||||
## What was built (clean compile, 236/236 EditMode, Play-validated)
|
||||
|
||||
- **Simulation/Items:** `EquipSlotId`, `EquipmentSlot` ([GhostField] OwnerSendType.All), `DefaultAbility`,
|
||||
`EquipRequest`/`UnequipRequest` RPCs; `ItemDefBlob` grown with `GrantedAbilityId`/`EquipSlot`/4 inline `ItemModSpec`
|
||||
+ `GetMod`; `InventoryMath.CanDeposit` (non-mutating fit check); `Tuning.EquipSourceIdBase` + SourceId map.
|
||||
- **Authoring:** `ItemDefinition` SO equip fields + `ItemModAuthoring`; baker writes the inline slots; `PlayerAuthoring`
|
||||
bakes the 4-row `EquipmentSlot` + `DefaultAbility`.
|
||||
- **Server:** `EquipSystem` (event-driven, owner-map, atomic, weapon→`AbilityRef`, gear→`StatModifier` by slot
|
||||
sentinel, target-agnostic strip, DefaultAbility on weapon-unequip).
|
||||
- **Client:** `EquipSendSystem` (keys 1-9 / U + build-safe static hooks); `HudSystem` equipment panel + click-to-equip
|
||||
(bag row) / click-to-unequip (slot), observe-only from replicated `EquipmentSlot`.
|
||||
- **Tests:** `ItemDatabaseBlobTests`, `EquipSystemTests` (7 cases).
|
||||
- **Content:** 4 catalog items — Rapid Blaster (→FastLight), Heavy Cannon (→SlowHeavy +10 dmg), Aether Vest (+15%
|
||||
MoveSpeed), Power Sigil (+20% Damage) — wired into the `ItemDatabase` subscene; re-baked.
|
||||
|
||||
## Play validation (host+client)
|
||||
|
||||
Equip weapon → `AbilityRef.Id` 1→2 on **both** worlds (prefab+base-stat swap, replicated); equip gear →
|
||||
`EffectiveCharacterStats.MoveSpeed` 6.0→6.90 (folded both worlds), `equipMods=1`, items left the bag. Unequip →
|
||||
AbilityRef→1 (DefaultAbility), MoveSpeed→6.0, mods stripped, items returned. Re-baked player handshakes cleanly. HUD
|
||||
equipment panel renders catalog names (`Weapon: Rapid Blaster` + `unequip`); equippable bag rows are click-wired.
|
||||
|
||||
## Next-session intent
|
||||
|
||||
**Phase 2 — tool-gated harvesting:** bake `RequiredToolType`/`RequiredToolTier` on `ResourceNode`/`BlightClutter`;
|
||||
`ResourceHarvestSystem` gates + scales yield by the owner's equipped Tool slot (the slot is already reserved + baked).
|
||||
Then **Phase 3 — crafting + per-player persistence** (additive `SaveData` v3 that restores AND replays equip).
|
||||
Reference in New Issue
Block a user