diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 87c7b2d..464590f 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -46,6 +46,50 @@ Copy this block when adding a new issue: # Active issues +## #50 — Road-edge tree at 0xA9B1 visible in acdream but not retail + +**Status:** OPEN +**Severity:** LOW (cosmetic; one spawned tree near the road in Holtburg) +**Filed:** 2026-05-08 +**Component:** scenery placement / Phase N (WorldBuilder rendering migration) + +**Description:** With `ACDREAM_USE_WB_SCENERY=1` (default since commit `b84ecbd`), +a tree at landblock 0xA9B1 around `(lx=85.08, ly=190.97)` appears in acdream but +neither retail nor ACME WorldBuilder render it. Upstream Chorizite/WorldBuilder +DOES render it, so our migration to WB's helpers (Phase N.1) inherited this +discrepancy from upstream. + +**Root cause (suspected):** ACME WorldBuilder includes a per-vertex road check that +skips the entire vertex when its road bit is set (see +`references/WorldBuilder-ACME-Edition/WorldBuilder/Editors/Landscape/GameScene.cs:1074`). +The current vertex (4,8) has a road bit set in the dat. ACME skips it; +Chorizite/WorldBuilder doesn't; we don't. + +**Fix attempt that didn't work:** commit `e279c46` added the per-vertex road check +directly to our `GenerateViaWb` (and legacy `Generate` for parity). It successfully +removed the offending tree but over-suppressed scenery in other landblocks (visual +regressions during user testing). Reverted in commit `677a726`. ACME's check likely +interacts with other factors (per-vertex building check, or something else in ACME's +pipeline) that we'd need to port together, not the road check alone. + +**Next steps:** +1. Investigate ACME's full per-vertex filter set (road + building + anything else) + and port them as a coherent unit, not piecemeal. +2. OR upstream the per-vertex road check to Chorizite/WorldBuilder (which is now our + submodule fork) so it lands as a generic ACME-conformance improvement. +3. OR consider switching fork target from Chorizite/WorldBuilder to ACME WorldBuilder + for future phases (N.2+). + +Visually undetectable to most users; one extra tree at one landblock. Defer until +other Phase N work catches a similar issue and a coherent fix becomes obvious. + +**Files:** +- `src/AcDream.Core/World/SceneryGenerator.cs` — `GenerateInternal` is the active path +- `src/AcDream.Core/World/WbSceneryAdapter.cs` — adapter used by `GenerateInternal` +- `references/WorldBuilder-ACME-Edition/WorldBuilder/Editors/Landscape/GameScene.cs:1074` — ACME's per-vertex road filter + +--- + ## #49 — Scenery (X, Y) placement drifts from retail at some landblocks **Status:** OPEN diff --git a/docs/plans/2026-04-11-roadmap.md b/docs/plans/2026-04-11-roadmap.md index 9e66f68..6ccac3e 100644 --- a/docs/plans/2026-04-11-roadmap.md +++ b/docs/plans/2026-04-11-roadmap.md @@ -57,6 +57,7 @@ | K | Input architecture — `Action` enum, `KeyChord`, `KeyBindings`, multicast `InputDispatcher` with scope-stack + modal capture, retail-default keymap (152 bindings), `keybinds.json` persistence, F11 Settings panel with click-to-rebind + conflict detection, main menu bar + View menu | Live ✓ | | L.0 | Full retail-style Settings interface — F11 tabbed panel with 6 tabs (Keybinds + Display + Audio + Gameplay + Chat + Character). `settings.json` at `%LOCALAPPDATA%\acdream\`, per-toon `Character` keying (swapped on EnterWorld). Display GL knobs (Resolution / Fullscreen / VSync / FOV / ShowFps) + Audio (Master / SFX) live-wired; Gameplay / Chat / Character settings persist for server-sync wiring later. Tab API extension to `IPanelRenderer`; chat Copy mode (read-only multi-line); per-panel layout reset; FramebufferResize handler keeps GL viewport + camera aspect + panel positions in sync. | Live ✓ | | C.1 | PES particle system + sky-pass refinements — retail-faithful `ParticleEmitterInfo` unpack with all 13 motion integrators (`Particle::Init`/`Update` ports of `0x0051c290`/`0x0051c930`), `PhysicsScriptRunner` with `CallPES` self-loop semantics, `ParticleHookSink` with `EmitterDied` cleanup, instanced billboard `ParticleRenderer` with material-derived blend (DAT emitters never default additive — pulled from particle GfxObj surface), global back-to-front sort, BC clipmap alpha-keying, AttachLocal `is_parent_local=1` live-parent follow via `UpdateEmitterAnchor`. Sky pass: `Translucent+ClipMap` → alpha-blend cloud sheet (matches `D3DPolyRender::SetSurface` `0x0059c4d0`), raw-`Additive` fog-skip (matches `0x0059c882`), per-keyframe `SkyObjectReplace` Translucency/Luminosity/MaxBright divide-by-100, bit `0x01` pre/post-scene split (matches `GameSky::CreateDeletePhysicsObjects` `0x005073c0`), Setup-backed (`0x020xxxxx`) sky objects via `SetupMesh.Flatten`, persistent GL sampler objects (Wrap + ClampToEdge) replace per-frame wrap-mode mutation (ported from WorldBuilder's `OpenGLGraphicsDevice`), post-scene Z-offset gated on `(Properties & 4) != 0 && (Properties & 8) == 0` per `GameSky::UpdatePosition` `0x00506dd0`. Sky-PES playback disabled by default (named-retail proves `GameSky` drops `pes_id`); `ACDREAM_ENABLE_SKY_PES=1` opens the experimental path. 1325 → 1331 tests. | Live ✓ | +| N.1 | WorldBuilder-backed scenery (Chorizite/WorldBuilder fork as submodule, SceneryHelpers + TerrainUtils replace our inline ports) | Live ✓ | Plus polish that doesn't get its own phase number: - FlyCamera default speed lowered + Shift-to-boost @@ -532,12 +533,16 @@ for our deletions/additions; merge upstream `master` periodically. **Sub-phases (strangler-fig with feature flags):** - **N.0 — Setup.** Submodule + project references + build green. ~1-2 hrs. -- **N.1 — Scenery algorithm calls.** Replace `IsOnRoad` / - `DisplaceObject` / slope-normal calc / rotation / scale inside - `SceneryGenerator.Generate()` with calls to WB's `SceneryHelpers` + - `TerrainUtils`. Tiny adapter `LandBlock → TerrainEntry[]`. Keeps our - data flow + `ScenerySpawn` shape. Feature flag - `ACDREAM_USE_WB_SCENERY=1`. ~1-2 days. +- **✓ SHIPPED — N.1 — Scenery algorithm calls.** Shipped 2026-05-08. + Replaced `IsOnRoad` / `DisplaceObject` / slope-normal calc / rotation / + scale inside `SceneryGenerator.Generate()` with calls to WB's + `SceneryHelpers` + `TerrainUtils`. Adapter `WbSceneryAdapter` produces + `TerrainEntry[]`. Visual verification at Holtburg confirmed Issue #49's + previously missing edge-vertex trees still visible after the migration; + rotation bug fixed (our retail port's `yawDeg = -(450-degrees)%360` + formula was ~180° off from retail's actual `Frame::set_heading` atan2 + round-trip). One known cosmetic difference filed in ISSUES.md + (road-edge tree at landblock 0xA9B1). - **N.2 — Terrain math helpers.** Refactor `TerrainSurface.SampleZ` / `SampleNormal` / `SampleSurface` to call WB's `TerrainUtils.GetHeight` / `GetNormal` internally. ~1-2 days.