acdream/memory/project_session_2026_04_17.md
Erik d910d570a3 memory: extend 2026-04-17 session handoff with evening bug-bash work
Adds the three evening client-debugging commits + the five new
architectural findings they produced:

- NPC clothing by-camera-angle flicker → instance-batching dedup fix
  (`(GfxObjId, PaletteHash ^ SurfaceOverridesHash)` as group key)
- Run animation broadcast fix → wire WalkForward+HoldKey.Run +
  separate LocalAnimationCommand for local RunForward cycle
- Jump animation via MotionCommand.Falling SubState swap (not Action,
  not Modifier — just a plain SubState cycle)

Also captures the lessons learned from the jump saga: trust empirical
motion-table dumps over assumptions, the retail animation taxonomy
(Style/SubState/Modifier/Action masks), and the wire/local-animation
separation pattern.

Updates the pickup table with the small remaining polish items
(backward-walk jitter, stop-running twitch, remote-char Z offset).
2026-04-18 15:55:31 +02:00

175 lines
9.1 KiB
Markdown

# Session 2026-04-17 — Debug overlay → full-day retail-AC research + client bug-bash
## Timeline
1. **Morning** — Debug overlay (TTF atlas + text batcher + HUD panels)
and input-control tuning (per-mode sensitivity, RMB free-orbit, wheel
zoom, F8/F9 sensitivity). Shipped in commit `ff325ab`.
2. **Midday** — User requested a deep investigation of the retail AC
client's GUI subsystem. Dispatched 6 parallel Opus-4.7 high-effort
agents, produced a 30,000-word research bundle + C# UI scaffold.
Shipped in commit `7230c15`.
3. **Afternoon** — User asked to research **all** remaining major AC
subsystems (R1-R13) while they were AFK for 2 hours. Dispatched 13
parallel Opus-4.7 agents, produced a 78,000-word research bundle +
master synthesis + 5 C# port scaffolds + rewritten roadmap.
Shipped in commit `3f913f1`.
4. **Evening** — Back to hands-on client debugging. Fixed three
significant live-play bugs one after another: NPC clothing by-angle
flicker, run-animation sync with retail observers, and jump animation.
Shipped in `3308cdd` + `08ea2c0` + `6bce9b8`.
## What shipped today — seven commits on main
| Commit | Title | Insert |
|-----------|--------------------------------------------------------------------|--------|
| `ff325ab` | feat(ui): debug overlay + refined input controls | 2,725 |
| `7230c15` | docs+feat(ui): retail UI deep-dive research + C# scaffold | 8,042 |
| `3f913f1` | docs+feat: 13 retail-AC deep-dives + scaffolds + roadmap | 15,312 |
| `d951304` | memory: session handoff + permanent research index | 222 |
| `3308cdd` | fix(movement+anim+session): clothing dedup + motion wire + jump-skill | 272 |
| `08ea2c0` | feat(anim): motion-action-queue infrastructure + findings | 128 |
| `6bce9b8` | fix(anim): **jump animation via Falling SubState** | 71 |
**Total ~26,800 lines added, 55+ new files.** All commits green on
build + 470 tests.
## Key files to know
### Research (the goldmine)
- **`docs/research/deepdives/00-master-synthesis.md`** — start here. Nav
hub for all 13 deep-dive slices; has the dependency graph and phase
sequencing (E/F/G/H).
- **`docs/research/deepdives/r01-…-r13-…`** — 13 subsystem deep-dives,
78,000 words total, every claim cited.
- **`docs/research/retail-ui/00-master-synthesis.md`** — UI framework
synthesis. 6 slice docs total, ~30,000 words.
- **`memory/project_retail_research_index.md`** — permanent quick-lookup
index for all 20 research docs.
### C# scaffolds (what to build on)
- `src/AcDream.App/UI/` — retail-style widget toolkit (`UiRoot`,
`UiElement`, `UiPanel`, `UiHost`, event types matching retail codes)
- `src/AcDream.Core/Items/ItemInstance.cs` — R6 inventory data model
- `src/AcDream.Core/Spells/SpellModel.cs` — R1 spell cast state machine
- `src/AcDream.Core/Combat/CombatModel.cs` — R2 damage math
- `src/AcDream.Core/Audio/AudioModel.cs` — R5 audio interfaces
- `src/AcDream.Core/Vfx/VfxModel.cs` — R4 particle data model
### Updated
- `docs/plans/2026-04-11-roadmap.md` — rewritten Phase E-H based on
the deep-dive synthesis. Old Phase E renamed to J.
## Architectural headline findings
1. **Retail UI widgets live in `keystone.dll`**, not `acclient.exe`.
We implement our own retained-mode toolkit with retail-faithful
event codes (0x01 click, 0x15 drag, 0x3E drop, 0x201 WM_LBUTTONDOWN)
and consume the same portal.dat fonts + sprites for visual identity.
2. **Of 94 GameEvents** (S→C, `0xF7B0` envelope), **zero are handled**
in acdream today. Biggest network-protocol gap; blocks inventory,
chat, quest tracking, allegiance.
3. **Motion hooks are the trigger source** for audio + VFX + combat
timing. R3 motion-hook expansion is the prereq for "feel alive"
(Phase E).
4. **Weather is 95% client-side** — deterministic from Portal Year
server clock. No `SetWeather` opcode.
5. **Retail lighting is D3D fixed-function** with 8-light cap, NO
attenuation inside Range, then hard cutoff. "Feels right" not
physical.
6. **Retail jumps are a SubState swap, not an Action.**
`MotionCommand.Falling (0x40000015)` is a SubState cycle whose
motion-table Links carry the leap-up AND landing transitions. No
action-queue port was needed; `SetCycle(Falling)` while airborne
+ normal SetCycle on land gives retail-faithful jump animation.
Costly lesson: I first tried Action (mask 0x10) + Modifier (mask
0x20) routing and broke the character into a torso. Empirical
motion-table dump is always worth more than my guesses.
7. **ACE's MovementData only computes ForwardSpeed for the
WalkForward/WalkBackwards branch.** Sending `RunForward` directly
leaves observers at `speed=0`. Correct wire format is
`WalkForward + HoldKey.Run + ForwardSpeed=runRate` — ACE
auto-upgrades to `RunForward` for broadcast. Our own client uses
a separate LocalAnimationCommand to play the RunForward cycle
locally while the wire stays WalkForward.
8. **Instance batching by GfxObjId alone is catastrophic for NPCs.**
Every humanoid shares the same body GfxObjs; grouping them all
into one DrawInstanced batch and using the first entry's texture
for the whole batch meant whoever sorted first at a given camera
angle "won" the palette. Fixed by keying instance groups on
`(GfxObjId, PaletteHash XOR SurfaceOverridesHash)`.
## Client state at end of session
Client runs, connects to local ACE, in-world as `+Acdream`. Working:
- Player moves, turns, strafes, jumps, lands. Jump animation plays via
Falling SubState. Run animation broadcasts correctly to retail
observers (WalkForward + HoldKey.Run wire format).
- Holtburg NPCs render with correct clothing / palette, stable across
camera angles (instance-batching dedup fix).
- Debug overlay: F1 help, F2 collision wireframes, F3 dump, F4/F5/F6
panel toggles, F8/F9 sensitivity tuning.
- Mouse: per-mode sensitivity (Chase 0.15x, Fly/Orbit 1.0x), RMB
free-orbit, wheel zoom.
Known small issues (non-blocking):
- Walk-backward animation's first step has a tiny jitter.
- Running → stopping has a slight twitch (missing SubState→Ready link
blend).
- Some retail chars have legs through the ground (Z-offset bug —
parked for later diagnosis).
- Jump feel is 95% retail, not 100%.
## Pickup for next session
**"What should I do tomorrow?" table:**
| If you want to… | Build… |
|---|---|
| Make the world feel alive (footsteps, sword whooshes, spell auras) | Phase E — R3 motion hooks → R5 audio → R4 particles |
| Actually fight monsters | Phase F.3 combat math + F.1 GameEvent dispatcher |
| Cast a buff + recall to lifestone | Phase F.4 spell state machine + F.1 GameEvent |
| See a character sheet | Phase F.2 item model + F.5 attributes panel (UI slice 05) |
| Enter a dungeon | Phase G.3 dungeon streaming (R9) |
| See a sky | Phase G.1 weather/day-night (R12) |
| Create a character in-client | Phase H.4 CharCreate (R7) |
| Polish animation (backward jitter + stop twitch) | Link-cycle walker for SubState→Ready transitions |
| Remote-char feet in ground | Z-offset diagnosis (compare server-sent Z vs our terrain at observer XY) |
The **master synthesis** (`docs/research/deepdives/00-master-synthesis.md`
§10) recommends a specific week-by-week sequence if the user wants
one-thing-at-a-time focus.
## Session feedback / lessons
- **Opus-4.7 high-effort parallel agents** are the right tool for
decompile-intensive research. 13-agent swarm for R1-R13 completed in
~13 minutes, producing ~78,000 words of grounded work. Cost is high
but quality justifies it for load-bearing research.
- **keystone.dll is a landmine** for anyone trying to "port the UI
faithfully" — the widget toolkit isn't in the decompile we have. Own-
toolkit approach is the only viable path.
- **Network protocol atlas (R8)** is the single biggest unblocker —
nearly every other system depends on opcodes we don't handle.
- **Diagnostic dumps > guessing.** The jump-animation saga took 4
launches + reverts before I added a diagnostic that dumped the
actual Links dict contents. That one dump (revealing
`Links[0x003D0007]` had an inner entry `0x40000015 Falling`)
instantly showed the right approach. Trust empirical motion-table
contents over any assumption about retail structure. Add dumps
liberally when the code is non-cooperative; remove when verified.
- **Retail animation lexicon:** Style (mask 0x80), SubState (0x40),
Modifier (0x20), Action (0x10). SubStates are looping cycles
(Ready/Walk/Run/Falling/Crouch). Modifiers overlay on a cycle.
Actions are transitions held in the Links dict (emotes, attacks).
For any new animation: dump the motion table, find where the
target motion lives, use SetCycle if it's in Cycles or the
Links/Modifiers path if it's transitional.
- **Wire-format vs local-animation separation:** we now route the
wire ForwardCommand separately from the local animation command
(RunForward cycle locally, WalkForward+HoldKey.Run on wire).
Matching ACE's broadcast expectations and retail client expectations
simultaneously sometimes requires two independent command streams.