Files
Project-M/Docs/Vault/07_Sessions/2026/2026-06-08_Equipment_Slots_Phase1.md
T
kronic 8ddfdbc6a5 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>
2026-06-08 11:09:40 -07:00

3.8 KiB

date, type, tags, permalink
date type tags permalink
2026-06-08 session
session
equipment
items
abilities
statmodifier
netcode
ultracode
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).