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)
|
## #2 — Lightning visual mismatch (sky PES path disproved)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,67 +100,129 @@ crib-sheet version.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Project Structure (target)
|
## Project Structure (current + target)
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
AcDream.Core/ Layer 2-4: no GL, no Silk.NET, pure logic
|
AcDream.Core/ Layer 2-4: no GL, no Silk.NET, pure logic
|
||||||
Physics/
|
Physics/
|
||||||
PhysicsBody.cs ← ported from decompiled (done)
|
PhysicsBody.cs -> body state / integration foundation (done)
|
||||||
CollisionPrimitives.cs ← ported from decompiled (done)
|
CollisionPrimitives.cs -> retail primitive helpers (partial, active)
|
||||||
MotionInterpreter.cs ← ported from decompiled (done)
|
MotionInterpreter.cs -> motion state machine (done, still L.1 polish)
|
||||||
AnimationSequencer.cs ← ported from decompiled (done)
|
AnimationSequencer.cs -> animation playback + root-motion data (done, L.1 active)
|
||||||
CellBsp.cs ← TODO: port from decompiled
|
TerrainSurface.cs -> triangle-aware terrain contact (done)
|
||||||
Transition.cs ← TODO: port from decompiled
|
BSPQuery.cs -> partial retail BSP dispatcher (active in L.2)
|
||||||
TerrainSurface.cs ← verified against ACME (done)
|
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/
|
World/
|
||||||
GameEntity.cs ← TODO: unified entity (replaces scattered state)
|
GameEntity.cs -> target unified entity, not current reality
|
||||||
WorldState.cs ← TODO: owns all entities
|
WorldState.cs -> target entity owner
|
||||||
CellTracker.cs ← TODO: per-entity cell management
|
CellTracker.cs -> target per-entity cell management
|
||||||
SceneryGenerator.cs ← verified against decompiled (done)
|
SceneryGenerator.cs -> verified against decompiled (done)
|
||||||
LandblockLoader.cs ← done
|
LandblockLoader.cs -> done
|
||||||
Terrain/
|
Terrain/
|
||||||
LandblockMesh.cs ← verified against ACME (done)
|
LandblockMesh.cs -> verified against ACME (done)
|
||||||
TerrainBlending.cs ← verified against ACME (done)
|
TerrainBlending.cs -> verified against ACME (done)
|
||||||
Meshing/
|
Meshing/
|
||||||
GfxObjMesh.cs ← cross-checked against ACME (done)
|
GfxObjMesh.cs -> cross-checked against ACME (done)
|
||||||
SetupMesh.cs ← cross-checked (done)
|
SetupMesh.cs -> cross-checked (done)
|
||||||
Textures/
|
Textures/
|
||||||
SurfaceDecoder.cs ← done
|
SurfaceDecoder.cs -> done
|
||||||
Dat/
|
Dat/
|
||||||
MotionResolver.cs ← done (move here from Meshing/)
|
MotionResolver.cs -> done (target move from Meshing/)
|
||||||
|
|
||||||
AcDream.Core.Net/ Layer 2: networking
|
AcDream.Core.Net/ Layer 2: networking
|
||||||
WorldSession.cs ← done (wire-compatible with ACE)
|
WorldSession.cs -> done (wire-compatible with ACE)
|
||||||
NetClient.cs ← done
|
NetClient.cs -> done
|
||||||
Messages/ ← done (CreateObject, MoveToState, etc.)
|
Messages/ -> done (CreateObject, MoveToState, etc.)
|
||||||
|
|
||||||
AcDream.Plugin.Abstractions/ Layer 5: plugin interfaces
|
AcDream.Plugin.Abstractions/ Layer 5: plugin interfaces
|
||||||
IAcDreamPlugin.cs ← done
|
IAcDreamPlugin.cs -> done
|
||||||
IPluginHost.cs ← done
|
IPluginHost.cs -> done
|
||||||
IGameState.cs ← done
|
IGameState.cs -> done
|
||||||
IEvents.cs ← done
|
IEvents.cs -> done
|
||||||
|
|
||||||
AcDream.App/ Layer 1 + Layer 4 wiring
|
AcDream.App/ Layer 1 + Layer 4 wiring
|
||||||
Rendering/
|
Rendering/
|
||||||
GameWindow.cs ← TODO: thin down to GL calls only
|
GameWindow.cs -> still owns too much runtime wiring
|
||||||
TerrainRenderer.cs ← done
|
TerrainRenderer.cs -> done
|
||||||
StaticMeshRenderer.cs ← done
|
StaticMeshRenderer.cs -> done
|
||||||
TextureCache.cs ← done
|
TextureCache.cs -> done
|
||||||
ChaseCamera.cs ← done
|
ChaseCamera.cs -> done
|
||||||
FlyCamera.cs ← done
|
FlyCamera.cs -> done
|
||||||
Streaming/
|
Streaming/
|
||||||
StreamingController.cs ← done
|
StreamingController.cs -> done
|
||||||
GpuWorldState.cs ← done
|
GpuWorldState.cs -> done
|
||||||
Input/
|
Input/
|
||||||
PlayerMovementController.cs ← done (uses ported physics)
|
PlayerMovementController.cs -> active movement driver
|
||||||
Plugins/
|
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:
|
Currently, entity state is scattered across:
|
||||||
- `WorldEntity` (position, rotation, mesh refs)
|
- `WorldEntity` (position, rotation, mesh refs)
|
||||||
|
|
@ -198,21 +260,21 @@ public sealed class GameEntity
|
||||||
{
|
{
|
||||||
Motion.ApplyCurrentMovement(); // set velocity from motion state
|
Motion.ApplyCurrentMovement(); // set velocity from motion state
|
||||||
Physics.UpdateObject(dt); // integrate position
|
Physics.UpdateObject(dt); // integrate position
|
||||||
// TODO: Transition.FindValidPosition // collision resolve
|
PhysicsEngine.ResolveWithTransition(); // current L.2 collision spine
|
||||||
Cell.UpdateCell(Physics.Position); // check cell transitions
|
Cell.UpdateCell(Physics.Position); // target: retail cell ownership
|
||||||
Animation.Advance(dt); // advance animation frames
|
Animation.Advance(dt); // advance animation frames
|
||||||
RebuildMeshRefs(); // compute per-part transforms
|
RebuildMeshRefs(); // compute per-part transforms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Every entity in the world — player, NPC, monster, lifestone, door, chest —
|
Target state: every entity in the world — player, NPC, monster, lifestone,
|
||||||
is a `GameEntity`. The renderer iterates them and draws. The plugin API
|
door, chest — becomes a `GameEntity`. The renderer iterates them and draws.
|
||||||
exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
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
|
1. Network tick
|
||||||
|
|
@ -224,15 +286,16 @@ exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
||||||
create terrain + scenery GameEntities
|
create terrain + scenery GameEntities
|
||||||
|
|
||||||
3. Input tick (player mode only)
|
3. Input tick (player mode only)
|
||||||
└── Read WASD/mouse → MotionInterpreter.DoMotion →
|
└── InputDispatcher scopes → PlayerMovementController →
|
||||||
|
MotionInterpreter/body prediction → ResolveWithTransition →
|
||||||
send MoveToState/AutonomousPosition to server
|
send MoveToState/AutonomousPosition to server
|
||||||
|
|
||||||
4. Entity tick (ALL entities, 30Hz fixed step)
|
4. Entity / animation tick
|
||||||
└── For each GameEntity: entity.Update(dt)
|
└── Current code still has scattered world/entity state. L.1 owns
|
||||||
This runs: motion → physics → collision → cell → animation
|
animation parity; L.2 owns movement/collision conformance.
|
||||||
|
|
||||||
5. Render tick
|
5. Render tick
|
||||||
└── For each GameEntity: read MeshRefs, draw
|
└── Read current entity mesh refs, draw
|
||||||
TerrainRenderer.Draw, StaticMeshRenderer.Draw
|
TerrainRenderer.Draw, StaticMeshRenderer.Draw
|
||||||
(frustum cull, translucency pass, etc.)
|
(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)
|
The old R1-R8 architecture sequence was a useful early refactor sketch, but it
|
||||||
**Goal:** Replace the scattered entity state with unified GameEntity.
|
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/`
|
Current movement/collision ownership:
|
||||||
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`
|
|
||||||
|
|
||||||
**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
|
The GameEntity / thin GameWindow refactor remains a valid target architecture,
|
||||||
**Goal:** GameWindow does only GL calls + input dispatch.
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -339,11 +339,12 @@ exposes them as `WorldEntitySnapshot`. GameWindow becomes thin.
|
||||||
```
|
```
|
||||||
For every AC-specific behavior:
|
For every AC-specific behavior:
|
||||||
|
|
||||||
1. DECOMPILE → Find the function in docs/research/decompiled/
|
0. GREP NAMED → Search docs/research/named-retail/ by class::method
|
||||||
2. CROSS-CHECK → Verify against ACE + ACME + holtburger
|
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
|
3. PSEUDOCODE → Translate to readable pseudocode
|
||||||
4. PORT → Faithful C# translation
|
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
|
6. INTEGRATE → Surgical wiring into the existing system
|
||||||
7. VERIFY → Visual + functional test
|
7. VERIFY → Visual + functional test
|
||||||
```
|
```
|
||||||
|
|
@ -359,9 +360,9 @@ For acdream-specific code (renderer, plugin API, streaming):
|
||||||
|
|
||||||
| Domain | Primary Oracle | Secondary |
|
| Domain | Primary Oracle | Secondary |
|
||||||
|--------|---------------|-----------|
|
|--------|---------------|-----------|
|
||||||
| Physics/collision | Decompiled acclient.exe | ACE Physics/ |
|
| Physics/collision | `docs/research/named-retail/` | ACE Physics/ + older decompiled chunks |
|
||||||
| Animation | Decompiled + ACE Animation/ | — |
|
| Animation | `docs/research/named-retail/` + ACE Animation/ | — |
|
||||||
| Terrain | ACME ClientReference.cs | Decompiled |
|
| Terrain | ACME ClientReference.cs | named retail / older decompiled chunks |
|
||||||
| Rendering | WorldBuilder (Silk.NET) | ACViewer |
|
| Rendering | WorldBuilder (Silk.NET) | ACViewer |
|
||||||
| Protocol | holtburger | AC2D |
|
| Protocol | holtburger | AC2D |
|
||||||
| Server behavior | ACE | — |
|
| Server behavior | ACE | — |
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# acdream — strategic roadmap
|
# 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.
|
**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.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.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 ✓ |
|
| 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 ✓ |
|
| 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 ✓ |
|
| 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 ✓ |
|
| 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:**
|
**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.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.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.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).
|
- **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.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.
|
- **✓ 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.
|
**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`.
|
**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:**
|
**Sub-pieces:**
|
||||||
- **L.1a — Audit & inventory.** Map retail named-decomp evidence, ACE
|
- **L.1a — Audit & inventory.** Map retail named-decomp evidence, ACE
|
||||||
cross-references, existing acdream hook points, and current gaps for each
|
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)
|
### Phase J — Long-tail (deferred / low-priority)
|
||||||
|
|
||||||
Not detailed here; each gets its own brainstorm when it becomes relevant.
|
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** ✓ |
|
| 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) |
|
| 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) |
|
| 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 talk to NPCs | **Phase H.3** (emote scripts + dialogs) |
|
||||||
| Can't open a door | **Phase F** (object-use action) |
|
| Can't open a door | **Phase F** (object-use action) |
|
||||||
| Portals render as a rotating black disk | **Phase E.3** (particle system) |
|
| 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** ✓ |
|
| Combat doesn't show in the chat log | **I.7 FIXED** ✓ |
|
||||||
| Accented character names show as `?` or garbled | **I.5 FIXED** ✓ (Windows-1252 codec) |
|
| Accented character names show as `?` or garbled | **I.5 FIXED** ✓ (Windows-1252 codec) |
|
||||||
| No sound | **Phase E.2** |
|
| 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 fight monsters | **Phase F.3** (combat math + damage) |
|
||||||
| Can't cast spells | **Phase F.4** |
|
| Can't cast spells | **Phase F.4** |
|
||||||
| No inventory panel | **Phase F.2 + F.5** |
|
| 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.
|
||||||
|
|
@ -1,131 +1,128 @@
|
||||||
# Collision System Port — Status and Plan
|
# Collision System Port - Status and Plan
|
||||||
|
|
||||||
## Current State (2026-04-14)
|
## Current State (2026-04-29)
|
||||||
|
|
||||||
The collision system has been patched multiple times but does NOT match
|
The collision system is no longer a pure placeholder and should not be treated
|
||||||
retail. The user has explicitly requested a **full faithful port** of
|
as "delete everything and start over." A partial retail transition port exists:
|
||||||
the retail collision system — no shortcuts, no simplifications.
|
|
||||||
|
|
||||||
## What Went Wrong
|
- `PhysicsEngine.ResolveWithTransition` is the active player movement resolver.
|
||||||
|
- `BSPQuery` contains a partial retail-style BSP dispatcher.
|
||||||
|
- `TransitionTypes` carries the active `SpherePath`, `CollisionInfo`,
|
||||||
|
transition, step, contact, and partial slide logic.
|
||||||
|
- `PhysicsDataCache` loads GfxObj, Setup, and CellStruct physics data.
|
||||||
|
- `ShadowObjectRegistry` gives the resolver a broadphase over nearby objects.
|
||||||
|
- `TerrainSurface` uses triangle-aware terrain contact.
|
||||||
|
|
||||||
Instead of porting the decompiled code line-by-line (as CLAUDE.md
|
This foundation is useful, but it is not complete retail collision parity.
|
||||||
mandates), I wrote simplified approximations:
|
The project now tracks the remaining work as Phase L.2 - Movement & Collision
|
||||||
- Static overlap instead of swept-sphere FindTimeOfCollision
|
Conformance:
|
||||||
- Custom FindObjCollisions instead of porting Sphere.IntersectsSphere
|
|
||||||
- Custom BSP query instead of porting BSPTree.find_collisions dispatcher
|
|
||||||
- Ad-hoc push-out instead of proper SlideSphere crease-projection
|
|
||||||
- Incremental patches that don't address root architectural issues
|
|
||||||
|
|
||||||
Each patch fixed one symptom but introduced new edge cases. The result
|
- Plan: `docs/plans/2026-04-29-movement-collision-conformance.md`
|
||||||
is a patchwork that handles ~60-70% of cases but fails on the rest.
|
- Roadmap owner: `docs/plans/2026-04-11-roadmap.md`
|
||||||
|
- Tactical follow-ups: `docs/ISSUES.md` #30-#34
|
||||||
|
|
||||||
## What Must Happen Next
|
## Durable Lesson
|
||||||
|
|
||||||
**Delete the existing collision code and start fresh.** Port from ACE's
|
Do not guess at AC physics, movement packets, terrain/cell ownership, or
|
||||||
complete C# implementation, cross-referencing the decompiled code for
|
collision constants. The previous patchwork failures came from simplified
|
||||||
ground truth. ACE has the ENTIRE system already in C#:
|
approximations:
|
||||||
|
|
||||||
### Files to port from ACE (in order):
|
- static overlap instead of swept-sphere transition behavior
|
||||||
|
- custom object collision instead of retail `CSphere` / `CCylSphere`
|
||||||
|
- incomplete BSP dispatch
|
||||||
|
- ad-hoc push-out instead of retail slide / edge / precipice handling
|
||||||
|
- server "no rubber-band" treated as proof of local collision correctness
|
||||||
|
|
||||||
1. **Sphere.cs** — `IntersectsSphere` (FUN_005387c0), `SlideSphere` (both variants), `StepSphereUp`, `StepSphereDown`, `LandOnSphere`, `CollideWithPoint`, `CollidesWithSphere`
|
The named retail decomp is now the primary source. Search
|
||||||
|
`docs/research/named-retail/acclient_2013_pseudo_c.txt` by `class::method`
|
||||||
|
before using older decompiled chunks or reference repos.
|
||||||
|
|
||||||
2. **BSPTree.cs** — `find_collisions` (6-path dispatcher)
|
## Active Approach
|
||||||
|
|
||||||
3. **BSPNode.cs** — `sphere_intersects_poly` (tree traversal with movement), `find_walkable`, `hits_walkable`, `sphere_intersects_solid`
|
Continue by conformance lanes rather than rewriting blindly:
|
||||||
|
|
||||||
4. **BSPLeaf.cs** — leaf-level polygon tests
|
1. **Truth & diagnostics (L.2a).** Add local placement/contact/cell,
|
||||||
|
object-hit, outbound-packet, server echo, and correction-delta probes.
|
||||||
|
2. **Movement wire/contact authority (L.2b).** Fix contact byte and full-cell
|
||||||
|
truth before using ACE acceptance as evidence.
|
||||||
|
3. **Transition parity (L.2c).** Port edge-slide, cliff-slide,
|
||||||
|
precipice-slide, step-up/down slide, and `NegPolyHit` dispatch.
|
||||||
|
4. **Shape fidelity (L.2d).** Finish `CSphere` / `CCylSphere` semantics,
|
||||||
|
live-entity shapes, and building object identity.
|
||||||
|
5. **Cell ownership (L.2e).** Port `CELLARRAY`, `find_cell_list`,
|
||||||
|
`check_other_cells`, `adjust_check_pos`, low-cell updates, and `cell_bsp`.
|
||||||
|
6. **Real-DAT and live observer conformance (L.2f).** Promote every synthetic
|
||||||
|
case to real-world fixtures and retail-observer checks.
|
||||||
|
|
||||||
5. **Polygon.cs** — `pos_hits_sphere`, `adjust_sphere_to_plane`, `check_walkable`
|
## What To Preserve
|
||||||
|
|
||||||
6. **Transition.cs** — `FindTransitionalPosition`, `TransitionalInsert`, `StepUp`, `StepDown`, `ValidateTransition`, `AdjustOffset`
|
- `CollisionPrimitives.cs` low-level helpers, while auditing remaining shape
|
||||||
|
gaps against named retail.
|
||||||
|
- `PhysicsDataCache.cs` DAT-backed collision data loading.
|
||||||
|
- `ShadowObjectRegistry.cs` broadphase concept.
|
||||||
|
- `TransitionTypes.cs` data structures and partial transition port.
|
||||||
|
- `BSPQuery.cs` partial dispatcher as the current porting surface.
|
||||||
|
- `PhysicsBody.cs`, `MotionInterpreter.cs`, and `PlayerWeenie.cs` foundations.
|
||||||
|
|
||||||
7. **SpherePath.cs** — `SetCheckPos`, `AddOffsetToCheckPos`, `CacheLocalSpaceSphere`, `SetCollide`, `SetWalkable`, `SetNegPolyHit`
|
## Known Gaps
|
||||||
|
|
||||||
8. **CollisionInfo.cs** — `SetContactPlane`, `SetSlidingNormal`, `SetCollisionNormal`
|
- Full `CELLARRAY` and adjacent-cell ownership are missing.
|
||||||
|
- `cell_bsp` is not yet a first-class runtime owner.
|
||||||
|
- Building portal transit and building entry/exit collision are incomplete.
|
||||||
|
- `edge_slide`, `cliff_slide`, `precipice_slide`, and `NegPolyHit` behavior are
|
||||||
|
incomplete.
|
||||||
|
- Live entity shape fidelity is simplified.
|
||||||
|
- Outbound movement contact/cell fields can be overconfident.
|
||||||
|
- Routine local/server correction diagnostics are missing.
|
||||||
|
|
||||||
9. **ObjectInfo.cs** — `ValidateWalkable`
|
## Retail Anchors
|
||||||
|
|
||||||
10. **LandCell.cs** — `FindEnvCollisions` (outdoor terrain)
|
Primary:
|
||||||
|
|
||||||
11. **EnvCell.cs** — `FindEnvCollisions` (indoor BSP)
|
- `docs/research/named-retail/acclient_2013_pseudo_c.txt`
|
||||||
|
- `docs/research/named-retail/acclient.h`
|
||||||
|
- `docs/research/named-retail/symbols.json`
|
||||||
|
|
||||||
12. **ObjCell.cs** — `FindObjCollisions`, `find_cell_list`
|
Key names:
|
||||||
|
|
||||||
### ACE source locations:
|
- `CTransition::find_transitional_position`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/Sphere.cs`
|
- `CTransition::transitional_insert`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/BSP/BSPTree.cs`
|
- `CTransition::step_up`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/BSP/BSPNode.cs`
|
- `CTransition::step_down`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/BSP/BSPLeaf.cs`
|
- `CTransition::edge_slide`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/Polygon.cs`
|
- `CTransition::cliff_slide`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/Transition.cs`
|
- `SPHEREPATH::step_up_slide`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/SpherePath.cs`
|
- `SPHEREPATH::precipice_slide`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/Collision/CollisionInfo.cs`
|
- `SPHEREPATH::adjust_check_pos`
|
||||||
- `references/ACE/Source/ACE.Server/Physics/Collision/ObjectInfo.cs`
|
- `CTransition::check_other_cells`
|
||||||
|
- `CObjCell::find_cell_list`
|
||||||
|
- `CPhysicsObj::is_valid_walkable`
|
||||||
|
- `CBuildingObj::find_building_collisions`
|
||||||
|
- `CCellStruct::sphere_intersects_cell`
|
||||||
|
- `CCylSphere::intersects_sphere`
|
||||||
|
- `CSphere::intersects_sphere`
|
||||||
|
- `CSphere::slide_sphere`
|
||||||
|
|
||||||
### Decompiled ground truth (named-retail is now primary, 2026-04-25):
|
Older fallback:
|
||||||
- **`docs/research/named-retail/acclient_2013_pseudo_c.txt`** — grep for
|
|
||||||
`BSPTree::`, `BSPNode::`, `BSPLeaf::`, `CPolygon::`, `CCylSphere::`,
|
|
||||||
`Transition::`, `CPhysicsObj::`, `SpherePath::` to find named bodies.
|
|
||||||
- **`docs/research/named-retail/acclient.h`** — verbatim retail struct
|
|
||||||
layouts for the BSP / Sphere / Transition types.
|
|
||||||
- **`docs/research/named-retail/symbols.json`** — name↔address lookup.
|
|
||||||
- `docs/research/decompiled/chunk_00530000.c` — older Ghidra fallback for
|
|
||||||
BSP / Polygon / Sphere collision (FUN_xxx names).
|
|
||||||
- `docs/research/decompiled/chunk_00500000.c` — older Ghidra fallback for
|
|
||||||
PhysicsObj / transition callers.
|
|
||||||
- `docs/research/acclient_function_map.md` — hand-curated cross-port index
|
|
||||||
(ACE / ACME mappings + struct-offset notes).
|
|
||||||
|
|
||||||
### Pseudocode (already written):
|
- `docs/research/decompiled/chunk_00530000.c`
|
||||||
- `docs/research/transition_pseudocode.md` — full system documented
|
- `docs/research/decompiled/chunk_00500000.c`
|
||||||
|
- `docs/research/acclient_function_map.md`
|
||||||
|
|
||||||
## What to Keep
|
Reference aids:
|
||||||
|
|
||||||
- `CollisionPrimitives.cs` — 9 low-level functions already faithfully ported from decompiled code. These are CORRECT and match retail.
|
- `references/ACE/Source/ACE.Server/Physics/`
|
||||||
- `PhysicsDataCache.cs` — GfxObj/Setup/CellStruct physics data loading from dats. Correct.
|
- `references/holtburger/` for movement wire behavior
|
||||||
- `ShadowObjectRegistry.cs` — cell-based spatial index. Correct concept, may need refinement.
|
- `references/AC2D/` for the older client-side movement packet reference
|
||||||
- `TransitionTypes.cs` data structures — SpherePath, CollisionInfo, ObjectInfo, PhysicsGlobals. Mostly correct, may need field additions.
|
|
||||||
- `PhysicsBody.cs` — Euler integration. Correct.
|
|
||||||
- `MotionInterpreter.cs` — Motion state machine. Correct.
|
|
||||||
- `PlayerWeenie.cs` — Run/Jump formulas. Correct.
|
|
||||||
|
|
||||||
## What to Replace
|
## Mandatory Workflow
|
||||||
|
|
||||||
- `BSPQuery.cs` — replace with faithful port of BSPTree/BSPNode/BSPLeaf
|
For every AC-specific function:
|
||||||
- `TransitionTypes.cs` Transition methods — replace FindTransitionalPosition, TransitionalInsert, FindEnvCollisions, FindObjCollisions, SlideSphere, AdjustOffset with faithful ports
|
|
||||||
- `PhysicsEngine.ResolveWithTransition` — may need restructuring
|
|
||||||
|
|
||||||
## Approach (MANDATORY — per CLAUDE.md)
|
1. Grep named retail first.
|
||||||
|
2. Cross-reference ACE / holtburger / AC2D where relevant.
|
||||||
For EVERY function:
|
3. Write readable pseudocode before porting.
|
||||||
|
4. Port faithfully; do not simplify.
|
||||||
1. **GREP NAMED FIRST, then DECOMPILE FALLBACK.** Search the named
|
5. Add conformance tests.
|
||||||
retail decomp first: `grep -n "ClassName::Method" docs/research/named-retail/acclient_2013_pseudo_c.txt`.
|
6. Integrate surgically into the active L.2 lane.
|
||||||
For struct layouts: `grep -n "^struct ClassName" docs/research/named-retail/acclient.h`.
|
7. Verify with synthetic tests, real-DAT fixtures, and live observer evidence.
|
||||||
Only if the named pseudo-C lacks a function (rare), fall back to the
|
|
||||||
older `docs/research/decompiled/` chunks via the function map at
|
|
||||||
`docs/research/acclient_function_map.md`.
|
|
||||||
|
|
||||||
2. **CROSS-REFERENCE ACE.** Read ACE's C# port of the same function.
|
|
||||||
ACE provides naming and structure. Note any differences.
|
|
||||||
|
|
||||||
3. **WRITE PSEUDOCODE.** Translate the decompiled C into readable
|
|
||||||
pseudocode BEFORE porting to C#. Add to
|
|
||||||
`docs/research/collision_port_pseudocode.md`.
|
|
||||||
|
|
||||||
4. **PORT FAITHFULLY.** Translate pseudocode to C# line-by-line.
|
|
||||||
Same variable names, same control flow, same boundary conditions.
|
|
||||||
Do NOT "improve" or "simplify" the algorithm.
|
|
||||||
|
|
||||||
5. **VERIFY.** When ACE and the decompiled code disagree, the
|
|
||||||
decompiled code wins. Document the difference.
|
|
||||||
|
|
||||||
### Execution order:
|
|
||||||
|
|
||||||
1. Sphere collision (Sphere.cs) — FUN_005387c0 and sub-functions
|
|
||||||
2. BSP tree (BSPTree/Node/Leaf) — find_collisions dispatcher
|
|
||||||
3. Polygon tests (Polygon.cs) — pos_hits_sphere, adjust_sphere_to_plane
|
|
||||||
4. Transition orchestrator (Transition.cs) — FindTransitionalPosition
|
|
||||||
5. Cell collision (LandCell/EnvCell/ObjCell) — FindEnvCollisions, FindObjCollisions
|
|
||||||
6. Wire into PhysicsEngine.ResolveWithTransition
|
|
||||||
7. Test: terrain → indoor walls → objects → step-up → every object type
|
|
||||||
|
|
|
||||||
49
memory/project_movement_collision_conformance.md
Normal file
49
memory/project_movement_collision_conformance.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Movement & Collision Conformance Crib
|
||||||
|
|
||||||
|
## Phase
|
||||||
|
|
||||||
|
Active phase: **L.2 - Movement & Collision Conformance**.
|
||||||
|
|
||||||
|
Plan: `docs/plans/2026-04-29-movement-collision-conformance.md`.
|
||||||
|
|
||||||
|
Roadmap: `docs/plans/2026-04-11-roadmap.md`.
|
||||||
|
|
||||||
|
## One-Sentence Framing
|
||||||
|
|
||||||
|
B.3 shipped the MVP resolver foundation; L.2 is the holistic conformance
|
||||||
|
program for physics, collision, buildings, edge/wall sliding, cell ownership,
|
||||||
|
movement packets, and server correction.
|
||||||
|
|
||||||
|
## Active Movement Spine
|
||||||
|
|
||||||
|
```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 diagnostics
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lane Ownership
|
||||||
|
|
||||||
|
- L.2a: truth probes, diagnostics, fixture capture.
|
||||||
|
- L.2b: movement wire/contact truth, cell id on packets, correction handling.
|
||||||
|
- L.2c: transition parity, edge-slide, cliff-slide, precipice-slide,
|
||||||
|
`NegPolyHit`.
|
||||||
|
- L.2d: `CSphere` / `CCylSphere`, live entity shapes, building object identity.
|
||||||
|
- L.2e: outdoor seams, `CELLARRAY`, `find_cell_list`, adjacent-cell checks,
|
||||||
|
`cell_bsp`, building entry/exit boundaries.
|
||||||
|
- L.2f: real-DAT fixtures and live retail-observer conformance.
|
||||||
|
|
||||||
|
## Non-Negotiables
|
||||||
|
|
||||||
|
- Grep named retail before changing AC-specific physics or movement behavior.
|
||||||
|
- Do not treat ACE accepting a position as proof of retail collision parity.
|
||||||
|
- Do not reintroduce rewrite-from-zero collision guidance. Continue the partial
|
||||||
|
retail port by L.2 lanes.
|
||||||
|
- G.3 dungeon/portal delivery waits on L.2e for trustworthy cell/building
|
||||||
|
ownership.
|
||||||
|
- L.1 animation work must coordinate with L.2 when root motion or observer
|
||||||
|
movement changes the predicted body path.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue