docs(B.4c): implementation plan — 4 tasks, door spawn-time sequencer + UM diagnostic
Task-by-task plan with full code in every step, no placeholders. Task 1: IsDoorSpawn helper + Door registration branch (state-seeded SetCycle from spawn PhysicsState ETHEREAL bit). Task 2: [door-cycle] diagnostic in OnLiveMotionUpdated for greppable verification. Task 3: Holtburg inn doorway visual test (user-performed). Task 4: ship handoff + close #58 + roadmap/CLAUDE/memory updates. Self-review table at bottom maps every spec section to its task(s); all covered. Companion to spec docs/superpowers/specs/2026-05-13-phase-b4c-design.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b4f131e5c6
commit
6ae38f7c6c
1 changed files with 444 additions and 0 deletions
444
docs/superpowers/plans/2026-05-13-phase-b4c-plan.md
Normal file
444
docs/superpowers/plans/2026-05-13-phase-b4c-plan.md
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
# Phase B.4c — Door Swing Animation Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make Holtburg's inn doors visibly swing open / closed when the player Uses them. Closes #58 and completes the M1 demo target *"open the inn door"* with full visual feedback.
|
||||
|
||||
**Architecture:** One block edit in `GameWindow.cs` adds a Door-specific spawn-time branch alongside the existing creature gate at line 2692. Detect Door entities by `spawn.Name == "Door"`. For each, build the same `AnimationSequencer` as creatures (load `MotionTable` from dats, construct sequencer) and immediately seed it with the `Off` cycle (closed) or `On` cycle (already open) based on the spawn's `PhysicsState` ETHEREAL bit. The existing `OnLiveMotionUpdated` handler then routes naturally — no downstream changes. Adds one diagnostic line in the UM handler for greppable verification. Spec: [`docs/superpowers/specs/2026-05-13-phase-b4c-design.md`](../specs/2026-05-13-phase-b4c-design.md).
|
||||
|
||||
**Tech Stack:** C# .NET 10 · existing `AnimationSequencer` + per-frame tick + WB renderer · no new dependencies.
|
||||
|
||||
---
|
||||
|
||||
## File map
|
||||
|
||||
| File | Op | Why |
|
||||
|---|---|---|
|
||||
| `src/AcDream.App/Rendering/GameWindow.cs` | Modify | Add `IsDoorSpawn` static helper + Door registration branch (after the existing `idleCycle` gate at line 2692) + `[door-cycle]` diagnostic in `OnLiveMotionUpdated`. |
|
||||
|
||||
No new files. No unit tests added — GameWindow integration code is runtime-verified per the project's existing precedent (B.4b's switch cases, L.2g's MotionUpdated routing).
|
||||
|
||||
---
|
||||
|
||||
## Task 1 — Add `IsDoorSpawn` helper + Door registration branch
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/AcDream.App/Rendering/GameWindow.cs`
|
||||
|
||||
This task adds two things in one commit: the static helper that detects Door entities, and the new `else if` branch in the live-spawn handler that registers them with a seeded `AnimationSequencer`.
|
||||
|
||||
- [ ] **Step 1: Add the `IsDoorSpawn` helper**
|
||||
|
||||
Insert this static helper immediately above the live-spawn handler. Use the `Edit` tool with this exact anchor:
|
||||
|
||||
`old_string`:
|
||||
```
|
||||
private void OnLiveEntitySpawnedLocked(AcDream.Core.Net.WorldSession.EntitySpawn spawn)
|
||||
```
|
||||
|
||||
`new_string`:
|
||||
```
|
||||
/// <summary>
|
||||
/// Phase B.4c — door detection by server-sent name. Doors fail the
|
||||
/// generic multi-frame-idle gate at line 2692 (no idle cycle), so we
|
||||
/// register them via a sibling branch with a state-seeded sequencer.
|
||||
/// </summary>
|
||||
private static bool IsDoorSpawn(AcDream.Core.Net.WorldSession.EntitySpawn spawn)
|
||||
=> spawn.Name == "Door";
|
||||
|
||||
private void OnLiveEntitySpawnedLocked(AcDream.Core.Net.WorldSession.EntitySpawn spawn)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add the Door registration branch**
|
||||
|
||||
Insert the new `else if` branch immediately after the existing `idleCycle` gate's closing brace (around line 2800). The anchor is the comment line that follows the gate. Use the `Edit` tool:
|
||||
|
||||
`old_string`:
|
||||
```
|
||||
}
|
||||
|
||||
// Dump a summary periodically so we can see drop breakdowns without
|
||||
// waiting for a graceful shutdown.
|
||||
if (_liveSpawnReceived % 20 == 0)
|
||||
```
|
||||
|
||||
`new_string`:
|
||||
```
|
||||
}
|
||||
else if (IsDoorSpawn(spawn) && _animLoader is not null)
|
||||
{
|
||||
// Phase B.4c — Door swing animation. Doors fail the
|
||||
// multi-frame-idle gate above (no idle cycle) but DO have a
|
||||
// MotionTable with On/Off cycles that ACE drives via
|
||||
// UpdateMotion. Register with a seeded sequencer so the
|
||||
// per-frame tick has frames to advance from frame 1 (without
|
||||
// the seed, Sequencer.Advance(dt) returns no frames and the
|
||||
// MeshRefs rebuild at line 7691 collapses the door to origin).
|
||||
//
|
||||
// Initial cycle mirrors ACE's Door.cs:43
|
||||
// (CurrentMotionState = motionClosed): Off when the door is
|
||||
// closed at spawn, On when the spawn PhysicsState carries the
|
||||
// ETHEREAL bit (door was already open in ACE's DB).
|
||||
uint mtableId = spawn.MotionTableId ?? (uint)setup.DefaultMotionTable;
|
||||
if (mtableId != 0)
|
||||
{
|
||||
var mtable = _dats.Get<DatReaderWriter.DBObjs.MotionTable>(mtableId);
|
||||
if (mtable is not null)
|
||||
{
|
||||
var sequencer = new AcDream.Core.Physics.AnimationSequencer(setup, mtable, _animLoader);
|
||||
|
||||
const uint NonCombatStance = 0x80000001u;
|
||||
const uint MotionOn = 0x4000000Bu; // ACE MotionCommand.On (door open)
|
||||
const uint MotionOff = 0x4000000Cu; // ACE MotionCommand.Off (door closed)
|
||||
const uint EtherealPs = 0x4u;
|
||||
uint spawnState = spawn.PhysicsState ?? 0u;
|
||||
uint initialCycle = (spawnState & EtherealPs) != 0 ? MotionOn : MotionOff;
|
||||
if (sequencer.HasCycle(NonCombatStance, initialCycle))
|
||||
sequencer.SetCycle(NonCombatStance, initialCycle);
|
||||
|
||||
var template = new (uint, IReadOnlyDictionary<uint, uint>?)[meshRefs.Count];
|
||||
for (int i = 0; i < meshRefs.Count; i++)
|
||||
template[i] = (meshRefs[i].GfxObjId, meshRefs[i].SurfaceOverrides);
|
||||
|
||||
_animatedEntities[entity.Id] = new AnimatedEntity
|
||||
{
|
||||
Entity = entity,
|
||||
Setup = setup,
|
||||
Animation = null, // sequencer-driven; tick reads sequencer state
|
||||
LowFrame = 0,
|
||||
HighFrame = 0,
|
||||
Framerate = 0f,
|
||||
Scale = scale,
|
||||
PartTemplate = template,
|
||||
CurrFrame = 0,
|
||||
Sequencer = sequencer,
|
||||
};
|
||||
|
||||
if (AcDream.Core.Physics.PhysicsDiagnostics.ProbeBuildingEnabled)
|
||||
Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[door-anim] registered guid=0x{spawn.Guid:X8} entityId=0x{entity.Id:X8} mtable=0x{mtableId:X8} initialCycle=0x{initialCycle:X8}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dump a summary periodically so we can see drop breakdowns without
|
||||
// waiting for a graceful shutdown.
|
||||
if (_liveSpawnReceived % 20 == 0)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Build green**
|
||||
|
||||
Run: `dotnet build src/AcDream.App/AcDream.App.csproj -c Debug`
|
||||
|
||||
Expected: build succeeds, 0 errors. Any new warnings should be tied to the additions only.
|
||||
|
||||
If a name like `meshRefs`, `entity`, `setup`, or `scale` doesn't resolve in scope at the insertion point, STOP and report — these are variables that exist in the surrounding scope at line 2800 of `OnLiveEntitySpawnedLocked` (verified during spec authoring at line 2700-2784 reads). They should be in scope; if Edit landed in the wrong place, fix the anchor first.
|
||||
|
||||
- [ ] **Step 4: Tests green**
|
||||
|
||||
Run: `dotnet test`
|
||||
|
||||
Expected: **1046 pass / 8 pre-existing-baseline fail** (same as main HEAD `3e08e10`). Any regression here means the new branch is touching unrelated code paths — investigate.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add src/AcDream.App/Rendering/GameWindow.cs
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(B.4c): door spawn-time AnimationSequencer with state-seeded initial cycle
|
||||
|
||||
Adds IsDoorSpawn helper and a sibling branch to the live-spawn
|
||||
handler's animation registration gate. Detects entities where
|
||||
spawn.Name == "Door" and registers them in _animatedEntities with an
|
||||
AnimationSequencer seeded from the spawn PhysicsState's ETHEREAL bit
|
||||
(Off cycle if closed, On if already open).
|
||||
|
||||
Mirrors ACE Door.cs:43 (CurrentMotionState = motionClosed) so the
|
||||
sequencer always has frames for the per-frame tick to advance from
|
||||
the first render. Without the seed, Advance(dt) returns no frames and
|
||||
the MeshRefs rebuild at line 7691 collapses the door to origin.
|
||||
|
||||
No changes to OnLiveMotionUpdated, AnimationSequencer, EntitySpawnAdapter,
|
||||
or the per-frame tick. The tick's sequencer branch at line 7497 reads
|
||||
ae.Sequencer.Advance(dt) and never touches ae.Animation in this path
|
||||
(only the legacy slerp else branch at line 7644+ does).
|
||||
|
||||
[door-anim] registered diagnostic gated on ACDREAM_PROBE_BUILDING.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2 — Add `[door-cycle]` UM dispatch diagnostic
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/AcDream.App/Rendering/GameWindow.cs`
|
||||
|
||||
Adds one diagnostic line in `OnLiveMotionUpdated` that fires whenever an `UpdateMotion` arrives for an entity named "Door". Greppable trail for verification of the open/close cycle dispatch.
|
||||
|
||||
- [ ] **Step 1: Locate the diagnostic insertion point**
|
||||
|
||||
Run (Grep tool):
|
||||
```
|
||||
pattern: ACDREAM_DUMP_MOTION.*== "1"
|
||||
path: src/AcDream.App/Rendering/GameWindow.cs
|
||||
output: content with -n
|
||||
```
|
||||
|
||||
Expected: one match around line 3075 in the `OnLiveMotionUpdated` body. The `[door-cycle]` diagnostic goes immediately after this `ACDREAM_DUMP_MOTION` block so both diagnostics are grouped.
|
||||
|
||||
- [ ] **Step 2: Add the `[door-cycle]` diagnostic**
|
||||
|
||||
Use the `Edit` tool. The anchor is the closing brace + blank line + the next code section ("Wire server-echoed RunRate") which follows the `ACDREAM_DUMP_MOTION` block at line 3075-3087:
|
||||
|
||||
`old_string`:
|
||||
```
|
||||
$"UM guid=0x{update.Guid:X8} mt=0x{update.MotionState.MovementType:X2} stance=0x{stance:X4} cmd={cmdStr} spd={spd:F2} " +
|
||||
$"| seq now style=0x{seqStyle:X8} motion=0x{seqMotion:X8}");
|
||||
}
|
||||
|
||||
// Wire server-echoed RunRate first — used for the player's own
|
||||
```
|
||||
|
||||
`new_string`:
|
||||
```
|
||||
$"UM guid=0x{update.Guid:X8} mt=0x{update.MotionState.MovementType:X2} stance=0x{stance:X4} cmd={cmdStr} spd={spd:F2} " +
|
||||
$"| seq now style=0x{seqStyle:X8} motion=0x{seqMotion:X8}");
|
||||
}
|
||||
|
||||
// Phase B.4c — durable per-Door UM dispatch trail for visual-test grep.
|
||||
if (AcDream.Core.Physics.PhysicsDiagnostics.ProbeBuildingEnabled
|
||||
&& _liveEntityInfoByGuid.TryGetValue(update.Guid, out var doorInfo)
|
||||
&& doorInfo.Name == "Door")
|
||||
{
|
||||
Console.WriteLine(System.FormattableString.Invariant(
|
||||
$"[door-cycle] guid=0x{update.Guid:X8} stance=0x{update.MotionState.Stance:X4} cmd=0x{(update.MotionState.ForwardCommand ?? 0u):X4}"));
|
||||
}
|
||||
|
||||
// Wire server-echoed RunRate first — used for the player's own
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Build green**
|
||||
|
||||
Run: `dotnet build src/AcDream.App/AcDream.App.csproj -c Debug`
|
||||
|
||||
Expected: build succeeds, 0 errors.
|
||||
|
||||
If the name `_liveEntityInfoByGuid` doesn't resolve, STOP and report. It exists in `GameWindow.cs` (verified during spec authoring; used elsewhere in `DescribeLiveEntity` around line 8758 of the B.4b-shipped tree).
|
||||
|
||||
If `doorInfo.Name` doesn't resolve, the field on the live-entity info struct may be named differently (e.g. `EntityName`). Use Grep to find the existing usage pattern and adjust.
|
||||
|
||||
- [ ] **Step 4: Tests green**
|
||||
|
||||
Run: `dotnet test`
|
||||
|
||||
Expected: same **1046 pass / 8 pre-existing-baseline fail** from Task 1.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add src/AcDream.App/Rendering/GameWindow.cs
|
||||
git commit -m "$(cat <<'EOF'
|
||||
feat(B.4c): [door-cycle] diagnostic in OnLiveMotionUpdated
|
||||
|
||||
Logs one line per UpdateMotion arriving for an entity named "Door"
|
||||
when ACDREAM_PROBE_BUILDING=1. Greppable trail for the B.4c visual
|
||||
test: confirms the dispatcher hit the sequencer for door open / close.
|
||||
|
||||
Durable subsystem-named tag per the Opus reviewer's B.4b feedback
|
||||
([B.4c] would rot after phase archival; [door-cycle] survives).
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3 — Visual verification at Holtburg inn doorway
|
||||
|
||||
**This task is performed by the user.** The implementing agent kicks off the launch in background; the user observes the running client and reports the result.
|
||||
|
||||
- [ ] **Step 1: Kill any stale client + wait for ACE session cleanup**
|
||||
|
||||
Run via PowerShell:
|
||||
```powershell
|
||||
Get-Process -Name AcDream.App -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||
Start-Sleep -Seconds 20
|
||||
```
|
||||
|
||||
Per CLAUDE.md "Logout-before-reconnect": ACE keeps the last session alive briefly after disconnect. 20s is the empirical minimum from B.4b's debug session.
|
||||
|
||||
- [ ] **Step 2: Launch the client with probes enabled**
|
||||
|
||||
Run via Bash tool with `run_in_background: true`:
|
||||
```powershell
|
||||
$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call"
|
||||
$env:ACDREAM_LIVE = "1"
|
||||
$env:ACDREAM_TEST_HOST = "127.0.0.1"
|
||||
$env:ACDREAM_TEST_PORT = "9000"
|
||||
$env:ACDREAM_TEST_USER = "testaccount"
|
||||
$env:ACDREAM_TEST_PASS = "testpassword"
|
||||
$env:ACDREAM_DEVTOOLS = "1"
|
||||
$env:ACDREAM_PROBE_BUILDING = "1"
|
||||
$env:ACDREAM_DUMP_MOTION = "1"
|
||||
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 |
|
||||
Tee-Object -FilePath "launch-b4c.log"
|
||||
```
|
||||
|
||||
- [ ] **Step 3: User performs the scenario**
|
||||
|
||||
In the running client:
|
||||
1. Wait ~8s for the player to spawn at Holtburg.
|
||||
2. Walk to the inn doorway (south building, north-facing door).
|
||||
3. Observe: door visually closed.
|
||||
4. Double-left-click the door.
|
||||
5. **Observe: door visibly swings open over a fraction of a second.**
|
||||
6. Walk forward through the open doorway.
|
||||
7. Wait ~30s in the inn.
|
||||
8. **Observe: door visibly swings closed.**
|
||||
9. Bump the closed door — confirm it blocks again.
|
||||
10. Close the client window.
|
||||
|
||||
- [ ] **Step 4: Grep the log**
|
||||
|
||||
Run via PowerShell:
|
||||
```powershell
|
||||
Select-String -Path launch-b4c.log -Pattern "door-anim|door-cycle|UM guid=.*Door|setstate.*0x7A9B4015"
|
||||
```
|
||||
|
||||
Expected matches (in approximate order):
|
||||
- `[door-anim] registered guid=0x... mtable=0x... initialCycle=0x4000000C` (one per closed door at world load)
|
||||
- (user double-clicks)
|
||||
- `UM guid=0x7A9B4015 mt=... stance=0x0001 cmd=0x000B ...` (existing UM dump for the open motion)
|
||||
- `[door-cycle] guid=0x7A9B4015 stance=0x0001 cmd=0x000B` (NEW; cmd=On)
|
||||
- `[setstate] guid=0x7A9B4015 entityId=0x000F4245 state=0x0001000C` (L.2g chain)
|
||||
- ~30s gap
|
||||
- `UM guid=0x7A9B4015 mt=... stance=0x0001 cmd=0x000C ...`
|
||||
- `[door-cycle] guid=0x7A9B4015 stance=0x0001 cmd=0x000C` (NEW; cmd=Off)
|
||||
- `[setstate] guid=0x7A9B4015 entityId=0x000F4245 state=0x00010008`
|
||||
|
||||
- [ ] **Step 5: Decide on follow-up based on observed behavior**
|
||||
|
||||
- **Animation plays + door rests at open pose for ~30s + animation plays again on close + rests at closed pose**: success. Proceed to Task 4.
|
||||
- **Animation plays as a loop instead of one-shot** (door spins continuously): pivot to Approach C from the spec (bespoke `DoorAnimationState` outside the sequencer). Out of B.4c scope; revise the spec and file a slice 2.
|
||||
- **No animation, but log shows the dispatch fired**: motion-table cycle resolution issue. Inspect `mtable.Cycles[(0x80000001 << 16) | 0x4000000B]` to see if the cycle is present. May need a different cycle key form.
|
||||
- **`[door-anim] registered` never logs**: spawn-time branch isn't firing. Check `spawn.Name` actual value (might be localized or padded). Add a one-line `Console.WriteLine` of `spawn.Name` in the live-spawn handler to surface it, then revise `IsDoorSpawn` accordingly.
|
||||
|
||||
---
|
||||
|
||||
## Task 4 — Ship handoff + close #58 + roadmap/CLAUDE/memory updates
|
||||
|
||||
**Files (in-repo):**
|
||||
- Create: `docs/research/2026-05-13-b4c-shipped-handoff.md`
|
||||
- Modify: `docs/ISSUES.md` (close #58)
|
||||
- Modify: `docs/plans/2026-04-11-roadmap.md` (add B.4c row to shipped table)
|
||||
- Modify: `CLAUDE.md` ("Currently in Phase L.2" paragraph + Next phase candidates)
|
||||
|
||||
**File (outside repo):**
|
||||
- Modify: `C:\Users\erikn\.claude\projects\C--Users-erikn-source-repos-acdream\memory\project_interaction_pipeline.md`
|
||||
|
||||
- [ ] **Step 1: Write the ship-handoff doc**
|
||||
|
||||
Create `docs/research/2026-05-13-b4c-shipped-handoff.md`. Model after `docs/research/2026-05-13-b4b-shipped-handoff.md` for structure: TL;DR / What shipped (commit table) / End-to-end flow with actual observed evidence / Open notes / Reproducibility / Worktree state.
|
||||
|
||||
Required content:
|
||||
- TL;DR: B.4c shipped, M1 demo target "open the inn door" now has full visual feedback. ~50 LOC, 2 implementation commits + 1 docs commit.
|
||||
- What shipped table (2 implementation commits from Tasks 1+2)
|
||||
- Actual observed `[door-anim]` and `[door-cycle]` log lines from Task 3 step 4
|
||||
- Worktree branch: `claude/phase-b4c-door-anim`, 4 commits ahead of `3e08e10` (the B.4b merge)
|
||||
|
||||
- [ ] **Step 2: Move #58 from Active to Recently Closed in `docs/ISSUES.md`**
|
||||
|
||||
Edit `docs/ISSUES.md`:
|
||||
- Cut the `## #58 — Door swing animation` block from "Active issues".
|
||||
- Paste under "Recently closed" with header changed to `## #58 — [DONE 2026-05-13] Door swing animation: ...`.
|
||||
- Add `**Status:** DONE` and `**Closed:** 2026-05-13` lines.
|
||||
- Add a one-paragraph closure summary describing the fix: Door-specific spawn-time branch + state-seeded SetCycle + UM diagnostic. Cite this PR's merge commit + the handoff doc.
|
||||
|
||||
- [ ] **Step 3: Update the roadmap's shipped table**
|
||||
|
||||
Edit `docs/plans/2026-04-11-roadmap.md`. Add a new row to the "shipped" table:
|
||||
|
||||
```
|
||||
| 2026-05-13 | Phase B.4c — Door swing animation | <commit> | Closes #58. Door-specific spawn-time AnimationSequencer registration with state-seeded initial cycle. M1 demo target "open the inn door" now has full visual feedback. |
|
||||
```
|
||||
|
||||
(Read the table first to match its column structure exactly — the B.4b row uses `Phase | What landed | Verification`; match that.)
|
||||
|
||||
- [ ] **Step 4: Update `CLAUDE.md` "Currently in Phase L.2" paragraph + Next phase candidates**
|
||||
|
||||
Edit `CLAUDE.md`:
|
||||
- Update "Currently in Phase L.2" paragraph to reflect B.4c shipped + visual-verified 2026-05-13.
|
||||
- Remove `#58 — Door swing animation` from the "Next phase candidates" list.
|
||||
- Elevate the next candidate (currently #2 in the list: "Triage the chronic open-issue list") to #1, OR pick a different next-phase based on M1 critical-path-ness. The natural next step per CLAUDE.md's "work-order autonomy" rule is whichever progresses M1's remaining demo targets ("click an NPC", "pick up an item") — file a one-line note that these are the M1-critical-path follow-ups even though they aren't pre-specced phases.
|
||||
|
||||
- [ ] **Step 5: Update the memory file** (outside the repo, NOT git-tracked)
|
||||
|
||||
Edit `C:\Users\erikn\.claude\projects\C--Users-erikn-source-repos-acdream\memory\project_interaction_pipeline.md`:
|
||||
- Append a "B.4c shipped 2026-05-13" entry to the components table:
|
||||
- `Door swing animation` — exists now (`GameWindow.cs IsDoorSpawn + sibling spawn-time branch`)
|
||||
- `[door-anim]` / `[door-cycle]` diagnostics — gated on `ACDREAM_PROBE_BUILDING`
|
||||
- Note: animation routing is door-specific, not general non-creature support yet (chests/levers/traps still drop through the gate).
|
||||
|
||||
- [ ] **Step 6: Commit the in-repo docs**
|
||||
|
||||
```bash
|
||||
git add docs/research/2026-05-13-b4c-shipped-handoff.md docs/ISSUES.md docs/plans/2026-04-11-roadmap.md CLAUDE.md
|
||||
git commit -m "$(cat <<'EOF'
|
||||
docs(B.4c): ship handoff + close #58 + roadmap/CLAUDE update
|
||||
|
||||
Phase B.4c shipped end-to-end 2026-05-13. Holtburg inn doorway
|
||||
double-click verified: door visually swings open, player walks
|
||||
through, door visually swings closed ~30s later.
|
||||
|
||||
2 implementation commits:
|
||||
- B.4c Task 1: door spawn-time AnimationSequencer with state-seeded cycle
|
||||
- B.4c Task 2: [door-cycle] diagnostic in OnLiveMotionUpdated
|
||||
|
||||
Closes #58. Memory file project_interaction_pipeline.md updated
|
||||
outside the repo.
|
||||
|
||||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
(The memory file lives outside the repo — update it but don't include it in this commit.)
|
||||
|
||||
- [ ] **Step 7: Hand off to merge (controller does final review + merge)**
|
||||
|
||||
After this commit, hand off to the controller. The controller will:
|
||||
1. Run the final whole-branch code review (Opus per CLAUDE.md "load-bearing quality review of a phase boundary").
|
||||
2. Merge `claude/phase-b4c-door-anim` → `main` with `--no-ff`.
|
||||
3. Verify tests on merged main.
|
||||
4. Remove the worktree (best-effort; submodules may block per the B.4b finishing experience).
|
||||
|
||||
---
|
||||
|
||||
## Self-review against the spec
|
||||
|
||||
| Spec section | Plan task(s) | Coverage |
|
||||
|---|---|---|
|
||||
| §Architecture: sibling branch after creature gate at line 2692 | Task 1 step 2 | covered |
|
||||
| §Architecture: state-seeded initial cycle from spawn.PhysicsState | Task 1 step 2 | covered |
|
||||
| §Components: `IsDoorSpawn(spawn) => spawn.Name == "Door"` | Task 1 step 1 | covered |
|
||||
| §Components: Door registration body (sequencer build + SetCycle + AnimatedEntity register) | Task 1 step 2 | covered |
|
||||
| §Components: `[door-anim] registered` diagnostic on spawn | Task 1 step 2 | covered (inline in registration body) |
|
||||
| §Components: `[door-cycle]` diagnostic in OnLiveMotionUpdated | Task 2 step 2 | covered |
|
||||
| §Data flow: spawn → seeded cycle → UM dispatch → state flip → animation | Tasks 1+2 + L.2g (existing) | covered (L.2g pipeline is the upstream dependency) |
|
||||
| §Error handling: door has no MotionTable | Task 1 step 2 (`if (mtableId != 0)` + inner `if (mtable is not null)`) | covered |
|
||||
| §Error handling: MotionTable lacks On/Off cycle | Task 1 step 2 (`if (sequencer.HasCycle(...))` gate around SetCycle) | covered |
|
||||
| §Error handling: `_animLoader` null | Task 1 step 2 (outer `&& _animLoader is not null`) | covered |
|
||||
| §Error handling: spawn.Name != "Door" | (no code change — silent fallback, acceptable per spec) | covered by omission |
|
||||
| §Testing: runtime visual verification at Holtburg | Task 3 | covered |
|
||||
| §Testing: log grep | Task 3 step 4 | covered |
|
||||
| §Acceptance: build + tests green | Tasks 1+2 steps 3-4 | covered |
|
||||
| §Acceptance: ISSUES.md #58 → Recently closed | Task 4 step 2 | covered |
|
||||
| §Acceptance: roadmap + CLAUDE.md update | Task 4 steps 3-4 | covered |
|
||||
| §Non-goals: sound effects, dust, lighting, collision rotation, generalized non-creature support | (none — explicitly deferred) | covered by omission |
|
||||
|
||||
No placeholders. No "TBD." Every code step shows the actual code; every command step shows the exact command and expected output. Type names (`AnimationSequencer`, `AnimatedEntity`, `MotionTable`, `EntitySpawn`) match across tasks. Diagnostic tags (`[door-anim]`, `[door-cycle]`) consistent throughout.
|
||||
Loading…
Add table
Add a link
Reference in a new issue