diff --git a/AGENTS.md b/AGENTS.md index 0a692f96..51b38ef1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -90,8 +90,8 @@ where ImGui cannot reach the 3D scene. Plugin gameplay UI uses the BCL-only `AcDream.Plugin.Abstractions.IUiRegistry.AddMarkupPanel` contract; plugins never import App or ImGui namespaces. Full design: [`docs/plans/2026-04-24-ui-framework.md`](docs/plans/2026-04-24-ui-framework.md). -Memory cribs: `memory/project_chat_pipeline.md` (chat pipeline as of -Phase I), `memory/project_input_pipeline.md` (input pipeline as of +Memory cribs: `claude-memory/project_chat_pipeline.md` (chat pipeline as of +Phase I), `claude-memory/project_input_pipeline.md` (input pipeline as of Phase K). **Input pipeline:** `src/AcDream.UI.Abstractions/Input/` (action enum, @@ -112,14 +112,18 @@ movement queries. component/target gates, live enchantment wire, Magic-scoped input, spell bar, spellbook, component book, effect indicators, shared main-panel switching, and positive/negative effects UI are implemented over the Step-9 projectile/DAT-effect foundation. The 2026-07-20 R6 complete-root-Frame/object-workset cutover is automated-test complete; -three independent conformance/architecture/adversarial re-reviews are clean, the Release build has -zero warnings, and the full suite is 6,452 passed / 5 skipped. Its unattended seven-destination +three independent conformance/architecture/adversarial re-reviews are clean, the Release build succeeds +(the clean documentation audit exposes 17 pre-existing test-project warnings, #228), and the full suite +is 6,452 passed / 5 skipped. Its unattended seven-destination connected input/portal/performance rebaseline also passes without an interactive desktop. Remaining ownership cleanup and registered TS-50/TS-51 timing residuals stay carried. **Next:** connected R6 locomotion/collision/projectile/teleport visual gate, then the final two-client -portal-out/materialization observer gate. **Carried:** #145-residual, #116, R6 residuals, Track MP0. +portal-out/materialization observer gate. **Carried:** #153, #116, R6 residuals, and the deferred +Modern Pipeline track (MP1b+). Start magic work at `claude-memory/project_magic_ui_and_casting.md`; detailed state is below. +Documentation entry point: [`docs/README.md`](docs/README.md). + For canonical state, read in this order: - [`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 @@ -141,7 +145,7 @@ For engineering reference (read on demand, not at session start): The memory dir also holds `feedback_*.md` lessons-learned (cross-cutting patterns the project has agreed on) and `project_*.md` per-subsystem cribs (chat pipeline, input pipeline, interaction pipeline, etc.). -See `memory/MEMORY.md` for the index. +See `claude-memory/MEMORY.md` for the index. ## Code Structure Rules diff --git a/CLAUDE.md b/CLAUDE.md index b2f821d0..4f02729d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -88,8 +88,8 @@ where ImGui cannot reach the 3D scene. Plugin gameplay UI uses the BCL-only `AcDream.Plugin.Abstractions.IUiRegistry.AddMarkupPanel` contract; plugins never import App or ImGui namespaces. Full design: [`docs/plans/2026-04-24-ui-framework.md`](docs/plans/2026-04-24-ui-framework.md). -Memory cribs: `memory/project_chat_pipeline.md` (chat pipeline as of -Phase I), `memory/project_input_pipeline.md` (input pipeline as of +Memory cribs: `claude-memory/project_chat_pipeline.md` (chat pipeline as of +Phase I), `claude-memory/project_input_pipeline.md` (input pipeline as of Phase K). **Input pipeline:** `src/AcDream.UI.Abstractions/Input/` (action enum, @@ -110,14 +110,18 @@ movement queries. component/target gates, live enchantment wire, Magic-scoped input, spell bar, spellbook, component book, effect indicators, shared main-panel switching, and positive/negative effects UI are implemented over the Step-9 projectile/DAT-effect foundation. The 2026-07-20 R6 complete-root-Frame/object-workset cutover is automated-test complete; -three independent conformance/architecture/adversarial re-reviews are clean, the Release build has -zero warnings, and the full suite is 6,452 passed / 5 skipped. Its unattended seven-destination +three independent conformance/architecture/adversarial re-reviews are clean, the Release build succeeds +(the clean documentation audit exposes 17 pre-existing test-project warnings, #228), and the full suite +is 6,452 passed / 5 skipped. Its unattended seven-destination connected input/portal/performance rebaseline also passes without an interactive desktop. Remaining ownership cleanup and registered TS-50/TS-51 timing residuals stay carried. **Next:** connected R6 locomotion/collision/projectile/teleport visual gate, then the final two-client -portal-out/materialization observer gate. **Carried:** #145-residual, #116, R6 residuals, Track MP0. +portal-out/materialization observer gate. **Carried:** #153, #116, R6 residuals, and the deferred +Modern Pipeline track (MP1b+). Start magic work at `claude-memory/project_magic_ui_and_casting.md`; detailed state is below. +Documentation entry point: [`docs/README.md`](docs/README.md). + For canonical state, read in this order: - [`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 @@ -139,7 +143,7 @@ For engineering reference (read on demand, not at session start): The memory dir also holds `feedback_*.md` lessons-learned (cross-cutting patterns the project has agreed on) and `project_*.md` per-subsystem cribs (chat pipeline, input pipeline, interaction pipeline, etc.). -See `memory/MEMORY.md` for the index. +See `claude-memory/MEMORY.md` for the index. ## Code Structure Rules diff --git a/README.md b/README.md index 56fa126a..6b35d6aa 100644 --- a/README.md +++ b/README.md @@ -5,54 +5,64 @@ A modern open-source C# / .NET 10 Asheron's Call client. Faithful port of the retail client's behaviour to Silk.NET with a modern, plugin-friendly architecture. The code is modern; the behaviour is retail. -**Status:** playable pre-alpha. You can log in to an ACE server, walk and -run through Dereth, see other players animate correctly, watch the -day-night cycle, hear ambient audio, and take weapons out. Many systems -are still stubbed or in-progress — see roadmap. +**Status:** playable pre-alpha; M3 ("Cast a spell") is active. The connected +client supports the complete M2 combat/loot/inventory loop plus retained +spellbook, component-book, favorite-spell, enchantment, portal-space, radar, +chat, character, and inventory UI. Current work is verification and retail +conformance, not a first-playable bring-up. + +Start at the [documentation map](docs/README.md) for the current milestone, +roadmap, tactical issues, architecture, retail-divergence register, research, +and durable memory. ## Stack - **Language:** C# .NET 10 -- **Graphics:** [Silk.NET](https://github.com/dotnet/Silk.NET) (OpenGL 4.3) +- **Graphics:** [Silk.NET](https://github.com/dotnet/Silk.NET) (OpenGL 4.3 + context; `GL_ARB_bindless_texture` and `GL_ARB_shader_draw_parameters` are + mandatory) - **Audio:** OpenAL via Silk.NET - **Dat parsing:** [Chorizite.DatReaderWriter](https://github.com/Chorizite/DatReaderWriter) - **Networking:** Custom UDP + ISAAC cipher + game-message layer, wire-compatible with ACEmulator server -## What works +## What works today -- Connecting to a local ACEmulator (ACE) server on `127.0.0.1:9000` -- Character selection and login -- Rendering Dereth terrain with retail-correct texture blending, - per-vertex lighting, and road overlays -- Static scenery (buildings, trees, scenery objects) via EnvCell walker -- Animated characters (own + remote) with walk / run / strafe / jump / - turn / attack motions sourced from the retail motion tables -- Network sync with remote players — you can watch other characters - animate correctly, including speeds and directional motion -- Day-night cycle driven from the retail Region dat (0x13000000) — - correct DayGroup picking via the retail LCG, correct keyframe - interpolation, correct per-keyframe sky-object replace -- Weather (rain/snow particles synced from the server via the retail - DayGroup name) -- Sky dome, stars, moon, clouds, sun — each rendered from the retail - Region's SkyObjects with texture scrolling and alpha fade -- Plugin host with live event replay-on-subscribe +- ACE login, character selection, world entry, chat, client commands, and + graceful logout. +- Outdoor, building, cellar, and dungeon streaming with portal-space travel, + terrain/scenery/EnvCell rendering, collision, lighting, sky, fog, audio, and + day/night presentation. +- Local and observed player/NPC/monster movement, animation, selection, radar, + combat stances, melee and missile presentation, death, corpses, chests, and + looting. +- Inventory bags, stack splitting, paperdoll/equipment, weapon switching, + quick bars, item use, giving items to NPCs, and server-authoritative item + movement. +- Retained retail-style gameplay UI for vitals, chat, toolbar, inventory, + character/skills, spellbook/components, helpful/harmful effects, combat and + spell bars, radar/compass, indicator pages, and confirmation dialogs. +- Spell catalog, learned/favorite spells, component preflight, connected casts, + enchantments, DAT-driven missiles/effects, recall, Hidden/UnHide, and portal + materialization presentation. +- Plugin host, shared input/command abstractions, and permanent ImGui developer + tools behind `ACDREAM_DEVTOOLS=1`. -## What's stubbed or in-progress +## Active gaps -- Indoor transitions (building interiors) — disabled, Phase B.3 pending -- Combat — animation works, damage math not wired -- Lightning visual — the retail PhysicsScript-driven flash is researched - but not wired (see `docs/research/2026-04-23-lightning-real.md`) -- TimeSync drift — we only sync calendar on login, not periodically, - so acdream's in-game clock gradually drifts from retail's -- Landscape draw distance — currently `ACDREAM_STREAM_RADIUS=2` (~400m) - vs retail's several kilometres +- R6's complete object-frame update path still needs the next local visual + comparison; the final M3 gate is a two-client portal-out/materialization + observer comparison. +- Issue `#225` still needs the lifestone/particle alpha-order visual check, + although its connected lifetime/performance gates pass. +- Narrow behavior debt remains in issue `#153` (an unstreamed far-teleport + edge case), issue `#116` (slide feel), and registered TS-50/TS-51 effect + timing. +- Many later retail systems remain roadmap work: advanced social/vendor/trade/ + crafting UI, full weather/lightning parity, deeper combat/stat systems, + graphical Linux, and a true headless multi-session bot host. -See `docs/plans/2026-04-11-roadmap.md` for the ordered phase list. -See `docs/ISSUES.md` for the rolling list of known bugs + small deferred -features (tactical, bug-level; the roadmap is strategic, phase-level). +See [docs/README.md](docs/README.md) for document authority and current links. ## Building + running @@ -74,7 +84,8 @@ $env:ACDREAM_TEST_HOST = "127.0.0.1" $env:ACDREAM_TEST_PORT = "9000" $env:ACDREAM_TEST_USER = "testaccount" $env:ACDREAM_TEST_PASS = "testpassword" -dotnet run --project src\AcDream.App\AcDream.App.csproj -c Debug +$env:ACDREAM_RETAIL_UI = "1" +dotnet run --project src\AcDream.App\AcDream.App.csproj -c Release ``` Offline CLI dat inspector (no server needed): @@ -89,8 +100,11 @@ dotnet run --project src/AcDream.Cli -- "C:\path\to\Asheron's Call" |---|---| | `ACDREAM_DUMP_SKY=1` | Per-second dump of the interpolated `SkyKeyframe` values + per-SkyObject draw info + texture alpha histograms | | `ACDREAM_DUMP_MOTION=1` | Dump every inbound `UpdateMotion` + resulting `SetCycle` | -| `ACDREAM_STREAM_RADIUS=N` | Tune landblock visible-window radius (default 2 = 5×5) | +| `ACDREAM_STREAM_RADIUS=N` | Legacy override for the configured two-tier streaming radii | | `ACDREAM_NO_AUDIO=1` | Suppress OpenAL init | +| `ACDREAM_RETAIL_UI=1` | Enable retained retail gameplay UI | +| `ACDREAM_DEVTOOLS=1` | Enable ImGui developer tools | +| `ACDREAM_UNCAPPED_RENDER=1` | Disable normal presentation pacing for throughput measurement | | `ACDREAM_DAY_GROUP=N` | Force a specific DayGroup index for A/B-testing weather presets | | `ACDREAM_RUN_SKILL=N` / `ACDREAM_JUMP_SKILL=N` | Client-side run/jump skill (default 200) | @@ -98,16 +112,20 @@ dotnet run --project src/AcDream.Cli -- "C:\path\to\Asheron's Call" ``` src/ - AcDream.App/ rendering + audio + main loop (Silk.NET) - AcDream.Core/ game state, meshing, physics, sky, weather, lighting + AcDream.App/ window, retained UI, rendering, audio, runtime wiring + AcDream.Content/ GL-free DAT mesh/texture extraction + AcDream.Core/ game state, physics, movement, world, gameplay logic AcDream.Core.Net/ UDP + ISAAC + game-message layer + AcDream.UI.Abstractions/ shared UI/input ViewModels, commands, contracts + AcDream.UI.ImGui/ permanent developer-tool renderer AcDream.Cli/ offline dat-inspector console app + AcDream.Bake/ offline content bake tooling AcDream.Plugin.Abstractions/ plugin host interfaces AcDream.Plugins.Smoke/ example plugin tests/ - AcDream.Core.Tests/ xUnit tests (742 passing) - AcDream.Core.Net.Tests/ network-layer tests + AcDream.*.Tests/ layer-matched xUnit projects (6,452 passing, + 5 intentional skips at the 2026-07-20 baseline) tools/ RetailTimeProbe/ Win32 P/Invoke ReadProcessMemory probe of @@ -122,7 +140,8 @@ references/ vendored read-only reference code — ACE, Gitignored. docs/ - architecture/ single-source-of-truth architecture doc + README.md documentation map + authority order + architecture/ architecture, structure, divergence, WB inventory plans/ phase roadmaps + per-phase specs research/ decompile-derived research, per-phase findings, deep-dive agent reports @@ -131,18 +150,20 @@ docs/ ## Development workflow -All AC-specific behaviour is ported from the decompiled retail client -(`docs/research/decompiled/`). The workflow is: +All AC-specific behaviour is ported from the named retail client oracle +(`docs/research/named-retail/`). The workflow is: -1. **Decompile first.** Find the matching function in the decompiled - client. -2. **Cross-reference.** Check against ACE's C# port and ACViewer / +1. **Grep named retail first.** Find the matching `class::method` in the + Sept 2013 named pseudo-C and headers. +2. **Decompile only as fallback.** Use the older Ghidra chunks when the named + oracle lacks the function. +3. **Cross-reference.** Check against ACE's C# port and ACViewer / WorldBuilder. -3. **Write pseudocode.** Translate C to readable pseudocode first. -4. **Port faithfully.** Translate line-by-line, preserving variable +4. **Write pseudocode.** Translate C to readable pseudocode first. +5. **Port faithfully.** Translate line-by-line, preserving variable names and control flow. -5. **Conformance test.** Add tests using golden values from retail. -6. **Integrate surgically.** Minimise churn in the surrounding pipeline. +6. **Conformance test.** Add tests using golden values from retail. +7. **Integrate surgically.** Minimise churn in the surrounding pipeline. Guessing at AC-specific algorithms is explicitly forbidden — see `CLAUDE.md` for the full workflow rationale and the list of failure @@ -150,7 +171,7 @@ modes we've paid for in the past. ## Reference repos -We cross-reference five external projects for every retail behaviour: +We cross-reference six external projects for retail behavior: - **ACE** (ACEmulator) — authoritative server-side protocol - **ACViewer** — MonoGame dat viewer; good for character appearance diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 47006cc8..94752ad6 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -15,10 +15,33 @@ What does NOT go here: ## Conventions - Sequential integer IDs (`#1`, `#2`, …). Commits that close an issue reference the ID in the message (e.g. `fix #3: periodic TimeSync parsing`). -- `Status` is `OPEN`, `IN-PROGRESS`, or `DONE`. DONE items move to the **Recently closed** section at the bottom with closed-date + commit SHA. +- `Status` is `OPEN`, `IN-PROGRESS`, or `DONE`. The status inside each issue is + authoritative. This long-lived file still has completed items interleaved + with open history; physical placement under an older heading is not status. +- New DONE items should move to **Recently closed** when practical. Do not do a + mechanical move of old blocks merely to tidy the file; preserve their + research context until a deliberate archive split. - Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending. - Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed. +## Current queue — 2026-07-20 + +- **Next visual gate:** R6 locomotion/collision/projectile/teleport comparison + after the complete-root-Frame/object-workset cutover. +- **M3 closing gate:** `#218`, final two-client portal-out/materialization and + indoor observer comparison. +- **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its + connected performance, lifetime, and unattended portal routes pass. +- **Carried behavior debt:** `#153` far-teleport unstreamed-edge arrival and + `#116` slide response. TS-50/TS-51 are tracked in the divergence register. +- **Deferred visual fidelity:** `#226` retail landscape detail overlay. +- **Build hygiene:** `#228` records 17 clean-Release test-project warnings; + production compilation and all tests pass. + +The [documentation map](README.md) defines how this tactical ledger relates to +the milestone, roadmap, architecture, divergence register, research, and +memory. + ## Template Copy this block when adding a new issue: @@ -44,6 +67,80 @@ Copy this block when adding a new issue: --- +## #228 — Clean Release build emits 17 test-project warnings + +**Status:** OPEN +**Severity:** LOW +**Filed:** 2026-07-20 +**Component:** tests / build hygiene + +**Description:** A fresh `dotnet build AcDream.slnx -c Release --no-restore` +succeeds with zero errors but emits 17 warnings from +`tests/AcDream.Core.Tests`. Earlier current-state prose claimed “zero warnings” +after an incremental gate in which those projects did not recompile. + +**Root cause / status:** The warnings are existing nullable-flow (`CS8600`, +`CS8602`, `CS8625`), never-assigned test fixture fields (`CS0649`), and xUnit +analyzer findings (`xUnit1025`, `xUnit1031`, `xUnit2013`, `xUnit2017`). One +duplicate `InlineData` also causes xUnit to skip a duplicate test-case ID during +discovery; the intended unique cases still pass. This is test hygiene, not a +production runtime failure. + +**Files:** `tests/AcDream.Core.Tests/Conformance/DatConcurrencyStressTests.cs`; +`tests/AcDream.Core.Tests/Physics/Motion/RemoteChaseEndToEndHarnessTests.cs`; +`tests/AcDream.Core.Tests/Physics/CellGraphMembershipTests.cs`; +`tests/AcDream.Core.Tests/Physics/DoorSetupGfxObjInspectionTests.cs`; +`tests/AcDream.Core.Tests/Physics/MotionInterpreterDoMotionFamilyTests.cs`; +`tests/AcDream.Core.Tests/Rendering/Wb/AcSurfaceMetadataTableTests.cs`; +`tests/AcDream.Core.Tests/Physics/MotionInterpreterTests.cs`; +`tests/AcDream.Core.Tests/Physics/CellArrayTests.cs`; +`tests/AcDream.Core.Tests/Streaming/StreamingControllerTwoTierTests.cs`. + +**Acceptance:** A non-incremental Release solution build reports zero warnings +and zero errors without suppressing analyzers or weakening nullable checking; +the full 6,452-pass / 5-skip suite remains green. + +--- + +## #226 — Retail landscape detail-texture overlay is not rendered + +**Status:** OPEN — deferred visual fidelity; the user-visible tiling regression +in #155 is fixed +**Severity:** LOW +**Filed:** 2026-07-20 +**Component:** rendering / terrain material + +**Description:** Retail can overlay a high-frequency landscape detail texture, +faded by viewer distance and gated by the Environment Detail Textures setting. +acdream now repeats every base/overlay/road surface at its authored +`TerrainTex.TexTiling`, which fixed the stretched/blurry symptom in #155, but +does not yet render this separate optional detail layer. + +**Root cause / status:** The earlier #155 investigation conflated two retail +mechanisms. `bb5acab9` ported the behavior that produced the observed mismatch: +`TexMerge::CopyAndTile`/`Merge` pass each source's authored base tiling into the +terrain composition. The still-missing detail pass is a distinct +`LScape::GenerateDetailSurfaces`/`ACRender::landPolyDraw` path. The first +experimental detail-array implementation sampled the wrong neutral/data +contract and was reverted rather than shipping a darkened ground. TS-52 records +the current divergence. + +**Files:** `src/AcDream.App/Rendering/TerrainAtlas.cs`; +`src/AcDream.App/Rendering/TerrainModernRenderer.cs`; +`src/AcDream.App/Rendering/Shaders/terrain_modern.frag`. + +**Research:** `docs/research/2026-07-13-retail-terrain-texture-tiling-pseudocode.md` +covers the now-shipped base contract. The detail symbols cited above must be +distilled into a dedicated pseudocode note as the first #226 implementation +step; the reverted experiment remains available in git history. + +**Acceptance:** With retail Environment Detail Textures enabled, close ground +shows the same high-frequency detail and distance fade without changing base +color/brightness. Disabling it produces the already-accepted authored base +tiling. + +--- + ## #225 — Scene particles overpaint translucent world objects **Status:** IN-PROGRESS — implementation/reviews and connected stress gate pass; final visual gate pending @@ -172,6 +269,16 @@ The run was performed over RDP, but software pacing was explicitly disabled and `pace` remained zero, so these are engine-throughput measurements rather than remote-display refresh measurements. The lifestone/particle visual gate remains. +The 2026-07-20 unattended R6 rebaseline repeated the seven-destination route +without an interactive desktop and exercised semantic turn, forward, charged +jump, and combat input through the production dispatcher. All seven portal +materializations, outbound movement gates, same-location memory/update checks, +fatal-log scan, and graceful WM_CLOSE teardown passed. Caul update p95 was +1.2 ms on the first visit and 1.1 ms on return; Sawato was 0.2/0.3 ms. This is +additional lifetime/correctness evidence, not a replacement for the translucent +lifestone visual check. See +`docs/research/2026-07-20-connected-r6-soak.md`. + **Files:** `src/AcDream.App/Rendering/RetailAlphaQueue.cs`; `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs`; `src/AcDream.App/Rendering/ParticleRenderer.cs`; @@ -210,7 +317,7 @@ degrade FPS, and revisiting an expired region restores its objects. ## #224 — Gameplay indicator bar only implemented effect icons -**Status:** IN-PROGRESS +**Status:** DONE — 2026-07-17, user visually confirmed after detail-panel polish **Severity:** MEDIUM **Filed:** 2026-07-17 **Component:** retained UI / gameplay indicators / session telemetry @@ -249,6 +356,13 @@ selected spell name/description now reflows to the authored width and its own `0x10000127` scrollbar works independently of the upper effect-list scrollbar. Vitae recovery XP also uses retail's grouped integer presentation. +**Resolution:** `52c529be`, `a96767ba`, `d1d60310`, `16c21e29`, and +`82789eea` ported the strip, shared pages, retail Vitae/Character Information, +button state, description wrapping, independent lower scrolling, and grouped +XP. The user accepted the resulting pages. Transport packet-loss averaging and +Mini Game gameplay remain explicitly tracked by AP-110 rather than keeping this +visible UI issue open. + **Files:** `src/AcDream.App/UI/Layout/IndicatorBarController.cs`; `src/AcDream.App/UI/Layout/DatWidgetFactory.cs`; `src/AcDream.Core.Net/WorldSession.cs`; `src/AcDream.App/UI/RetailUiRuntime.cs`. @@ -2618,42 +2732,42 @@ BCL-only. **2026-07-09 triage:** investigated, verdict STILL_OPEN — a fix for this exact bug (`9444a328`, normalizing the panel root to (0,0) for off-screen FBO captures) exists but only on unmerged branches (`codex/mockup-stage` / `claude/peaceful-visvesvaraya-e0a196`); `StudioWindow.cs` on this branch still has no position-normalization code and the mechanism is unfixed here. -## #155 — Outdoor terrain textures look stretched + blurry vs retail (missing landscape DETAIL-texture overlay) +## #155 — Outdoor terrain textures looked stretched and blurry vs retail -**Status:** OPEN — **root cause VERIFIED (oracle-first); fix attempt implemented + REVERTED** (rendered the ground black). Ready for a focused fresh implementation pass. -**Severity:** MEDIUM (visible — outdoor ground reads soft/stretched everywhere vs retail's crisp ground; user side-by-side screenshots) +**Status:** DONE — 2026-07-13, `bb5acab9`, user visually confirmed +**Severity:** MEDIUM **Filed:** 2026-06-25 -**Component:** render — terrain texturing (WB-derived modern path: `TerrainAtlas` / `TerrainModernRenderer` / `terrain_modern.frag`) +**Component:** rendering / terrain texture composition -**Description (user-observed, 2026-06-25):** Outdoor terrain textures look stretched and less detailed than retail — a cobblestone road's stones look too big/blurry, grass is softer. Side-by-side: retail crisp, acdream smeared. +**Description:** Cobblestone, roads, and grass appeared enlarged and soft even +though the high-resolution source surfaces, mipmaps, and anisotropic filtering +were active. -**Root cause (VERIFIED — decomp + dat, not guessed):** acdream renders one base texture tiled **once per 24 m landcell** (`terrain_modern.frag:49` `const float TILE = 1.0;`, `vBaseUV` 0→1 per cell) and **ignores the dat's detail-texture fields entirely**. Retail overlays a high-frequency **landscape detail texture** on the base ground; that overlay is what keeps retail's ground crisp up close. Filtering is NOT the problem (the ground array already has mipmaps + `LinearMipmapLinear` + 16× anisotropy, `TerrainAtlas.cs:187-193`); resolution is NOT the problem (terrain is 512² in both Portal and HighRes). +**Corrected root cause / resolution:** The first investigation attributed the +whole symptom to retail's separate detail-texture overlay and incorrectly +claimed the base `TerrainTex.TexTiling` field did not exist. The later +named-retail/DAT audit disproved that claim. Retail +`TexMerge::CopyAndTile @ 0x00503580` and `TexMerge::Merge @ 0x005038C0` pass +each base, overlay, and road surface's authored `TexTiling` into composition. +acdream had hard-coded one repeat per 24-metre landcell. `bb5acab9` carries the +field through `TerrainAtlas`, uploads a layer-indexed table, and applies it in +the modern shader while leaving cell-scale alpha masks unchanged. The user +confirmed the outdoor textures now match the expected scale. -**Verified retail mechanism (decomp `docs/research/named-retail/acclient_2013_pseudo_c.txt`):** -- Dat fields on `DatReaderWriter.Types.TerrainTex` (confirmed via reflection on Chorizite.DatReaderWriter 2.1.7): `DetailTextureId` (`QualifiedDataId`, `.DataId`) + `DetailTexTiling` (`uint`). acdream currently reads neither (only `TextureId`). -- `ACRender::landPolyDraw` 0x006b6525 (lines 702299-702300): **detail UV = `curr_detail_tiling × baseUV`** (the detail texture tiles `detail_tiling×` relative to the base). -- `landPolyDraw` 0x006b6450-0x006b649c (lines 702263-702287): **distance fade** — detail alpha is FULL at camera depth `< 10`, lerps to 0 by depth `50`, gone beyond. (Detail only sharpens up close.) -- 0x0059cab4 / lines 425099-425112: blend = **`TEXOP_MODULATE`** (modern equivalent: MODULATE2X `base*detail*2`, neutral at gray 0.5). -- `TexMerge::GetDetailTiling` 0x00503a10 (line 263852); `LScape::GenerateDetailSurfaces`/`SetDetailTexturing` 0x00506b40 (line 268389). Gated by the `EnvironmentDetailTextures` graphics preference (`Render::m_RenderPrefs.EnvironmentDetailTextures`). -- **FAITHFULNESS NOTE:** retail uses a **single landscape detail-tiling SCALAR** — `GetDetailTiling(region, 0)` reads `TerrainDesc[0].DetailTexTiling` (category 0 = landscape; default **2.0** @0x0081eca8), stored in global `Render::curr_detail_tiling` and applied to ALL terrain UVs. It is **NOT per-terrain-type**. Prefer the single scalar. +The optional high-frequency Environment Detail Textures pass is a different +retail mechanism. It remains deferred under #226/TS-52 and does not keep this +fixed user-visible regression open. -**⚠ DO-NOT-RETRY:** the first investigation agent **FABRICATED a base `TexTiling` field** — it does **NOT** exist on `TerrainTex` (only `DetailTexTiling`). Do not re-introduce a "read `TexTiling`, multiply the base UV" fix; the base tiling is not a per-type dat field. (Verify the actual base landcell UV scale in the decomp before touching `TILE`.) +**Files:** `src/AcDream.App/Rendering/TerrainAtlas.cs`; +`src/AcDream.App/Rendering/TerrainModernRenderer.cs`; +`src/AcDream.App/Rendering/TerrainTextureTilingTable.cs`; +`src/AcDream.App/Rendering/Shaders/terrain_modern.frag`. -**Fix attempt (implemented + REVERTED, this session):** built a parallel detail `GL_TEXTURE_2D_ARRAY` (per type from `DetailTextureId`) + `uDetailTiling[]` + the shader block `rgb *= mix(vec3(1.0), detail*2.0, fade)` with the 10→50 depth fade. It **compiled, linked, ran with no GL error** — but the ground rendered **black/dark up close**: the detail array sampled near-zero, so MODULATE2X collapsed `rgb` to 0. **The bindless handles were verified NOT swapped** (renderer correctly binds `(terrain, alpha, detail)`). The bug is in the detail-texture **DATA**: the no-detail gray fill (`NoDetailGray=128`) didn't land as neutral, OR `DetailTextureId` decodes dark/black, OR AC's detail textures are not 0.5-centered (so MODULATE2X darkens). Reverted via `git checkout` — terrain back to the working (blurry) state. +**Research:** `docs/research/2026-07-13-retail-terrain-texture-tiling-pseudocode.md`. -**NEXT (debugging steps for the fresh pass):** -1. **Dump the detail array content** — are the layers ~0.5 gray or ~0 black? (Throwaway: decode each `DetailTextureId` + print mean brightness.) This tells you gray-fill vs decode vs texture-content. -2. If the textures decode dark, AC detail textures may not be gray-centered → use plain MODULATE or re-center, not MODULATE2X. Confirm the actual blend visually. -3. Confirm `DetailTextureId` → `SurfaceTexture` → `RenderSurface` resolves (do the detail textures even exist for these terrain types? many may be 0 → must fall to the gray no-op). -4. Use retail's **single landscape scalar** (`TerrainDesc[0].DetailTexTiling`, default 2.0), not per-type (faithfulness note above). -5. Gate behind an `EnvironmentDetailTextures` equivalent. -6. **Secondary (separate, unconfirmed):** is the base `TILE=1.0` (once per cell) correct vs retail? Verify the landcell base UV scale in the decomp during the fix — it may also contribute to "stretched." - -**Files (the reverted attempt, for reference):** `TerrainAtlas.cs` (detail array build + gray fill + `DetailTiling`), `terrain_modern.frag` (uDetail sampler + MODULATE2X + fade), `TerrainModernRenderer.cs` (bind detail handle + upload `uDetailTiling[]`). - -**Milestone note:** freeze-override render-polish (off the M1.5 critical path); resume when prioritized. Detail-overlay is a real retail feature acdream lacks — register an AP row when it ships (or note it as a known divergence until then). - -**Acceptance:** outdoor ground (cobblestone road + grass) reads crisp up close matching retail, detail fades cleanly past ~50 m, no overall color/brightness shift (modulate neutral); user side-by-side vs retail. +**Acceptance:** Authored grass, road, base, and overlay textures repeat at +retail scale without reducing source resolution or changing blend masks — +passed in the connected visual gate. --- @@ -2699,9 +2813,18 @@ BCL-only. --- -## #153 — Portals only work once per session (can't run in, run out, re-enter) +## #153 — Far teleport onto an unstreamed landblock edge can run away -**Status:** 🟡 PARTIALLY FIXED — REOPENED 2026-06-21 (a NARROWER residual). The cell-relative carried-anchor (Option B, Slices 1–3+7, `438bb68`→`403a338`) **fixes the cascade for a STREAMED-terrain arrival** (live-verified: `+Je` ran through ~10 far-town landblocks across 2 sessions, zero march). BUT a third live session found the cascade **RECURS when a teleport arrives onto a NOT-YET-STREAMED landblock NEAR AN EDGE.** Evidence (`launch5.log`): arrival `[snap] claim=0xC98C0028 pos=(113.666,190.259,22.010) branch=NO-LANDBLOCK (lbs=0) -> verbatim` (local Y=190.3, **1.7 m from the 192 boundary**) → cell marches `0xC98C(lbY 0x8C) → 0xC9FE(lbY 0xFE)` +2/tick while Z free-falls 22→−19; the outbound wire then sends the marched cell `C9FE0031` with compensating garbage `localY=−21684` → ACE `MOVEMENT SPEED` / `failed transition` → player stuck. Contrast same session: hub `0x00070133` VALIDATED→fine; far town `0x977B000C` arrived unstreamed but **mid-block** (Y=73.8) → Z free-fall only, NO march. **ROOT (hypothesis, NOT yet apparatus-confirmed):** outdoor teleport places immediately but the destination streams a few ticks later (`streaming: dungeon EXIT-expand -> (201,140)` logs just after placement); during that gap the resolve runs against an empty world, and at an edge the player crosses into the unstreamed neighbour where the carried anchor (which computes to `(0,0,0)` at the recentered center) gives no protection. Same root as the Z free-fall (`#135`/`#138` placed-but-unstreamed gap). **DO NOT guess-patch** (original #145 burned 5 attempts) — needs a capture + an anchor/guard diagnostic at the crossing FIRST. Likely fix shape: a streaming-gap HOLD (freeze the per-tick resolve — no march, no fall — until the player's landblock loads; the async equivalent of retail's synchronous load), which would fix both symptoms. Suites still green; `TeleportFarTownRunawayTests` covers the STREAMED case only. [Prior "fixed" banner was premature — 2 clean sessions wasn't enough for a streaming-timing bug.] +**Status:** IN-PROGRESS — the original repeat-portal failure and streamed-arrival +cascade are fixed; a narrower unstreamed-arrival-near-edge residual remains. +The cell-relative carried anchor (Option B, Slices 1–3+7, +`438bb68`→`403a338`) passed roughly ten streamed far-town transitions. The +recorded residual arrives within about 2 metres of a 192-metre landblock edge +before the neighbour is resident, then advances membership through unstreamed +cells while producing an inconsistent outbound cell/local-position pair. Keep +the capture-first/DO-NOT-RETRY constraints and detailed verified mechanism +below; this is the issue formerly misreferenced in living docs as +“#145-residual.” Issue #145 is an unrelated completed UI Z-order bug. **Status (historical):** REOPENED 2026-06-21 — RESIDUAL: a teleport to a FAR town triggers a per-frame **resolver runaway** (the 2026-06-20 source-drop fix holds for Holtburg↔dungeon, but far-town destinations regress). #138 (objects come back) is confirmed SEPARATE + fixed. Root cause under research (retail-decomp oracle workflow). **Severity:** HIGH (blocks far-town portal travel; breaks collision after the teleport — user, 2026-06-21) @@ -3060,7 +3183,7 @@ Both are the **entity-lifecycle/render path across a teleport**, NOT the streami **Acceptance:** portal out of the 0x0007 dungeon → full outdoor world streams (trees/scenery present), **server objects (doors/NPCs/portals) render**, **own avatar renders across repeated round-trips**, collision works, position tracks (no avatar-vs-camera desync). -**2026-07-10 gate — PASSED, #138 CLOSED:** the user confirmed the full dungeon round-trip end-to-end — ENTER + NAVIGATE (dungeon streams, renders, collides, navigable, doors work) AND the EXIT (portal OUT to the outdoor world, world streams, collision holds, position tracks). This completes the #138 acceptance and lands M1.5. **Separate follow-up still open:** `#145-residual` (the far-town teleport-OUT arrival cascade) is a narrow far-teleport streaming edge case tracked on its own; it is NOT a #138 or M1.5 blocker and stays open for capture-harness-first work if it recurs. +**2026-07-10 gate — PASSED, #138 CLOSED:** the user confirmed the full dungeon round-trip end-to-end — ENTER + NAVIGATE (dungeon streams, renders, collides, navigable, doors work) AND the EXIT (portal OUT to the outdoor world, world streams, collision holds, position tracks). This completes the #138 acceptance and lands M1.5. **Separate follow-up still open:** #153 (the far-town teleport-OUT arrival cascade) is a narrow far-teleport streaming edge case tracked on its own; it is NOT a #138 or M1.5 blocker and stays open for capture-harness-first work if it recurs. --- @@ -7468,7 +7591,7 @@ App 741+2skip / UI 425 / Net 385 green. --- -## #170 — Remote creature chase+attack renders wrong vs retail (glide, run not sustained) +## Historical closing summary for #170 — Remote creature chase+attack **Status:** DONE (2026-07-04, user visual gate passed — "as close to retail now as I can see"). Three-fix arc: `427332ac` deleted the per-frame @@ -8712,10 +8835,10 @@ The mechanism named as the suspect in #68 (`RemoteMoveToDriver`'s arrival handli --- -## #87 — Drop WB fork patch by switching to PrepareEnvCellGeomMeshDataAsync +## #227 — [DONE] Drop WB fork patch by switching to PrepareEnvCellGeomMeshDataAsync **Status:** DONE (2026-07-09, investigated this session). -Superseded by Phase O (2026-05-21, dropped the `WorldBuilder.Shared`/`Chorizite.OpenGLSDLBackend` project references entirely — there's no more forked submodule to patch/revert) and Phase A8 (2026-05-28, shipped `EnvCellRenderer.cs` which already calls the narrow `PrepareEnvCellGeomMeshDataAsync(geomId, environmentId, cellStructure, surfaces)` entry point at `EnvCellRenderer.cs:355`, using the bit-32-tagged synthetic geom id the issue proposed). `ObjectMeshManager.cs`'s bounds/type dispatch now branches on resolution type before calling `TryGet`, so the blind `TryGet` bug is structurally gone. `EnvCellRenderer` remains the live production cell-rendering path under Phase U as of commit `6aabe0b5` (Jul 6 2026). Note: a second, unrelated, already-DONE issue also uses the heading `## #87` elsewhere in this file (a pre-existing numbering collision, left untouched). +Superseded by Phase O (2026-05-21, dropped the `WorldBuilder.Shared`/`Chorizite.OpenGLSDLBackend` project references entirely — there's no more forked submodule to patch/revert) and Phase A8 (2026-05-28, shipped `EnvCellRenderer.cs` which already calls the narrow `PrepareEnvCellGeomMeshDataAsync(geomId, environmentId, cellStructure, surfaces)` entry point at `EnvCellRenderer.cs:355`, using the bit-32-tagged synthetic geom id the issue proposed). `ObjectMeshManager.cs`'s bounds/type dispatch now branches on resolution type before calling `TryGet`, so the blind `TryGet` bug is structurally gone. `EnvCellRenderer` remains the live production cell-rendering path under Phase U as of commit `6aabe0b5` (Jul 6 2026). This historical item was renumbered from a duplicate `#87` heading to `#227` during the 2026-07-20 documentation audit; the original indoor-cell issue retains #87. --- diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..c6a643d5 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,98 @@ +# acdream documentation map + +This page is the entry point for project documentation. It distinguishes +current sources of truth from implementation history so an old plan or issue +banner cannot silently override the current program state. + +## Current snapshot — 2026-07-20 + +- **Active milestone:** M3, “Cast a spell.” The automated implementation and + connected single-client magic/portal presentation gates are complete. +- **Next visual gates:** the R6 locomotion/collision/projectile/teleport retail + comparison, then the final two-client portal-out/materialization observer + comparison (`#218`). +- **Separate visual verification:** the shared-alpha lifestone/particle result + in `#225`; its connected resource-lifetime and performance routes pass. +- **Carried behavior debt:** `#153` (far teleport onto an unstreamed edge), + `#116` (two narrowed slide-response cases), and divergence rows TS-50/TS-51. +- **Deferred engineering tracks:** Modern Pipeline MP1b+ and Linux/headless + automation (Track LH). Neither is part of the active M3 gate. +- **Divergence audit:** 178 active rows — IA 17, AD 37, AP 85, TS 34, + and UN 5 — plus the retained retired TS-37 history note. +- **Latest automated baseline:** Release build succeeds with 17 known + test-project warnings (`#228`); 6,452 tests passed and 5 intentionally + skipped. The unattended connected R6 route + completed seven portal materializations, production input exercises, and a + graceful close. See + [`research/2026-07-20-connected-r6-soak.md`](research/2026-07-20-connected-r6-soak.md). + +## Sources of truth + +Read these in this order when deciding what to do next: + +1. [`plans/2026-05-12-milestones.md`](plans/2026-05-12-milestones.md) — the + active playable outcome, freeze boundaries, and visual gates. +2. [`plans/2026-04-11-roadmap.md`](plans/2026-04-11-roadmap.md) — strategic + phase ledger: shipped, active, deferred, and future work. +3. [`ISSUES.md`](ISSUES.md) — tactical defects and small follow-ups. The status + inside an issue is authoritative; physical order is not. +4. [`architecture/retail-divergence-register.md`](architecture/retail-divergence-register.md) + — every known place runtime behavior can differ from retail. +5. [`architecture/acdream-architecture.md`](architecture/acdream-architecture.md) + and [`architecture/code-structure.md`](architecture/code-structure.md) — + ownership, dependency, update-thread, and extraction rules. +6. [`architecture/worldbuilder-inventory.md`](architecture/worldbuilder-inventory.md) + — rendering/DAT code already owned in-tree versus mechanisms still ours to + port. + +If these disagree, milestones control the current outcome, the roadmap controls +work ordering, the issue status controls the individual defect, and the +architecture documents control implementation shape. Reconcile the stale +document in the same change; do not leave both claims standing. + +## Research and implementation records + +- [`research/named-retail/`](research/named-retail/) is the primary retail + oracle: named pseudo-C, headers, symbols, and types from the Sept 2013 build. +- [`research/decompiled/`](research/decompiled/) is the older Ghidra fallback. +- [`research/`](research/) contains focused pseudocode, traces, fixtures, and + gate reports. A dated research note records evidence; it does not become a + new roadmap. +- [`superpowers/specs/`](superpowers/specs/) and + [`superpowers/plans/`](superpowers/plans/) are per-slice design and execution + records. Completed plans remain historical. +- [`audit/`](audit/) contains completion and conformance audits. + +## Durable memory + +- [`../claude-memory/MEMORY.md`](../claude-memory/MEMORY.md) indexes the live + subsystem memories and the render/physics digests. Read a domain digest + before changing that subsystem, especially its DO-NOT-RETRY table. +- [`../memory/`](../memory/) contains stable engineering references such as the + modern rendering pipeline, two-tier streaming, and toolchain notes. + +Memory accelerates recall; it does not outrank the canonical documents above. +When current truth changes, update the relevant canonical document and distill +only the durable lesson into memory. + +## Historical and deprecated documents + +- [`bugs.md`](bugs.md) is the April 2026 bug snapshot. It is preserved for + archaeology and is not an active ledger. +- Dated plans and specs describe the decision at that time. Their completion + wording is historical unless the current milestone/roadmap explicitly links + the item as active. +- Old `R1→R8` architecture sequencing is superseded. Current execution comes + from the milestones and strategic roadmap. + +## Documentation maintenance rules + +- Update milestone, roadmap, issue, divergence, architecture, and memory claims + in the same commit when a shipped change affects them. +- Keep one issue ID per defect. Narrow an issue in place; do not reuse another + issue's number as a shorthand. +- Mark automated, connected, and visual gates separately. An automated pass is + not a visual acceptance, and an RDP throughput sample is not a local-display + visual comparison. +- Preserve research history, but remove stale “current/next” claims from living + documents once the state advances. diff --git a/docs/architecture/acdream-architecture.md b/docs/architecture/acdream-architecture.md index ef0610bc..58785815 100644 --- a/docs/architecture/acdream-architecture.md +++ b/docs/architecture/acdream-architecture.md @@ -13,6 +13,11 @@ A modern C# .NET 10 Asheron's Call client that: inheritance, interfaces, dependency injection) while matching retail behavior exactly +**Current program status is intentionally not duplicated in this architecture +document.** Start at [`../README.md`](../README.md), then use the milestone and +roadmap linked there. This file governs ownership and dependency shape even +when the active gameplay milestone changes. + ## Guiding Principle **The code is modern. The behavior is retail.** @@ -790,12 +795,15 @@ and `docs/superpowers/specs/`. Current movement/collision ownership: - **B.3** is shipped MVP history: first collision resolver foundation. -- **L.1** owns animation/motion parity, including root-motion coupling. -- **L.2** owns movement and collision conformance: +- **L.1/R6** own animation/motion parity and the complete retail object-frame + update order over canonical `LiveEntityRuntime` records. +- **L.2** owns the remaining movement and collision conformance: `docs/plans/2026-04-29-movement-collision-conformance.md`. -- **G.3** owns dungeon streaming and portal-space delivery after L.2e lands - trustworthy `cell_bsp`, `CELLARRAY`, adjacent-cell checks, and building - entry/exit boundaries. +- **G.3 is shipped**: dungeon streaming, portal-space presentation, collision, + lighting, doors, and the full round-trip gate landed. The separate far- + teleport unstreamed-edge residual is issue #153, not unfinished G.3. +- **M3** owns current connected magic/portal acceptance; Track LH is the future + presentation-independent Linux/headless extraction. The GameEntity / thin GameWindow refactor remains a valid target architecture, but it is not a prerequisite for L.2. Do not resurrect old R1-R8 phase numbers diff --git a/docs/architecture/code-structure.md b/docs/architecture/code-structure.md index eb6e0b8e..b6bd3835 100644 --- a/docs/architecture/code-structure.md +++ b/docs/architecture/code-structure.md @@ -4,7 +4,8 @@ "Code Structure Rules" section in `CLAUDE.md`. **Purpose:** Describe the desired structural state of the App layer, explain the rules we've adopted, and lay out the safe extraction -sequence from today's reality (one 15,288-line `GameWindow.cs`) to the +sequence from today's reality (one 14,557-line `GameWindow.cs` at the +2026-07-20 audit) to the target (thin `GameWindow`, small focused collaborators). **Companion to:** [`acdream-architecture.md`](acdream-architecture.md) (the layered architecture) and @@ -20,7 +21,7 @@ layer is wire-compatible, the UI has a stable contract, plugins load. The structural debt is concentrated in **one file**: ``` -src/AcDream.App/Rendering/GameWindow.cs 15,288 lines +src/AcDream.App/Rendering/GameWindow.cs 14,557 lines (2026-07-20) ``` `GameWindow` is the single object that: @@ -341,7 +342,7 @@ Each step is **one PR-sized refactor**. Each must build clean, all tests pass, and visual verification at Holtburg looks identical to the previous step. Don't bundle two steps. -### Step 1 — `RuntimeOptions` (this PR) +### Step 1 — `RuntimeOptions` — SHIPPED (`eda936dc`) **Scope:** Replace startup-time env var reads with a typed options object built once in `Program.cs`. @@ -357,7 +358,7 @@ new `tests/AcDream.App.Tests/` project). **Verification:** `dotnet build` + `dotnet test` green. Visual launch verifies live mode + dat dir resolution still work. -### Step 2 — `LiveSessionController` +### Step 2 — `LiveSessionController` — SHIPPED (`0b25df53`) **Scope:** Extract `TryStartLiveSession` + the WorldSession ownership + the post-EnterWorld drain (`OnLiveStateUpdated`, `OnLiveEntityDeleted`, diff --git a/docs/architecture/retail-divergence-register.md b/docs/architecture/retail-divergence-register.md index f3722f77..7ff19324 100644 --- a/docs/architecture/retail-divergence-register.md +++ b/docs/architecture/retail-divergence-register.md @@ -214,7 +214,7 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps. | AP-117 | Outdoor particle `CLandCell::IsInView` state is reconstructed with the modern landscape renderer's per-cell frustum plus active doorway clip-plane/scissor-AABB tests; retail `LScape::landcell_check` uses `Render::get_clip_height` + `Render::block_check` on terrain-cell corner intervals | `src/AcDream.App/Rendering/TerrainModernRenderer.cs` (`CollectVisibleCells`) | The mandatory modern renderer batches terrain by landblock and has no retail `ViewIntervalType` product. Publishing cell visibility from the exact landscape draw slices preserves ownership/order and removes the former object-survivor dependency without adding a second view pipeline | At a terrain cell grazing a frustum or doorway boundary, the conservative AABB test may freeze or resume particles on a slightly different frame than retail; whole regions outside the active doorway slice are rejected, and authored distance, login/portal fail-closed behavior, and indoor PView cells remain exact | `LScape::landcell_check @ 0x005050A0`; `CLandCell::IsInView @ 0x00532CB0`; `CPhysicsObj::ShouldDrawParticles @ 0x0050FE60` | | AP-118 | An AutoWield transaction begun in active combat preserves the ready mode implied by the requested weapon. After authoritative `WieldObject`, a mode that settled without a blocker transition clears immediately; local ACE's observed pre-wield transition plus `ready -> NonCombat`, or post-wield `NonCombat -> ready -> NonCombat`, causes one normal `ChangeCombatMode` request from the trailing notice. Explicit user combat input cancels settlement. Retail's client does not need this extra request against the retail server. | `src/AcDream.App/UI/AutoWieldController.cs`; production binding in `GameWindow.cs` | Local ACE queues a trailing NonCombat callback during primary-weapon replacement and rejects an earlier request while the shuffle is busy; responding to the authoritative notice that completes that exact sequence orders the ordinary request after it without suppressing any server state | A non-ACE server that emits a different intermediate sequence can retain the settlement until a later explicit combat request, replacement, or logout clears it; peace-mode equips send none | `CPlayerSystem::AutoWield @ 0x00560A60`; `ACCWeenieObject::ServerSaysMoveItem @ 0x0058DBB0`; ACE `Player_Inventory.TryShuffleStance` / `TryDequipObjectWithNetworking` | -## 4. Temporary stopgap (TS) — 34 active rows (TS-20 retired 2026-07-16 — the later named-retail audit disproved the proposed DrawingBSP polygon filter; TS-37 is a retired-row historical note, not an active count; TS-39 retired R5-V3 — sticky seams bound to the ported PositionManager/StickyManager, radii threaded; TS-45 retired 2026-07-07 — hand-rolled `SphereCollision` replaced by the faithful CSphere family port, fixing the player-vs-monster crowd wedge; TS-3 retired 2026-07-07 — `frames_stationary_fall` accounting ported in the #182 verbatim UpdateObjectInternal rebuild, fixing the airborne falling-animation wedge; TS-41 retired 2026-07-07 — SERVERVEL synth-velocity remote body-drive replaced by the retail interp catch-up + unconditional MovementManager::UseTime, the remote-creature de-overlap #184; TS-42 retired 2026-07-19 — semantic animation completion now precedes the ordered Target/Movement/PartArray/Position tail; TS-44 narrowed again 2026-07-19 — complete orientation joined interpolation, only during-stick enqueue suppression remains) +## 4. Temporary stopgap (TS) — 34 active rows + TS-37 historical note (TS-20 retired 2026-07-16 — the later named-retail audit disproved the proposed DrawingBSP polygon filter; TS-37 is a retired-row historical note, not an active count; TS-39 retired R5-V3 — sticky seams bound to the ported PositionManager/StickyManager, radii threaded; TS-45 retired 2026-07-07 — hand-rolled `SphereCollision` replaced by the faithful CSphere family port, fixing the player-vs-monster crowd wedge; TS-3 retired 2026-07-07 — `frames_stationary_fall` accounting ported in the #182 verbatim UpdateObjectInternal rebuild, fixing the airborne falling-animation wedge; TS-41 retired 2026-07-07 — SERVERVEL synth-velocity remote body-drive replaced by the retail interp catch-up + unconditional MovementManager::UseTime, the remote-creature de-overlap #184; TS-42 retired 2026-07-19 — semantic animation completion now precedes the ordered Target/Movement/PartArray/Position tail; TS-44 narrowed again 2026-07-19 — complete orientation joined interpolation, only during-stick enqueue suppression remains) | # | Divergence | Where (file:line) | Why it is safe / justified | Risk if assumption breaks | Retail oracle | |---|---|---|---|---|---| @@ -255,6 +255,7 @@ AP-94..AP-112 for the confirmed retail-UI completion gaps. | TS-49 | Hidden-object availability is bridged through `TargetManager.NotifyVoyeurOfEventAndClear(ExitWorld)` because acdream has not ported retail's DetectionManager. Retail `CObjCell::hide_object` sends `LeftDetection` to detection voyeurs; acdream instead uses the existing non-Ok target update to tear down MoveTo/Sticky consumers and clear watched-role subscriptions while preserving the hidden object's own watcher role. | `src/AcDream.App/Rendering/EntityPhysicsHost.cs` (`NotifyHidden`); `src/AcDream.Core/Physics/Motion/TargetManager.cs` (`NotifyVoyeurOfEventAndClear`) | The current movement consumers already share TargetManager's status fan-out; the bridge prevents pursuit of an unavailable object without inventing a second partial detection database. | Plugins or future systems listening specifically for retail detection enter/leave events receive no `LeftDetection`; only movement/sticky target consumers observe the equivalent availability loss. | `CObjCell::hide_object @ 0x0052BE30`; retire by porting DetectionManager/CObjCell detection-voyeur delivery and routing Hidden through `LeftDetection` | | TS-50 | `AnimationDone` executes semantically at each owner's retail `CPhysicsObj::process_hooks` boundary, but all other animation hooks are retained in `AnimationHookFrameQueue` until final root/part/equipped-child pose publication. Retail executes the complete hook stream before transition and the Target/Movement/PartArray/Position manager tail because its current CPartArray pose already exists in-place. Static owners correctly reach `process_hooks` only after their root, parts, and children are current. | `src/AcDream.App/Rendering/Vfx/AnimationHookFrameQueue.cs`; `src/AcDream.App/Rendering/RetailStaticAnimatingObjectScheduler.cs`; frame drain in `src/AcDream.App/Rendering/GameWindow.cs` | The modern renderer publishes immutable effect-pose snapshots after all root/child composition; deferred visual sinks avoid attaching particles/lights/audio to the previous pose. Semantic `AnimationDone` is split out and exact, so motion completion and manager behavior are not delayed. Pose-owner lifetime tokens prevent deferred hooks from crossing delete/local-ID reuse. | A non-AnimationDone hook with same-quantum semantic consequences (notably `CallPES`, default-script chaining, audio/particle creation relative to a transition) runs later than retail and can observe post-tail state or start one render frame late. | `CPhysicsObj::process_hooks @ 0x00511550`; `CPhysicsObj::UpdatePositionInternal @ 0x00512C30`; `CPhysicsObj::animate_static_object @ 0x00513DF0`; retire by publishing the current per-object/child pose before hook routing or splitting semantic and presentation sinks without changing authored hook order | | TS-51 | Particle and PhysicsScript tails advance once per render frame after the complete ordinary/static object worksets. Retail advances each object's ParticleManager and ScriptManager inside every admitted `UpdateObjectInternal` quantum; `animate_static_object` also advances that static owner's managers using its whole admitted elapsed interval. | `src/AcDream.App/Rendering/GameWindow.cs` (`AdvanceLiveObjectRuntime` final `_particleSystem.Tick(dt)` / `_scriptRunner.Tick(...)`) | The current managers are shared presentation/runtime owners rather than per-object manager instances. R6 makes root motion, animation, object clocks, workset membership, and manager order faithful without pretending the shared tails have per-owner timing. Splitting ownership safely requires a later effect-lifetime slice. | A render fragment below retail's minimum object quantum can advance an effect while its owner waits; a catch-up frame advances an owner's root through several quanta but its effect tail only once; static default scripts/particles use render elapsed rather than `animate_static_object` elapsed/discard timing. | `CPhysicsObj::UpdateObjectInternal @ 0x005156B0`; `CPhysicsObj::animate_static_object @ 0x00513DF0`; retire by giving live/static owners incarnation-bound particle/script managers and ticking each manager in the owning object quantum | +| TS-52 | The terrain shader applies retail-authored base/overlay/road `TerrainTex.TexTiling` but omits the separate Environment Detail Textures pass and its viewer-distance fade (**#226**). | `src/AcDream.App/Rendering/TerrainAtlas.cs`; `src/AcDream.App/Rendering/TerrainModernRenderer.cs`; `src/AcDream.App/Rendering/Shaders/terrain_modern.frag` | `bb5acab9` fixed the user-visible stretched/blurry regression by porting the distinct base-tiling contract. An earlier experimental detail array darkened the whole ground because its source/neutral blend contract was wrong, so it was correctly reverted rather than guessed into production. | With retail's Environment Detail Textures preference enabled, close terrain lacks the extra high-frequency modulation/fade even though authored base texture scale is correct. | `LScape::GenerateDetailSurfaces` / `SetDetailTexturing @ 0x00506B40`; `ACRender::landPolyDraw @ 0x006B6450..0x006B6525`; issue #226 | --- diff --git a/docs/bugs.md b/docs/bugs.md index 711b3880..518eced7 100644 --- a/docs/bugs.md +++ b/docs/bugs.md @@ -1,11 +1,18 @@ -# acdream — known bugs +# acdream — historical bug snapshot (deprecated) -Track visual, gameplay, and protocol bugs here. Close by moving to -the "Fixed" section with the commit hash that resolved it. +> **Not an active issue tracker.** This file preserves the 2026-04-14 snapshot +> for archaeology. Several “open” entries below were superseded, narrowed, or +> fixed by later collision/rendering work. Do not update status here and do not +> use these BUG numbers for new work. The canonical tactical ledger is +> [`ISSUES.md`](ISSUES.md); current program navigation is in +> [`README.md`](README.md). + +The text below is intentionally retained as historical evidence of what was +believed at the time. --- -## Open +## Historical open snapshot (not current) ### BUG-001: Wrong cloth textures on characters - **Observed:** 2026-04-13 @@ -53,7 +60,7 @@ the "Fixed" section with the commit hash that resolved it. --- -## Fixed +## Historical fixed snapshot ### BUG-002: Jump not visible from retail client - **Fixed:** 5634e71 — Jump packet (opcode 0xF61B) now sent to server. diff --git a/docs/plans/2026-04-11-roadmap.md b/docs/plans/2026-04-11-roadmap.md index f7ddaa22..9a95b345 100644 --- a/docs/plans/2026-04-11-roadmap.md +++ b/docs/plans/2026-04-11-roadmap.md @@ -1,6 +1,6 @@ # acdream — strategic roadmap -**Status:** Living document. Updated 2026-07-20. **M3 active; automated implementation complete, visual gates pending.** M2's connected demo loop is complete. M3 now has the retail cast-intent/component/target lifecycle, exact live enchantment wire state, scoped Magic input, retained spell bar, spellbook, component book, positive/negative effects panels with authored rows and selected-spell details, the complete seven-control gameplay indicator strip and its Character Information/Link/Vitae detail pages, and shared `gmPanelUI` geometry/switching over the Step 9 projectile/PhysicsScript/particle/portal foundation. The remaining M3 work is the connected single-client magic-UI/casting gate and final two-client portal-out/materialization observer gate. +**Status:** Living document. Updated 2026-07-20. **M3 active; automated implementation and connected single-client magic/portal gates complete.** M2's connected demo loop is complete. M3 now has the retail cast-intent/component/target lifecycle, exact live enchantment wire state, scoped Magic input, retained spell bar, spellbook, component book, positive/negative effects panels with authored rows and selected-spell details, the complete seven-control gameplay indicator strip and its Character Information/Link/Vitae detail pages, and shared `gmPanelUI` geometry/switching over the Step 9 projectile/PhysicsScript/particle/portal foundation. The next gate is a local visual rebaseline of the new R6 object-frame path; the final M3 requirement is the two-client portal-out/materialization observer gate. Issue #225's lifestone/particle alpha comparison is a separate rendering visual gate. **Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file. --- @@ -30,9 +30,13 @@ active enchantment, then recall through the DAT-driven portal presentation. Connected-gate correction now also pins type-12 spellbook tabs, retail zero text margins, and `PassToChildren` Closed/Open chrome through real-DAT fixtures. -3. **Pending user visual gate:** connected projectile/self-buff casts plus the - complete retained magic UI interaction checklist. -4. **Pending user visual gate:** two-client portal-out/materialization observer +3. **Done (connected user gates):** projectile/self-buff casts, protection + effects, spellbook/component-book filtering and deletion, favorite spell + bar interaction, recall, portal-space presentation, and retained indicator + pages. +4. **Pending local visual gate:** locomotion, collision, projectile, and + teleport comparison after the R6 complete-root-Frame/object-workset cutover. +5. **Pending two-client visual gate:** portal-out/materialization observer presentation before M3 closes, including #218's finished Hidden silhouette, fully rendered destination reveal, and no indoor stop-time position snap. @@ -43,10 +47,10 @@ the active slice only when they block this demo or represent a severe regression ## Historical program: Phase W — Unified Cell Graph (UCG) -**[SUPERSEDED — G.3 dungeon work shipped; M1.5 next step = #138 round-trip -gate + #145-residual. See the shipped table + `docs/plans/2026-05-12-milestones.md` -M1.5 section for current status. This section's W1/W2a history below is kept -for record.]** +**[SUPERSEDED — G.3 shipped and M1.5 landed after the #138 round-trip gate. +Issue #153 is a separate far-teleport edge residual. See the shipped table + +`docs/plans/2026-05-12-milestones.md` M1.5 section for current status. This +section's W1/W2a history below is kept for record.]** **Pivot (2026-06-02).** The render-pipeline reset stalled because the indoor "world from below" is a cell-**membership** disagreement between the render-side `CellVisibility` and @@ -606,7 +610,7 @@ Research: R9 + R12 + R13. - **✓ SHIPPED — G.1 — Sky + weather + day-night.** Deterministic client-side from Portal Year time. Sky dome geometry + keyframe gradients + rain/snow particles. See `r12-weather-daynight.md`. Full data + visual stack shipped: Region dat loader, keyframe interp, WeatherSystem with 5-kind PDF + transitions + storm flashes, WorldSession→WorldTimeService sync via ConnectRequest+TimeSync, SkyRenderer with sky-object arcs + UV scroll, rain/snow billboard renderer, F7/F10 debug cycle keys. - **✓ SHIPPED — G.2 — Dynamic lighting.** 8-light D3D-style fixed pipeline. Hard-cutoff at Range, no attenuation inside. Cell ambient. Shader UBO per frame. See `r13-dynamic-lighting.md`. SceneLightingUbo std140 at binding=1 feeds terrain + mesh + mesh_instanced + sky shaders. LightingHookSink auto-registers Setup.Lights at entity stream-in, flips IsLit on SetLightHook, unregisters on landblock unload. - **Indoor portal-based cell tracking (follow-up to Indoor walking Phase 1 / issue #87).** Replace `PhysicsDataCache.TryFindContainingCell` AABB containment with retail's `CObjMaint::HandleObjectEnterCell` portal traversal. When the player crosses a cell portal boundary, `CellId` propagates through the `CEnvCell` portal connectivity graph. Prerequisite for wall collision from outside (#85) and the remaining #84 threshold symptom. PDB symbols and `acclient.h` `CCellStructure` refs are in place (see #87). **Unblocks G.3.** -- **✓ SHIPPED — G.3 — Dungeon streaming + portal space.** `EnvCellStreamer`, portal-visibility BFS, `PlayerTeleport (0xF751)` handling with post-transition `LoginComplete`, and the retail DAT-authored portal-space CreatureMode viewport (Setup `0x02000306`, animation `0x030005AC`, exact camera/light/timing/view-plane transitions, forward-axis roll, direct portal→world viewport switch, projection warp, destination viewer reset, object/physics-before-network frame barrier, pre-network input movement/jump output, post-inbound AutonomousPosition, non-advancing spatial reconciliation, and retail `set_hidden` PartArray timeline teardown on both Hidden and UnHide; `/ls` and spell-recall corrective visual gates passed 2026-07-16, with non-blocking visual polish deferred). Dungeons render, stream, teleport-in, collide, light, and their doors work — see the shipped-table rows (G.3, G.3a, #137 collision, A7.L1 lighting) below and the M1.5 section of `docs/plans/2026-05-12-milestones.md` for current gate status (one recorded end-to-end dungeon round-trip user gate outstanding; live residual = far-town teleport-OUT arrival cascade, #145-residual REOPENED). See `r09-dungeon-portal-space.md` and `docs/research/2026-07-15-retail-portal-space-pseudocode.md`. +- **✓ SHIPPED — G.3 — Dungeon streaming + portal space.** `EnvCellStreamer`, portal-visibility BFS, `PlayerTeleport (0xF751)` handling with post-transition `LoginComplete`, and the retail DAT-authored portal-space CreatureMode viewport (Setup `0x02000306`, animation `0x030005AC`, exact camera/light/timing/view-plane transitions, forward-axis roll, direct portal→world viewport switch, projection warp, destination viewer reset, object/physics-before-network frame barrier, pre-network input movement/jump output, post-inbound AutonomousPosition, non-advancing spatial reconciliation, and retail `set_hidden` PartArray timeline teardown on both Hidden and UnHide; `/ls` and spell-recall corrective visual gates passed 2026-07-16, with non-blocking visual polish deferred). Dungeons render, stream, teleport, collide, light, and their doors work; the final end-to-end dungeon round-trip gate passed 2026-07-10. See the shipped-table rows (G.3, G.3a, #137 collision, A7.L1 lighting) and the M1.5 section of `docs/plans/2026-05-12-milestones.md`. The far-town unstreamed-edge arrival residual is tracked separately as #153. See `r09-dungeon-portal-space.md` and `docs/research/2026-07-15-retail-portal-space-pseudocode.md`. **Acceptance:** walk outside at dusk, see the sky gradient + sun moving; enter a torch-lit dungeon via portal; leave back to daylight. @@ -647,7 +651,7 @@ the way retail + holtburger expect. - Attacking a creature produces "You hit Drudge for 12 slashing damage (87%)" lines in chat. - Accented character names round-trip through the wire correctly (CP1252). -**Memory crib:** `memory/project_chat_pipeline.md`. +**Memory crib:** `claude-memory/project_chat_pipeline.md`. --- @@ -704,7 +708,7 @@ with retail's MMB-hold mouse-look. dormant — light up in Phase L when `CombatState.CurrentMode` is wired (issue #L.3). -**Memory crib:** `memory/project_input_pipeline.md`. +**Memory crib:** `claude-memory/project_input_pipeline.md`. --- @@ -915,8 +919,9 @@ diagnostic scaffolding, not yet the final collision system. InterpolationManager into the owned PositionManager facade remains the final R6 ownership cleanup. Final 2026-07-20 gate: three independent retail/architecture/adversarial - re-reviews are clean; Release build is warning-free; the repository suite is - 6,452 passed / 5 skipped. The unattended connected Release rebaseline also + re-reviews are clean; Release builds successfully with 17 known test-project + warnings tracked by #228; the repository suite is 6,452 passed / 5 skipped. + The unattended connected Release rebaseline also passes: seven portal materializations across Caul, Sawato, Rynthid, Aerlinthe, Holtburg, and same-location revisits; production-dispatcher turn, forward, charged-jump, and combat inputs; outbound movement evidence; @@ -1441,8 +1446,8 @@ OpenGL ceiling; revisit macOS only if a supported graphics backend is chosen. ## Cross-cutting work tracked in parallel -- **Test coverage.** Each phase lands with unit + integration tests in `tests/`. Current count: 98 Core + 96 Core.Net = 194. Keep the ratio as new phases land. -- **Memory files.** Project state under `memory/project_phase_*_state.md` is updated when a phase ships. `MEMORY.md` is the index. +- **Test coverage.** Each phase lands with layer-matched unit and integration tests in `tests/`. Current Release baseline: 6,452 passed / 5 intentional skips (2026-07-20). +- **Memory files.** Live subsystem state and digests are indexed by `claude-memory/MEMORY.md`; stable engineering references remain under `memory/`. Canonical program status stays in milestones/roadmap/issues. - **`CLAUDE.md` discipline.** Check all four references (ACE, ACViewer, WorldBuilder, Chorizite) before committing to an approach. WorldBuilder is the closest stack match and should be checked first. --- @@ -1470,8 +1475,8 @@ OpenGL ceiling; revisit macOS only if a supported graphics backend is chosen. | Character clothing missing / wrong | **5 FIXED** ✓ | | Statue wrong color / wrong scale | **5 FIXED** ✓ | | Holtburg sign half-buried | **5 FIXED** ✓ | -| Can't walk past the loaded 3×3 window | **A.1 FIXED** ✓ (5×5 default, `ACDREAM_STREAM_RADIUS` to tune) | -| Frame hitch crossing landblock boundary | **Phase A.3** (synchronous loader for now; async returns when DatCollection is thread-safe) | +| Can't walk past the loaded 3×3 window | **A.1/A.5 FIXED** ✓ (two-tier streaming, near 4 / far 12 by default; legacy override remains) | +| Frame hitch crossing landblock boundary | **A.3/A.5 async streaming SHIPPED**; residual content-load hitches are measured under Modern Pipeline MP1c | | Walking around doesn't move me on the server | **Phase B.2/B.3 FIXED** ✓ for coarse server movement; fine retail collision parity is **Phase L.2** | | Packet loss / out-of-order UDP causes stale or missing world updates | **Phase M.3** | | Server asks for retransmit and client doesn't resend cached packets | **Phase M.3** | @@ -1482,22 +1487,22 @@ OpenGL ceiling; revisit macOS only if a supported graphics backend is chosen. | Sliding along buildings / walls feels wrong | **Phase L.2c + L.2d** | | Roof edge / cliff / precipice blocks or slides wrong | **Phase L.2c** | | Crossing outdoor cell seams reports the wrong cell | **Phase L.2e** | -| Can't talk to NPCs | **Phase H.3** (emote scripts + dialogs) | -| Can't open a door | **Phase F** (object-use action) | -| Portals render as a rotating black disk | **Phase E.3** (particle system) | -| Chimneys have no smoke | **Phase E.3** | -| Houses have no fireplace fire | **Phase E.3** | +| Can't talk to NPCs | Basic select/use/give interaction works; full emote conversation/dialog systems remain **Phase H.3** | +| Can't open a door | **FIXED** ✓ — object-use, animation, fading hooks, and collision transitions shipped | +| Portals render as a rotating black disk | **FIXED** ✓ — DAT particles/effects and portal-space presentation shipped | +| Chimneys have no smoke | **Phase E.3 SHIPPED** ✓ | +| Houses have no fireplace fire | **Phase E.3/G.2 SHIPPED** ✓ | | No fireplace / torch lighting | **Phase G.2** (shipped; Setup.Lights auto-register, 8-light cap with hard-cutoff) | | Skin/hair color slightly off | **Phase C.3** | | No chat window | **Phase H.1 / I.1-I.7 FIXED** ✓ | | Chat? You can finally type and send messages | **I.4 FIXED** ✓ (shipped 2026-04-25) | | Combat doesn't show in the chat log | **I.7 FIXED** ✓ | | Accented character names show as `?` or garbled | **I.5 FIXED** ✓ (Windows-1252 codec) | -| No sound | **Phase E.2** | -| Dungeons / foundry interior missing | **Phase G.3 — SHIPPED** (render/stream/teleport-in/collide/light/doors all closed; M1.5 next step = #138 round-trip gate + #145-residual) | -| Can't fight monsters | **Phase F.3** (combat math + damage) | -| Can't cast spells | **Phase F.4** | -| No inventory panel | **Phase F.2 + F.5** | +| No sound | **Phase E.2 SHIPPED** ✓ (remaining unsupported codecs are TS-9) | +| Dungeons / foundry interior missing | **Phase G.3 — SHIPPED + M1.5 gate passed 2026-07-10** (render/stream/teleport/collision/light/doors closed; separate far-teleport edge residual = #153) | +| Can't fight monsters | **M2 LANDED 2026-07-15** ✓ — melee/missile, death, loot, inventory loop user-gated | +| Can't cast spells | **M3 connected single-client casting/effects gate passed** ✓; final two-client portal observer gate remains | +| No inventory panel | **D.5 / M2 SHIPPED + user-gated** ✓ — bags, stacks, paperdoll, equipment, drag/drop, loot | | No character creation — must use ACE admin | **Phase H.4** | | Sky is a flat color | **Phase G.1** (shipped; F7 cycles time, F10 cycles weather) | | Can't join allegiance | **Phase H.2** | diff --git a/docs/plans/2026-05-12-milestones.md b/docs/plans/2026-05-12-milestones.md index 221a7926..39b0e3cf 100644 --- a/docs/plans/2026-05-12-milestones.md +++ b/docs/plans/2026-05-12-milestones.md @@ -15,11 +15,14 @@ new R6 object-update cutover has passed its unattended connected input/portal/ performance rebaseline; its locomotion/collision/projectile/teleport visual gate remains for the next local viewing session before that observer gate. Carried: -#145-residual, #116 slide-response, the remaining R6 ownership cleanup plus +#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus registered TS-50/TS-51 timing residuals (the complete-root-Frame/object-workset cutover is automated-test complete 2026-07-20; three independent re-reviews are -clean, Release builds with zero warnings, and 6,452 tests pass / 5 skip), and -Track MP0. +clean, Release builds with 17 known test-project warnings tracked by #228, and +6,452 tests pass / 5 skip), and +the deferred Modern Pipeline track (MP1b+). The separate #225 shared-alpha +implementation has passed connected lifetime/performance gates and awaits only +its lifestone/particle visual comparison. --- @@ -219,7 +222,7 @@ lighting (#79/#93/#80). The indoor-physics workarounds (#90 stickiness + `TryFindIndoorWalkablePlane` synthesis) were removed by A6.P4 — no duct-tape left. **Explicit caveats carried forward (NOT M1.5 blockers — tracked as their own follow-ups):** the far-town teleport-OUT arrival cascade -(#145-residual, REOPENED — a narrow far-teleport streaming edge case, +(#153, REOPENED — a narrow far-teleport streaming edge case, capture-harness-first) and #116 slide-response feel-debt. Next: **M2 — "Kill a drudge."** @@ -238,10 +241,10 @@ multi-landblock dungeon LOD + `PlayerTeleport` handling), and it has since blowup (RESOLVED), dungeon doors (#187/#188), and A7 dungeon lighting (#79/#93/#80/#154, all CLOSED). M1.5's dungeon-demo scenario (enter via portal, navigate 3-5 rooms, walls block, smooth transitions) is -functionally met; M1.5 now awaits ONE recorded end-to-end dungeon -round-trip user gate. The sole remaining live-code residual is the -far-town teleport-OUT arrival cascade (**#145-residual, REOPENED** — see -below). +functionally met. The final end-to-end dungeon round-trip gate passed on +2026-07-10 and landed M1.5. The separate live-code residual is the far-town +teleport-OUT arrival cascade (**#153, REOPENED** — see below); it is not a +dungeon-round-trip blocker. **Building/cellar demo — DONE + user-gated.** The indoor world reads as solid. Across the @@ -311,10 +314,9 @@ shipped: teleport-into-dungeon (G.3a hold-until-hydrate FSM, #137 (`0efa7ed2`); the #95 portal-graph visibility blowup RESOLVED (9.1M→~39k instances, `a40c38e8`); dungeon doors shipped (#187 `e2e285b8`, #188 `3284dd0a`); A7 dungeon lighting closed -(#79/#93/#80/#154, `44cced71`/`d275ed55`/`9ebb2060`). Remaining: one -recorded end-to-end dungeon round-trip user gate, plus the far-town -teleport-OUT arrival cascade residual (**#145-residual, REOPENED** — -capture-harness-first). +(#79/#93/#80/#154, `44cced71`/`d275ed55`/`9ebb2060`). The recorded end-to-end +dungeon round-trip passed on 2026-07-10. The far-town teleport-OUT arrival +cascade residual remains separate (**#153, REOPENED** — capture-harness-first). **2026-07-15 portal presentation completion (single-client visual gate passed 2026-07-16; non-blocking polish deferred).** The @@ -482,7 +484,7 @@ the A6 physics/membership family + A6.P4 per-cell shadow architecture, A7 indoor/dungeon lighting, and **full Phase G.3 dungeon support** (streaming collapse/expand, teleport in/out, dungeon collision/lighting/doors). No rework until M7 polish. Exempt from the freeze as still-open bugs (rule 2's -"actively broken" clause): #145-residual (far-town teleport-OUT cascade) and +"actively broken" clause): #153 (far-town teleport-OUT cascade) and #116 (slide-response) — these are tracked follow-ups, not frozen work. **Estimated timeline:** 3–5 weeks calendar (17–26 days focused work). Bigger