acdream/src/AcDream.Core
Erik 3b7dc46219 fix(phys): GetNearbyObjects dedup-by-entityId silently drops multi-part shadows
Apparatus test (DoorCollisionApparatusTests) loads door GfxObj 0x010044B5
from the real dat, builds the door entity's shape list via
ShadowShapeBuilder, registers via RegisterMultiPart, and sweeps a player
sphere into the door from three angles. Pre-fix: all three assertions
fail — the sphere walks straight through. The [cyl-test] probe fires
every tick (the small Sphere shape is queried) but no [resolve-bldg] —
the per-Part BSP entry is never reached.

Root cause: ShadowObjectRegistry.GetNearbyObjects deduplicates on
entry.EntityId via HashSet<uint>. Pre-RegisterMultiPart each entity had
exactly one shadow row, so dedup-by-entityId correctly suppressed
multi-cell duplication. After Task 4's RegisterMultiPart introduced
multi-shape rows (1 Sphere + 1 per-Part-BSP for doors; potentially more
for creatures + items), the dedup silently drops everything after the
first. ShadowShapeBuilder emits Sphere shapes before Part-BSPs, so the
Sphere wins and the BSP is dropped — exactly the "Task 7 produced zero
[resolve-bldg] hits" finding from the 2026-05-24 evening handoff.

Fix: dedup on the full ShadowEntry. record-struct equality compares
all fields (EntityId, GfxObjId, Position, Rotation, Radius,
CollisionType, CylHeight, Scale, State, Flags, LocalPosition,
LocalRotation). Distinct shapes of the same entity are not equal and
make it through; the same shape registered in multiple cells (its
fields identical across calls) dedups exactly as before.

Apparatus verification post-fix: all 4 tests pass.
  - Dead-center front approach: BLOCKED at Y=11.5 normal=(0,-1,0).
  - 50 cm off-center: BLOCKED at Y=11.5 normal=(0,-1,0).
  - Back approach from inside: BLOCKED at Y=12.8 normal=(0,+1,0).
  - Diagnostic dump: BSP fires at tick 5.

What this fix DOES NOT do: switch live RegisterLiveEntityCollision to
use ShadowShapeBuilder + RegisterMultiPart. That's Task 7 of the
original plan, still reverted. With this foundation fix in place,
Task 7 should now actually deliver door blocking in production.

Test impact: 44/44 in the shape/registry/door scope pass. The broader
Physics suite shows the pre-existing PhysicsResolveCapture
static-state flakiness documented in CLAUDE.md — 6 baseline failures
without my new tests, 10 with them (4 extra are my apparatus tests'
IsPlayer-flag resolves getting captured by a concurrent Capture-test
race). Independent of this fix; verified by isolating each test
class.

Findings + apparatus reasoning:
docs/research/2026-05-24-door-dat-inspection-findings.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 18:47:04 +02:00
..
Allegiance feat(allegiance): Phase H.2 AllegianceRequests + AllegianceTree model 2026-04-18 17:17:45 +02:00
Audio feat(audio): Phase E.2 OpenAL engine + SoundTable cookbook + hook wiring 2026-04-18 16:38:26 +02:00
Chat fix(chat): /help client-side handler + System dedup + ThatIsNotAValidCommand template 2026-04-25 21:22:07 +02:00
Combat feat(combat): Phase L.1c wire live attack input 2026-04-28 11:58:57 +02:00
Items feat(items): Phase F.2 ItemRepository + AppraiseRequest round-trip 2026-04-18 16:55:36 +02:00
Lighting feat(lighting): Phase G.2 — Setup.Lights + SetLightHook wiring 2026-04-19 10:46:49 +02:00
Meshing feat(vfx #C.1.5b): SetupPartTransforms helper for per-part anchor transforms 2026-05-11 23:54:33 +02:00
Physics fix(phys): GetNearbyObjects dedup-by-entityId silently drops multi-part shadows 2026-05-24 18:47:04 +02:00
Player feat(player): #6 fold enchantment buffs into vital max via EnchantmentMath 2026-04-25 17:55:15 +02:00
Plugins fix(movement+anim+session): clothing dedup, motion wire format, jump-skill default 2026-04-18 15:01:32 +02:00
Rendering feat(O-T3): extract GL infrastructure to AcDream.App 2026-05-21 16:00:31 +02:00
Selection fix(picker): Cluster A #86 — cell-BSP ray occlusion in WorldPicker 2026-05-19 14:41:56 +02:00
Spells fix(player): EnchantmentMask bit fix + Vitae key=0 + absolute Vitals overlay 2026-04-25 18:15:20 +02:00
Terrain chore(phys): A6.P3 #98 triage — revert neg-poly + bldg-check experiments 2026-05-23 15:11:49 +02:00
Textures feat(O-T2): extract pure stateless helpers to AcDream.Core.Rendering.Wb 2026-05-21 15:13:26 +02:00
Ui fix(retail): rotation rate, useability gate, retail toast strings 2026-05-16 12:17:54 +02:00
Vfx fix(vfx #56): ParticleHookSink applies CreateParticleHook.PartIndex transform 2026-05-11 23:57:20 +02:00
World chore(phys): A6.P3 #98 triage — revert neg-poly + bldg-check experiments 2026-05-23 15:11:49 +02:00
AcDream.Core.csproj chore(O-T7): code-review housekeeping after WB extraction 2026-05-21 17:29:06 +02:00