feat(runtime) Campaign CA CA3 #431: live derived-stat recompute — a raise is visible without a relog
The recompute half of #431, on the CA1 verdict that retail computes derived values LIVE at inquiry (Set* writes raw; InqSkillBaseLevel 0x00592140 -> SkillFormula::Calculate 0x00591960 re-derive per call; InqRunRate 0x00592800 runs every motion tick; UI notifications carry no value and widgets re-pull): - LocalPlayerState gains the SkillTable formula resolver — the same delegate shape (and App-side implementation, RetailSkillFormula over the loaded SkillTable) the PlayerDescription path already uses. An attribute write re-derives every skill snapshot's cached formula contribution; recomputing at the only write that changes the inputs yields values identical to retail's compute-on-read at every read. A freshly TRAINED skill unseen at login derives its contribution live instead of defaulting to zero forever. - The router pushes movement-skill totals down the SAME seam PlayerDescription uses (UpdateMovementSkillBase -> vitae/enchantment recompute -> OnSkillsUpdated -> the App stats applier) after an attribute update, and after a skill update for Run (24) / Jump (22) only. This is what turns a Quickness raise into visible run speed mid-session; the server's own movement-packet echo (HandleRunRateUpdate -> ApplyServerRunRate) remains the correcting authority. - Vitals maxima needed no new plumbing: GetMaxApprox reads attribute currents live and the vitals window binds getter lambdas re-read per frame, so CA2's attribute fan-out completes that path. The character panel already subscribes to AttributeChanged/CharacterChanged. Tests: router behavior test drives the real WorldSession events through the real router and asserts the full chain (state write, live 160/2=80 re-derivation, movement push totals, and that a non-movement skill does NOT push); the subscription-count contract now includes the two new events; Core tests cover the fresh-train resolver derivation. Full hermetic suite 15,335 passed / 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
65430d4c7c
commit
5781895977
5 changed files with 251 additions and 21 deletions
|
|
@ -120,7 +120,7 @@ neighborhood).
|
|||
| Slice | Status | Evidence |
|
||||
|---|---|---|
|
||||
| CA1 | COMPLETE 2026-08-24 | docs/research/2026-08-24-advancement-wire-and-recompute.md — six inbound messages pinned byte-for-byte with 3-source agreement; live-at-inquiry recompute verdict verified by hand in Ghidra; RetailSkillFormula already ports 0x00591960 exactly |
|
||||
| CA2 | — | |
|
||||
| CA3 | — | |
|
||||
| CA2 | COMPLETE 2026-08-24 (`65430d4c`) | 0x02E3/0x02DD parsers + WorldSession events + router routing into LocalPlayerState; conformance tests incl. holtburger golden fixture; 0x02DF deliberately unparsed (no ACE producer) |
|
||||
| CA3 | COMPLETE 2026-08-24 | Live formula recompute (SkillFormulaBonusResolver over RetailSkillFormula) on attribute writes + fresh-train derivation; movement re-applied down the PD seam (PushMovementSkillTotals — Quickness raise → run speed, no relog); vitals bar pull-model verified; router behavior + fresh-train tests |
|
||||
| CA4 | — | |
|
||||
| CA5 | — | |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue