docs(phys L.2g): design spec for dynamic PhysicsState toggling (doors)
L.2d slice 1.5 ship identified the Holtburg doorway blocker as a closed
Door entity (Setup 0x020019FF) whose PhysicsState.Ethereal bit flips
when the player Uses the door. The L.2d shape-fidelity work doesn't
cover this — the door's collision shape is correct; what's missing is
honoring the *runtime* state change.
L.2g is the new sub-phase that handles it. Scope is narrow:
* Parse inbound GameMessageSetState (0xF74B).
* Plumb the new PhysicsState value into ShadowObjectRegistry's
cached per-entity state so the existing CollisionExemption.IsExempt
already-in-place short-circuit sees up-to-date bits.
* Verify the Holtburg inn-door scenario: walk in blocked, Use door,
walk through, auto-close blocks again after 30s.
* Confirm UpdateMotion (NonCombat, On/Off) drives non-creature
entities (door swing animation).
Why a new L.2 sub-letter (and not B.4 or Door-special-case): the wire
mechanism (SetState flipping Ethereal) is also how ACE handles activated
traps, opened chests, spell projectiles becoming ethereal. Generic
infrastructure with doors as the verification scenario; lane is the
informal sixth "dynamic state."
Roadmap state:
* L.2 plan-of-record adds the L.2g section after L.2f.
* Milestones doc M1 phase list extended `a-f` -> `a-g`.
* CLAUDE.md status pointer + "next phase candidates" list updated to
name L.2g slice 1 implementation as the natural next step.
Risk: low. Wire-byte width has a hex-dump fallback path in slice 1
(holtburger says 12 bytes, ACE writes 16, capture settles it). ETHEREAL
plumbing already exists; we feed it new data. No resolver changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9206d1d4e0
commit
2c10dd4d67
4 changed files with 353 additions and 14 deletions
33
CLAUDE.md
33
CLAUDE.md
|
|
@ -618,10 +618,16 @@ acdream's plan lives in two files committed to the repo:
|
|||
approval.
|
||||
|
||||
**Currently in Phase L.2 (Movement & Collision Conformance).** L.2a slices
|
||||
1+2+3 shipped 2026-05-12 (this evening); the natural next step is the
|
||||
L.2d slice 1 brainstorm / design spec. Cold-start prompt for the next
|
||||
session: [`docs/research/2026-05-12-l2d-next-session-prompt.md`](docs/research/2026-05-12-l2d-next-session-prompt.md).
|
||||
Full handoff: [`docs/research/2026-05-12-l2a-shipped-l2d-handoff.md`](docs/research/2026-05-12-l2a-shipped-l2d-handoff.md).
|
||||
1+2+3 + L.2d slice 1+1.5 shipped 2026-05-12. L.2d closed at the Holtburg
|
||||
site ("watch-and-wait" — no more slices until a new shape-fidelity bug
|
||||
shows up elsewhere); doorway blocker identified as a Door entity, not
|
||||
building BSP. L.2g (dynamic PhysicsState toggling — doors) brainstormed
|
||||
and design-spec'd 2026-05-12 evening; **the natural next step is the
|
||||
L.2g slice 1 implementation** (parse `SetState` 0xF74B, plumb new
|
||||
PhysicsState into ShadowObjectRegistry, verify Holtburg inn doorway).
|
||||
Design spec: [`docs/superpowers/specs/2026-05-12-l2g-dynamic-physicsstate-design.md`](docs/superpowers/specs/2026-05-12-l2g-dynamic-physicsstate-design.md).
|
||||
L.2d ship handoff: [`docs/research/2026-05-13-l2d-slice1-shipped-handoff.md`](docs/research/2026-05-13-l2d-slice1-shipped-handoff.md).
|
||||
L.2a→L.2d handoff (now superseded by the L.2d ship): [`docs/research/2026-05-12-l2a-shipped-l2d-handoff.md`](docs/research/2026-05-12-l2a-shipped-l2d-handoff.md).
|
||||
|
||||
**Phase L.2a (Truth & Diagnostics) slices 1-3 shipped 2026-05-12.**
|
||||
Three commits land the L.2 "make every bad movement outcome explainable"
|
||||
|
|
@ -699,13 +705,18 @@ together comprise the streaming + rendering perf foundation for the
|
|||
project.
|
||||
|
||||
**Next phase candidates (in rough preference order):**
|
||||
- **L.2d slice 1 brainstorm + spec** (`docs/research/2026-05-12-l2d-next-session-prompt.md`).
|
||||
Direct continuation of tonight's L.2a evidence: port `CBuildingObj` collision
|
||||
+ per-cell walkability so doorway gaps are walkable. Unblocks "walk into a
|
||||
building" + sets up G.3 dungeon streaming. **Note:** triage the 8 pre-existing
|
||||
test failures first (none introduced by L.2a slices — verified by stash + rerun
|
||||
— but most touch movement/physics code L.2d will evolve). See the handoff doc's
|
||||
"Open concerns" section.
|
||||
- **L.2g slice 1 implementation — dynamic PhysicsState toggling for doors.**
|
||||
Direct continuation of tonight's L.2d slice 1.5 evidence: parse inbound
|
||||
`SetState (0xF74B)` wire message, plumb the new `PhysicsState` value into
|
||||
`ShadowObjectRegistry`'s cached entity state so the existing
|
||||
`CollisionExemption.IsExempt(...)` check sees up-to-date bits, and verify
|
||||
the Holtburg inn-door scenario walks through cleanly when the server flips
|
||||
Ethereal. Unblocks the M1 demo's *"open the inn door"* line. Spec:
|
||||
[`docs/superpowers/specs/2026-05-12-l2g-dynamic-physicsstate-design.md`](docs/superpowers/specs/2026-05-12-l2g-dynamic-physicsstate-design.md).
|
||||
**Note:** triage the 8 pre-existing test failures still hanging over the
|
||||
physics modules first (none introduced by L.2a/L.2d slices — verified by
|
||||
stash + rerun — but most touch code adjacent to where L.2g will plumb the
|
||||
new state mutator).
|
||||
- **Triage the chronic open-issue list** in `docs/ISSUES.md` — #2 (lightning),
|
||||
#4 (sky horizon-glow), #28 (aurora), #29 (cloud thinness), #37 (humanoid
|
||||
coat), #50 (stray tree), #41 (remote-motion blips) have been open since
|
||||
|
|
|
|||
|
|
@ -228,6 +228,44 @@ client sees when observing acdream.
|
|||
- Require conformance notes in tests or research docs for every AC-specific
|
||||
algorithm ported under L.2.
|
||||
|
||||
### L.2g - Dynamic PhysicsState Toggling
|
||||
|
||||
Goal: server-driven post-spawn state changes (chiefly `ETHEREAL` flips) are
|
||||
honored by the local collision stack.
|
||||
|
||||
Triggered 2026-05-12 evening by the L.2d slice 1.5 trace: the Holtburg
|
||||
doorway blocker is a closed Door entity (Setup `0x020019FF`) whose
|
||||
`PhysicsState.Ethereal` bit flips when the player Uses the door. The L.2d
|
||||
shape-fidelity work doesn't cover this — the door's collision shape is
|
||||
already correct; what's missing is honoring the *runtime* state change.
|
||||
|
||||
Scope is intentionally narrow:
|
||||
|
||||
- Parse inbound `GameMessageSetState (opcode 0xF74B)`.
|
||||
- Plumb the new `PhysicsState` value into `ShadowObjectRegistry`'s cached
|
||||
per-entity state so the existing `CollisionExemption.IsExempt(...)` check
|
||||
sees the up-to-date bits.
|
||||
- Verify the Holtburg inn-door scenario: walk into doorway → blocked, Use
|
||||
door → door swings open AND player can walk through, auto-close after
|
||||
30s → door closes AND player is blocked again.
|
||||
- Confirm the existing `UpdateMotion` pipeline drives `(NonCombat, On/Off)`
|
||||
on non-creature entities (door swing animation). If not, one-line fix.
|
||||
|
||||
Excluded from L.2g scope (deferred):
|
||||
|
||||
- Door-specific UX polish: "door is locked" sound, creature-AI bump-open.
|
||||
- Any Door-specific class hierarchy — generic state-flip infrastructure
|
||||
is enough; doors are the verification scenario, not a privileged case.
|
||||
|
||||
Lane: informal sixth lane "dynamic state." The existing five-lane table
|
||||
treats per-entity state as static-after-spawn; L.2g makes it dynamic.
|
||||
|
||||
Full design spec:
|
||||
[docs/superpowers/specs/2026-05-12-l2g-dynamic-physicsstate-design.md](../superpowers/specs/2026-05-12-l2g-dynamic-physicsstate-design.md).
|
||||
|
||||
M1 critical path: this slice unblocks the *"open the inn door"* demo
|
||||
scenario.
|
||||
|
||||
## Named Retail Anchors
|
||||
|
||||
Primary source: `docs/research/named-retail/acclient_2013_pseudo_c.txt`.
|
||||
|
|
|
|||
|
|
@ -101,9 +101,13 @@ doorway. Open the inn door. Click an NPC and see selection feedback. Pick
|
|||
up an item from the ground.
|
||||
|
||||
**Phases to ship:**
|
||||
- **L.2 (all sub-lanes a–f)** — Movement & Collision Conformance. Currently
|
||||
active; L.2a slices 1+2+3 shipped 2026-05-12.
|
||||
- **B.4** — `Use` / `UseWithTarget` / `PickUp` outbound messages.
|
||||
- **L.2 (all sub-lanes a–g)** — Movement & Collision Conformance. Currently
|
||||
active; L.2a slices 1+2+3 + L.2d slice 1+1.5 shipped 2026-05-12. L.2g
|
||||
(dynamic PhysicsState toggling — doors) brainstormed + design-spec'd
|
||||
2026-05-12 evening, implementation next.
|
||||
- **B.4** — `Use` / `UseWithTarget` / `PickUp` outbound messages
|
||||
(shipped 2026-04-28; remains in M1 scope until L.2g completes the
|
||||
inbound-state half of the Use round-trip).
|
||||
|
||||
**Freeze on landing:**
|
||||
- L.2 zone (collision, cell ownership, transition parity, wire authority)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,286 @@
|
|||
# Phase L.2g — Dynamic PhysicsState Toggling
|
||||
|
||||
**Status:** Design spec, created 2026-05-12 evening after L.2d slice 1+1.5
|
||||
ship and brainstorm completion.
|
||||
**Branch:** `claude/gallant-mestorf-3bf2e3`.
|
||||
**Predecessor:** [docs/research/2026-05-13-l2d-slice1-shipped-handoff.md](../../research/2026-05-13-l2d-slice1-shipped-handoff.md)
|
||||
identified the Holtburg-doorway blocker as a closed Door entity (Setup
|
||||
`0x020019FF`), not a building-collision-mesh bug. L.2g is the
|
||||
sub-phase that handles the door-state work the L.2d handoff deferred.
|
||||
**Roadmap owner:** new L.2 sub-lane "dynamic state" — the L.2 plan-of-record
|
||||
([docs/plans/2026-04-29-movement-collision-conformance.md](../../plans/2026-04-29-movement-collision-conformance.md))
|
||||
explicitly anticipates the L.2g letter (L.2d revised sub-direction
|
||||
paragraph, lines 195–197).
|
||||
**Milestone:** M1 — Walkable + clickable world. Demo scenario *"open
|
||||
the inn door"* depends on this slice landing.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
After the player Uses a door, ACE broadcasts two messages: an
|
||||
`UpdateMotion` to play the swing-open animation, and a
|
||||
`GameMessageSetState (opcode 0xF74B)` to flip the door entity's
|
||||
`PhysicsState.Ethereal` bit. The client must honor the state flip so
|
||||
the door's collision cylinder stops blocking the threshold while the
|
||||
door is open. The auto-close (30s) is a second SetState round-trip;
|
||||
client just follows.
|
||||
|
||||
acdream already parses `PhysicsState` from `CreateObject` and
|
||||
already short-circuits ETHEREAL targets in
|
||||
[CollisionExemption.cs](../../../src/AcDream.Core/Physics/CollisionExemption.cs).
|
||||
**The single missing piece is parsing `0xF74B SetState` and
|
||||
propagating the new state to `ShadowObjectRegistry`'s cached entity
|
||||
record.** Everything else already works. Slice 1 is roughly one
|
||||
commit.
|
||||
|
||||
---
|
||||
|
||||
## Why L.2g (and not B.4 or "doors only")
|
||||
|
||||
Three placement options were considered during the 2026-05-12
|
||||
brainstorm:
|
||||
|
||||
| Option | Verdict |
|
||||
|---|---|
|
||||
| **Nest under B.4 interaction** | Rejected. B.4's scope is the *outbound* Use / UseWithTarget / PickUp packet (shipped 2026-04-28). Door state is an inbound + collision-state-toggle problem, not an outbound interaction one. |
|
||||
| **Special-case Door Setup ID (`0x020019FF`)** | Rejected. Same wire mechanism (`SetState` flipping Ethereal) is also how ACE handles activated traps, opened chests, spell projectiles that become ethereal, and any other server-driven collision-state flip. Specializing on Door Setup ID would leave all those cases broken and re-emerge later as separate bugs. |
|
||||
| **New L.2 sub-phase "L.2g — Dynamic PhysicsState toggling"** | **Selected.** L.2 already owns "movement & collision conformance"; a door you can't walk through after the server says it's open is a collision-conformance bug. Generic infrastructure (any entity, any state bit) with doors as the verification scenario. |
|
||||
|
||||
The L.2 plan-of-record's L.2d revised paragraph already names L.2g
|
||||
as a possible letter for this work; we're claiming it.
|
||||
|
||||
**Lane assignment:** informal sixth lane "dynamic state." Updates the
|
||||
lane table in the L.2 plan-of-record to include collision-state-toggle
|
||||
as a first-class concern.
|
||||
|
||||
---
|
||||
|
||||
## Problem evidence
|
||||
|
||||
From the L.2d slice 1.5 trace (Holtburg, 2026-05-12):
|
||||
|
||||
```
|
||||
live: spawn guid=0x7A9B4015 name="Door" setup=0x020019FF
|
||||
pos=(132.6,17.1,94.1)@0xA9B40029 itemType=0x00000080
|
||||
[entity-source] id=0x000F4244 entityId=0x000F4244 src=0x020019FF
|
||||
gfxObj=0x020019FF lb=0xA9B40029 type=Cylinder note=server-spawn-root
|
||||
```
|
||||
|
||||
Five Door entities across Holtburg town (cells `0xA9B40029`,
|
||||
`0xA9B40154`, `0xA9B40155`); each blocks its building's threshold with a
|
||||
Cylinder collision. The 121 wall hits the L.2a probe attributed to the
|
||||
building BSP turned out to be the player **already pushed back by the
|
||||
Door cylinder** then grazing the doorframe. Slice 1.5's per-tick probe
|
||||
showed `nObj=3` on every doorway resolve: one Door + two sphere checks
|
||||
against the building BSP.
|
||||
|
||||
The actual blocker is the closed Door, not the building. The blocker
|
||||
goes away when the Door's PhysicsState gains the Ethereal bit (server
|
||||
sets this in `Door.Open()`, see
|
||||
[references/ACE/Source/ACE.Server/WorldObjects/Door.cs:127](../../../references/ACE/Source/ACE.Server/WorldObjects/Door.cs)).
|
||||
|
||||
---
|
||||
|
||||
## Wire flow
|
||||
|
||||
### Server → client when the player Uses a door
|
||||
|
||||
ACE's `Door.ActOnUse(player)` runs the following sequence:
|
||||
|
||||
1. Check `IsLocked` + behind-test (AC retail allows opening locked doors
|
||||
from behind). If locked-and-not-behind: broadcast a "door is locked"
|
||||
chat string + sound effect, no state change. Otherwise:
|
||||
2. `EnqueueBroadcastMotion(motionOpen)` — broadcasts an
|
||||
`UpdateMotion` to all clients in range, motion = `(NonCombat, On)`.
|
||||
This is the door's animation command.
|
||||
3. `Ethereal = true; EnqueueBroadcastPhysicsState()` — broadcasts a
|
||||
`GameMessageSetState (0xF74B)`. The new `PhysicsState` value has bit
|
||||
`0x4` (Ethereal) set.
|
||||
4. Sets `IsBusy = true` for the duration of the open animation.
|
||||
5. Schedules `FinalizeClose` after `ResetInterval` (default 30s).
|
||||
|
||||
### Server → client when the auto-close fires
|
||||
|
||||
1. `EnqueueBroadcastMotion(motionClosed)` — `UpdateMotion (NonCombat, Off)`.
|
||||
2. After the close animation completes, server runs `FinalizeClose`:
|
||||
`Ethereal = false; EnqueueBroadcastPhysicsState()` — another
|
||||
`0xF74B SetState` with the Ethereal bit cleared.
|
||||
|
||||
### The wire format of `0xF74B SetState`
|
||||
|
||||
Two sources, **mildly disagreeing on sequence-field width:**
|
||||
|
||||
[GameMessageSetState.cs](../../../references/ACE/Source/ACE.Server/Network/GameMessages/Messages/GameMessageSetState.cs)
|
||||
in ACE writes:
|
||||
|
||||
```
|
||||
guid : uint32 (4)
|
||||
state : uint32 (4)
|
||||
instance_sequence : uint32 (4) <-- ACE says u32
|
||||
state_sequence : uint32 (4) <-- ACE says u32
|
||||
```
|
||||
|
||||
[properties.rs](../../../references/holtburger/crates/holtburger-protocol/src/messages/object/messages/properties.rs)
|
||||
in holtburger parses:
|
||||
|
||||
```
|
||||
guid : uint32 (4)
|
||||
state : uint32 (4)
|
||||
instance_sequence : uint16 (2) <-- holtburger says u16
|
||||
state_sequence : uint16 (2) <-- holtburger says u16
|
||||
```
|
||||
|
||||
Holtburger has been validated against a retail-format server in the
|
||||
wild. ACE's `Writer.Write((uint)sequence)` may or may not be using a
|
||||
packed-write extension that downsizes to u16 — needs verification. **The
|
||||
slice 1 implementation will default to holtburger's 12-byte format and
|
||||
add a startup hex-dump probe to confirm before the parser is
|
||||
committed.** If the actual payload is 16 bytes, the parser can be
|
||||
trivially widened.
|
||||
|
||||
### `PhysicsState.Ethereal`
|
||||
|
||||
Value `0x00000004` (bit 2). Confirmed in:
|
||||
|
||||
- ACE: `references/ACE/Source/ACE.Entity/Enum/PhysicsState.cs:10`
|
||||
- acdream: `src/AcDream.Core/Physics/PhysicsBody.cs:30`
|
||||
- Retail header: `docs/research/named-retail/acclient.h:2819` (cited
|
||||
as `ETHEREAL_PS=0x4` in `CollisionExemption.cs:43`).
|
||||
|
||||
---
|
||||
|
||||
## Current acdream state
|
||||
|
||||
| Component | State |
|
||||
|---|---|
|
||||
| `PhysicsState` enum (Ethereal bit) | ✅ defined in `src/AcDream.Core/Physics/PhysicsBody.cs:30` |
|
||||
| `CollisionExemption.IsExempt(...)` | ✅ already short-circuits when `(ETHEREAL_PS \| IGNORE_COLLISIONS_PS)` are both set on the target. Cites `acclient_2013_pseudo_c.txt:276782`. |
|
||||
| `CreateObject` parses `PhysicsState` into the entity's shadow record | ✅ since 2026-04-29 |
|
||||
| `UpdateMotion` pipeline for remote entities | ✅ works for player remotes; need to confirm it accepts non-creature entities with `(NonCombat, On/Off)` |
|
||||
| `SetState (0xF74B)` inbound parser | ❌ does not exist |
|
||||
| Propagating a post-spawn PhysicsState change into `ShadowObjectRegistry`'s cached state | ❌ does not exist |
|
||||
| `[entity-source]` probe log captures `state` bits | ❌ — handoff's "slice 1.6" suggestion |
|
||||
|
||||
---
|
||||
|
||||
## Slice plan
|
||||
|
||||
### Slice 0.5 (optional prereq, fold into slice 1 if convenient)
|
||||
|
||||
Add `PhysicsState` + `EntityCollisionFlags` to the `[entity-source]`
|
||||
probe log line. Makes ETHEREAL flips observable from launch-log grep.
|
||||
~5 LOC under the existing `ACDREAM_PROBE_BUILDING` flag.
|
||||
|
||||
### Slice 1 — MVP (the M1-blocker slice)
|
||||
|
||||
Goal: walk into the Holtburg inn doorway, click Use on the door, walk
|
||||
through.
|
||||
|
||||
Touchpoints:
|
||||
|
||||
- `src/AcDream.Core.Net/` — new `SetStateMessage` parser for opcode
|
||||
`0xF74B`. Default to holtburger's 12-byte format; add a hex-dump
|
||||
emit on first message receipt to confirm exact byte width before the
|
||||
parser commits.
|
||||
- `src/AcDream.Core.Net/WorldSession.cs` (or wherever inbound game-
|
||||
message dispatch lives) — route `0xF74B` to the new parser, then
|
||||
forward the `(guid, newState)` pair to the entity layer.
|
||||
- `src/AcDream.Core/Physics/ShadowObjectRegistry.cs` — new
|
||||
`UpdatePhysicsState(guid, newState)` method that mutates the
|
||||
cached state bits on the matching shadow entry. The existing
|
||||
`CollisionExemption` check reads from this cached state, so no
|
||||
resolver changes needed.
|
||||
- Tests — synthetic test in
|
||||
`tests/AcDream.Core.Tests/` that constructs a ShadowEntry with
|
||||
`Ethereal=false`, calls `UpdatePhysicsState` flipping it on, and
|
||||
asserts the next collision query returns "exempt."
|
||||
- Visual verification — Holtburg inn doorway. Walk in, observe blocked.
|
||||
Click Use. Observe door swings open AND player can now walk through.
|
||||
Wait 30 seconds. Observe door closes AND player is blocked again.
|
||||
|
||||
Acceptance:
|
||||
- `dotnet build` + `dotnet test` green.
|
||||
- `[resolve]` probe shows the Door cylinder no longer firing when the
|
||||
door is open.
|
||||
- Visual verification at Holtburg passes.
|
||||
- Wire-byte width settled by hex-dump evidence; parser uses correct width.
|
||||
|
||||
### Slice 2 — animation confirmation
|
||||
|
||||
Goal: the door visually swings open and shut, not just becomes
|
||||
walk-through.
|
||||
|
||||
Most likely a no-op: the existing `UpdateMotion` pipeline that runs
|
||||
`(NonCombat, On/Off)` commands for player remotes should drive any
|
||||
entity with a MotionTable. Doors have a MotionTable (the same Setup
|
||||
`0x020019FF`). Slice 2 is **verify, then either declare done or fix
|
||||
whatever's missing**.
|
||||
|
||||
If a fix is needed, the most likely cause is the motion handler
|
||||
gating on `entity is Creature` somewhere upstream — a one-line removal
|
||||
or a stance-relaxation in `MotionInterpreter`.
|
||||
|
||||
### Deferred — UX polish
|
||||
|
||||
These open only if observation demands them:
|
||||
|
||||
- Sound on "door is locked" (ACE sends a `GameMessageSound` for
|
||||
`Sound.OpenFailDueToLock`; verify acdream's audio pipeline plays it
|
||||
via the existing 0xF755 handler).
|
||||
- Bump-AI for creatures (ACE's `Door.OnCollideObject` auto-opens for
|
||||
creatures with `AiOptions != 0`). This is server-driven; client gets
|
||||
the same `SetState` flow. Probably no-op for the client.
|
||||
|
||||
---
|
||||
|
||||
## Open questions to resolve in implementation
|
||||
|
||||
1. **Wire-byte width of `0xF74B` sequence fields.** Default to
|
||||
holtburger (u16+u16 = 12 bytes total). Confirm via hex-dump in slice
|
||||
1. If wrong, widen to ACE's claimed format (u32+u32 = 16 bytes).
|
||||
2. **Does `UpdateMotion`'s existing handler dispatch motion to non-
|
||||
creature entities?** Verified in slice 2. If no, one-line fix.
|
||||
3. **Does ACE's `EnqueueBroadcastPhysicsState` skip the player who
|
||||
triggered the Use, or include them?** Reading ACE's code, `EnqueueBroadcast(...)`
|
||||
broadcasts to *everyone in range including self*. Slice 1 verifies the
|
||||
player's own client receives the SetState (not just observers).
|
||||
|
||||
---
|
||||
|
||||
## Acceptance for L.2g overall
|
||||
|
||||
- All slices marked above as "Acceptance" pass.
|
||||
- L.2 plan-of-record updated with an L.2g section (matching this spec's framing).
|
||||
- M1 milestone doc updated: `L.2 (all sub-lanes a–f)` → `L.2 (all sub-lanes a–g)`.
|
||||
- CLAUDE.md's "currently in Phase L.2" paragraph updated to point at L.2g as the active sub-phase.
|
||||
- A short ship handoff doc filed at
|
||||
`docs/research/2026-05-XX-l2g-shipped-handoff.md` when slice 1+2 land.
|
||||
|
||||
---
|
||||
|
||||
## Named retail anchors (for slice 1 code citations)
|
||||
|
||||
- `CPhysicsObj::set_state` — the retail client's setter. Search by
|
||||
`set_state\(` in
|
||||
[docs/research/named-retail/acclient_2013_pseudo_c.txt](../../research/named-retail/acclient_2013_pseudo_c.txt).
|
||||
- `CPhysicsObj::report_collision_with_object` — the retail per-object
|
||||
collision-test entry; calls `CollisionExemption.IsExempt`-equivalent
|
||||
inline.
|
||||
- Header struct: `CPhysicsObj` in
|
||||
[docs/research/named-retail/acclient.h](../../research/named-retail/acclient.h)
|
||||
— `state` field is the `PhysicsState` bitmask.
|
||||
|
||||
---
|
||||
|
||||
## Risk + rollback
|
||||
|
||||
Risk is low. Wire-byte width has a fallback path (widen if hex-dump
|
||||
shows 16 bytes). ETHEREAL plumbing already exists; we're feeding it
|
||||
fresh data from one new source. No resolver changes. If slice 1 lands
|
||||
broken, rollback is a single revert of one commit.
|
||||
|
||||
The slice does **not** touch the broader L.2 collision path. It does
|
||||
not change `ResolveWithTransition`, BSPQuery, ShadowObjectRegistry
|
||||
broadphase, or any movement-prediction code. The change-surface is
|
||||
strictly "one new wire message + one new mutator on cached state."
|
||||
Loading…
Add table
Add a link
Reference in a new issue