feat(render) Campaign FW3.1: production walk world data behind the seam
The retail frame walk's world model now materializes from production landblock-build owners through the legal IDatReaderWriter seam, with zero frame wiring (FW3.2 roots the frame): - WalkCellFactory: WalkCell built in the SAME pass as LoadedCell (EnvCellLandblockBuild.BuildVisibilityCell) from the raw portal Flags/polygons/planes/stab lists already parsed there; stored as LoadedCell.Walk, committed atomically with the cell. The fixture-pinned decodes (inverse-0x2 portal side, 0xFFFF->0xFFFFFFFF exit widening) live here. - WalkBuildingFactory + WalkBuildingRegistry: the production WalkBuilding build (drawing BSP with PORT nodes, degrade ladder, portal sides/stab lists, sort center, model frame) from the SAME LandBlockInfo the streaming build already fetches, under the factory's existing DAT lock - closing the gap where BuildingLoader drops every walk field at load. - WalkLandscapeAssembler: the retail 51x51 viewer-centred grid (mid_radius 25) fed incrementally from landblock publish/retire; per-block z-slab (heightTable[max]+200 / [min]-1) computed worker-side in LandblockBuildFactory from the heights already in hand. O(1) SetViewer on same-block frames. - WalkProductionFrameContext: the walk's frame contexts over CellVisibility + WalkBuildingRegistry with a generic inverse-view-projection ray caster (rays feed cross products only - scale-free) and the znear=0.1 CY plane. - Publication: LandblockRenderPublisher owns both walk registries, publishing in the same AdvanceCompleteOne step as BuildingRegistry and retiring in RemoveBuildingRegistry - same commit, same retirement, no new ticket stage. Conformance: ALL TEN oracle fixtures replay identically through the PRODUCTION builders (WalkProductionWorldConformanceTests) - same signatures as the test adapter, first run. Known gap documented for FW3.2: far-tier landblocks carry no EnvCell transaction, so their z-slab never reaches the assembler. Suites: full Release build 0 warnings; Walk lane 186/1 skip; hermetic 6,738/0 (+24); RuntimeDatAccessArchitectureTests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b95850defe
commit
b10ad662b0
14 changed files with 1711 additions and 2 deletions
|
|
@ -178,6 +178,15 @@ public sealed class LandblockBuildFactory
|
|||
worldOffset,
|
||||
_heightTable));
|
||||
var envCellBuild = new AcDream.App.Rendering.Wb.EnvCellLandblockBuildBuilder(landblockId);
|
||||
// Campaign FW3.1: the walk landscape's per-block z-slab
|
||||
// (CLandBlock::calc_lighting-adjacent unpack @0x0052f1d0). Every
|
||||
// near-tier landblock has outdoor terrain heights regardless of
|
||||
// whether it has interior cells or buildings, so this is
|
||||
// unconditional — unlike WalkBuildings (added below, inside
|
||||
// BuildInteriorEntitiesForStreaming, where LandBlockInfo is already
|
||||
// in hand).
|
||||
(float walkMaxZ, float walkMinZ) = ComputeWalkZSlab(baseLoaded.Heightmap.Height);
|
||||
envCellBuild.SetWalkZSlab(walkMaxZ, walkMinZ);
|
||||
merged.AddRange(BuildInteriorEntitiesForStreaming(
|
||||
landblockId,
|
||||
lbX,
|
||||
|
|
@ -448,6 +457,17 @@ public sealed class LandblockBuildFactory
|
|||
(lbY - origin.CenterY) * 192f,
|
||||
0f);
|
||||
|
||||
// Campaign FW3.1: the walk's building placements (portals + drawing
|
||||
// BSP + degrade ladder + sort center), read from the SAME
|
||||
// LandBlockInfo.Buildings this method already fetched above — no
|
||||
// extra DAT read. This closes the gap where Wb.BuildingLoader
|
||||
// .AddBuilding (update thread, no DAT access) keeps only
|
||||
// ModelId/Frame/portal-flags/stab-lists for its own BFS seeding and
|
||||
// drops everything the frame walk needs.
|
||||
envCellBuild.AddWalkBuildings(
|
||||
AcDream.App.Rendering.Walk.WalkBuildingFactory.Build(
|
||||
_dats, landblockId, lbInfo.Buildings, lbOffset));
|
||||
|
||||
// Per-landblock id namespace — see AcDream.Core.World.InteriorEntityIdAllocator
|
||||
// for the full bit layout + history. Distinct from scenery (0x80000000+) and
|
||||
// landblock stabs (0xC0000000+, ids from LandblockLoader).
|
||||
|
|
@ -649,6 +669,24 @@ public sealed class LandblockBuildFactory
|
|||
}
|
||||
|
||||
|
||||
/// <summary>Campaign FW3.1: retail's per-block z-slab
|
||||
/// (<c>WalkLandscapeDatBuilder</c>'s port target —
|
||||
/// <c>CLandBlock::calc_lighting</c>-adjacent unpack @0x0052f1d0):
|
||||
/// <c>max_zval = heightTable[maxByte] + 200</c>,
|
||||
/// <c>min_zval = heightTable[minByte] - 1</c>, over the landblock's own
|
||||
/// 81-byte heightmap. Uses <see cref="_heightTable"/> — already a
|
||||
/// constructor field, so this needs no additional DAT read.</summary>
|
||||
private (float MaxZ, float MinZ) ComputeWalkZSlab(byte[] heights)
|
||||
{
|
||||
byte maxByte = 0, minByte = 255;
|
||||
foreach (byte h in heights)
|
||||
{
|
||||
if (h > maxByte) maxByte = h;
|
||||
if (h < minByte) minByte = h;
|
||||
}
|
||||
return (_heightTable[maxByte] + 200f, _heightTable[minByte] - 1f);
|
||||
}
|
||||
|
||||
private static float SampleTerrainZ(DatReaderWriter.DBObjs.LandBlock block, float[] heightTable, float localX, float localY)
|
||||
{
|
||||
uint landblockX = (block.Id >> 24) & 0xFFu;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue