Docs: DR-045 combat demo pass + session log + CLAUDE.md gotchas
DR-045 (real boss, GoalTarget=2, readable-but-fair) + session log. CLAUDE.md: core-loop demo note (GoalTarget=2, boss kit), source-gen file-using gotcha, EB-1/2/END-1/2 bullets condensed to DR pointers to stay under the 40KB budget. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
---
|
||||
title: Combat Demo-Readiness Pass — Real Boss Fight, Readable-but-Fair Threat, Onboarding + Loop Flow
|
||||
date: 2026-07-04
|
||||
tags: [session, combat, boss, demo, feel, onboarding, netcode, dots-dev, ultracode]
|
||||
permalink: gamevault/07-sessions/2026/2026-07-04-combat-demo-feel-pass
|
||||
---
|
||||
|
||||
# Combat Demo-Readiness Pass (/dots-dev, ultracode)
|
||||
|
||||
Operator brief: *"comprehensive pass of combat to make it demo-ready — adjust/improve/add/tune, nothing off limits, fun
|
||||
& fluid; also fix onboarding + the overall game loop to make logical sense for a demo."* Decisions + full change list:
|
||||
[[DR-045_Combat_Demo_Feel_Boss_Fight]]. (Second session of the day — see also [[2026-07-04_Demo_Polish_Pass]].)
|
||||
|
||||
## How it went
|
||||
|
||||
1. **Ground fan-out** (`wf_3bb890df-74e`, 5 read-only lenses; 4 done, the tuning lens quota-died but was fully covered
|
||||
by the enemy + player lenses' file:line tables). Surfaced the headline bugs: the boss health bar pegs full for 7/8 of
|
||||
the fight (`Health.Max` not replicated, boss ×8s both Current+Max), boss spawns on the party's heads, boss hitbox
|
||||
unscaled, solo-melee **perma-stunlocks any enemy incl. the boss** (every hit zeroes windup), grunts can't catch a
|
||||
moving player (speed 4.2 < 6 + windup cancels on step-back), the Charger "stagger" doesn't stagger, the onboarding
|
||||
Fabricator beat is unaffordable on lap 1 (50 Ore − 40 Turret = 10 < 30) so it silently times out, the crystal-mining
|
||||
lesson never shows, and Return false-completes on death.
|
||||
2. **Forks → operator** (AskUserQuestion): all three recommended — real boss, GoalTarget=2, readable-but-fair.
|
||||
3. **Pre-code adversarial review** (`wf_1dcddfa5-c0e`, 3 lenses + critics). Two confirmed (cone knockback must be
|
||||
HasComponent-guarded + inside `isServer`; Return must NOT gate on the 1-tick `Returning` edge). The critic swarm hit
|
||||
the Fable/session limit mid-run — I self-adjudicated all 23 candidates against the code (matched the 2 confirmed) and
|
||||
folded the fixes in. Key design simplification it drove: **drop the boss lunge** → seek + slam + summon only, which
|
||||
removed the whole `LungeState`/`IsLunging` double-writer entanglement.
|
||||
4. **Serial MCP implementation** (~24 edits + 4 new files) in compile-checked batches: server/sim (BossState, BossAISystem,
|
||||
EnemyMoveUtil, ZoneEnemySpawnUtil, EnemyAISystem, RoomEnemyDirectorSystem, knockback immunity ×3, DashSystem, Tuning,
|
||||
GoalTarget) → client (HudSystem, CombatFeedbackSystem, EnemyAnimationDriveSystem, EnemyHitFlashSystem, FeelConfig,
|
||||
PrototypeCameraRig) → onboarding (OnboardingStepMath, OnboardingSystem, OnboardingState, SettingsScreen) → prefab
|
||||
(grunt speed). Zero new `[GhostField]`; the only re-bakes are prefab/const VALUE edits (no ghost-hash change).
|
||||
5. **Verify**: 456/456 EditMode (2 onboarding tests updated to the new D2/D3 contracts). Live Play smoke — forced a Boss
|
||||
room and confirmed the boss spawns correct (360/360 HP, 1.28 hitbox, 1.6 scale, BossState), seeks the player, and its
|
||||
slam fires; `GoalProgress.Target=2` server==client; console clean.
|
||||
6. **Post-impl diff review** (`wf_71f634ea-3fa`, clean run, 0 failures): 4 candidates, only 1 confirmed — cosmetic
|
||||
orphaned doc-comments + a stray `;` from the anchor-edit tooling (fixed). No functional/netcode/determinism/
|
||||
simplification regressions survived. Re-ran tests → still 456/456.
|
||||
|
||||
## Gotchas worth remembering
|
||||
|
||||
- **The SystemAPI-source-generator copies the source file's `using` directives into `*.g.cs`.** Adding a
|
||||
`RefRO<LocalTransform>` query to `HudSystem` (which lacked `using Unity.Transforms;`) compiled the hand-written call but
|
||||
emitted CS0246 for `LocalTransform` only in the generated file. Fix = add the using to the FILE (the asmdef already
|
||||
referenced Unity.Transforms directly — this is the file-using flavor of the known asmdef-direct-ref gotcha).
|
||||
- **`script_apply_edits` anchors are REGEX** — unescaped `()` in an anchor silently matches zero (empty group), so a
|
||||
whole multi-op call fails "anchor not found." Escape `\(` `\)` (and `.` where it matters). `anchor_insert position:after`
|
||||
on a code line that has a trailing `// comment` lands the inserted text BETWEEN the code and its comment → orphaned
|
||||
comments (the post-impl review caught 3). Prefer anchoring on the comment-free token or clean up after.
|
||||
- **A runtime-added replicated component does NOT replicate** (ghost composition is baked) — so a server-only boss
|
||||
discriminator (`BossState`, runtime `AddComponent`) is the right shape; client boss identity comes from the
|
||||
already-replicated `RunInfo.CurrentRoomType==Boss` + baked `EnemyTelegraph.Kind` + position, never a new ghost field.
|
||||
- **`Health.Max` is not a `[GhostField]`** — a server-side `hp.Max *= N` never reaches the client. Reconstruct
|
||||
client-side (`bakedMax × multiplier`) rather than adding a ghost field (kept the whole pass re-bake-free).
|
||||
- **A workflow's critic swarm can die on the session/Fable limit mid-run** — the completed lenses' findings are still in
|
||||
`journal.jsonl`; self-adjudicate the un-critiqued candidates against the code rather than treating the empty result as
|
||||
a clean pass.
|
||||
- **`GoalProgress.Target` is a baker LITERAL** (not a serialized authoring field) so editing the const + recompile
|
||||
re-bakes it (no "serialized value wins over the initializer" trap); `CycleDirectorSpawnSystem` clamps a saved Target to
|
||||
the baked value, so old saves roll forward to 2 cleanly. Verified `Target=2` on both worlds at Play.
|
||||
|
||||
## Validation
|
||||
|
||||
456/456 EditMode · live Play netcode smoke (boss spawn/seek/slam + GoalTarget=2 server==client + console clean) · two
|
||||
adversarial reviews (pre-code folded, post-impl clean bar 1 cosmetic finding fixed). L3 visual/fun-gate (the boss fight
|
||||
feel, the onboarding first-lap) is the operator's playtest.
|
||||
|
||||
## Next-session intent
|
||||
|
||||
Operator fun-gate: play the boss fight (slam dodge window, phase-two adds, is it a memorable climax?) + the first-lap
|
||||
onboarding (does the Fabricator beat land now?) + a 2-run demo timing. Live-tune `BossSlam*/BossPhase2*/BossSummon*`
|
||||
(Tuning consts, recompile) + the finisher hit-stop frames (FeelConfig, live). Then the standalone 2-instance LAN smoke
|
||||
(DR-044 §5, still open).
|
||||
Reference in New Issue
Block a user