feat(physics): S2 chunk 1b - callers supply the visual part array; installed-DAT comparator

Every production registration now hands ShadowObjectRegistry the object's
whole visual part array beside its collision dispatch: static publication
(App LandblockPhysicsPublisher and the headless Content twin) through
ShadowShapeBuilder.FromStaticRenderParts, live entities (Runtime
LiveEntityCollisionBuilder) through the new FromSetupRenderParts, which walks
every Setup part with the same physics-sphere-else-drawing-sphere and
part-box rule from the PhysicsDataCache Runtime already reaches. Nothing
consumes the retail products yet; the App hermetic lane still passes
6,758/6,758.

The Lane=InstalledDat comparator registers five real fixtures through the
real publication inputs and prints retail CELLARRAY, collision cells, and
the old render cells side by side: Facility Hub stair Setup 0x02000623
(7 cells incl. 0x8A02015F/015E), cathedral ramp 0x020009A2 (3 cells, the
genuine multi-part case), the #334 Neftet formation (25 cells), and a
landblock-edge crosser (6 cells, 2 in the neighbor block). All three
answers agree for BSP-bearing objects, as the shared primitive predicts;
the divergence chunk 3 expects appears only for decorative non-BSP parts.

Core Physics 2,202/2,202; Runtime 1,884/1,884; App hermetic 6,758/6,758;
comparator + stair pin 5/5; solution Release build 0 warnings / 0 errors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-02 21:52:35 +02:00
parent 059b8883ab
commit 5a2792d689
7 changed files with 908 additions and 11 deletions

View file

@ -953,6 +953,20 @@ public sealed class LandblockPhysicsPublisher
entity.MeshRefs,
entity.IsBuildingShell,
publication.StagingCache.GetGfxObj);
// Campaign OVERHAUL S2 chunk 1b: retail's WHOLE visual part array —
// every visual part of this static, colliding or not — beside the
// BSP-only/primitive-only COLLISION dispatch above and below. The
// SAME resolver pair WalkProductionWorldData.ResolveStaticRenderCells
// already reads off this landblock's PhysicsDataCache. A side
// product only: no consumer reads it yet.
IReadOnlyList<ShadowShape> partArray =
ShadowShapeBuilder.FromStaticRenderParts(
entity.MeshRefs,
publication.StagingCache.GetGfxObj,
publication.StagingCache.GetVisualBounds,
out _);
entityBspCount = bspShapes.Count;
if (entityBspCount > 0)
{
@ -967,7 +981,8 @@ public sealed class LandblockPhysicsPublisher
publication.Origin.Y,
landblock.LandblockId,
seedCellId: entity.ParentCellId ?? 0u,
isStatic: true);
isStatic: true,
partArray: partArray);
LogMultipartRegistration(landblock, entity, bspShapes);
}
@ -1060,7 +1075,8 @@ public sealed class LandblockPhysicsPublisher
publication.Origin.Y,
landblock.LandblockId,
seedCellId: entity.ParentCellId ?? 0u,
isStatic: true);
isStatic: true,
partArray: partArray);
LogSetupRegistration(landblock, entity, setupShapes);
entityCylinderCount = setupShapes.Count;
}