docs(physics): Phase L.2 movement collision conformance plan
Formalize Phase L.2 as the active holistic movement/collision program, align the roadmap and architecture docs, file tactical physics follow-ups, and refresh collision memory away from rewrite-from-zero guidance. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
e44d24cec6
commit
d4c3f947d2
6 changed files with 689 additions and 242 deletions
135
docs/ISSUES.md
135
docs/ISSUES.md
|
|
@ -177,6 +177,141 @@ missing is the plugin-API surface.
|
|||
|
||||
---
|
||||
|
||||
## #30 — AutonomousPosition contact byte is too often grounded
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** HIGH
|
||||
**Filed:** 2026-04-29
|
||||
**Component:** physics / net / movement
|
||||
|
||||
**Description:** Outbound movement can claim grounded contact even when the
|
||||
local resolver result is uncertain or airborne. `AutonomousPosition.Build`
|
||||
defaults `lastContact` to 1, and the app path needs an audit to ensure
|
||||
`ResolveResult.IsOnGround` is what reaches the wire.
|
||||
|
||||
**Root cause / status:** Tracked under Phase L.2b. This can make ACE accept
|
||||
movement that is not actually retail-valid and can hide edge/step-down bugs.
|
||||
|
||||
**Files:** `src/AcDream.Core.Net/Messages/AutonomousPosition.cs`,
|
||||
`src/AcDream.Core.Net/Messages/MoveToState.cs`,
|
||||
`src/AcDream.App/Input/PlayerMovementController.cs`.
|
||||
|
||||
**Research:** `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
**Acceptance:** Ground contact byte is derived from the current resolved
|
||||
movement result for both autonomous heartbeat and movement-state sends. Tests
|
||||
cover grounded, airborne, and failed-transition cases.
|
||||
|
||||
---
|
||||
|
||||
## #31 — Low outdoor cell id can go stale after transition movement
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** HIGH
|
||||
**Filed:** 2026-04-29
|
||||
**Component:** physics / cells / movement
|
||||
|
||||
**Description:** Local movement can cross 24m outdoor cell boundaries while
|
||||
the low cell id used for outbound full cell id remains stale. This can combine
|
||||
correct landblock high bits with the wrong outdoor-cell low byte.
|
||||
|
||||
**Root cause / status:** Tracked under Phase L.2e. `CELLARRAY`,
|
||||
`CObjCell::find_cell_list`, adjacent-cell checks, and low-cell ownership are
|
||||
not fully ported.
|
||||
|
||||
**Files:** `src/AcDream.Core/Physics/PhysicsEngine.cs`,
|
||||
`src/AcDream.Core/Physics/TransitionTypes.cs`,
|
||||
`src/AcDream.App/Input/PlayerMovementController.cs`.
|
||||
|
||||
**Research:** `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
**Acceptance:** Crossing a 24m outdoor-cell seam updates the local resolved
|
||||
cell id and the outbound full cell id. Tests cover intra-landblock seams and
|
||||
landblock-edge seams.
|
||||
|
||||
---
|
||||
|
||||
## #32 — Retail edge-slide / cliff-slide / precipice-slide incomplete
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** HIGH
|
||||
**Filed:** 2026-04-29
|
||||
**Component:** physics / collision
|
||||
|
||||
**Description:** When walking along walls, roof edges, cliff edges, or failed
|
||||
step-down boundaries, retail often slides along the boundary. acdream still
|
||||
hard-blocks or accepts too much in several of these cases.
|
||||
|
||||
**Root cause / status:** Tracked under Phase L.2c. Named retail anchors include
|
||||
`CTransition::edge_slide`, `CTransition::cliff_slide`,
|
||||
`SPHEREPATH::precipice_slide`, and `SPHEREPATH::step_up_slide`.
|
||||
|
||||
**Files:** `src/AcDream.Core/Physics/TransitionTypes.cs`,
|
||||
`src/AcDream.Core/Physics/BSPQuery.cs`,
|
||||
`tests/AcDream.Core.Tests/`.
|
||||
|
||||
**Research:** `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
**Acceptance:** Synthetic and real-DAT tests cover wall-slide, roof-edge slide,
|
||||
cliff/precipice slide, failed step-up/step-down, and the jump-clears-edge case.
|
||||
|
||||
---
|
||||
|
||||
## #33 — Live entity collision shape collapses to one cylinder
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-04-29
|
||||
**Component:** physics / entities
|
||||
|
||||
**Description:** Live world entities do not yet use exact retail
|
||||
`CSphere` / `CCylSphere` shape semantics. Several paths collapse the entity to
|
||||
a simplified root-centered cylinder or fallback radius, which is not enough for
|
||||
retail object and creature collision parity.
|
||||
|
||||
**Root cause / status:** Tracked under Phase L.2d. Requires auditing object
|
||||
shape extraction, `Setup.Radius` fallback, building object identity, and live
|
||||
entity broadphase records against named retail.
|
||||
|
||||
**Files:** `src/AcDream.Core/Physics/CollisionPrimitives.cs`,
|
||||
`src/AcDream.Core/Physics/ShadowObjectRegistry.cs`,
|
||||
`src/AcDream.Core/Physics/PhysicsDataCache.cs`.
|
||||
|
||||
**Research:** `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
**Acceptance:** Live object collision uses the appropriate retail sphere or
|
||||
cylsphere data where available. Tests prove at least one multi-shape object and
|
||||
one live creature case no longer use the single-cylinder fallback.
|
||||
|
||||
---
|
||||
|
||||
## #34 — Missing routine local/server correction diagnostic
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-04-29
|
||||
**Component:** physics / net / diagnostics
|
||||
|
||||
**Description:** The client needs an opt-in diagnostic that logs local predicted
|
||||
position/contact/cell, outbound movement fields, server `UpdatePosition` echo,
|
||||
and correction delta. Current correction visibility is too focused on portal
|
||||
arrival and not enough on normal walking.
|
||||
|
||||
**Root cause / status:** Tracked under Phase L.2a/L.2b. Without this probe,
|
||||
ACE's tolerance can hide local collision divergence.
|
||||
|
||||
**Files:** `src/AcDream.Core.Net/WorldSession.cs`,
|
||||
`src/AcDream.App/Input/PlayerMovementController.cs`,
|
||||
`src/AcDream.App/Rendering/GameWindow.cs`.
|
||||
|
||||
**Research:** `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
**Acceptance:** With the diagnostic enabled, a walking session logs local
|
||||
resolved placement, outbound cell/contact fields, server echo placement, and
|
||||
correction delta in a grep-friendly format.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## #2 — Lightning visual mismatch (sky PES path disproved)
|
||||
|
||||
|
|
|
|||
|
|
@ -100,67 +100,129 @@ crib-sheet version.
|
|||
|
||||
---
|
||||
|
||||
## Project Structure (target)
|
||||
## Project Structure (current + target)
|
||||
|
||||
```
|
||||
src/
|
||||
AcDream.Core/ Layer 2-4: no GL, no Silk.NET, pure logic
|
||||
Physics/
|
||||
PhysicsBody.cs ← ported from decompiled (done)
|
||||
CollisionPrimitives.cs ← ported from decompiled (done)
|
||||
MotionInterpreter.cs ← ported from decompiled (done)
|
||||
AnimationSequencer.cs ← ported from decompiled (done)
|
||||
CellBsp.cs ← TODO: port from decompiled
|
||||
Transition.cs ← TODO: port from decompiled
|
||||
TerrainSurface.cs ← verified against ACME (done)
|
||||
PhysicsBody.cs -> body state / integration foundation (done)
|
||||
CollisionPrimitives.cs -> retail primitive helpers (partial, active)
|
||||
MotionInterpreter.cs -> motion state machine (done, still L.1 polish)
|
||||
AnimationSequencer.cs -> animation playback + root-motion data (done, L.1 active)
|
||||
TerrainSurface.cs -> triangle-aware terrain contact (done)
|
||||
BSPQuery.cs -> partial retail BSP dispatcher (active in L.2)
|
||||
TransitionTypes.cs -> SpherePath / CollisionInfo / transition helpers (active in L.2)
|
||||
PhysicsDataCache.cs -> GfxObj / Setup / CellStruct collision data (done, active)
|
||||
ShadowObjectRegistry.cs -> broadphase for nearby physics objects (active)
|
||||
PhysicsEngine.cs -> ResolveWithTransition active player path
|
||||
CellBsp.cs -> not a first-class runtime owner yet (L.2e)
|
||||
World/
|
||||
GameEntity.cs ← TODO: unified entity (replaces scattered state)
|
||||
WorldState.cs ← TODO: owns all entities
|
||||
CellTracker.cs ← TODO: per-entity cell management
|
||||
SceneryGenerator.cs ← verified against decompiled (done)
|
||||
LandblockLoader.cs ← done
|
||||
GameEntity.cs -> target unified entity, not current reality
|
||||
WorldState.cs -> target entity owner
|
||||
CellTracker.cs -> target per-entity cell management
|
||||
SceneryGenerator.cs -> verified against decompiled (done)
|
||||
LandblockLoader.cs -> done
|
||||
Terrain/
|
||||
LandblockMesh.cs ← verified against ACME (done)
|
||||
TerrainBlending.cs ← verified against ACME (done)
|
||||
LandblockMesh.cs -> verified against ACME (done)
|
||||
TerrainBlending.cs -> verified against ACME (done)
|
||||
Meshing/
|
||||
GfxObjMesh.cs ← cross-checked against ACME (done)
|
||||
SetupMesh.cs ← cross-checked (done)
|
||||
GfxObjMesh.cs -> cross-checked against ACME (done)
|
||||
SetupMesh.cs -> cross-checked (done)
|
||||
Textures/
|
||||
SurfaceDecoder.cs ← done
|
||||
SurfaceDecoder.cs -> done
|
||||
Dat/
|
||||
MotionResolver.cs ← done (move here from Meshing/)
|
||||
MotionResolver.cs -> done (target move from Meshing/)
|
||||
|
||||
AcDream.Core.Net/ Layer 2: networking
|
||||
WorldSession.cs ← done (wire-compatible with ACE)
|
||||
NetClient.cs ← done
|
||||
Messages/ ← done (CreateObject, MoveToState, etc.)
|
||||
WorldSession.cs -> done (wire-compatible with ACE)
|
||||
NetClient.cs -> done
|
||||
Messages/ -> done (CreateObject, MoveToState, etc.)
|
||||
|
||||
AcDream.Plugin.Abstractions/ Layer 5: plugin interfaces
|
||||
IAcDreamPlugin.cs ← done
|
||||
IPluginHost.cs ← done
|
||||
IGameState.cs ← done
|
||||
IEvents.cs ← done
|
||||
IAcDreamPlugin.cs -> done
|
||||
IPluginHost.cs -> done
|
||||
IGameState.cs -> done
|
||||
IEvents.cs -> done
|
||||
|
||||
AcDream.App/ Layer 1 + Layer 4 wiring
|
||||
Rendering/
|
||||
GameWindow.cs ← TODO: thin down to GL calls only
|
||||
TerrainRenderer.cs ← done
|
||||
StaticMeshRenderer.cs ← done
|
||||
TextureCache.cs ← done
|
||||
ChaseCamera.cs ← done
|
||||
FlyCamera.cs ← done
|
||||
GameWindow.cs -> still owns too much runtime wiring
|
||||
TerrainRenderer.cs -> done
|
||||
StaticMeshRenderer.cs -> done
|
||||
TextureCache.cs -> done
|
||||
ChaseCamera.cs -> done
|
||||
FlyCamera.cs -> done
|
||||
Streaming/
|
||||
StreamingController.cs ← done
|
||||
GpuWorldState.cs ← done
|
||||
StreamingController.cs -> done
|
||||
GpuWorldState.cs -> done
|
||||
Input/
|
||||
PlayerMovementController.cs ← done (uses ported physics)
|
||||
PlayerMovementController.cs -> active movement driver
|
||||
Plugins/
|
||||
AppPluginHost.cs ← done
|
||||
AppPluginHost.cs -> done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GameEntity: The Unified Entity (TODO — the big refactor)
|
||||
## Movement And Collision Architecture
|
||||
|
||||
Phase L.2 is the current organizing program for physics, collision,
|
||||
boundaries, buildings, sliding, cell ownership, movement packets, and server
|
||||
authority. Detailed plan: `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
The active player movement spine is:
|
||||
|
||||
```text
|
||||
InputDispatcher / PlayerMovementController
|
||||
-> MotionInterpreter + local body prediction
|
||||
-> PhysicsEngine.ResolveWithTransition
|
||||
-> TransitionTypes + BSPQuery + ShadowObjectRegistry
|
||||
-> ResolveResult contact/cell state
|
||||
-> MoveToState / AutonomousPosition outbound messages
|
||||
-> WorldSession server echo or correction handling
|
||||
```
|
||||
|
||||
What exists and is active:
|
||||
|
||||
- `PhysicsEngine.ResolveWithTransition` is the path used for local player
|
||||
collision resolution.
|
||||
- `BSPQuery` contains the partial retail-style BSP collision dispatcher used by
|
||||
the transition path.
|
||||
- `TransitionTypes` carries `SpherePath`, `CollisionInfo`, `ObjectInfo`,
|
||||
transition validation, step-up/down, contact-plane handling, and partial
|
||||
slide behavior.
|
||||
- `PhysicsDataCache` loads GfxObj, Setup, and CellStruct physics data from DATs.
|
||||
- `ShadowObjectRegistry` gives movement a broadphase over nearby objects and
|
||||
buildings.
|
||||
- `TerrainSurface` uses triangle-aware terrain contact; older "bilinear terrain
|
||||
Z" descriptions are historical B.3 language, not current architecture.
|
||||
|
||||
What remains incomplete:
|
||||
|
||||
- `CELLARRAY`, `CObjCell::find_cell_list`, adjacent-cell checks, and low outdoor
|
||||
cell id updates across 24m seams.
|
||||
- `cell_bsp` / `CellBSP` as the authoritative runtime owner for indoor and
|
||||
building collision.
|
||||
- Building portal transit and normal walking through building entry/exit
|
||||
boundaries.
|
||||
- Full retail `edge_slide`, `cliff_slide`, `precipice_slide`, and `NegPolyHit`
|
||||
dispatch behavior.
|
||||
- Exact `CSphere` / `CCylSphere` object-shape parity, especially for live
|
||||
entities that currently collapse to a simplified cylinder fallback.
|
||||
- Routine local/server correction diagnostics. ACE accepting a position is a
|
||||
compatibility signal, not proof of fine retail collision parity.
|
||||
|
||||
Ownership by phase:
|
||||
|
||||
- B.3 is shipped MVP history: first resolver foundation and tests.
|
||||
- L.1 owns animation/motion parity, including root-motion coupling.
|
||||
- L.2 owns the movement/collision conformance stack listed above.
|
||||
- G.3 owns dungeon streaming and portal-space delivery after L.2e gives it
|
||||
trustworthy cell/building boundaries.
|
||||
|
||||
---
|
||||
|
||||
## GameEntity: The Unified Entity (target refactor)
|
||||
|
||||
Currently, entity state is scattered across:
|
||||
- `WorldEntity` (position, rotation, mesh refs)
|
||||
|
|
@ -198,21 +260,21 @@ public sealed class GameEntity
|
|||
{
|
||||
Motion.ApplyCurrentMovement(); // set velocity from motion state
|
||||
Physics.UpdateObject(dt); // integrate position
|
||||
// TODO: Transition.FindValidPosition // collision resolve
|
||||
Cell.UpdateCell(Physics.Position); // check cell transitions
|
||||
PhysicsEngine.ResolveWithTransition(); // current L.2 collision spine
|
||||
Cell.UpdateCell(Physics.Position); // target: retail cell ownership
|
||||
Animation.Advance(dt); // advance animation frames
|
||||
RebuildMeshRefs(); // compute per-part transforms
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Every entity in the world — player, NPC, monster, lifestone, door, chest —
|
||||
is a `GameEntity`. The renderer iterates them and draws. The plugin API
|
||||
exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
||||
Target state: every entity in the world — player, NPC, monster, lifestone,
|
||||
door, chest — becomes a `GameEntity`. The renderer iterates them and draws.
|
||||
The plugin API exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
||||
|
||||
---
|
||||
|
||||
## Per-Frame Update Order (matches retail)
|
||||
## Per-Frame Update Order (current runtime)
|
||||
|
||||
```
|
||||
1. Network tick
|
||||
|
|
@ -224,15 +286,16 @@ exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
|||
create terrain + scenery GameEntities
|
||||
|
||||
3. Input tick (player mode only)
|
||||
└── Read WASD/mouse → MotionInterpreter.DoMotion →
|
||||
└── InputDispatcher scopes → PlayerMovementController →
|
||||
MotionInterpreter/body prediction → ResolveWithTransition →
|
||||
send MoveToState/AutonomousPosition to server
|
||||
|
||||
4. Entity tick (ALL entities, 30Hz fixed step)
|
||||
└── For each GameEntity: entity.Update(dt)
|
||||
This runs: motion → physics → collision → cell → animation
|
||||
4. Entity / animation tick
|
||||
└── Current code still has scattered world/entity state. L.1 owns
|
||||
animation parity; L.2 owns movement/collision conformance.
|
||||
|
||||
5. Render tick
|
||||
└── For each GameEntity: read MeshRefs, draw
|
||||
└── Read current entity mesh refs, draw
|
||||
TerrainRenderer.Draw, StaticMeshRenderer.Draw
|
||||
(frustum cull, translucency pass, etc.)
|
||||
|
||||
|
|
@ -248,89 +311,26 @@ exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
|||
|
||||
---
|
||||
|
||||
## Execution Plan: How to Get There
|
||||
## Roadmap Model
|
||||
|
||||
### Phase R1: GameEntity Refactor (the foundation)
|
||||
**Goal:** Replace the scattered entity state with unified GameEntity.
|
||||
The old R1-R8 architecture sequence was a useful early refactor sketch, but it
|
||||
is no longer the execution plan. The strategic source of truth is now
|
||||
`docs/plans/2026-04-11-roadmap.md`, with per-phase details in `docs/plans/`
|
||||
and `docs/superpowers/specs/`.
|
||||
|
||||
1. Create `GameEntity` class in `AcDream.Core/World/`
|
||||
2. Move `AnimatedEntity` fields into `GameEntity.Animation`
|
||||
3. Move `WorldEntity` fields into `GameEntity.Physics` + position
|
||||
4. Move `_entitiesByServerGuid` into `WorldState`
|
||||
5. Move animation tick from `GameWindow.TickAnimations` into `GameEntity.Update`
|
||||
6. GameWindow.OnRender reads `GameEntity.MeshRefs` instead of `WorldEntity.MeshRefs`
|
||||
Current movement/collision ownership:
|
||||
|
||||
**Test:** Everything looks the same as before. No visual change.
|
||||
- **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:
|
||||
`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.
|
||||
|
||||
### Phase R2: Thin GameWindow
|
||||
**Goal:** GameWindow does only GL calls + input dispatch.
|
||||
|
||||
1. Extract entity creation from `OnLiveEntitySpawned` into `WorldState.SpawnEntity`
|
||||
2. Extract motion updates from `OnLiveMotionUpdated` into `WorldState.UpdateMotion`
|
||||
3. Extract player movement from the giant OnUpdate block into `PlayerController`
|
||||
4. GameWindow.OnUpdate calls: network.Tick → streaming.Tick → input.Tick → worldState.Tick → render
|
||||
|
||||
**Test:** Everything works the same. GameWindow.cs drops from 2000+ to ~500 lines.
|
||||
|
||||
### Phase R3: CellBSP + Wall Collision
|
||||
**Goal:** Entities can't walk through walls.
|
||||
|
||||
1. Port CellBSP from decompiled code (sphere_intersects_cell)
|
||||
2. Port Transition.FindValidPosition (swept sphere collision)
|
||||
3. Wire into GameEntity.Update between physics and cell tracking
|
||||
4. Indoor transitions become correct (wall stops you, doorway lets you through)
|
||||
|
||||
**Test:** Walk into building wall → stopped. Walk through doorway → enter.
|
||||
|
||||
### Phase R4: Complete Animation State Machine
|
||||
**Goal:** Every animation works for every entity type.
|
||||
|
||||
1. Port full MotionInterp.PerformMovement from decompiled (all 5 movement types)
|
||||
2. Port Links table resolution for smooth transitions
|
||||
3. Port idle modifiers (fidgets)
|
||||
4. Jump animation (wire jump motion command through the pipeline)
|
||||
|
||||
**Test:** All entity types animate correctly. Transitions are smooth.
|
||||
|
||||
### Phase R5: Lighting from Retail
|
||||
**Goal:** Sun, ambient, per-vertex lighting match retail.
|
||||
|
||||
1. Port AdjustPlanes (FUN_00532440) — face normals + per-vertex lighting
|
||||
2. Extract global lighting constants from decompiled DAT addresses
|
||||
3. Replace hardcoded shader constants with ported values
|
||||
|
||||
**Test:** Side-by-side with retail client shows matching lighting.
|
||||
|
||||
### Phase R6: Server Compliance
|
||||
**Goal:** ACE accepts all movement, no rubber-banding.
|
||||
|
||||
1. Server-authoritative Z (trust server position, local is cosmetic)
|
||||
2. Proper MoveToState with full RawMotionState packing
|
||||
3. Keepalive ping (5s idle)
|
||||
4. Graceful session management
|
||||
|
||||
**Test:** Walk around, other clients see smooth movement. No ACE errors.
|
||||
|
||||
### Phase R7: Interaction
|
||||
**Goal:** Click NPCs, open doors, pick up items, chat.
|
||||
|
||||
1. Use/UseWithTarget game actions
|
||||
2. Door open animation (server sends UpdateMotion → animate)
|
||||
3. Chat send/receive
|
||||
4. Basic inventory (pickup/drop)
|
||||
|
||||
**Test:** Open a door, talk to an NPC, send a chat message.
|
||||
|
||||
### Phase R8: Plugin API Completion
|
||||
**Goal:** Plugins can observe and control everything.
|
||||
|
||||
1. IGameState exposes all GameEntity fields
|
||||
2. IEvents fires for all world changes
|
||||
3. IActions covers: Move, Cast, Use, Say, Pickup, Drop
|
||||
4. IPacketPipeline hooks all 4 stages
|
||||
5. Lua macro engine (MoonSharp) ships as a built-in plugin
|
||||
|
||||
**Test:** A Lua script auto-loots gems. A C# plugin displays an overlay.
|
||||
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
|
||||
for new work; add or update roadmap phases instead.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -339,11 +339,12 @@ exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
|||
```
|
||||
For every AC-specific behavior:
|
||||
|
||||
1. DECOMPILE → Find the function in docs/research/decompiled/
|
||||
2. CROSS-CHECK → Verify against ACE + ACME + holtburger
|
||||
0. GREP NAMED → Search docs/research/named-retail/ by class::method
|
||||
1. FALLBACK → Use older docs/research/decompiled/ chunks only if needed
|
||||
2. CROSS-CHECK → Verify against ACE + ACME + holtburger where relevant
|
||||
3. PSEUDOCODE → Translate to readable pseudocode
|
||||
4. PORT → Faithful C# translation
|
||||
5. TEST → Conformance test against decompiled golden values
|
||||
5. TEST → Conformance test against retail/decomp golden values
|
||||
6. INTEGRATE → Surgical wiring into the existing system
|
||||
7. VERIFY → Visual + functional test
|
||||
```
|
||||
|
|
@ -359,9 +360,9 @@ For acdream-specific code (renderer, plugin API, streaming):
|
|||
|
||||
| Domain | Primary Oracle | Secondary |
|
||||
|--------|---------------|-----------|
|
||||
| Physics/collision | Decompiled acclient.exe | ACE Physics/ |
|
||||
| Animation | Decompiled + ACE Animation/ | — |
|
||||
| Terrain | ACME ClientReference.cs | Decompiled |
|
||||
| Physics/collision | `docs/research/named-retail/` | ACE Physics/ + older decompiled chunks |
|
||||
| Animation | `docs/research/named-retail/` + ACE Animation/ | — |
|
||||
| Terrain | ACME ClientReference.cs | named retail / older decompiled chunks |
|
||||
| Rendering | WorldBuilder (Silk.NET) | ACViewer |
|
||||
| Protocol | holtburger | AC2D |
|
||||
| Server behavior | ACE | — |
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# acdream — strategic roadmap
|
||||
|
||||
**Status:** Living document. Updated 2026-04-11 after Phase 6, 7.1, 9.1, 9.2 landed.
|
||||
**Status:** Living document. Updated 2026-04-29 for Phase L.2 movement/collision conformance planning.
|
||||
**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.
|
||||
|
||||
---
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
| A.1 | Streaming landblock loader — runtime-configurable visible window (default 5×5, `ACDREAM_STREAM_RADIUS`), camera-centered offline / player-centered live, hysteresis-based unloads, pending-spawn list for late CreateObject events | Live ✓ |
|
||||
| A.2 | Frustum culling — per-landblock AABB test (Gribb-Hartmann), terrain + static-mesh renderers skip culled landblocks, perf overlay in window title | Visual ✓ |
|
||||
| A.3 | Background net receive thread — dedicated daemon thread buffers UDP into Channel, render thread drains | Visual ✓ |
|
||||
| B.3 | Physics collision engine — TerrainSurface (heightmap Z), CellSurface (indoor floor polygon projection), PhysicsEngine (resolver with step-height + cell transitions). Populated from streaming pipeline. | Tests ✓ |
|
||||
| B.3 | Physics MVP resolver foundation — terrain contact, CellSurface prototype, streaming-populated collision inputs, and first `PhysicsEngine` resolver path. Not the complete retail collision system. | Tests ✓ |
|
||||
| B.2 | Player movement mode — Tab-toggled WASD ground walking, walk/run/idle animations, third-person chase camera, MoveToState + AutonomousPosition outbound, portal entry. Outdoor-only MVP. | Live ✓ |
|
||||
| D.1 | 2D ortho overlay + font rendering (StbTrueTypeSharp atlas + TextRenderer + DebugOverlay) | Visual ✓ |
|
||||
| E.1 | Motion-hook expansion — AnimationSequencer fires all 27 hook types per crossed frame; PosFrames root motion + vel/omega exposure; IAnimationHookSink + AnimationHookRouter fan-out | Tests ✓ |
|
||||
|
|
@ -94,7 +94,7 @@ Plus polish that doesn't get its own phase number:
|
|||
**Sub-pieces:**
|
||||
- **✓ SHIPPED — B.1 — Outbound ack pump.** Shipped as Phase 4.9 — per-packet ACK_SEQUENCE, not periodic. Server no longer drops idle clients.
|
||||
- **✓ SHIPPED — B.2 — Player movement mode.** Tab-toggled WASD ground walking with collision-resolved outdoor terrain, walk/run/idle/turn-right animations, third-person chase camera, outbound MoveToState (0xF61C) + AutonomousPosition (0xF753) server messages, portal entry works. Outdoor→indoor transition disabled for MVP (CellSurface floor polygons too aggressive without portal-based detection). Minor polish remaining: strafe animation, turn-left animation. Spec: `docs/superpowers/specs/2026-04-12-player-movement-design.md`.
|
||||
- **✓ SHIPPED — B.3 — Physics collision engine.** TerrainSurface (heightmap bilinear Z), CellSurface (indoor floor polygon projection via barycentric interpolation), PhysicsEngine (top-level resolver with step-height enforcement, outdoor↔indoor cell transitions, gravity reporting). Populated from streaming pipeline. 16 unit tests with fake data. Spec: `docs/superpowers/specs/2026-04-12-physics-collision-engine-design.md`.
|
||||
- **✓ SHIPPED — B.3 — Physics MVP resolver foundation.** Terrain contact, CellSurface prototype, streaming-populated collision inputs, and first `PhysicsEngine` resolver path. This shipped enough foundation for outdoor walking and early portal experiments, but it is not the complete retail collision system. Current conformance work lives under **Phase L.2 — Movement & Collision Conformance**. Spec history: `docs/superpowers/specs/2026-04-12-physics-collision-engine-design.md`.
|
||||
- **B.4 — `Use` / `UseWithTarget` / `PickUp`.** Outbound interaction messages. Drives opening doors, looting, talking to vendors.
|
||||
- **B.5 — Chat.** `SendTell`, `SendChat` outbound + receive/display inbound (display side depends on Phase D.1).
|
||||
|
||||
|
|
@ -204,7 +204,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.
|
||||
- **G.3 — Dungeon streaming + portal space.** `EnvCellStreamer`, portal-visibility BFS, `PlayerTeleport (0xF751)` handling with `LoginComplete` re-send, "pink bubble" loading state. See `r09-dungeon-portal-space.md`.
|
||||
- **G.3 — Dungeon streaming + portal space.** `EnvCellStreamer`, portal-visibility BFS, `PlayerTeleport (0xF751)` handling with `LoginComplete` re-send, "pink bubble" loading state. **Blocked on L.2e** for trustworthy `cell_bsp`, indoor/outdoor portal transit, adjacent-cell ownership, and building entry/exit collision boundaries. See `r09-dungeon-portal-space.md`.
|
||||
|
||||
**Acceptance:** walk outside at dusk, see the sky gradient + sun moving; enter a torch-lit dungeon via portal; leave back to daylight.
|
||||
|
||||
|
|
@ -318,6 +318,11 @@ queues, speed scaling, and PosFrame root motion.
|
|||
|
||||
**Plan of record:** `docs/plans/animation-system-audit.md`.
|
||||
|
||||
**Coupling to L.2:** L.1 owns animation/motion parity. L.2 owns collision,
|
||||
contact truth, movement packets, and server-visible placement. They meet where
|
||||
root motion or observer movement changes the predicted body path; any such
|
||||
change must keep both phase plans in sync.
|
||||
|
||||
**Sub-pieces:**
|
||||
- **L.1a — Audit & inventory.** Map retail named-decomp evidence, ACE
|
||||
cross-references, existing acdream hook points, and current gaps for each
|
||||
|
|
@ -349,6 +354,55 @@ queues, speed scaling, and PosFrame root motion.
|
|||
|
||||
---
|
||||
|
||||
### Phase L.2 — Movement & Collision Conformance
|
||||
|
||||
**Status:** ACTIVE.
|
||||
|
||||
**Goal:** make acdream's movement and collision behavior retail-faithful across
|
||||
terrain, buildings, walls, roof edges, cell seams, portal boundaries, outbound
|
||||
movement packets, and server correction. This is the holistic bucket for the
|
||||
work previously scattered across B.3 physics follow-ups, L.1 motion coupling,
|
||||
and G.3 dungeon/portal ownership.
|
||||
|
||||
**Plan of record:** `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||
|
||||
**Current foundation:** `PhysicsEngine.ResolveWithTransition`,
|
||||
`BSPQuery`, `TransitionTypes`, `PhysicsDataCache`, and
|
||||
`ShadowObjectRegistry` exist and are active. They are partial retail ports and
|
||||
diagnostic scaffolding, not yet the final collision system.
|
||||
|
||||
**Sub-lanes:**
|
||||
- **L.2a — Truth & diagnostics.** Local placement/contact/cell logs, object-hit
|
||||
probes, correction-delta diagnostics, retail-observer capture workflow, and
|
||||
real-DAT fixture capture.
|
||||
- **L.2b — Movement wire/contact authority.** Fix outbound contact truth,
|
||||
full-cell id handling, packet cadence, and routine server correction handling.
|
||||
- **L.2c — Transition parity: edge/slide/neg-poly.** Port and test retail
|
||||
`edge_slide`, `cliff_slide`, `precipice_slide`, step-up/down slide, and
|
||||
`NegPolyHit` dispatch behavior.
|
||||
- **L.2d — Shape fidelity: sphere/cylsphere/building objects.** Finish
|
||||
`CSphere` / `CCylSphere` parity, live-entity object shapes, building object
|
||||
collision identity, and `Setup.Radius` fallback audit.
|
||||
- **L.2e — Cell ownership: outdoor seams, `CELLARRAY`, `cell_bsp`.** Update
|
||||
low outdoor cell id across 24m seams, port adjacent-cell checks, activate
|
||||
`cell_bsp`, and hand G.3 a trustworthy building/portal boundary model.
|
||||
- **L.2f — Real-DAT and live retail-observer conformance.** Promote synthetic
|
||||
tests to real-world fixtures and verify local acdream view plus retail
|
||||
observer view. ACE accepting a position is a compatibility check, not proof
|
||||
of fine-grained retail collision parity.
|
||||
|
||||
**Acceptance:**
|
||||
- A developer can trace the active movement path: input/motion -> body
|
||||
prediction -> `ResolveWithTransition` -> contact/cell result -> outbound
|
||||
packets -> server echo/correction.
|
||||
- Buildings, edge-slide, wall-slide, cell seams, packet authority, and dungeon
|
||||
portal ownership each have an L.2 lane.
|
||||
- Every AC-specific algorithm port cites named retail decomp, or a documented
|
||||
fallback when named retail lacks the body.
|
||||
- `dotnet build` and `dotnet test` are green for each implementation slice.
|
||||
|
||||
---
|
||||
|
||||
### Phase J — Long-tail (deferred / low-priority)
|
||||
|
||||
Not detailed here; each gets its own brainstorm when it becomes relevant.
|
||||
|
|
@ -431,7 +485,10 @@ port in any phase — no separate listing here.
|
|||
| 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) |
|
||||
| Walking around doesn't move me on the server | **Phase B.3 FIXED** ✓ |
|
||||
| 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** |
|
||||
| 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) |
|
||||
|
|
@ -444,7 +501,7 @@ port in any phase — no separate listing here.
|
|||
| 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** |
|
||||
| Dungeons / foundry interior missing | **Phase G.3** after **L.2e** cell/building ownership |
|
||||
| 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** |
|
||||
|
|
|
|||
208
docs/plans/2026-04-29-movement-collision-conformance.md
Normal file
208
docs/plans/2026-04-29-movement-collision-conformance.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# Phase L.2 - Movement & Collision Conformance
|
||||
|
||||
**Status:** ACTIVE planning document, created 2026-04-29.
|
||||
**Roadmap owner:** Phase L.2 in `docs/plans/2026-04-11-roadmap.md`.
|
||||
**Scope:** player movement prediction, retail collision/transition behavior,
|
||||
building boundaries, edge and wall sliding, cell ownership, outbound movement
|
||||
packets, and server-correction diagnostics.
|
||||
|
||||
## Purpose
|
||||
|
||||
Phase B.3 shipped the first usable physics foundation: terrain contact,
|
||||
basic resolver behavior, streaming-populated collision inputs, and enough
|
||||
movement wire support to walk on ACE. That was not the complete retail
|
||||
collision system.
|
||||
|
||||
Phase L.2 is the conformance program that turns that foundation into a
|
||||
retail-faithful movement stack. It is the single organizing bucket for work
|
||||
that otherwise looks scattered across B.3 physics, L.1 animation/motion, and
|
||||
G.3 dungeon/portal space.
|
||||
|
||||
The active movement spine is:
|
||||
|
||||
```text
|
||||
input + motion command
|
||||
-> local body prediction / root-motion source
|
||||
-> PhysicsEngine.ResolveWithTransition
|
||||
-> TransitionTypes + BSPQuery + ShadowObjectRegistry contact/cell result
|
||||
-> MoveToState / AutonomousPosition outbound packets
|
||||
-> server echo or correction diagnostics
|
||||
```
|
||||
|
||||
Live ACE accepting a position, or the absence of visible rubber-banding, is
|
||||
not proof of retail collision parity. ACE can tolerate coarse or locally
|
||||
invalid fine-grained movement. L.2 therefore requires retail-decomp evidence,
|
||||
synthetic conformance tests, real-DAT fixtures, and live retail-observer checks.
|
||||
|
||||
## Current Foundation
|
||||
|
||||
Already active in acdream:
|
||||
|
||||
- `PhysicsEngine.ResolveWithTransition` is the local player collision path.
|
||||
- `BSPQuery` contains a partial retail-style BSP dispatcher and step/contact
|
||||
logic.
|
||||
- `TransitionTypes` carries `SpherePath`, `CollisionInfo`, `ObjectInfo`,
|
||||
transition validation, step-up/down, and partial slide behavior.
|
||||
- `PhysicsDataCache` loads GfxObj, Setup, and CellStruct physics data from DATs.
|
||||
- `ShadowObjectRegistry` gives the resolver a broadphase over nearby world
|
||||
objects.
|
||||
- `TerrainSurface` uses triangle-aware terrain sampling rather than the older
|
||||
bilinear placeholder.
|
||||
|
||||
Known incomplete areas:
|
||||
|
||||
- Full `CELLARRAY` ownership and `CObjCell::find_cell_list` / adjacent-cell
|
||||
checks are not ported.
|
||||
- `cell_bsp` / `CellBSP` is not fully represented as a first-class runtime
|
||||
owner.
|
||||
- Building entry/exit and indoor/outdoor portal transit are not solved by the
|
||||
normal walking path.
|
||||
- Retail `edge_slide`, `cliff_slide`, and `precipice_slide` behavior is
|
||||
incomplete; failed edge/step-down cases often hard-block instead of sliding.
|
||||
- `NegPolyHit` handling is a stub relative to the retail transition dispatch.
|
||||
- Live entities collapse to a simplified cylinder shape; exact retail
|
||||
sphere/cylsphere and object-shape behavior is not yet matched.
|
||||
- Outbound contact/cell fields can be too optimistic, so server agreement does
|
||||
not necessarily mean local conformance.
|
||||
|
||||
## Lane Model
|
||||
|
||||
L.2 uses five working lanes. The roadmap breaks them into six sub-lanes because
|
||||
real-DAT and live verification spans every lane.
|
||||
|
||||
| Lane | Owns | Roadmap slice |
|
||||
|---|---|---|
|
||||
| Diagnostics | Truth probes, dump flags, server-correction logging, retail observer harness | L.2a, L.2f |
|
||||
| Transition parity | `FindTransitionalPosition`, step-up/down, edge-slide, cliff-slide, precipice-slide, `NegPolyHit` dispatch | L.2c |
|
||||
| Geometry fidelity | `CSphere`, `CCylSphere`, object shape extraction, building object collision, walkable polygon context | L.2d |
|
||||
| Cell/building ownership | outdoor cell seams, low-cell id updates, `CELLARRAY`, `cell_bsp`, building entry/exit | L.2e |
|
||||
| Movement/network authority | contact byte, full cell id, MoveToState / AutonomousPosition cadence, root motion vs velocity prediction, correction response | L.2b, L.2f |
|
||||
|
||||
## Roadmap Slices
|
||||
|
||||
### L.2a - Truth & Diagnostics
|
||||
|
||||
Goal: make every bad movement outcome explainable.
|
||||
|
||||
- Add targeted diagnostics for local placement, contact plane, object hit,
|
||||
water, cell id, outbound packet fields, server echo, and correction delta.
|
||||
- Keep diagnostics opt-in via env vars and devtools panels.
|
||||
- Record enough data for side-by-side retail-observer runs without drowning
|
||||
normal logs.
|
||||
- Build real-DAT fixture capture for known walls, building ledges, rooftops,
|
||||
slopes, landblock seams, and dungeon entrances.
|
||||
|
||||
### L.2b - Movement Wire / Contact Authority
|
||||
|
||||
Goal: stop sending movement packets that claim more certainty than the local
|
||||
resolver has earned.
|
||||
|
||||
- Fix outbound contact state so `AutonomousPosition` and `MoveToState` do not
|
||||
always claim grounded contact.
|
||||
- Track local result cell id and outbound full cell id separately from the last
|
||||
server placement until correction proves they agree.
|
||||
- Reconcile packet cadence with retail/holtburger references.
|
||||
- Wire routine server correction handling and diagnostics, not only portal
|
||||
reseating.
|
||||
|
||||
### L.2c - Transition Parity: Edge / Slide / Neg-Poly
|
||||
|
||||
Goal: match retail movement at walls, roof edges, step boundaries, and
|
||||
precipices.
|
||||
|
||||
- Port and test `edge_slide`, `cliff_slide`, `precipice_slide`, and
|
||||
`step_up_slide` behavior from named retail.
|
||||
- Preserve walkable polygon context needed for precipice/edge decisions.
|
||||
- Replace `NegPolyHit` stub behavior with the retail dispatch path.
|
||||
- Confirm the user-visible rule: walk-only motion is blocked by step,
|
||||
edge, walkable, and collision rules; jumping clears `OnWalkable` and only
|
||||
succeeds when the airborne path actually clears geometry.
|
||||
|
||||
### L.2d - Shape Fidelity: Sphere / CylSphere / Building Objects
|
||||
|
||||
Goal: object collisions use retail shape semantics, not one simplified
|
||||
fallback.
|
||||
|
||||
- Finish `CSphere` / `CCylSphere` parity for static and live objects.
|
||||
- Stop treating all live entities as one root-centered cylinder.
|
||||
- Preserve enough building identity to model `CBuildingObj` collision and
|
||||
`bldg_check` behavior.
|
||||
- Audit `Setup.Radius` and cylinder fallback behavior against retail before
|
||||
relying on them for conformance.
|
||||
|
||||
### L.2e - Cell Ownership: Outdoor Seams, CELLARRAY, cell_bsp
|
||||
|
||||
Goal: the resolver knows which cell owns the movement and which adjacent cells
|
||||
must be checked.
|
||||
|
||||
- Update low outdoor cell id across 24m cell boundaries and landblock seams.
|
||||
- Port the retail adjacent-cell search: `find_cell_list`, `check_other_cells`,
|
||||
and `adjust_check_pos`.
|
||||
- Promote `cell_bsp` / `CellBSP` from partial data to active runtime owner.
|
||||
- Hand G.3 a trustworthy building/portal boundary so dungeon streaming is not
|
||||
asked to solve collision ownership after the fact.
|
||||
|
||||
### L.2f - Real-DAT and Live Retail-Observer Conformance
|
||||
|
||||
Goal: prove the stack against real terrain/building/cell data and what a retail
|
||||
client sees when observing acdream.
|
||||
|
||||
- Add real-DAT fixtures for representative movement cases.
|
||||
- Use retail client observer runs to verify motion packets, animation/movement
|
||||
coupling, and server-visible placement.
|
||||
- Treat ACE acceptance as a coarse compatibility check only.
|
||||
- Require conformance notes in tests or research docs for every AC-specific
|
||||
algorithm ported under L.2.
|
||||
|
||||
## Named Retail Anchors
|
||||
|
||||
Primary source: `docs/research/named-retail/acclient_2013_pseudo_c.txt`.
|
||||
Struct source: `docs/research/named-retail/acclient.h`.
|
||||
Address lookup: `docs/research/named-retail/symbols.json`.
|
||||
|
||||
Use these names before falling back to older `docs/research/decompiled/`
|
||||
chunks:
|
||||
|
||||
- `CTransition::find_transitional_position` - `0x0050BDF0`
|
||||
- `CTransition::transitional_insert` - `0x0050B6F0`
|
||||
- `CTransition::step_up` - `0x0050B610`
|
||||
- `CTransition::step_down` - `0x0050B2A0`
|
||||
- `CTransition::edge_slide` - `0x0050B3D0`
|
||||
- `CTransition::cliff_slide` - `0x0050A6D0`
|
||||
- `SPHEREPATH::step_up_slide` - `0x0050C3B0`
|
||||
- `SPHEREPATH::precipice_slide` - `0x0050CC80`
|
||||
- `SPHEREPATH::adjust_check_pos` - `0x0050CC00`
|
||||
- `CTransition::adjust_offset` - `0x0050A370`
|
||||
- `CTransition::check_other_cells` - `0x0050AE50`
|
||||
- `CPhysicsObj::is_valid_walkable` - `0x0050F530`
|
||||
- `CObjCell::find_cell_list` - `0x0052B4E0`
|
||||
- `CBuildingObj::find_building_collisions`
|
||||
- `CCellStruct::point_in_cell`
|
||||
- `CCellStruct::sphere_intersects_cell`
|
||||
- `CCellStruct::box_intersects_cell`
|
||||
- `CCylSphere::intersects_sphere`
|
||||
- `CSphere::intersects_sphere`
|
||||
- `CSphere::slide_sphere`
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. Land L.2a diagnostics first. Do not make another physics change blind.
|
||||
2. Fix L.2b packet/contact truth so logs and server echoes describe reality.
|
||||
3. Port L.2c transition parity in narrow slices with named-retail citations and
|
||||
conformance tests.
|
||||
4. Improve L.2d shape fidelity where transition parity depends on object
|
||||
contact semantics.
|
||||
5. Land L.2e cell/building ownership before G.3 dungeon/portal work relies on
|
||||
indoor/outdoor walking.
|
||||
6. Promote each synthetic case to L.2f real-DAT and live observer coverage.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- A developer can name the active movement path and the current incomplete
|
||||
pieces without reading old chat logs.
|
||||
- `dotnet build` and `dotnet test` stay green for each implementation slice.
|
||||
- Every AC-specific port cites named retail decomp or a documented fallback.
|
||||
- Real-DAT fixtures cover buildings, walls, roof edges, outdoor seams, and at
|
||||
least one dungeon/building entrance path before L.2 is marked shipped.
|
||||
- Retail observer view and acdream local view both agree on contact, position,
|
||||
and movement state for the representative cases.
|
||||
Loading…
Add table
Add a link
Reference in a new issue