Add a canonical documentation map, modernize the public README, and align milestone, roadmap, architecture, issue, divergence, and session guidance with the July 20 baseline. Correct the far-teleport residual to issue #153, close visually accepted indicator and terrain-tiling work, record the remaining detail-overlay and build-warning debt, and deprecate the duplicate legacy bug ledger. Co-authored-by: OpenAI Codex <codex@openai.com>
936 lines
55 KiB
Markdown
936 lines
55 KiB
Markdown
# acdream — milestones (morale + scope layer)
|
||
|
||
**Status:** Living document. Created 2026-05-12.
|
||
**Sits above:** [`docs/plans/2026-04-11-roadmap.md`](2026-04-11-roadmap.md) (the strategic phase index).
|
||
**Currently working toward:** **M3 — "Cast a spell." M2 — "Kill a drudge"
|
||
LANDED 2026-07-15.** The complete connected melee/missile, death/loot,
|
||
inventory, and item-giving demo is user-gated. The shared projectile/effect
|
||
foundation is hardened through Step 9. Spellbook/component-book filtering,
|
||
favorite spell bar, connected casting/enchantment effects, and portal-space
|
||
presentation have passed their single-client visual gates. The corrective bounded
|
||
render/resource-lifetime integration passed its seven-destination connected
|
||
stress gate without a crash or cumulative collapse. The remaining M3 visual
|
||
requirement is the final two-client portal-out/materialize observer gate. The
|
||
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:
|
||
#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 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.
|
||
|
||
---
|
||
|
||
## Why this document exists
|
||
|
||
The roadmap is a phase index — week- to month-scale, ~50 phases by the time
|
||
v1.0 lands. Phases ship in vertical slices (architecture-first, horizontal
|
||
completion deferred), which is the right strategy for a solo open-source
|
||
project at this scale — but it leaves a chronic "everything is half-built"
|
||
feeling because no single phase ship feels like a real milestone.
|
||
|
||
This document sits **one altitude above** the roadmap. Each milestone is:
|
||
|
||
- **~6–10 weeks of focused work** (not a single phase, not a whole year).
|
||
- Defined by a **concrete playable scenario** — when the scenario works
|
||
end-to-end, the milestone lands.
|
||
- A **scope-freeze event**: when a milestone lands, the phases it covers go
|
||
off-limits until v1.0's final polish pass (M7).
|
||
|
||
Crossing a milestone is a textual event — milestones doc gets the writeup,
|
||
the freeze list flips, CLAUDE.md's "currently working toward" line advances.
|
||
Phases ship; milestones **land**.
|
||
|
||
---
|
||
|
||
## Operating rules
|
||
|
||
1. **One active milestone at a time.** Everything not on the critical path to
|
||
the current milestone gets filed in `docs/ISSUES.md` with a `post-MN` tag
|
||
and explicitly muted until the milestone hits. This is what kills the
|
||
jumping-between-things feeling.
|
||
|
||
2. **Frozen phases are off-limits.** "Frozen" means no rework, no polish, no
|
||
follow-up commits unless something is actively broken (player crash,
|
||
regression). Visual nice-to-haves, "while I'm here" cleanups, and
|
||
architecture second-guesses are all post-M7. The freeze is the discipline
|
||
mechanism that makes the milestone meaningful — without it, M0's many
|
||
shipped phases keep silently consuming attention.
|
||
|
||
3. **The milestone log is the morale instrument.** When a milestone hits:
|
||
- Pin a one-paragraph writeup at the top of this doc describing what
|
||
works end-to-end (any caveats or known regressions are explicit).
|
||
- Update the freeze list. Update CLAUDE.md's "currently working toward"
|
||
line to the next milestone.
|
||
- NO demo videos. User explicitly removed that requirement 2026-05-16
|
||
("pointless of recording videos, for what purpose?").
|
||
|
||
4. **State both altitudes at session start.** "Currently working toward M1.
|
||
Current phase: L.2 collision. Next concrete step: L.2d slice 1 spec." This
|
||
keeps the high-level orientation visible alongside the immediate task and
|
||
makes mid-session drift obvious.
|
||
|
||
---
|
||
|
||
## The milestones
|
||
|
||
### M0 — "Connect & explore" — ✅ DONE (crossed months ago)
|
||
|
||
**Demo scenario:** Log in, walk Holtburg in chase camera, see other characters
|
||
animate, send a chat message and see the echo, watch day turn to night,
|
||
listen to footsteps and ambient audio.
|
||
|
||
**Phases included (frozen):**
|
||
|
||
| Phase | What landed |
|
||
|---|---|
|
||
| 1–3 | Terrain + per-vertex normals + per-cell texture blending |
|
||
| 4 | UDP codec + handshake + character login + WorldSession |
|
||
| 5 | ObjDesc: AnimPartChange + TextureChanges + SubPalettes + ObjScale |
|
||
| 6.1–6.7 | Motion + animation foundation (idle, frame playback, slerp, UpdateMotion, UpdatePosition) |
|
||
| 7.1 | EnvCell room geometry — walls/floors/ceilings |
|
||
| 9.1–9.2 | Translucent render pass + back-face culling |
|
||
| A.1–A.5 | Streaming landblock loader → two-tier streaming |
|
||
| B.1–B.3 | Outbound ack pump + player movement + physics MVP resolver |
|
||
| D.1, D.2a | 2D overlay + ImGui scaffold + `AcDream.UI.Abstractions` layer |
|
||
| E.1–E.5 | Motion hooks + audio + particles + combat wire + spell wire |
|
||
| F.1, F.2 | GameEvent dispatcher + item model + Appraise |
|
||
| G.1, G.2 | Sky + day/night + weather + dynamic lighting |
|
||
| H.1, I.1–I.8 | Chat wire + UI consolidation + holtburger inbound parity + combat translator |
|
||
| K, L.0 | Input architecture + retail bindings + Settings panel |
|
||
| N.0–N.6.1 | WB rendering migration (modern path mandatory) |
|
||
| C.1, C.1.5a/b | Particle system + portal/EnvCell static-script wiring |
|
||
| R.1–R.3 | Retail research infrastructure (PDB extract + named decomp) |
|
||
|
||
**Status:** This is everything shipped through 2026-05-12. ~25 phase ships.
|
||
**Worth saying out loud: this is the hard half of the project.** The engine
|
||
runs, the world renders correctly, the network connects, the input is wired,
|
||
the data layers for combat/spells/items/audio/particles all exist. What's
|
||
missing is the gameplay loop on top.
|
||
|
||
---
|
||
|
||
### M1 — "Walkable + clickable world" — ✅ LANDED 2026-05-16
|
||
|
||
**Landing writeup (2026-05-16, after Phase B.6 ship `d640ed7`):**
|
||
All four M1 demo targets work end-to-end. You can log into `+Acdream`
|
||
at Holtburg, walk freely without getting stuck (L.2 collision is
|
||
retail-faithful through the doorway). Click any inn door at any
|
||
range, press R, the character runs (or walks if close) toward it
|
||
with the correct animation cycle including the leg-shuffle turn-first
|
||
phase, opens the door via ACE's server-side `MoveToChain` callback.
|
||
Same for clicking an NPC — runs over, body rotates to face, dialogue
|
||
fires from ACE without any client-side retry. Pickup items at any
|
||
range with F or R; spell components, food, money, weapons all work;
|
||
signs and other `BF_STUCK` scenery correctly block at the gate.
|
||
AP cadence matches retail (0 Hz idle, ~1 Hz smooth motion, per-event
|
||
on cell/plane changes). Run/walk threshold matches retail observation
|
||
(1m of distance left to walk). The earlier ladder of workarounds —
|
||
client-side retry, per-frame chatty AP, MoveToState suppression
|
||
grace period — all deleted via the Phase B.6 architectural refactor
|
||
(`d640ed7`). M1's demo path is now bit-for-bit retail-faithful end
|
||
to end.
|
||
|
||
|
||
|
||
**Demo scenario:** Walk through Holtburg without getting stuck on the inn
|
||
doorway. Open the inn door. Click an NPC and see selection feedback. Pick
|
||
up an item from the ground.
|
||
|
||
**Demo-target status (as of 2026-05-14):**
|
||
|
||
| # | Target | Status | Evidence |
|
||
|---|---|---|---|
|
||
| 1 | Walk through Holtburg without getting stuck | ✅ met | L.2a/d/g shipped 2026-05-12; Holtburg doorway verified |
|
||
| 2 | Open the inn door | ✅ met | B.4b (interaction) + B.4c (swing animation) shipped 2026-05-13 |
|
||
| 3 | Click an NPC and see selection feedback | ✅ met | B.4b chain + chat handlers; verified 2026-05-14 (Tirenia + Royal Guard double-click → NPC dialogue in chat panel) |
|
||
| 4 | Pick up an item from the ground | ✅ met (close-range path) | B.5 + post-B.5 `PickupEvent (0xF74A)` fix shipped 2026-05-14; visual-verified at Holtburg; creature-pickup guard added in `a01ebd5` |
|
||
|
||
**Landing artifacts done 2026-05-16:**
|
||
- ✅ Landing writeup pinned at top of this milestone block (above the table).
|
||
- ✅ Freeze list applied (see below).
|
||
- ✅ `CLAUDE.md`'s "currently working toward" advanced to M2.
|
||
|
||
**Known polish items deferred to post-M7 (do not gate M1 landing):**
|
||
- **#61** — AnimationSequencer link→cycle frame-0 flash on door swing. LOW.
|
||
- **#62** — PARTSDIAG null-guard. Latent, not reachable today.
|
||
- **#63** — ✅ CLOSED by Phase B.6 (`d640ed7`). Server-initiated
|
||
`MoveToObject` is now honored end-to-end; ACE's `MoveToChain`
|
||
callback fires server-side on arrival.
|
||
- **#64** — Local-player pickup animation does not render (retail
|
||
observers see it correctly). LOW.
|
||
- **#69, #74, #75** — all closed by Phase B.6 (`d640ed7`). Turn-first
|
||
animation, retail-narrow AP cadence, body-direct auto-walk
|
||
architecture.
|
||
|
||
**Phases that shipped to clear M1:**
|
||
- **L.2 (a + d + g sub-lanes)** — Movement & Collision Conformance.
|
||
L.2a slices 1+2+3 + L.2d slice 1+1.5 + L.2g slice 1+1b+1c shipped
|
||
2026-05-12 / 2026-05-13. Visual-verified via the B.4b doorway test.
|
||
- **B.4b** — outbound Use + `WorldPicker` + double-click detection +
|
||
`CollisionExemption` widening + `ServerGuid→entity.Id` translation
|
||
(the ID-mismatch trap surfaced during L.2g slice 1c). Shipped
|
||
2026-05-13.
|
||
- **B.4c** — door swing animation: spawn-time `AnimationSequencer`
|
||
registration + stance-value fix (`NonCombat = 0x3D` not `0x01`, which
|
||
had been causing doors to render halfway underground). Shipped
|
||
2026-05-13.
|
||
- **B.5** — `BuildPickUp` (PutItemInContainer 0x0019) + `SendPickUp`
|
||
helper + F-key wiring + new `PickupEvent (0xF74A)` despawn handler.
|
||
Shipped 2026-05-14.
|
||
- **B.5 polish** (`a01ebd5`) — guard `SendPickUp` against creature
|
||
targets so F-on-NPC produces a "Can't pick that up" toast instead of
|
||
the malformed pickup that triggered ACE's `WeenieError 0x0029` + NPC
|
||
emote chain. (Briefly visited adding "You pick up the X." chat /
|
||
toast feedback for ground pickups in `87ba5c9`, then reverted in
|
||
`20ecb23` — retail doesn't show that line for ground pickups; only
|
||
for items received from NPCs / other characters, and that path is
|
||
separate.)
|
||
|
||
**Freeze on landing:**
|
||
- L.2 zone (collision, cell ownership, transition parity, wire authority)
|
||
- B.4 zone (interaction outbound)
|
||
- B.5 zone (pickup outbound + inbound despawn)
|
||
|
||
**What "M1 lands" looks like:** the existing Holtburg traversal works as a
|
||
retail player would expect. Doorways are walkable. Buildings have solid
|
||
walls. Outdoor cell seams report the right cell. Clicking an NPC selects it
|
||
and produces NPC chat. The Use action opens doors. F picks up items at
|
||
close range and the player sees "You pick up the X." in chat.
|
||
|
||
---
|
||
|
||
### M1.5 — "Indoor world feels right" — ✅ LANDED 2026-07-10 (building/cellar demo + full dungeon round-trip both user-gated; EXTENDED 2026-06-13 to include dungeon support / Phase G.3)
|
||
|
||
**✅ M1.5 LANDED 2026-07-10.** The indoor world reads as solid end-to-end.
|
||
A player can walk into a building and climb a multi-floor inn without
|
||
sling-out or wall-clip; descend a cottage cellar and ascend without falling
|
||
through; and — the piece that extended this milestone — **enter a dungeon
|
||
via portal, navigate its rooms, and portal back out to the outdoor world**,
|
||
with walls blocking, lighting reading correctly, and no position desync.
|
||
Both demo halves are user-gated: the building/cellar demo across the 2026-06
|
||
sessions, and the full dungeon round-trip (enter + navigate re-confirmed,
|
||
then the exit round-trip confirmed) on 2026-07-10. Dungeon support (full
|
||
Phase G.3) shipped with every sub-piece individually gated: teleport-in
|
||
(#133), collision (#137), portal-graph visibility (#95), doors (#187/#188),
|
||
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
|
||
(#153, REOPENED — a narrow far-teleport streaming edge case,
|
||
capture-harness-first) and #116 slide-response feel-debt. Next: **M2 —
|
||
"Kill a drudge."**
|
||
|
||
**EXTENDED 2026-06-13 — dungeons pulled into M1.5 scope; G.3 SHIPPED.** The
|
||
building/cellar demo (below) is DONE + user-gated. Attempting the dungeon
|
||
demo initially surfaced that dungeons didn't work AT ALL — terrain-less
|
||
dungeon landblocks appeared unsupported anywhere in the streaming/load/
|
||
render/physics pipeline (`LandblockLoader.Load` returning null, no terrain
|
||
mesh, teleport snap Resolving before hydration — issue #133). That premise
|
||
was refuted at design time (commit `90786c19`: the dungeon `LandBlock` is
|
||
flat-terrain and streams via the existing pipeline). The user chose the
|
||
FULL Phase G.3 scope (dungeon streaming + portal-space loading screen +
|
||
multi-landblock dungeon LOD + `PlayerTeleport` handling), and it has since
|
||
**SHIPPED**: teleport-into-dungeon (G.3a hold-until-hydrate FSM closes
|
||
#133), dungeon collision (#137 CLOSED), the #95 portal-graph visibility
|
||
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. 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
|
||
2026-06 sessions the holistic retail-faithful render port (Option A: ONE
|
||
`DrawInside(viewer_cell)`, no inside/outside branch — BR-2..BR-7 / T1..T6)
|
||
shipped and was user-gated, and the indoor physics/membership family was
|
||
brought to retail fidelity (the A6.P4 per-cell shadow architecture; the
|
||
#107/#111/#112 spawn + membership fixes; the cellar-lip wedge). End-to-end,
|
||
user-gated this milestone: walk into a building and climb a multi-floor inn
|
||
without sling-out or wall-clip; descend a cottage cellar and ascend it
|
||
without falling through (the #98 + cellar-lip + #108 grass-window closes);
|
||
walls block everywhere (indoor + stab-shell, the #99 door run-through
|
||
closed); cell transitions are smooth (the doorway "flap" family killed —
|
||
#119/#128, #112, #113, #124, #129/#130/#131/#132, #108-residual, #127 all
|
||
closed with user gates). The #90-stickiness + `TryFindIndoorWalkablePlane`
|
||
synthesis workarounds were removed by A6.P4. Remaining feel-level debt is
|
||
tracked (#116 slide-response, partial Ghidra fix shipped). A7 indoor/
|
||
dungeon lighting fidelity CLOSED 2026-07-09 (#79/#93/#80/#154).
|
||
|
||
**Interleaved parity tracks (reconciled 2026-07-04 — NOT milestones).** Two
|
||
work streams have run alongside M1.5, both driven by the user's live
|
||
side-by-side-vs-retail sessions, both issue-level per the operating rules
|
||
(observed defects → ISSUES → fix → user gate), and both stay subordinate
|
||
to M1.5 rather than becoming milestones of their own: (1) **D.2b retail
|
||
UI** — inventory window / paperdoll / item interaction shipped and gated;
|
||
next container-switching (`claude-memory/project_d2b_retail_ui.md`);
|
||
(2) **the R5 movement-manager arc — DONE 2026-07-05** — the retail
|
||
MovementManager family port (TargetManager voyeur system V2,
|
||
StickyManager/PositionManager V3, V4 behavioral items, V5 MovementManager
|
||
facade — every entity now holds ONE `MovementManager` owning its
|
||
interp+moveto pair) that closed the #170 chase-slide and #171 pack-melee
|
||
gates (`docs/research/2026-07-03-r5-managers/r5-wiring-handoff.md` has the
|
||
arc close-out). Rationale:
|
||
rule 1's "one active milestone" governs where NEW scope goes — these
|
||
tracks fix observed retail-parity defects in already-shipped systems,
|
||
which the operating rules have always allowed; declaring them milestones
|
||
would manufacture scope where a tactical ledger (ISSUES + handoffs)
|
||
already carries them.
|
||
|
||
**Modern Pipeline side track (Track MP — user-commissioned 2026-07-05; NOT
|
||
a milestone, NOT part of M1.5).** A performance modernization arc (baked
|
||
asset pipeline → retail distance-degrade → ECS render world with delta
|
||
submission → zero-alloc frame loop) targeting smoothness first, then 300+
|
||
FPS in dense towns. Spec:
|
||
`docs/superpowers/specs/2026-07-05-modern-pipeline-design.md`; phase table
|
||
in the roadmap ("Track MP"). **Freeze exception (explicit, user-authorized
|
||
2026-07-05):** this track may reopen the otherwise-frozen streaming and
|
||
WB-rendering subsystems — but only under its own gated phases (pixel- and
|
||
feel-identical conformance gates, legacy path deleted at each gate), never
|
||
as ad-hoc rework. Rule 2's freeze still binds all NON-MP work. MP runs in
|
||
dedicated side-track sessions; the M1.5 critical path wins every conflict,
|
||
and MP4 is hard-queued behind #137.
|
||
|
||
The 2026-07-18 repeated-portal lifetime repair is a freeze-allowed corrective
|
||
change, not a resumption of Track MP. It keeps the current renderer and visual
|
||
ranges while balancing owners, bounding residency, and fence-delaying physical
|
||
GPU reuse; MP's pak/ECS/throughput redesign remains parked.
|
||
|
||
**Dungeon support (Phase G.3, issue #133) — SHIPPED.** The original
|
||
premise here (terrain-less dungeon landblocks unsupported anywhere in the
|
||
streaming/load/render/physics pipeline) was refuted at design time
|
||
(commit `90786c19`: the dungeon `LandBlock` is flat-terrain and streams
|
||
via the existing pipeline). Full G.3 scope (streaming + portal-space
|
||
loading screen + multi-landblock LOD + `PlayerTeleport` handling) has
|
||
shipped: teleport-into-dungeon (G.3a hold-until-hydrate FSM,
|
||
`7947d7a`/`2ce5e5c8`/`47ae237e`) closed #133; dungeon collision closed
|
||
#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`). 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
|
||
temporary black tunnel cover is retired. F751 transit now renders retail's
|
||
client-enum-resolved DAT Setup `0x02000306` with animation `0x030005AC` at
|
||
40 frames/s in a dedicated CreatureMode-equivalent viewport, using retail's
|
||
camera, distant light, random eased forward-axis roll, frame-aligned exit
|
||
window, exact 100-sample view-plane curve, projection warp, and destination
|
||
viewer reset. Retail switches the portal and world viewports directly without
|
||
a black alpha fade; both compose below retained UI, so
|
||
chat, panels, toolbar, cursor, and input remain live throughout travel. See
|
||
`docs/research/2026-07-15-retail-portal-space-pseudocode.md`.
|
||
|
||
The live frame barrier now also matches `SmartBox::UseTime`: local/remote
|
||
object, projectile, animation, final-pose, animation-hook, particle, and
|
||
owner-script work completes before the inbound network queue is dispatched.
|
||
Local movement/jump output is committed on that same pre-network side, while a
|
||
non-advancing post-network pass reconciles children and attached effect/light
|
||
anchors after authoritative root moves. The accepted Hidden and UnHide paths
|
||
now also port `CPhysicsObj::set_hidden @ 0x00514C60` completely. Hidden invokes
|
||
the PartArray boundary after its effect, child visibility, collision stop, and
|
||
cell hide; UnHide invokes it after effect/child/collision restoration but before
|
||
the cell becomes visible. Both route through `CPartArray::HandleEnterWorld` →
|
||
`MotionTableManager::HandleEnterWorld`. That
|
||
strips every link animation and aborts pending motion completions before a
|
||
spell-cast recoil or recall remainder can survive portal space. This is the
|
||
generic retail visibility boundary, not a recall classifier, an arrival reset,
|
||
or a Hidden-time animation exception. Installed-DAT conformance covers both
|
||
the Lifestone recall boundary and a MagicPortal casting timeline. The user
|
||
confirmed `/ls` and spell-recall arrivals no longer replay their animation
|
||
tails; additional portal visual polish is explicitly deferred.
|
||
|
||
**2026-07-16 corrective portal gate (#218).** A side-by-side retail observer
|
||
check found three distinct state-publication defects after the arrival-tail
|
||
fix. Hidden now recomposes the post-`HandleEnterWorld` cyclic pose without
|
||
advancing animation time before its zero-time purple PES hooks run. Portal
|
||
space now waits for both completed static/EnvCell mesh uploads (including the
|
||
texture flush) and collision residency; dense
|
||
outdoor landblocks no longer abort at the obsolete 256-entry procedural
|
||
scenery id boundary (`0x8XXYYIII`, 4,096 entries). Finally, successful indoor
|
||
transitions commit the full resolved EnvCell/frame into the canonical outbound
|
||
Position, preventing stop-time snaps to the dungeon entrance on retail
|
||
observers. GPU-evicted meshes are re-staged from a bounded texture-complete CPU
|
||
cache instead of becoming false-ready or permanently absent. Portal readiness
|
||
also requires Near-tier ownership throughout the ring; stale worker completions
|
||
carry a hard-recenter generation and cannot overwrite a newer tier/window, and
|
||
a first Near completion demoted in flight is published as its equivalent
|
||
terrain-only Far payload rather than dropped. Upload completion is separate
|
||
from logical mesh ownership; landblock/static/EnvCell pins now balance across
|
||
unload and zero-owner late uploads remain evictable. A self-contained promotion
|
||
that supersedes a queued Far load publishes directly as a real Near landblock;
|
||
there is no provisional transaction waiting indefinitely for a base that the
|
||
streamer intentionally cancelled. Near-to-Far now has an explicit cross-layer
|
||
demotion transaction that preserves terrain while retiring EnvCells, indoor
|
||
physics/buildings, static collision, lights, translucency state, entities, and
|
||
render pins. Cross-landblock static shadow footprints are removed by logical
|
||
owner while dynamic registrations remain refloodable; duplicate Near
|
||
completions are publication-idempotent. Full unload shares the static-owner
|
||
teardown, and surviving adjacent owners remember withdrawn prefixes so their
|
||
cross-seam rows return when a landblock is promoted again.
|
||
Automated gates are green; the connected single-/two-client visual gate is
|
||
pending.
|
||
|
||
---
|
||
|
||
#### (historical M1.5 working notes below)
|
||
|
||
🔵 ACTIVE (resumed 2026-05-21 after Phase O ship)
|
||
|
||
**2026-05-30 — render-pipeline pivot.** The indoor *rendering* seam (seamless
|
||
in/out: the flap, missing/transparent walls, terrain bleed) will be solved by a
|
||
**single unified retail-faithful render pipeline (Phase U)**, replacing the
|
||
abandoned two-pipe inside/outside split (A8/A8.F, issue #103). The two-pipe split
|
||
is a WorldBuilder inheritance; retail uses one portal-visibility pass and is
|
||
seamless by construction. Decision + scope:
|
||
[`docs/research/2026-05-30-unified-render-pipeline-decision-and-handoff.md`](../research/2026-05-30-unified-render-pipeline-decision-and-handoff.md).
|
||
Camera-collision + a physics viewer-cap fix shipped 2026-05-30 and are kept (they
|
||
were a detour from the real seam fix, but retail-faithful and worth keeping). A6
|
||
(physics) and A7 (lighting) are unaffected.
|
||
|
||
**Phase O — DatPath Unification — shipped 2026-05-21.** ONE thing
|
||
touches the DATs. ~33 WB files (~7.7K LOC) extracted into
|
||
`src/AcDream.{Core,App}/Rendering/Wb/`; project references to
|
||
`WorldBuilder.Shared` + `Chorizite.OpenGLSDLBackend` dropped;
|
||
`DefaultDatReaderWriter` eliminated. Visual side-by-side passed at
|
||
Holtburg town, inn interior, and dungeon. Phase O pre-empted M1.5
|
||
per user direction 2026-05-21; M1.5 now resumes from the 2026-05-20
|
||
baseline with no code changes lost — Phase O did not touch dat-loading
|
||
infrastructure for physics or collision, only the rendering pipeline.
|
||
M1.5's planned phases (A6 + A7) are unaffected.
|
||
|
||
**Demo scenario (updated 2026-05-21):** The original demo target was
|
||
"enter the Holtburg Sewer dungeon" but that location doesn't exist on
|
||
this ACE server (discovered during A6.P1 capture session). Additionally,
|
||
A6.P1 surfaced **issue #95** (portal-graph visibility blowup) which makes
|
||
ANY dungeon visually unusable on entry. **[SUPERSEDED — #95 RESOLVED
|
||
(9.1M→~39k instances, `a40c38e8`); dungeons ship; see M1.5 section
|
||
above.]** Demo scenario revised in two parts:
|
||
|
||
**Building/cellar demo (achievable after A6.P3 lands):**
|
||
Walk into the Holtburg inn, climb to the 2nd floor, walk around without
|
||
sling-out or wall-clip. Enter a cottage cellar, descend without falling
|
||
through. Throughout:
|
||
- Walls block — no walk-through anywhere, indoor or stab-shell.
|
||
- Stairs work — ascend + descend without falling through or stuck-in-falling.
|
||
- Items block — furniture, decorations.
|
||
- Cell transitions are smooth — no CellId ping-pong, no flicker.
|
||
- Lighting reads correctly — torchlit rooms are bright, no spotlight
|
||
artifacts, static decorations participate in env lighting.
|
||
|
||
**Dungeon demo (blocked on issue #95 fix; promote to post-M1.5 if
|
||
the visibility bug isn't addressed in M1.5 scope):** **[SUPERSEDED — #95
|
||
RESOLVED, dungeons ship; see M1.5 section above.]**
|
||
Enter any dungeon via portal (substitute for "Holtburg Sewer"). Navigate
|
||
~3-5 rooms without rendering corruption (no see-through-walls, no
|
||
other-dungeons-rendered-inside). Walls block, stairs work, items block,
|
||
lighting correct, cell transitions smooth.
|
||
|
||
**Why this is its own milestone:** M1 landed walkable + clickable as a
|
||
specification (the doorways open, NPCs select, items pick up — all visible
|
||
in the demo target). But continued indoor testing surfaced a deep family of
|
||
physics + lighting bugs (BSP push-back distance probably diverges from
|
||
retail, per-frame ContactPlane synthesis is a known unfaithful stop-gap,
|
||
indoor lighting + item-spotlight bugs reported during 2026-05-21 sessions).
|
||
Three workarounds shipped today (#89 sphere-overlap CheckBuildingTransit,
|
||
#90 sphere-overlap stickiness, #92 spawn-cell-id seed) closed the visible
|
||
symptom at Holtburg inn, but #90 specifically is a CLAUDE.md-rules
|
||
workaround (explicit retail divergence) that needs a proper root-cause fix.
|
||
The umbrella indoor-physics issue (#83) has been open since 2026-05-19 with
|
||
multiple aborted fix attempts. Promoting this to milestone scope forces the
|
||
fix to be central, retail-anchored, and complete — not another whack-a-mole
|
||
patch.
|
||
|
||
**Phases included:**
|
||
|
||
| Phase | What it does |
|
||
|---|---|
|
||
| A6 — Indoor physics fidelity (cdb-driven) | Capture retail's per-tick BSP collision response state at 9 scenarios (4 buildings + 5 dungeon sites). Analyze the gap vs ours. Fix BSP correction paths. Remove #90 stickiness + `TryFindIndoorWalkablePlane` synthesis workarounds. |
|
||
| A7 — Indoor lighting fidelity (RenderDoc + retail-decomp) | Capture per-cell light state + per-pixel attribution at the same 9 scenarios. Analyze cell-light association, visibility culling, per-entity light direction. Fix indoor lighting + #80 (upper-floor dark) + #81 (static-stab atmospheric) + the held-item-spotlight bug. |
|
||
|
||
**Issues in scope (M1.5):**
|
||
|
||
- **#80** — Camera on 2nd floor goes very dark
|
||
- **#81** — Static building stabs don't react to atmospheric lighting
|
||
- **#83** — Indoor multi-Z walking broken (cellars, 2nd floors, intermittent falling-stuck)
|
||
- **#88** — Indoor static objects vibrate (suspected sub-step state corruption — A6.P2 maps to Finding 2 family)
|
||
- **#90** — CellId ping-pong (workaround in place; remove during A6.P4)
|
||
- **#95** — Portal-graph visibility blowup (filed 2026-05-21; **blocks the dungeon half of the M1.5 demo** but is NOT in A6 scope; either add a dedicated phase inside M1.5 to fix it OR promote the dungeon demo to post-M1.5) **[SUPERSEDED — RESOLVED, 9.1M→~39k instances, `a40c38e8`; dungeons ship; see M1.5 section above.]**
|
||
- **L-indoor** — Lighting indoors broken (file as new # during M1.5 kickoff)
|
||
- **L-spotlight** — Items projecting spotlight on walls (file as new # during M1.5 kickoff)
|
||
- **Stairs walk-through** — captured + characterized by A6.P2 (Finding 2 family); fix in A6.P3
|
||
- **2nd-floor walking** — captured + characterized by A6.P2 (Finding 2 — scen3 shows infinite CP-write ratio on flat 2nd-floor walk); fix in A6.P3
|
||
- **Cellar descent** — same physics family as stairs; fix in A6.P3
|
||
- **Indoor sling-out** (new symptom from A6.P1 scen4) — captured + mapped to A6.P2 Finding 3 (cell-resolver in ResolveCellId / CheckBuildingTransit); fix in A6.P3
|
||
- **`TryFindIndoorWalkablePlane`** — synthesis workaround removal (Bug A's original goal, finally unblocked; A6.P4)
|
||
|
||
**Frozen phases during M1.5:** all M0 + M1 phases stay frozen. Plus
|
||
specifically the recently-shipped A4 + #89 + #91 + #92 — those
|
||
land in main as the M1.5 baseline and shouldn't be revisited except as part
|
||
of A6.P4 removal of the workarounds.
|
||
|
||
**Frozen as of M1.5 landing (2026-07-10):** all M1.5 phases are now frozen
|
||
per rule 2 — the indoor render port (Option A `DrawInside(viewer_cell)`),
|
||
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): #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
|
||
than a normal milestone because lighting is open-ended (less existing
|
||
diagnostic infrastructure than physics). Could be shorter if the cdb
|
||
analysis surfaces a single-fix opportunity.
|
||
|
||
**What "M1.5 lands" looks like:** the indoor world reads as solid. Players
|
||
can navigate buildings, basements, multi-floor inns, and dungeons without
|
||
encountering walls they walk through, lighting that looks wrong, or
|
||
position glitches. The two known workarounds (#90 stickiness +
|
||
TryFindIndoorWalkablePlane synthesis) are removed; the codebase no longer
|
||
has indoor-physics "duct-tape." Dungeons are usable enough to support M2's
|
||
"kill a drudge" demo target (drudges live in dungeons; this milestone
|
||
unblocks that).
|
||
|
||
---
|
||
|
||
### M2 — "Kill a drudge" — ✅ LANDED 2026-07-15
|
||
|
||
**Demo scenario:** Equip a sword. Walk to a drudge. Swing. See "You hit
|
||
Drudge for 12 slashing damage (87%)" in chat. Watch the swing animation
|
||
play. Drudge dies, drops loot. Pick up the loot. Open the inventory panel
|
||
and see it.
|
||
|
||
**Landed:** The connected Release client now completes that entire loop. Both
|
||
melee and missile weapons switch through server-authoritative inventory
|
||
transactions; attacks face the selected hostile target before release; combat
|
||
animation, damage text, persistent death, auto-target, loot, inventory/stack
|
||
operations, paperdoll/toolbar interaction, and world-item giving have passed
|
||
user gates. Work discovered outside this demo remains explicitly carried below
|
||
rather than keeping the milestone open indefinitely.
|
||
|
||
**First port target when M2 starts (per the M2 combat-math research memo,
|
||
`docs/research/2026-06-04-combat-math-deep-dive.md`):**
|
||
`CombatMath.ComputeDamage` — damage-calc + armor-resists are port-ready
|
||
(ACE is the high-confidence oracle; two known scaffold bugs in
|
||
`CombatModel.cs` identified — additive attributeBonus + subtractive armor).
|
||
Hit-roll is well-documented client-side; the server sigmoid/crit +
|
||
weapon-timing (the x87 `GetPowerBarLevel` artifact) come after. NOTE: M2
|
||
was briefly started 2026-06-13 then re-deferred when M1.5 was extended to
|
||
include dungeons.
|
||
|
||
**Phases to ship:**
|
||
- **F.2 (panels)** — Inventory panel reading `ItemRepository` (data already
|
||
shipped in F.2 base; M2 ships the visual surface).
|
||
- **F.3** — Combat math + damage flow.
|
||
- **F.5a** — Visible-at-login dev panels (Attributes, Skills, Equipped,
|
||
Inventory list) — minimal ImGui surfaces, retail-skin deferred to M5.
|
||
- **L.1c** — Combat animation wiring (draw/sheath, attack swings by
|
||
stance/power/height, hit reactions, evades).
|
||
- **L.1c held-object foundation (implemented and live-gated 2026-07-11)** — exact
|
||
equipment-aware default combat mode (bow→Missile, caster→Magic) plus retail
|
||
CreateObject/ParentEvent child attachment and per-frame hand-follow rendering.
|
||
- **L.1c inventory weapon switching (implemented and live-gated 2026-07-15)** —
|
||
inventory double-click ports retail's two-stage `AutoWield`: return the occupied
|
||
primary weapon to the main pack, then any incompatible shield/ammo, waiting
|
||
for every server move confirmation before wielding the requested
|
||
bow/sword/caster/two-hander. The shared transaction works
|
||
in peace and war, remains busy through the exact final `WieldObject`
|
||
acknowledgement independently of rollback bookkeeping, and prevents rapid
|
||
switches from overlapping or remaining stuck; ACE owns stance-specific motions and its PropertyInt 40 update
|
||
now drives the client `CombatState`.
|
||
- **M2 item giving (implemented and starter-dungeon live-gated 2026-07-13)** —
|
||
a physical inventory drag released over a 3-D creature now ports
|
||
`ItemHolder::AttemptPlaceIn3D` through the exact `GiveObjectRequest 0x00CD`
|
||
packet, including selected partial-stack quantities and authoritative-only
|
||
inventory mutation. Release coordinates feed the existing world picker, and
|
||
`PlayerDescription.Options1` preserves retail's player secure-trade
|
||
preference. See
|
||
`docs/research/2026-07-13-retail-give-item-pseudocode.md` and issue #216.
|
||
- **M2/M3 missile, effect, and portal presentation campaign (automated Steps 0–9
|
||
complete and independently reviewed 2026-07-14)** — named-retail projectile and
|
||
physics-script behavior is pinned in one oracle, the complete `PhysicsDesc`
|
||
and F754/F755 wire surfaces are parsed with retail timestamp gates, and
|
||
`LiveEntityRuntime` now separates logical lifetime from spatial rebucketing.
|
||
Landblock churn and equipment attachment preserve one stable local entity and
|
||
cannot replay create-time scripts. A narrow raw-hook seam now decodes retail's
|
||
inherited `CreateBlockingParticle` payload for both PhysicsScripts and
|
||
Animations, while exact stored-order `PhysicsScriptTable` threshold lookup and
|
||
Setup-versus-network default precedence are pinned by conformance tests.
|
||
`EntityEffectController` now replays pre-create F754/F755 once in mixed order
|
||
against the canonical local owner; the Core scheduler uses one serial FIFO per
|
||
owner, preserves duplicates, supports deterministic delayed `CallPES`, and
|
||
routes default/part-default hooks through the complete hook fan-out. The
|
||
update-frame clock is published before packet/default dispatch and republished
|
||
before animation hooks. Existing cell-less/Frozen queues pause and resume with
|
||
retail eligibility, while new ordinary F754/F755/default plays on an
|
||
already-created cell-less owner drop. Hidden/UnHide bypasses that ordinary
|
||
gate through retail `set_hidden` -> `play_script_internal`, queuing until
|
||
eligibility returns. Attached children advance through their parent. Every sink shares canonical
|
||
`WorldEntity.Id`, and static allocator overflow fails before aliasing another
|
||
landblock. Live SoundTable ownership is installed independently of animation
|
||
eligibility and replaced/cleared on each PhysicsDesc application; DAT statics
|
||
retain Setup defaults. Concurrent-safe DAT reads stay off the streaming lock; malformed
|
||
zero-time recursive chains fail diagnostically while valid timed weather loops
|
||
continue. The
|
||
live-pose step now publishes exact root/indexed rigid-part transforms after
|
||
animation and equipped-child composition, advances existing FP hooks, drains
|
||
animation hooks, refreshes attached emitters/lights, advances particles, then
|
||
ticks PhysicsScripts in fixed retail frame order. World-released particles remain at their birth positions while
|
||
parent-local particles follow; normal/blocking/anonymous logical emitter
|
||
semantics are exact; pending projections skip particle updates/draw while
|
||
retaining absolute creation times, the same emitter, and its logical ID, so
|
||
re-entry expires elapsed state once without backlog emission. Moving Setup lights follow top-level and held-object
|
||
roots and honor authoritative Lighting/SetLight transitions; missing emitter
|
||
assets diagnose without a fabricated fallback. Stable Setup-part indices do
|
||
not collapse around missing visuals, nested attachments update parent-first,
|
||
and per-child pose buffers are reused. Rigid attachment/effect frames exclude
|
||
visual Setup scale, attachment withdrawal cascades through descendants, and
|
||
later pose publication recovers the complete descendant chain parent-first;
|
||
light registration follows final projection visibility. Step 6 adds the pure
|
||
Core retail projectile driver: 0.2-second catch-up quanta, the 50-unit/second
|
||
clamp, final-state gravity, world-space omega, full-3D AlignPath, scaled
|
||
Setup-local sphere sweeps, exact missile target/ethereal exclusions,
|
||
self-shadow rejection, retail collision response, and full-cell landblock
|
||
rebasing. Missile adds PathClipped but never PerfectClip. AP-67, TS-2, TS-10,
|
||
TS-11, and TS-12 are retired; AP-83/AP-91 remain dormant. Step 7 attaches
|
||
that primitive to the canonical `LiveEntityRecord`: arrows, bolts, and spell
|
||
missiles share one body and one renderer identity across prediction,
|
||
authoritative State/Vector/Position/Movement corrections, full-cell
|
||
rebucketing, pending-landblock residence, delete, session reset, and GUID
|
||
reuse. MovementManager presentation shares the same body and the canonical
|
||
live-record cell regardless of which component was created first;
|
||
pending/leave-world shadows retain their registration for exact re-entry even
|
||
if Missile classification changes while pending; static missile effect
|
||
roots follow every predicted frame, and materialized rehydration never uses a
|
||
stale spawn cell. No impact, damage, effect, or delete event is synthesized
|
||
client-side. Step 8 ports retail's constructor-state → PhysicsDesc
|
||
transition, ordered Lighting/NoDraw/Hidden state side effects, DAT-driven
|
||
typed Hidden/UnHide effects, direct-child NoDraw propagation, retained
|
||
particles/lights, mesh/collision/interaction suppression, and exact remote
|
||
`teleport_hook` teardown followed by a placement snap before the airborne
|
||
gate. Ordinary visible CreateObject does not fabricate UnHide; pending
|
||
F754/F755 packets replay only after construction-state effects. TS-43 is
|
||
retired. Step 9 adds a deterministic 96-owner whole-lifecycle gate spanning
|
||
projectile ticks, repeated DAT-effect plays, loaded↔pending landblock churn,
|
||
dynamic lights, particle bindings, collision shadows, rapid deletion,
|
||
same-GUID generation reuse, unknown pre-create effect packets, and session
|
||
reset. A separate 96-owner renderer-seam gate balances every
|
||
`EntitySpawnAdapter` mesh reference. Teardown now proves zero retained live
|
||
records/bodies/projectiles, render owners, spatial buckets/rescues,
|
||
PhysicsScript queues/anchors, effect profiles/packets, emitters/logical IDs,
|
||
poses, lights, and active/suspended shadow registrations. The hardening pass
|
||
also fixed undrained persistent-rescue retention and rejects queued spatial
|
||
visibility edges that no longer match current incarnation truth. A companion
|
||
twelve-cycle gate drives exact recall motion `0x10000153` through CallPES,
|
||
Hidden, unloaded-destination placement, hydration, and UnHide. Logical
|
||
teardown is incarnation-specific across callback-driven GUID reuse; per-GUID
|
||
epochs reject create resurrection after a nested delete/reset, resource
|
||
registration is atomic, terminal session clear rejects registrations outside
|
||
its teardown snapshot, and visibility fan-out drains all owners before
|
||
aggregating observer failures. Canonical cell/projection state finishes
|
||
committing before those aggregates rethrow; per-GUID epoch tombstones survive
|
||
accepted delete until session clear, and superseded creates cannot discard a
|
||
prior-incarnation cleanup failure. Per-record projection tokens also prevent
|
||
an outer rebucket/withdrawal from overwriting a replacement incarnation or a
|
||
newer same-record projection created synchronously by an observer.
|
||
TS-26's
|
||
`UpdatePosition` freshness gap is retired by the nine-channel timestamp
|
||
gates; TS-49 remains the explicit
|
||
DetectionManager/`LeftDetection` gap. A 2026-07-14 corrective visual slice
|
||
ports `CPhysicsPart::Always2D`: mode-1/no-degrade particles now keep every
|
||
authored mesh polygon through the modern global buffer, while other degrade
|
||
modes retain the billboard path. This restores the four-piece apex of
|
||
Armor/protection shield effects. MP2's 2026-07-17 corrective performance
|
||
slice now ports the complete retail particle distance/cell-view gate and
|
||
degraded update branches: DAT-authored ranges (Aerlinthe's dominant swarm is
|
||
64 world units), exact infinite-emitter freeze/finite-emitter conditional
|
||
stop bookkeeping, and emitter-first render rejection. The landscape renderer
|
||
publishes outdoor landcells independently of surviving object meshes.
|
||
Terrain/entity streaming distance is
|
||
unchanged; the user-requested default Extended setting doubles only particle
|
||
range, while Retail remains available as the exact cutoff. The
|
||
final two-client visual gate is still pending.
|
||
- **L.1c local attack receive path (implemented and live-gated 2026-07-15)** —
|
||
local non-autonomous mt-0 UpdateMotion now uses retail's wholesale interpreted
|
||
funnel and action-stamp gate, so ACE's server-selected melee/missile action
|
||
drives the player's motion table; direct command-list replay is removed.
|
||
- **M2 basic combat bar (implemented and live-gated 2026-07-15)** — authored
|
||
`gmCombatUI` LayoutDesc `0x21000073` now pops for Melee/Missile and shares one
|
||
press/hold/release attack-request owner across DAT buttons and keybindings.
|
||
Retail x86 resolves full charge to 1.0 s (0.8 s dual wield), also retiring the
|
||
guessed jump-charge timing. The corrective gate ports the right-to-left red
|
||
meter, silent AttackDone control status, target-frame Keep in View with
|
||
retained manual orbit, persistent corpse motion protected from the AP-80
|
||
velocity adaptation, and post-death nearest-target acquisition when Auto
|
||
Target is enabled. Both multi-frame and static/reactive spawns now share
|
||
retail's wire-driven description-before-enter-world lifecycle: the corpse's
|
||
authoritative Dead state is retained and `HandleEnterWorld` strips its
|
||
Ready→Dead transition before the first rendered tick. Corpse persistence was
|
||
visually confirmed live on 2026-07-12. The follow-up #205 correction makes
|
||
the toolbar consume the final reentrant Auto Target selection and restricts
|
||
automatic candidates to hostile non-player monsters; live gate passed
|
||
2026-07-12. See
|
||
`docs/research/2026-07-12-death-and-auto-target-pseudocode.md`.
|
||
- **Retail client command families (implemented 2026-07-13; corrective live gate pending)** —
|
||
both chat surfaces now route a named-decomp command catalog into an App-layer
|
||
controller, keeping ACE administrator verbs on the explicit server-command
|
||
path. The implemented set covers travel, character/time queries, local UI and
|
||
location commands, named/automatic layout persistence, AFK/consent, emotes,
|
||
friends, squelch/filter, and fill-components, with exact Core.Net messages and
|
||
authoritative social-state parsing. See
|
||
`docs/research/2026-07-13-retail-client-command-families-pseudocode.md`.
|
||
The first connected gate passed the family except for raw suicide success
|
||
code `0x004A` and the incomplete title-bar-only FPS toggle; the corrective
|
||
pass maps retail's success text and mounts the authored SmartBox FPS element.
|
||
Confirmation reuse now follows retail's `DialogFactory`: fresh DAT roots,
|
||
property-backed results, context ids, independent queues/priority, callbacks,
|
||
close notices, and server abort handling; `/die`, gameplay requests, and
|
||
guarded item uses share the type-1 presenter.
|
||
- **L.1b** — Command router + motion-state cleanup (prereq for L.1c).
|
||
|
||
**Freeze on landing:**
|
||
- Combat math zone
|
||
- Inventory zone (data + dev panel; retail-skin reopens in M5)
|
||
- L.1b/c combat-animation zone
|
||
|
||
**What "M2 lands" looks like:** the gameplay loop is real. You can fight,
|
||
take damage, kill things, see loot, manage your inventory. The game becomes
|
||
a game.
|
||
|
||
---
|
||
|
||
### M3 — "Cast a spell" — 🔵 ACTIVE (started 2026-07-15)
|
||
|
||
**Demo scenario:** Cast Flame Bolt at a drudge. Watch the cast animation,
|
||
the projectile, the impact. Self-cast a buff (Strength Self). See the
|
||
enchantment in a buff list. Recall to lifestone — full recall animation,
|
||
correct teleport, correct re-spawn.
|
||
|
||
**Starting position:** E.5 already supplies the cast wire and authoritative
|
||
spell/enchantment state, while the M2/M3 campaign supplies traveling physical
|
||
and spell missiles, DAT PhysicsScripts, live part-attached particles/lights,
|
||
Hidden/UnHide, and recall motion/effects. Representative projectiles and
|
||
protection effects pass the single-client visual gate. M3 begins with a focused
|
||
named-retail gap audit of F.4/L.1d—not a rewrite of this foundation—then fills
|
||
the spellbook/active-enchantment UI and completes the two-client portal gate.
|
||
|
||
**Implementation update (2026-07-15):** The automated F.4/L.1d audit and port
|
||
are complete. Cast requests now use retail component-formula selection,
|
||
target compatibility, shared busy/completion ownership, and exact
|
||
targeted/untargeted messages. Live enchantment add/remove/dispel/purge state is
|
||
fully parsed with layer identity and client-clock normalization. The authored
|
||
Magic combat page, eight favorite tabs, caster endowment, spellbook/component
|
||
book, scoped keys, positive/negative effects windows, and the authored
|
||
seven-control gameplay indicator strip are mounted in the retained runtime.
|
||
The strip now uses retail DAT states for link quality, Helpful/Harmful effects,
|
||
Vitae, burden, mini-game availability, and end-character-session; live link
|
||
age, player load, and enchantment registries drive their retail thresholds and
|
||
the burden/effect/logout actions use the shared panel/dialog owners. Main-panel
|
||
visibility now flows through retail's one-active `gmPanelUI` owner. M3 remains
|
||
active only for the connected single-client magic
|
||
UI/casting visual gate and the final two-client portal observer gate.
|
||
The 2026-07-17 indicator follow-up also mounts authored Character Information,
|
||
Link Status, Vitae, and Mini Game detail roots as children of that same
|
||
main-panel owner. Helpful, Harmful, Character Information, Link, and Vitae
|
||
therefore replace Inventory/Character/Magic in one canonical window rectangle.
|
||
Helpful/Harmful instantiate retail's DAT icon/name/time row and selected-spell
|
||
information presentation. The burden icon sends panel 3 (Character Information),
|
||
not panel 11 (Attributes/Skills). Link uses retail's payload-free ping/RTT
|
||
cadence; Vitae uses PropertyInt 129/139 and the retail XP-pool threshold formula.
|
||
The detail conformance pass also restores Vitae's omitted penalty explanation,
|
||
ports the exact Character Information report/property meanings, prevents
|
||
double-compositing authored translucent panel centers, and initializes the
|
||
end-session control in its visible Normal DAT state before hover.
|
||
Helpful/Harmful selected descriptions now use retail text reflow and the
|
||
authored lower information scrollbar independently of the spell-list
|
||
scrollbar; Vitae recovery XP uses grouped client-language integer formatting.
|
||
The first connected gate exposed and corrected two retained-import defects:
|
||
spellbook tabs are authored stateful text controls (not buttons), and retail
|
||
text starts with zero margins. Real-DAT fixtures now pin spellbook binding,
|
||
Closed/Open child-state propagation, and Magic-tab strings I through VIII.
|
||
The follow-up spellbook slice now clones the DAT-authored one-column
|
||
spell-shortcut presentation (icon, name, separator, selected overlay), binds
|
||
its authored scrollbar, ports exact school/level filter masks and stable
|
||
display-order sorting, carries learned spells into the open favorite bar, and
|
||
routes Delete through the shared retail confirmation factory plus
|
||
server-authoritative `CM_Magic::Event_RemoveSpell (0x01A8)` response path.
|
||
The component-book follow-up now instantiates retail's category and component
|
||
listbox templates from LayoutDesc `0x21000033`, preserving localized headings,
|
||
row/selection textures, icon/name/count columns, and desired-value editing.
|
||
The spell metadata source is now the complete installed end-of-retail
|
||
SpellTable DID `0x0E00000E` (6,266 records). The former 3,956-row CSV is kept
|
||
only as a research fixture, so every spell ACE can teach resolves through the
|
||
same DAT-backed catalog used by formulas, casting, spellbook rows, and effects.
|
||
|
||
**Phases to ship:**
|
||
- **F.4** — Spell cast state machine (buffs + recalls first, projectile
|
||
spells second).
|
||
- **L.1d** — Spell-casting animation wiring (cast command classification,
|
||
windup, release, fizzle/interruption, recoil).
|
||
- **F.5 (Spellbook panel)** — dev-skin surface for learned spells + active
|
||
enchantments.
|
||
|
||
**Freeze on landing:**
|
||
- F.4 spell zone
|
||
- L.1d cast-animation zone
|
||
- Spellbook dev-panel surface
|
||
|
||
**What "M3 lands" looks like:** mages are real characters. Buffs work,
|
||
recalls work, the first projectile spells work. Combat from M2 + casting
|
||
from M3 = retail-equivalent gameplay loop for melee and casters.
|
||
|
||
---
|
||
|
||
### M4 — "Live in the world" — 🔵 (~6–10 weeks)
|
||
|
||
**Demo scenario:** Create a fresh character from scratch (no ACE admin).
|
||
Spawn. Talk to an NPC. Accept a quest. Walk to a dungeon entrance. Portal
|
||
in (pink-bubble loading). Walk through the dungeon. Complete the quest.
|
||
Walk back out.
|
||
|
||
**Phases to ship:**
|
||
- **H.3** — Emote scripts + quests + dialogs (122 EmoteType × 39 Trigger
|
||
mini-VM).
|
||
- **G.3** — Dungeon streaming + portal space + `PlayerTeleport` handling.
|
||
(Unblocked by L.2e from M1.)
|
||
- **H.4** — Character creation (`0xE000002 CharGen` + heritages + appearance
|
||
picker + preview).
|
||
- **L.1e** — Emote + posture animation wiring.
|
||
|
||
**Freeze on landing:**
|
||
- H.3 dialog/quest zone
|
||
- G.3 dungeon zone
|
||
- H.4 character-creation zone
|
||
- L.1e emote-animation zone
|
||
|
||
**What "M4 lands" looks like:** the world feels populated and interactive.
|
||
You can do quests, enter dungeons, create characters. Combined with M2/M3,
|
||
the client is **functionally playable** — minus visual polish.
|
||
|
||
---
|
||
|
||
### M5 — "Looks like retail" — 🟢 PARALLELIZABLE WITH M3/M4 (~4–8 weeks)
|
||
|
||
**Demo scenario:** Side-by-side screenshot of acdream vs retail at the same
|
||
location, same time of day, same character. Hard to tell apart at a glance.
|
||
Open the inventory panel — retail-skinned with the right font, icons, and
|
||
9-slice panel borders.
|
||
|
||
**Phases to ship:**
|
||
- **C.1.5c** — Sky-PES dispatch chain (closes #2 lightning, #28 aurora,
|
||
#29 cloud thinness).
|
||
- **C.2** — Dynamic point lights (fireplaces, lamps, torches with proper
|
||
local lighting).
|
||
- **C.3** — Palette range tuning (skin/hair/eye colors match retail).
|
||
- **C.4** — Double-sided translucent polys.
|
||
- **D.2b** — Custom retail-look UI backend. **In progress:** vitals + chat + toolbar + inventory (window manager, B-Grid, B-Controller, B-Wire, drag-drop, container-switching) + paperdoll (equip slots, 3-D doll UiViewport, Slots toggle) + **Character window** (Attributes tab, visually confirmed 2026-06-26) + **UI Studio** (standalone panel previewer + 26-window retail dump + interactive click-routing + headless screenshot) + **importer dat-fidelity** (Fix A/B/C: justification, FontColor, per-element FontDid resolver [studio-only; #157 tracks live-game path]) are shipped. Current campaign: shared retained-widget/window architecture, then selected-object mana/stack completion. **Retail correction:** the main toolbar is object-only; the eight favorite-spell lists drive separate spell bars. Execution plan: `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`.
|
||
- **D.3–D.7** — AcFont + dat sprites + core panels reskinned + HUD +
|
||
cursor manager. **D.6 radar/compass shipped 2026-07-10 and the separate retail
|
||
jump power bar was implemented 2026-07-13; D.7 complete retail
|
||
cursor catalog/precedence shipped and user-confirmed 2026-07-11.** The radar uses the retained
|
||
UI architecture using the retail DAT layout and recovered runtime behavior;
|
||
the jump bar uses the same retained composition with movement-owned charge timing.
|
||
Live-game visual confirmation remains the user gate.
|
||
- **L.1f** — NPC/monster + item-use animation coverage.
|
||
|
||
**Freeze on landing:**
|
||
- Visual polish zone (C.1.5c, C.2, C.3, C.4)
|
||
- D.2b → D.7 UI-skin zone
|
||
- L.1f NPC-anim zone
|
||
|
||
**What "M5 lands" looks like:** the client visually convinces. Screenshots
|
||
become postable. The "old / broken vs retail" feeling that drives most of
|
||
the chronic ISSUES.md entries is gone.
|
||
|
||
---
|
||
|
||
### M6 — "Plugins ship" — 🟢 (~4 weeks)
|
||
|
||
**Demo scenario:** A third party (not you) writes a small plugin against
|
||
the published API — XP tracker, loot logger, simple chat filter — and it
|
||
loads cleanly. Sample plugin lives in the repo with documented build steps.
|
||
|
||
**Phases to ship:**
|
||
- Plugin API surface: stable contract over `AcDream.Core` + `AcDream.UI.Abstractions`,
|
||
versioned, with the world-state interfaces exposed.
|
||
- Plugin host: load isolation, lifecycle, error containment.
|
||
- Sample plugin (XP tracker or loot logger) — proves the API by using it.
|
||
- Plugin docs page.
|
||
|
||
**Freeze on landing:**
|
||
- Plugin API v1 surface (additive changes only post-freeze).
|
||
|
||
**What "M6 lands" looks like:** the differentiator vs the retail client is
|
||
real. acdream offers something retail never did, and the API is documented
|
||
well enough that other people can build on it.
|
||
|
||
---
|
||
|
||
### M7 — "v1.0" — 🟢 (open-ended polish)
|
||
|
||
**Demo scenario:** Long-running stress test: log in, play for 4 hours
|
||
across outdoor + dungeon + portal + combat + spell + chat scenarios,
|
||
reconnect once mid-session, log out clean. No crashes, no protocol errors,
|
||
no visual regressions, no audio dropouts.
|
||
|
||
**Phases to ship:**
|
||
- **Phase M** — Network stack conformance (retransmit, ACK piggybacking,
|
||
echo/keepalive, fragment splitting, typed actions). Deferred until now
|
||
because ACE handles loss gracefully — but v1.0 needs proper network
|
||
hardening.
|
||
- **H.2** — Allegiance.
|
||
- **N.6 slice 2 + N.7–N.10** — Finish WB rendering migration (EnvCells,
|
||
sky/particles via WB, visibility manager, GL infrastructure
|
||
consolidation).
|
||
- **Phase J long-tail** — Player rig polish, group/fellowship UI, trade
|
||
window, salvage/tinker UI, house ownership, society UI, dev-mode tools.
|
||
- **L.1g** — Animation polish + conformance.
|
||
- Final visual + audio polish pass against ISSUES.md chronic backlog.
|
||
|
||
**What "M7 lands" looks like:** v1.0. Ship.
|
||
|
||
---
|
||
|
||
## Estimated timeline
|
||
|
||
| Milestone | Effort | Cumulative |
|
||
|---|---|---|
|
||
| M0 | DONE | DONE |
|
||
| M1 | ~4–6 wk | ~5 wk |
|
||
| M2 | ~6–10 wk | ~13 wk |
|
||
| M3 | ~3–4 wk | ~17 wk |
|
||
| M4 | ~6–10 wk | ~25 wk |
|
||
| M5 | ~4–8 wk (parallel) | overlaps M3/M4 |
|
||
| M6 | ~4 wk | ~29 wk |
|
||
| M7 | open-ended | v1.0 |
|
||
|
||
**Roughly 9–12 months of focused solo work from 2026-05-12 to v1.0.** That's
|
||
honest for an open-source project of this scale. The biggest single rock is
|
||
M2 (combat math + animations + inventory panels lining up); M5 can be
|
||
chipped at in parallel by subagents while you drive M3/M4.
|
||
|
||
---
|
||
|
||
## What this document is **not**
|
||
|
||
- **Not a release schedule.** Internal morale + scope layer only. If acdream
|
||
goes public-alpha at some point, that's a separate decision built on top
|
||
of one of these milestones.
|
||
- **Not immutable.** When reality and the milestones diverge, update the
|
||
milestones in the same session you discover the divergence. Same rule as
|
||
the roadmap.
|
||
- **Not a replacement for the roadmap.** Phases are still where the
|
||
implementation details live. This doc is the orientation layer above them.
|
||
- **Not granular enough for daily work.** Daily work happens at the phase /
|
||
sub-phase / commit level. The milestone is the multi-week target you're
|
||
aiming at.
|