fix(render): harden portal exit handoff
This commit is contained in:
parent
ddbd7e4096
commit
82e4b4cb6d
17 changed files with 896 additions and 119 deletions
323
AGENTS.md
323
AGENTS.md
|
|
@ -132,8 +132,194 @@ user-accepted, including exact response flags, independent examination
|
|||
window, inscription transaction, complete creature/item/spell reports,
|
||||
favorite-spell press/right-click behavior, modern scarab/prismatic formula,
|
||||
DAT component icons, foreground stacking, and authored 310 x 400 extent.
|
||||
Resume at Slice 4 equipped-child world picking, then vendor browse and
|
||||
authoritative transactions.
|
||||
Slice 4 equipped-child world picking passed its two-client Coldeve gate and
|
||||
was user-accepted 2026-07-29. **Slices 5 and 6 (the complete vendor
|
||||
experience — browse, staged buying, selling, walk-to-use, the authored
|
||||
panel) closed user-accepted 2026-08-08; the six-slice program is COMPLETE
|
||||
(see the plan's PROGRAM CLOSEOUT). The vendor arc also exposed and fixed
|
||||
two latent client-wide crashers (#348 cursor-handle exhaustion, #350
|
||||
render-ledger overflow).** **Campaign P — physics retail-feel parity
|
||||
(`docs/plans/2026-07-29-physics-parity-campaign.md`) is CLOSED 2026-07-31
|
||||
— final user matrix accepted.** Every physics-scope gap from the
|
||||
2026-07-29 audit landed and user-gated: #266 run speed (retail's ==800
|
||||
sentinel — ACE's >=800 is a misread; never re-import), the #265/#166
|
||||
landing-momentum + bounce family
|
||||
(`docs/research/2026-07-30-landing-bounce-family.md`), the #267 vitae
|
||||
panel, #268 (panel colors + augmentation bonuses), #269 (slope-stop slide
|
||||
— the live-trace contact-plane-restore fix), and TS-8 (0x02C2 StatMod
|
||||
parse). See the plan doc for the retired-row ledger. **Campaign A — audio
|
||||
retail parity (`docs/plans/2026-08-08-audio-parity-campaign.md`) is
|
||||
CODE-COMPLETE 2026-08-08** with slices A1–A6 landed and listening-gate
|
||||
rounds user-driven; open tail: #358 (Ctrl+M mute chord never fires) and
|
||||
the formal plan-status flip. **Campaign CH — chat & interface-text retail
|
||||
parity (`docs/plans/2026-08-09-chat-parity-campaign.md`) is CLOSED
|
||||
USER-ACCEPTED 2026-08-10** after five connected gate rounds: retail
|
||||
colors, the SpewBox with retail's two-plane glyph outlines, working side
|
||||
channels, the 152-verb command registry, the CH6 window shell (floating
|
||||
windows, all-corner resize, opacity), and verbatim /help. Carried tail:
|
||||
#360/#361, #366, #369, AP-177/190/191, and the round-5 review S1–S3
|
||||
polish items. **Campaign OP — the retail four-tab Options panel
|
||||
(`docs/plans/2026-08-10-options-panel-campaign.md`) is CODE-COMPLETE
|
||||
2026-08-11.** Retail's Options panel (Gameplay Options / Character / Chat /
|
||||
Config, LayoutDesc `0x2100002B`) plus the Configure Keyboard screen are
|
||||
acdream's ONE in-client settings surface (design D1): F11/toolbar open the
|
||||
authored tab host; `RuntimeCharacterOptionsState` + the 53-id
|
||||
`CharacterOptionTable` own option storage; retail's wire split ships exactly
|
||||
(21 auto-save ids → `0x0005` immediate, the rest ride the real `0x01A1`
|
||||
PlayerModule blob with Apply/logout/480 s flushes, header always `0x460`);
|
||||
headless bots declare options by name (OP7's live bot-vs-ACE gate PASSED);
|
||||
OP9 retired the dead F11 `SettingsPanel`/`SettingsVM` surface and the
|
||||
`GameplaySettings` record outright. OP1/OP2/OP7/OP9 CLOSED through dual/
|
||||
combined Opus review. **2026-08-14 re-gate round:** the whole gate-4 fix
|
||||
batch (#372 both halves, #374, #375, #378–#382, #385) is USER-PASSED; the
|
||||
OP8 first look filed + same-day-fixed #394/#395/#396 (authored 18px-serif
|
||||
row-caption font; the retail `GetNameFromKey` key-name pipeline — DAT
|
||||
tables `0x2300000A`/`0x2300000B`/`0x23000007` via GetDIDByEnum category 4,
|
||||
OS-localized fallback, register AD-96; the `InitiateBinding` capture-
|
||||
instruction WAIT dialog) plus the WaitDialog-type-0x19 crash (`2a81e813`,
|
||||
live-verified no-crash). **STILL OWED: the full §OP3–§OP6 script sections
|
||||
and §OP8's visual re-check** — script
|
||||
`docs/research/2026-08-11-campaign-op-test-script.md`, launch with
|
||||
`ACDREAM_RETAIL_UI=1`. Tail:
|
||||
#371, #373, AP-198/199/201/202/203. START at
|
||||
`claude-memory/project_settings_options_digest.md`.
|
||||
|
||||
**Campaign FA — the retail social panel (Fellowship & Allegiance)
|
||||
(`docs/plans/2026-08-11-fellowship-allegiance-campaign.md`) is
|
||||
CODE-COMPLETE 2026-08-12.** Retail authors ONE four-tab `gmPanelUI` social
|
||||
panel (Friends / Allegiance / Fellowship / Squelch, host slot
|
||||
`0x1000018F`, id 12; F3 = Allegiance, F4 = Fellowship, keyboard-only —
|
||||
Allegiance is the authored DEFAULT tab), mounted with the OP3 Options-panel
|
||||
recipe. The Fellowship and Allegiance pages are LIVE end-to-end: real wire
|
||||
(FA1 repaired the never-called H.2 builders + parsers — retail's FOUR
|
||||
tree-rejection rules, ELEVEN version gates, the byte-decoded `>=9` size and
|
||||
the truncated XP-share table), two session-scoped Runtime owners
|
||||
(`RuntimeFellowshipState`/`RuntimeAllegianceState`, both clear at
|
||||
generation reset — D2 corrected), and the authored panels through
|
||||
`LayoutImporter`. Friends/Squelch bind read-only to J4.1's owners.
|
||||
**The fellowship two-session flow is PROVEN over the live wire** — FA6's
|
||||
automated bot-vs-ACE gate (`testaccount`/`+Acdream` + `testaccount2`/
|
||||
`+Horan`) passed: the recruited bot's OWN `RuntimeFellowshipState` flips
|
||||
`IsInFellowship`. Six FA slices, each dual-lens Opus reviewed → fix round →
|
||||
narrow re-review; the reviews caught what tests can't (retail's 4th tree
|
||||
rule, the D2 reset-lifetime inversion, the D6 server-side invite filter,
|
||||
a seam-map entry that would have re-introduced a fixed bug). OWED: the
|
||||
user's connected gates (§FA3-§FA6 of
|
||||
`docs/research/2026-08-12-campaign-fa-test-script.md`, several
|
||||
`[TWO-CLIENT]`), and **#384** — the allegiance-swear bot gate is
|
||||
deferred/disabled because ACE returns NOTHING to the `0x001D` swear at
|
||||
0.005 m (no confirmation, no tree update, no error; needs ACE-console
|
||||
disambiguation — the swear CODE is done+reviewed, only its automated
|
||||
two-session proof is unverified; register AD-87). Tail: #383 (installed-
|
||||
DAT vs committed-fixture drift, found at FA3). START at
|
||||
`claude-memory/project_fellowship_allegiance_campaign.md`.
|
||||
|
||||
**2026-08-13/14 gate block — SOCIAL GATES + SECURE TRADE all
|
||||
USER-PASSED.** The social panel's connected gate rounds closed (border-only
|
||||
move cursor, amber row selection, wrapped empty-state text, composed
|
||||
confirmation sentences via the new `DatStringResolver.ResolveTemplate`
|
||||
StringTable-interleave port, the refused-drop SpewBox notice via the
|
||||
`InventoryTransactionState.RequestFailed` seam, live friends
|
||||
Online/Offline through the authored row state machine + the new UiText
|
||||
per-state string swap). Same block: powerbar mode captions
|
||||
(jump 'Height' right-aligned per-STATE justify / 'Power'↔'Accuracy' by
|
||||
combat mode), release-edge airborne jump refusal (supersedes CH round-1's
|
||||
press-edge report), and **SECURE TRADE SHIPPED + two-client user gate
|
||||
PASSED 2026-08-14** — gmSecureTradeUI window (LayoutDesc `0x2100000D`),
|
||||
full `0x1F6`–`0x208` wire, `RuntimeTradeState` as the third sibling
|
||||
J-owner, both retail open paths, staged-item trading marker
|
||||
(`ClientObject.TradeState` now live), cancel text. START at
|
||||
`claude-memory/project_secure_trade.md`; the deferred-Func lesson is
|
||||
`claude-memory/feedback_resolve_deferred_funcs_per_call.md`. Register:
|
||||
AD-93/AD-94 filed, AD-85 narrowed, AD-81 amended, AD-89/AD-95 retired.
|
||||
Filed: #393 (texture-detail options, post-M4).
|
||||
|
||||
**Campaign LA — the alpha launcher (ACTIVE 2026-08-14):** Avalonia
|
||||
launcher/installer/updater (Windows+Linux) + the retail character-
|
||||
management screen, driven autonomously under a user-set goal: Fable
|
||||
plans, Sonnet implements, Opus dual-lens reviews (architectural +
|
||||
retail-faithful). Spec:
|
||||
`docs/superpowers/specs/2026-08-14-launcher-campaign-design.md`; plan +
|
||||
ledger: `docs/plans/2026-08-14-launcher-campaign.md`; START at
|
||||
`claude-memory/project_launcher_direction.md`. Key recon corrections
|
||||
already binding: retail's select screen (`gmCharacterManagementUI`) has
|
||||
NO 3D preview (chargen-only machinery); UI Studio no longer exists
|
||||
(deleted at Campaign V — ignore stale memory/docs claims otherwise);
|
||||
App `Program.cs` has no subcommand dispatch (the `--session-config` flag
|
||||
is additive).
|
||||
LA0 through LA11's automated scope are review-closed. The launcher composer is now
|
||||
compiled into both host test suites, and Launcher.Core runs in the portable
|
||||
Windows/Ubuntu CI closure. The self-contained Avalonia launcher,
|
||||
transactional two-host plugin lifetime, shared login-command route,
|
||||
Runtime-owned retail selection state, authored DAT character screen, and
|
||||
crash-safe verified installer plus atomic cross-platform updater/self-updater
|
||||
are integrated. Windows group-isolated Headless stop, isolated update fixtures,
|
||||
strict status/redaction evidence, and the exact Windows/Ubuntu operator script
|
||||
are landed; the integrated preflight passes 32/32 commands and 14,012 tests /
|
||||
5 skips. Only the connected/visual/real-DAT user gate remains before shipment.
|
||||
|
||||
**Campaign CC — retail character creation (CLOSED USER-ACCEPTED
|
||||
2026-08-16).** All seven slices REVIEW-CLOSED; the connected gate ran as
|
||||
one extended round (findings GF-1..16 + re-tests R2/R3/R4, fix batches
|
||||
A-G + closeout + two re-test rounds, final build `1.0.2-cc.o`) and
|
||||
PASSED. **Milestone: the first live character ever created by acdream
|
||||
against ACE landed mid-round.** The gate round's own harvest hardened
|
||||
shared surfaces well beyond chargen: authored text margins (P0x23-26),
|
||||
the authored Unselected/Selected state pair + per-state label color,
|
||||
un-consumed Type-12 media children (frames/scrollbars client-wide),
|
||||
single-sprite scrollbar thumbs, UiButton/UiDatElement Tint, the
|
||||
dialog-always-on-top re-raise (the invisible-modal input blackhole), a
|
||||
truthful client crash self-report + bounded stderr capture (#405-#407
|
||||
fixed, #406 fixed; #408/#409/#410 filed for their own rounds). The full retail creation flow: Create
|
||||
button (retail's exact `UpdateButtons` roster<slots ghost gate) →
|
||||
`gmCharGenMainUI`'s six-page flow (Heritage / Profession / Skills /
|
||||
Appearance with live 3D preview / Town / Summary with its own zoomed-out
|
||||
viewport) → byte-exact 0xF656 with the 55-slot invariant → complete
|
||||
0xF643 handling (roster append + retail log-straight-in; every rejection
|
||||
dialog, incl. the corrected ground truth that retail shows NameDBDown
|
||||
for Pending/Undef — the plan's original "retail swallows it" was
|
||||
DISPROVEN at CC5's review) → the §LA1 `characterCreated`/`creationFailed`
|
||||
launcher status cycle. `RandomizeCharacter` + sub-primitives are ported
|
||||
(retail's ctor-time open-roll incl. the gender-flip quirk; humans-only
|
||||
random heritage ids 1-4 — a real retail quirk). Plan + ledger:
|
||||
`docs/plans/2026-08-15-character-creation-campaign.md`; connected gate
|
||||
script: `docs/research/2026-08-16-campaign-cc-test-script.md` (launch:
|
||||
launcher flow, or `ACDREAM_RETAIL_UI=1` + `ACDREAM_OPEN_CHARGEN=1`);
|
||||
START at `claude-memory/project_character_creation_campaign_handoff.md`.
|
||||
Register churn: AP-214/AP-225/TS-82/AD-101 retired; AP-211 updated;
|
||||
AP-212 narrowed; AP-215–AP-229 filed (AP-221 one-shot preview binding,
|
||||
AP-222 spin-highlight no-op, AP-229 stacked-screens-vs-retail-teardown
|
||||
are the ones a gate tester will meet). Known-flake set now also names
|
||||
`RuntimeCollisionReportingStateTests.WarmedSteadyContactRefreshDoesNotAllocate`
|
||||
(full-solution parallel load only). Suites at `2176ba76`: full solution
|
||||
14,426 / 4 skips, App 5257/3, Runtime 1735/0, Launcher.Core 324/0.
|
||||
|
||||
**Placement cutover — C4 COMPLETE 2026-08-05, merged to main.** Every
|
||||
placement route now runs through the canonical residence + continuation-
|
||||
executor owner. Routes landed this session: 4b-3 remote teleport/cell-less
|
||||
(`6dc7ba51`), 6 drops (`1b484937`, zero production lines), 5 projectile
|
||||
(`36255af0`), 7 child-cell propagation (`cd3129e9`), 3 portal
|
||||
(`e0f96a55`), plus the `OnPosition` dual-tail collapse (`edc911b0`) that
|
||||
retired the duplication behind three separate defects. Suite 11,027 →
|
||||
**11,090 passed / 4 skipped / 0 failed**. Connected gates: routes 3, 6 and 7
|
||||
user-passed 2026-08-05 with probe evidence; route 7's is THIN (one
|
||||
`cause=propagate`) and 4b-3's `cause=cellless` case remains unrun with an
|
||||
UNESTABLISHED trigger — route 7 invalidated its recorded recipe.
|
||||
**C5 COMPLETE — the placement campaign is FULLY CLOSED (`addb5657`,
|
||||
2026-08-07).** C5a deleted the legacy resolver outright and retired
|
||||
AP-1/AP-145 (closing #318); C5b closed #275 and filed AP-147/AP-148; C5c's
|
||||
closeout passed its 11,196-test automated gate and the owed connected-gate
|
||||
batch USER-PASSED 2026-08-07. #280's portal-prefetch fix and its dual
|
||||
review also landed (AP-149/150/151), and AP-22 retired 2026-08-06. Start
|
||||
any new placement work at `claude-memory/project_placement_cutover_closed.md`
|
||||
(probes deliberately NOT stripped; start at #331).
|
||||
|
||||
**Read `docs/research/2026-08-05-c4-closeout-handoff.md` before any
|
||||
placement work.** Its seven process findings remain binding. The two that
|
||||
cost the most that campaign: a contract asserting a mechanism that does not
|
||||
exist caused three separate defects, and inferring a fact you can observe
|
||||
made one fix strictly worse than the bug it replaced — it removed the
|
||||
invariant failure while leaving the bug.
|
||||
|
||||
**Modern Runtime/performance status:** Slices A–K of
|
||||
`docs/plans/2026-07-24-modern-runtime-architecture.md` are complete. Slice L is
|
||||
|
|
@ -566,9 +752,10 @@ The capped/RDP jump-presentation cadence alias is deferred as issue #235:
|
|||
uncapped Release presentation is smooth, while physics, collision, and wire
|
||||
truth remain correct.
|
||||
See `docs/plans/2026-07-22-gamewindow-slice-8-composition-lifecycle.md` and
|
||||
`docs/architecture/code-structure.md`. **Carried:** #153, #116, remaining
|
||||
R6 ownership cleanup, TS-50/TS-51/TS-53, Modern Runtime Slice L, and #225's
|
||||
lifestone/particle alpha visual gate.
|
||||
`docs/architecture/code-structure.md`. **Carried:** #116 (Campaign P P2),
|
||||
remaining R6 ownership cleanup, TS-50/TS-51/TS-53, Modern Runtime Slice L,
|
||||
and #225's lifestone/particle alpha visual gate. #153 closed 2026-07-30
|
||||
(Campaign P P5 ledger evidence chain).
|
||||
|
||||
Start structural work at `memory/project_gamewindow_decomposition.md` and
|
||||
`docs/architecture/code-structure.md`; start
|
||||
|
|
@ -578,6 +765,9 @@ render/streaming work at `claude-memory/project_render_pipeline_digest.md`.
|
|||
Documentation entry point: [`docs/README.md`](docs/README.md).
|
||||
|
||||
For canonical state, read in this order:
|
||||
- [`docs/plans/2026-07-29-network-transport-campaign.md`](docs/plans/2026-07-29-network-transport-campaign.md) — Campaign N, the retail reliable-transport port — **CLOSED 2026-07-29, user-accepted** (#260 closed; a real wire loss recovered live during the acceptance session). Still the SSOT for the transport mechanism, the ACE constraint table, and the landmine list — read it (or `claude-memory/project_network_transport_digest.md`) before touching anything under `src/AcDream.Core.Net/`.
|
||||
- [`docs/plans/2026-07-27-vulkan-campaign.md`](docs/plans/2026-07-27-vulkan-campaign.md) — Campaign V, OpenGL → Vulkan — **CLOSED 2026-07-29**; the completed record of the RHI contract, V0–V11 slices, and the GL deletion. Historical reference for `src/AcDream.App/Rendering/`.
|
||||
- [`docs/ci-and-releases.md`](docs/ci-and-releases.md) — **the Gitea CI/release SSOT (2026-08-19)**: every push to main gates on two self-hosted runners (RARE-win / eriktestLinux) and publishes a Gitea Release the launcher installs from; payloads are release attachments, the `latest` release is the launcher's pointer, old releases are pruned to 5. Load-sensitive tests live in `Lane=Timing` (see `docs/release-gate.md`) — do NOT chase them individually.
|
||||
- [`docs/plans/2026-05-12-milestones.md`](docs/plans/2026-05-12-milestones.md) — milestone targets + freeze list per milestone
|
||||
- [`docs/plans/2026-04-11-roadmap.md`](docs/plans/2026-04-11-roadmap.md) — what's shipped, what's in flight, what's next
|
||||
- [`docs/ISSUES.md`](docs/ISSUES.md) — open + recently closed bugs (tactical)
|
||||
|
|
@ -1367,67 +1557,44 @@ governed by whether the previous shutdown was graceful or forced.
|
|||
### Test character
|
||||
|
||||
`+Acdream` at server guid `0x5000000A`. Starts at or near Holtburg. Has
|
||||
basic stats; `ACDREAM_RUN_SKILL` / `ACDREAM_JUMP_SKILL` env vars (default
|
||||
200) set the *client-side* skill value used by `PlayerWeenie.InqRunRate`
|
||||
for local motion prediction. **These are NOT synced to the server** —
|
||||
ACE's own character data is authoritative for broadcast motion. If you
|
||||
see a speed/anim mismatch between local and observer views, the fix is
|
||||
to sync the runSkill from ACE via `UpdateMotion.ForwardSpeed` echo (wired
|
||||
via `PlayerMovementController.ApplyServerRunRate`) or from
|
||||
`PlayerDescription (0x0013)`.
|
||||
basic stats. Run/jump skills arrive FROM the server and drive local motion
|
||||
prediction (`LiveMovementStatsApplier` → `PlayerMovementController`); the
|
||||
hardcoded fallbacks before the server speaks are 200 run / 300 jump. The
|
||||
former `ACDREAM_RUN_SKILL` / `ACDREAM_JUMP_SKILL` client-side overrides no
|
||||
longer exist — see the Retired section of
|
||||
[`docs/launch-options.md`](docs/launch-options.md). If you see a speed/anim
|
||||
mismatch between local and observer views, check the server sync path
|
||||
(`UpdateMotion.ForwardSpeed` echo via
|
||||
`PlayerMovementController.ApplyServerRunRate`, or
|
||||
`PlayerDescription (0x0013)`).
|
||||
|
||||
### Diagnostic env vars
|
||||
|
||||
- `ACDREAM_DUMP_MOTION=1` — dump every inbound `UpdateMotion` (guid,
|
||||
stance, cmd, speed) + resulting `SetCycle` call. Massive for remote-
|
||||
animation debugging.
|
||||
- `ACDREAM_STREAM_RADIUS=N` — tune landblock visible-window radius
|
||||
(default 2 = 5×5).
|
||||
- `ACDREAM_NO_AUDIO=1` — suppress OpenAL init for headless / driver-
|
||||
broken setups.
|
||||
- `ACDREAM_REMOTE_VEL_DIAG=1` — dump per-tick / per-UM remote motion
|
||||
diagnostics (`[UM_RAW]`, `[SCFAST]`, `[SCFULL]`, `[SETCYCLE]`,
|
||||
`[FWD_WIRE]`, `[OMEGA_DIAG]`, `[SEQSTATE]`, `[PARTSDIAG]`,
|
||||
`[VEL_DIAG]`, `[UPCYCLE]`). Heavy.
|
||||
- `ACDREAM_PROBE_RESOLVE=1` — one `[resolve]` line per
|
||||
`PhysicsEngine.ResolveWithTransition` call: input + target + output
|
||||
position/cell, ok-vs-partial, grounded-in, contact-plane status,
|
||||
wall normal if hit, **responsible entity guid**, env flag, walkable
|
||||
polygon valid. Heavy (~30 Hz × every entity). Runtime-toggleable via
|
||||
the DebugPanel "Diagnostics" section if `ACDREAM_DEVTOOLS=1`.
|
||||
- `ACDREAM_PROBE_CELL=1` — one `[cell-transit]` line per
|
||||
`PlayerMovementController.CellId` change: old → new cell, world
|
||||
position, reason tag (`resolver` / `teleport`). Low volume — only
|
||||
fires on actual cell crossings. Runtime-toggleable via the same
|
||||
DebugPanel section.
|
||||
- `ACDREAM_PROBE_PUSH_BACK=1` — emits three line types per physics
|
||||
tick: `[push-back]` (per `BSPQuery.AdjustSphereToPlane` call),
|
||||
`[push-back-disp]` (per `BSPQuery.FindCollisions` dispatch),
|
||||
`[push-back-cell]` (per `Transition.CheckOtherCells` off-cell hit).
|
||||
Heavy under motion (~100–500 lines/sec). Pair with retail's cdb
|
||||
breakpoint set at `tools/cdb/a6-probe.cdb` for the A6.P1 capture
|
||||
protocol. Runtime-toggleable via the DebugPanel.
|
||||
- `ACDREAM_PROBE_FLAP=1` — capture probe for indoor visibility
|
||||
decisions at frame boundaries. Used to converge the U.4c flap fix
|
||||
(root indoor visibility at player's cell, not eye).
|
||||
- `ACDREAM_PROBE_STICKY=1` — per-guid sticky-melee timeline: `[sticky]`
|
||||
lifecycle lines (STICK/UNSTICK/LEASE-EXPIRE/TARGET-status teardown),
|
||||
per-armed-tick steer lines (signed gap dist, applied delta, heading
|
||||
delta), `[sticky-snap-skip]` at the suppressed NPC UP-snap site.
|
||||
Heavy while a pack is stuck (~60 Hz × stuck count). Converged the
|
||||
#171 residuals (the deep-overlap sign pin AP-82).
|
||||
- `ACDREAM_CAPTURE_RESOLVE=<path>` — live capture of every player-side
|
||||
`PhysicsEngine.ResolveWithTransition` call. Each call appends one
|
||||
JSON Lines record with full inputs, PhysicsBody snapshot before AND
|
||||
after, plus the `ResolveResult`. Filtered to `IsPlayer` mover flag
|
||||
— NPC / remote DR calls don't pollute. Pairs with the trajectory
|
||||
replay harness comparison tests to diff captured vs harness state
|
||||
per field — the first divergence pinpoints missing apparatus state.
|
||||
Capture is OFF when the env var is unset (one null-check cost per
|
||||
call).
|
||||
- `ACDREAM_DUMP_CELLS=<path>` / `ACDREAM_DUMP_GFXOBJS=<path>` — dump
|
||||
resolved cell/GfxObj polygon tables as JSON when ids cache. Used
|
||||
for harness fixture extraction.
|
||||
Every environment variable and command-line argument the client reads —
|
||||
what it does, its exact value shape, and **what else it changes about the
|
||||
run** — is documented in
|
||||
[`docs/launch-options.md`](docs/launch-options.md). That file is the single
|
||||
source of truth for every probe we have and how to turn one on, and it is
|
||||
enforced by `LaunchOptionsDocumentationTests`: a flag without a documented
|
||||
row fails the build, and so does a documented row whose read site was
|
||||
deleted. **Any future probe that stays in the code gets its row there in
|
||||
the same commit — no exceptions.**
|
||||
|
||||
The binding rules:
|
||||
|
||||
- **Every probe and dump is OFF by default.** Nothing that prints, records,
|
||||
or costs performance may activate without its env var explicitly set
|
||||
(`=1`). The only default-on flags are retail *behaviors* wearing an
|
||||
A/B off-switch (`ACDREAM_RETAIL_CHASE`, `ACDREAM_CAMERA_COLLIDE`,
|
||||
`ACDREAM_CAMERA_ALIGN_SLOPE`, `ACDREAM_RETAIL_CLOSE_DEGRADES` — `=0`
|
||||
disables); that set is frozen by `LaunchOptionsDocumentationTests` —
|
||||
never add a default-on diagnostic.
|
||||
- **Read the side-effects column before any measurement.** Flags that look
|
||||
inert are not: `ACDREAM_AUTOMATION_ARTIFACT_DIR` also builds a per-frame
|
||||
diagnostics referee (#432), and `ACDREAM_STREAM_RADIUS` measures a
|
||||
streaming window production never uses.
|
||||
- **A temporary probe dies with its investigation.** Add the row when you
|
||||
add the probe; delete both in the commit that fixes the issue.
|
||||
|
||||
### Outbound motion wire format (acdream → ACE)
|
||||
|
||||
|
|
@ -1478,8 +1645,8 @@ already-running ACE session via the handshake race.
|
|||
|
||||
## Reference repos: cross-check the relevant ones
|
||||
|
||||
The `references/` tree holds **six** vendored projects (ACE, ACViewer,
|
||||
WorldBuilder, Chorizite.ACProtocol, holtburger, AC2D). They overlap in
|
||||
The `references/` tree holds **five** vendored projects (ACE, ACViewer,
|
||||
WorldBuilder, Chorizite.ACProtocol, holtburger). They overlap in
|
||||
some areas and disagree in others. Before committing to an approach,
|
||||
**cross-reference at least two of them** for the domain you're working
|
||||
in — the per-domain hierarchy in the next section tells you which to
|
||||
|
|
@ -1488,7 +1655,7 @@ the relevant references is almost always the truth. The user has
|
|||
repeatedly had to remind me about this when I narrowly searched one ref
|
||||
and missed obvious answers in another.
|
||||
|
||||
The six references:
|
||||
The five references:
|
||||
|
||||
- **`references/ACE/`** — ACEmulator server. Authority on the wire
|
||||
protocol (packet framing, ISAAC, game message opcodes, serialization
|
||||
|
|
@ -1538,15 +1705,15 @@ The six references:
|
|||
the message-builder layer. ACE shows what the server expects;
|
||||
holtburger shows what a real client actually sends.
|
||||
|
||||
- **`references/AC2D/`** — **C++ AC client emulator.** Oldest reference,
|
||||
fixed-function OpenGL, but has the **real AC terrain split formula**
|
||||
(`FSplitNESW` with constants `0x0CCAC033`, `0x421BE3BD`, `0x6C1AC587`,
|
||||
`0x519B8F25`) which differs from WorldBuilder's physics-path formula.
|
||||
Also has the complete `0xF61C` movement packet format with flag bits
|
||||
and the `stMoveInfo` sequence counters. Key lesson from AC2D: it does
|
||||
NOT do client-side terrain Z — it sends movement keys to the server
|
||||
and uses the server's authoritative Z. See
|
||||
`docs/research/2026-04-12-movement-deep-dive.md` for the full analysis.
|
||||
**AC2D is a retired reference (2026-07-29).** It was a C++ AC client demo
|
||||
and the sixth entry in this list; it is no longer vendored under
|
||||
`references/` and must not be re-cloned. Everything we took from it is
|
||||
already written down and still stands: the terrain split formula
|
||||
`FSplitNESW` (constants `0x0CCAC033`, `0x421BE3BD`, `0x6C1AC587`,
|
||||
`0x519B8F25`), the `0xF61C` movement packet layout, and the finding that a
|
||||
client need not compute terrain Z itself. The historical analysis lives in
|
||||
`docs/research/2026-04-12-movement-deep-dive.md`; the UI dat-id work it fed
|
||||
is in `docs/research/retail-ui/`. Cite those, not the repo.
|
||||
|
||||
### Reference hierarchy by domain
|
||||
|
||||
|
|
@ -1571,9 +1738,9 @@ decompiled client code and would have fixed it in minutes.
|
|||
| **EnvCell / dungeon rendering** (cell geometry, portal visibility, collision mesh) | **WorldBuilder `EnvCellRenderManager.cs` + `PortalRenderManager.cs`** | ACME `EnvCellManager.cs` (more complete for collision); ACViewer `Physics/Common/EnvCell.cs` | WB is acdream's geometry base; ACME for collision until ported. |
|
||||
| **Particles / sky** (particle systems, weather, sky particles) | **WorldBuilder `SkyboxRenderManager.cs` + `ParticleEmitterRenderer.cs` + `ParticleBatcher.cs`** | retail decomp | WB is acdream's particle base. |
|
||||
| **Visibility / culling** (frustum, cell visibility) | **WorldBuilder `VisibilityManager.cs` + `Frustum.cs`** | — | WB. |
|
||||
| **Network protocol** (wire format, packet framing, fragment assembly, ISAAC) | **holtburger** `crates/holtburger-session/` | AC2D `cNetwork.cpp` (simpler, good for cross-check) | ACE shows the server side; holtburger + AC2D show the client side. |
|
||||
| **Client behavior** (what to send when, login flow, ack pattern, keepalive) | **holtburger** `crates/holtburger-core/src/client/` | AC2D `cNetwork.cpp` + `cInterface.cpp` | holtburger is the most complete; AC2D is simpler but confirmed working. |
|
||||
| **Movement** (MoveToState format, AutonomousPosition, sequence counters, speed) | **holtburger** `client/movement/` | AC2D `cNetwork.cpp:2592-2664` (0xF61C format) | See `docs/research/2026-04-12-movement-deep-dive.md` for the full cross-reference. |
|
||||
| **Network protocol** (wire format, packet framing, fragment assembly, ISAAC) | **holtburger** `crates/holtburger-session/` | `docs/research/named-retail/` | ACE shows the server side; holtburger shows the client side. AC2D was the second client-side cross-check here — retired reference; historical analysis remains in `docs/research/2026-04-12-movement-deep-dive.md`. |
|
||||
| **Client behavior** (what to send when, login flow, ack pattern, keepalive) | **holtburger** `crates/holtburger-core/src/client/` | `docs/research/named-retail/` | holtburger is the most complete. AC2D was the simpler confirmed-working cross-check — retired reference; historical analysis remains in `docs/research/2026-04-12-movement-deep-dive.md`. |
|
||||
| **Movement** (MoveToState format, AutonomousPosition, sequence counters, speed) | **holtburger** `client/movement/` | `docs/research/named-retail/` | AC2D `cNetwork.cpp:2592-2664` was the `0xF61C` format secondary — retired reference; historical analysis remains in `docs/research/2026-04-12-movement-deep-dive.md`, which carries the packet layout and the terrain-split formula verbatim. |
|
||||
| **Server expectations** (what ACE accepts/rejects, validation thresholds) | **ACE** `Source/ACE.Server/Network/` | — | Only ACE knows what the server actually validates. |
|
||||
| **Silk.NET / .NET 10 idioms** (GL calls, shader setup, VAO patterns) | **WorldBuilder original** | ACME (same stack) | Both use the same backend; original has cleaner isolated examples. |
|
||||
| **Protocol field order** (packed dwords, type prefixes, flag enums) | **Chorizite.ACProtocol** `Types/*.cs` | holtburger (cross-check) | Generated from protocol XML; has accurate field comments. |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue