docs: Campaign P - physics retail-feel parity plan (P1-P7 + final visual matrix)
User-directed pre-vendor detour from the 2026-07-29 physics audit. Goal: Retail Movement Parity v1 - zero physics TS rows, no unargued feel-affecting AP rows, issues #262/#165/#166/#116/#167/#72/#153 closed, one batched connected visual matrix. Sonnet implements, Opus reviews at slice boundaries. Roadmap gains the Campaign P entry and records Campaign N's user-accepted closure; CLAUDE.md current-state pointer updated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d1390bd84d
commit
978ce1dcda
3 changed files with 227 additions and 4 deletions
|
|
@ -126,8 +126,13 @@ user-accepted, including exact response flags, independent examination
|
||||||
window, inscription transaction, complete creature/item/spell reports,
|
window, inscription transaction, complete creature/item/spell reports,
|
||||||
favorite-spell press/right-click behavior, modern scarab/prismatic formula,
|
favorite-spell press/right-click behavior, modern scarab/prismatic formula,
|
||||||
DAT component icons, foreground stacking, and authored 310 x 400 extent.
|
DAT component icons, foreground stacking, and authored 310 x 400 extent.
|
||||||
Resume at Slice 4 equipped-child world picking, then vendor browse and
|
Slice 4 equipped-child world picking passed its two-client Coldeve gate and
|
||||||
authoritative transactions.
|
was user-accepted 2026-07-29. **Campaign P — physics retail-feel parity
|
||||||
|
(`docs/plans/2026-07-29-physics-parity-campaign.md`) is the ACTIVE
|
||||||
|
user-directed detour** closing every physics-scope gap from the 2026-07-29
|
||||||
|
audit (stat-coupled movement, response-layer edge family, remote residuals,
|
||||||
|
entry restrictions/water, #262/#153/#167, ledger). Vendor browsing (Slice 5)
|
||||||
|
and authoritative vendor transactions resume after Campaign P closes.
|
||||||
|
|
||||||
**Modern Runtime/performance status:** Slices A–K of
|
**Modern Runtime/performance status:** Slices A–K of
|
||||||
`docs/plans/2026-07-24-modern-runtime-architecture.md` are complete. Slice L is
|
`docs/plans/2026-07-24-modern-runtime-architecture.md` are complete. Slice L is
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ falsification ledger — is [`2026-07-27-vulkan-campaign.md`](2026-07-27-vulkan-
|
||||||
The user signed the V10 cutover; V11 deleted GL (−27,670 lines) and all
|
The user signed the V10 cutover; V11 deleted GL (−27,670 lines) and all
|
||||||
deferred reruns pass on the GL-free tree.
|
deferred reruns pass on the GL-free tree.
|
||||||
|
|
||||||
**Campaign N — retail reliable network transport (ACTIVE, started
|
**Campaign N — retail reliable network transport (CLOSED 2026-07-29,
|
||||||
2026-07-29):** the #260 live-server wedge root-caused to missing packet-loss
|
user-accepted; #260 closed — a real wire loss recovered live during the
|
||||||
|
acceptance session):** the #260 live-server wedge root-caused to missing packet-loss
|
||||||
recovery in both directions (no outbound retransmission; inbound ISAAC burned
|
recovery in both directions (no outbound retransmission; inbound ISAAC burned
|
||||||
in arrival order) — acdream could not survive a single lost UDP packet, and
|
in arrival order) — acdream could not survive a single lost UDP packet, and
|
||||||
loopback gates were structurally blind to it. The campaign ports retail's
|
loopback gates were structurally blind to it. The campaign ports retail's
|
||||||
|
|
@ -34,6 +35,18 @@ N0–N6 with a permanent loss-injection gate at N5 and a user Coldeve
|
||||||
endurance session as final acceptance. The plan is
|
endurance session as final acceptance. The plan is
|
||||||
[`2026-07-29-network-transport-campaign.md`](2026-07-29-network-transport-campaign.md).
|
[`2026-07-29-network-transport-campaign.md`](2026-07-29-network-transport-campaign.md).
|
||||||
|
|
||||||
|
**Campaign P — physics retail-feel parity (ACTIVE, started 2026-07-29):**
|
||||||
|
user-directed pre-vendor detour closing every physics-scope gap the
|
||||||
|
2026-07-29 audit found: stat-coupled movement (burden/stamina/vitae →
|
||||||
|
run/jump), the collision response-layer edge family (friction gate,
|
||||||
|
PrecipiceSlide, sled, steep-poly chain, #116), remote-object residuals
|
||||||
|
(Setup sphere lists, PK bits, #165), world specials (entry restrictions,
|
||||||
|
water sink-in), deferred fidelity (#167, #153), the #262 login defect, and
|
||||||
|
a ledger pass. Goal: zero physics TS rows, no unargued feel-affecting AP
|
||||||
|
rows, one final batched connected visual matrix. Sonnet implements, Opus
|
||||||
|
reviews. The plan is
|
||||||
|
[`2026-07-29-physics-parity-campaign.md`](2026-07-29-physics-parity-campaign.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Current program: world interaction completion (M4 prelude)
|
## Current program: world interaction completion (M4 prelude)
|
||||||
|
|
|
||||||
205
docs/plans/2026-07-29-physics-parity-campaign.md
Normal file
205
docs/plans/2026-07-29-physics-parity-campaign.md
Normal file
|
|
@ -0,0 +1,205 @@
|
||||||
|
# Campaign P — Physics Retail-Feel Parity
|
||||||
|
|
||||||
|
**Filed:** 2026-07-29. **Directed by the user** as a pre-vendor-management
|
||||||
|
detour after the same-day physics/collision retail-fidelity audit. The
|
||||||
|
world-interaction program (Slice 5, vendor browsing) resumes when this
|
||||||
|
campaign closes.
|
||||||
|
|
||||||
|
**Execution model:** Claude drives autonomously slice-to-slice. Sonnet
|
||||||
|
subagents implement bounded chunks against this plan's specs; an Opus
|
||||||
|
review subagent gates every slice boundary. The only user stops are
|
||||||
|
(a) the final batched connected visual matrix, (b) a DO-NOT-RETRY
|
||||||
|
conflict, (c) anything destructive. All the CLAUDE.md workflow rules
|
||||||
|
apply: grep-named-first → pseudocode → port → conformance test; register
|
||||||
|
moves in the same commit; no workarounds.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The parity goal (the autonomy contract)
|
||||||
|
|
||||||
|
**"Retail Movement Parity v1"** — the campaign is DONE when all of the
|
||||||
|
following are auditable-true:
|
||||||
|
|
||||||
|
1. **Zero physics-scope temporary stopgaps.** TS-1, TS-4, TS-5, TS-23,
|
||||||
|
TS-46 retired by porting the retail mechanism. TS-24, TS-35, TS-40
|
||||||
|
either retired or re-classified (IA/AD) with a recorded justification.
|
||||||
|
2. **No feel-affecting approximations left unargued.** AP-7 resolved by
|
||||||
|
decoding retail's friction state gate; AP-10 restored to retail's
|
||||||
|
0.1 m water sink-in; AP-25 replaced by the retail effective-skill
|
||||||
|
chain (vitae/enchantment-aware); AP-71 (`check_entry_restrictions`)
|
||||||
|
ported.
|
||||||
|
3. **Issue ledger:** #262, #165, #166, #116, #167, #72, #153 closed;
|
||||||
|
the stale "pending visual gate" statuses on #172/#173/#174/#175/#41
|
||||||
|
reconciled (folded into the final matrix below). Explicitly excluded:
|
||||||
|
#235 (user-deferred 2026-07-27) and #256/#257 (lifecycle/memory, not
|
||||||
|
physics feel — separate track).
|
||||||
|
4. **Verification:** each port carries decomp citations + conformance
|
||||||
|
tests; `dotnet build` + full Release suite green at every slice
|
||||||
|
commit; one batched connected visual matrix (below) passes at the
|
||||||
|
end, run by the user.
|
||||||
|
|
||||||
|
Anything not in this list is out of scope for the campaign — file it,
|
||||||
|
don't chase it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slices
|
||||||
|
|
||||||
|
### P1 — Stat-coupled movement (burden / stamina / vitae) — retires TS-5, AP-25, the burden gap
|
||||||
|
|
||||||
|
Today `PlayerWeenie.SetBurden` has zero callers, `CanJump` is always
|
||||||
|
true, `JumpStaminaCost` is 0, and pushed run/jump skill is
|
||||||
|
attributeBonus + init + ranks only. Retail modulates movement by
|
||||||
|
character state continuously.
|
||||||
|
|
||||||
|
**Retail anchors (named decomp, verified 2026-07-29):**
|
||||||
|
- `ACCWeenieObject::{CanJump 0x0058c400, JumpStaminaCost 0x0058c440, InqJumpVelocity 0x0058c520, InqRunRate 0x0058c560, InqMaxRunRate 0x0058c5a0}` — thin delegations to the qualities DB (pseudo-C ~406512).
|
||||||
|
- `CACQualities::{InqMaxRunRate 0x00591b20, CanJump 0x00591b50, JumpStaminaCost 0x00591b90, InqRunRate 0x00592800, InqJumpVelocity 0x00592980, InqLoad 0x0058f130}` (pseudo-C ~412901–413975, ~409756) — the real load/skill/vitae composition. `InqJumpVelocity` ends in `sqrt(GetJumpHeight(...) * 19.6)` (pc 413975).
|
||||||
|
- `MovementSystem::{GetRunRate 0x006b0950, GetJumpHeight 0x006b09b0, JumpStaminaCost 0x006b0a40}` (pseudo-C ~695958) — GetJumpHeight readable: `LoadMod(load) * (skill/(skill+1300) * 22.2 + 0.05) * power / scaling`, floor 0.35; JumpStaminaCost readable: `ceil(((power + 0.5) * load) * 8 + 2)` on the arg3==0 branch.
|
||||||
|
- `EncumbranceSystem::{EncumbranceCapacity 0x004fcc00, Load 0x004fcc40, LoadMod 0x004fcc70}` (pseudo-C ~256393).
|
||||||
|
- Cross-refs: ACE `MovementSystem`/`EncumbranceSystem` C# ports; holtburger if it models load.
|
||||||
|
|
||||||
|
**Work:**
|
||||||
|
1. Port the full chain into Core (`EncumbranceSystem` + `MovementSystem`
|
||||||
|
statics; `PlayerWeenie` becomes the CACQualities-shaped composition).
|
||||||
|
Where BN x87 mush blocks a branch (GetRunRate body), use Ghidra MCP
|
||||||
|
or the ACE port as the tiebreaker and cite which.
|
||||||
|
2. Determine, from `CACQualities::InqRunRate`'s own body, exactly which
|
||||||
|
skill level retail feeds (base vs enchantment/vitae-adjusted) and
|
||||||
|
port THAT — scoped to the run/jump query path only, reading vitae +
|
||||||
|
relevant skill enchantments from the M3 active-effect state. Do not
|
||||||
|
build a general effective-skill engine.
|
||||||
|
3. Plumb the inputs from Runtime: burden (EncumbranceVal/capacity from
|
||||||
|
PlayerDescription + property updates), current stamina (vitals),
|
||||||
|
vitae. Extend `RuntimeMovementSkillState` (J4.4 seam) so updates flow
|
||||||
|
mid-session, same as run/jump skill today.
|
||||||
|
4. Wire the existing `jump_is_allowed` stamina-refusal branch and the
|
||||||
|
`ReportExhaustion` dual-dispatch gate (R3-W4 seam) to a real
|
||||||
|
consumer, matching retail's refusal/weak-jump behavior.
|
||||||
|
5. Conformance tests: formula tables (golden values incl. 800-skill cap,
|
||||||
|
load-mod knees at 100%/200%, stamina cost ceil), gating tests
|
||||||
|
(no-stamina jump refusal), plumbing tests (burden/stamina/vitae
|
||||||
|
changes move the produced rate). Register: delete TS-5 + AP-25 rows,
|
||||||
|
note the retirement in the same commit.
|
||||||
|
|
||||||
|
### P2 — Response-layer edge family — retires TS-1, TS-4, AP-7; closes #166, #116
|
||||||
|
|
||||||
|
The collision *response* layer (what happens after a hit): ground
|
||||||
|
friction, cliff edges, downhill landings, near-perpendicular wall
|
||||||
|
slides. One oracle-driven pass; the physics digest's DO-NOT-RETRY table
|
||||||
|
binds every subagent here.
|
||||||
|
|
||||||
|
**Work (research doc FIRST, then port):**
|
||||||
|
1. **AP-7:** decode the state gate on retail's friction block
|
||||||
|
(`calc_friction` region, pseudo-C ~276702-276705) that lets retail
|
||||||
|
use threshold 0.25 without hammering normal locomotion (the reverted
|
||||||
|
L.3c attempt). Ghidra MCP for the x87 branch if BN is garbled.
|
||||||
|
2. **TS-1:** port the `EdgeSlide → PrecipiceSlide / CliffSlide` chain
|
||||||
|
(precipice context, steep-plane bookkeeping) replacing our
|
||||||
|
stop-at-edge.
|
||||||
|
3. **#166:** port the landing "sled" (Sledding state set/clear sites;
|
||||||
|
the sled friction constants already sit in `calc_friction`).
|
||||||
|
4. **TS-4:** replace the Path-6 steep-poly in-place-slide shortcut with
|
||||||
|
retail's `SetCollide → Path-4 → ContactPlane` landing chain, and
|
||||||
|
remove the two BSP-layer `SetSlidingNormal` writes (retail's only
|
||||||
|
in-transition writer is `validate_transition`).
|
||||||
|
5. **#116:** the near-perpendicular lateral-slide loss + first-airborne-
|
||||||
|
frame divergence, driven by the existing tick-22760 replay and D4
|
||||||
|
pins.
|
||||||
|
6. Apparatus: extend the trajectory-replay tests; capture fixtures
|
||||||
|
before changing behavior. Register: delete TS-1/TS-4/AP-7 rows.
|
||||||
|
|
||||||
|
### P3 — Remote-object residuals — retires TS-46, TS-23; closes #165; narrows/retires AD-25
|
||||||
|
|
||||||
|
1. **TS-46:** pass the Setup's verbatim sphere LIST into the transition
|
||||||
|
(`CPhysicsObj::transition 0x00512dc0 → init_sphere`) instead of the
|
||||||
|
two-scalar reconstruction, for local player and remotes; derive
|
||||||
|
remote step-up/step-down from the Setup instead of the pinned 0.4 m.
|
||||||
|
Captured-fixture replays must stay green or be re-baselined with
|
||||||
|
evidence.
|
||||||
|
2. **AD-25:** align the remote post-resolve with the ported
|
||||||
|
`handle_all_collisions` (grounded-bounce rule) as the player half
|
||||||
|
already did in #182.
|
||||||
|
3. **#165:** remotes visibly penetrate walls before stopping — diagnose
|
||||||
|
against the (now Setup-true) sweep; suspect list starts at the
|
||||||
|
catch-up step length vs sweep sub-steps.
|
||||||
|
4. **TS-23:** parse PlayerKillerStatus from PlayerDescription/property
|
||||||
|
updates and plumb PK/PKLite/Impenetrable onto local + remote player
|
||||||
|
movers (`OBJECTINFO::init 0x0050cf30` state bits). Non-PK ACE
|
||||||
|
behavior must be provably unchanged.
|
||||||
|
|
||||||
|
### P4 — World specials — retires AP-71, AP-10
|
||||||
|
|
||||||
|
1. **AP-71:** port the `CObjCell::check_entry_restrictions` gate at the
|
||||||
|
head of `find_env_collisions` (pc:309576) — barred house cells block
|
||||||
|
at the threshold client-side.
|
||||||
|
2. **AP-10:** restore retail's 0.1 m water sink-in; while there, verify
|
||||||
|
the water-contact step behavior (`WATER_CONTACT_TS` consumers)
|
||||||
|
against retail and file anything found.
|
||||||
|
|
||||||
|
### P5 — Deferred fidelity — closes #167, #153, #72
|
||||||
|
|
||||||
|
1. **#167:** decode the two unknown x87 ConstraintManager constants
|
||||||
|
(Ghidra) and port leash arming.
|
||||||
|
2. **#153:** the far-teleport arrival onto an unstreamed landblock near
|
||||||
|
a 192 m edge — apparatus first (the issue's own trigger table), then
|
||||||
|
the streaming-gap hold shape ALREADY sketched there (freeze the
|
||||||
|
per-tick resolve until the landblock loads — the async equivalent of
|
||||||
|
retail's synchronous load; this is an AD row, not a workaround, and
|
||||||
|
gets filed as one).
|
||||||
|
3. **#72:** close on the R6 evidence (DAT-authored omega ±1.5 rad/s is
|
||||||
|
live; the cdb confirmation ask is obsolete).
|
||||||
|
|
||||||
|
### P6 — #262 login run-on-the-spot (live defect)
|
||||||
|
|
||||||
|
Probe-instrumented fresh-process login repros (`ACDREAM_PROBE_RESOLVE=1`
|
||||||
|
+ net probes) against local ACE; the issue's hypothesis list is the
|
||||||
|
script. Root cause, fix, regression test. No workarounds (no auto-recall,
|
||||||
|
no synthetic position kick). Runs serialized (owns the build tree +
|
||||||
|
client).
|
||||||
|
|
||||||
|
### P7 — Ledger + camera feel
|
||||||
|
|
||||||
|
1. Retire the stale TS-25 row (outbound stance ships via
|
||||||
|
`RawState.CurrentStyle` since #219) and refresh TS-24/TS-35/TS-40
|
||||||
|
classifications.
|
||||||
|
2. #115 camera-drag: investigation-only against `CameraManager`
|
||||||
|
constants (AD-37's vector-nlerp vs retail quaternion-slerp is the
|
||||||
|
prime suspect); fix if a concrete divergence falls out, otherwise
|
||||||
|
re-classify with evidence.
|
||||||
|
3. Reconcile #172/#173/#174/#175/#41 statuses via the final matrix.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Final batched connected visual matrix (the ONE user gate)
|
||||||
|
|
||||||
|
1. Burden >100%: run slows, jump shrinks; ~200%: barely moves/jumps.
|
||||||
|
2. Repeated jumps drain stamina; low stamina → weak/refused jump;
|
||||||
|
exhaustion behavior matches retail.
|
||||||
|
3. Fresh vitae: movement penalty present.
|
||||||
|
4. Walk off a cliff/roof edge: slides over like retail, no dead stop.
|
||||||
|
5. Downhill jump landing: sled glide + bounce.
|
||||||
|
6. Shallow-angle wall graze: lateral slide preserved.
|
||||||
|
7. Packed crowd: spacing + shuffle-out unchanged (regression).
|
||||||
|
8. Two-client: remote stops at walls without visible penetration;
|
||||||
|
remote ceiling-jump bounces down immediately (#173); Holtburg portal
|
||||||
|
platform step-up (#172); door Use after jumping (#174); closed-door
|
||||||
|
collision matches the visual door (#175); observed-player blips
|
||||||
|
gone (#41).
|
||||||
|
9. Locked/barred house: blocked at the threshold.
|
||||||
|
10. Wading: slight retail sink-in.
|
||||||
|
11. ~20 fresh logins: no run-on-the-spot.
|
||||||
|
12. Regression sweep: walk/run/strafe/turn/jump/stairs/doors/water
|
||||||
|
edges feel unchanged from the accepted R6 baseline.
|
||||||
|
|
||||||
|
## Risk notes
|
||||||
|
|
||||||
|
- P2 and P3 touch the frozen-adjacent transition internals — every
|
||||||
|
subagent prompt must carry the digest's DO-NOT-RETRY table and the
|
||||||
|
no-workarounds rule; 3 failed attempts on any item = stop and build
|
||||||
|
apparatus, per [[feedback_apparatus_for_physics_bugs]].
|
||||||
|
- TS-46 changes the collision capsule of every mover; the captured
|
||||||
|
replay fixtures pin behavior — re-baseline only with a recorded
|
||||||
|
retail argument.
|
||||||
|
- P1's enchantment-aware skill read is the scope-creep risk; it is
|
||||||
|
bounded to the run/jump query path by this plan.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue