wip(assembler): round L13 -- one density field for every route (multiplayer determinism fix)

Region pages fell back to the legacy GetDensityAt evaluator while the base shape used the Core
manifest field, so a tile's density (and sometimes mesh) depended on streaming history. Pages
are now bound to their world's base FStandaloneShapeWorld evaluator before publication; density,
lattice, detail, classification and solid queries all delegate to it. WorldAssemblyEvaluatorVersion
5 -> 6. Route-parity audit: fails on L12 (5/5); after the fix 0 mismatches over 87 tile pairs
(base/page, base/native-only, edited, two histories), 56 exact-query pairs, 2.3M page samples,
4 seeds/recipes. Page-tile proof audit: 1,274 blocks, 0 violations. The spawn and island worlds
are unchanged; crossing output changed as intended. Reviewer interleaved spawn: +1.1% (noise).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-20 01:54:54 +02:00
1 parent 32b8670833
commit 976d012a86
10 files changed
+767 -11

No files matched your search

+17
View File
@@ -1823,6 +1823,23 @@ column metrics. All W1/W12 L1 hashes, exact queries, and the seed-0 FloatingIsla
the pre-L7 binary with Clang FP contraction off and GCC defaults. See the pre-L7 binary with Clang FP contraction off and GCC defaults. See
[`Standalone/Research/WorldAssemblerM3/Linux7/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux7/REPORT.md). [`Standalone/Research/WorldAssemblerM3/Linux7/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux7/REPORT.md).
### 8.36 Route-invariant Core density — World Assembler M3 L13
For an unedited Core world, tile density, mesh, payload, and topology are a function of the world
manifest/recipe, seed, and tile key. The reviewed manifest field is authoritative: SurfaceWorld uses
its `Heightfield2D`, while FloatingIslands uses its `FloatingIslandFieldV1`. `World::densityAt` and
tile generation read the same `FStandaloneShapeWorld` instance. A compiled analytic region page
retains bounded spatial bins for page ownership and routing, but `SetSharedDensitySource` binds it to
that base shape before publication; density, lattice, detail, classification, and solid queries
delegate to the shared evaluator. This keeps exact queries, collision occupancy signs, page tiles,
and base tiles on one field. Player edits remain explicit versioned overlays on that world state.
The route-binding change increments `WorldAssemblyEvaluatorVersion` from 5 to 6. Do not restore a
page-local legacy evaluator: it disagrees with the reviewed field. Uniform-block proof audits must
fill and check page tiles against the evaluator they actually sample. This is the shared Core path;
the Unreal adapter and its asynchronous MPSC/Epoch flow are unchanged. See
[`Standalone/Research/WorldAssemblerM3/Linux13/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux13/REPORT.md).
## 9. Multiplayer model (listen-server first, dedicated-friendly) ## 9. Multiplayer model (listen-server first, dedicated-friendly)
> **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a > **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a
+9
View File
@@ -1128,6 +1128,15 @@ Mixed/Unknown remains on the fill path. The headless `--audit-uniform-block-proo
verification, while `--profile-lod-work` reports per-LOD filled samples; both are off by default. verification, while `--profile-lod-work` reports per-LOD filled samples; both are off by default.
Implementation and evidence: [`Standalone/Research/WorldAssemblerM3/Linux9/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux9/REPORT.md). Implementation and evidence: [`Standalone/Research/WorldAssemblerM3/Linux9/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux9/REPORT.md).
### 3.22 Route-invariant Core density — World Assembler M3 Linux13
| Symbol | Canonical file | Role |
|---|---|---|
| `FStandaloneShapeWorld::SetSharedDensitySource`, `SharedDensitySource` | `Standalone/Core/src/ShapeWorldInternal.h`, bound before publication in `Standalone/Core/src/VoxelForgeCore.cpp` | Makes compiled analytic pages delegate field, lattice, detail, classification, and solid queries to the Core world's base shape; `WorldAssemblyEvaluatorVersion` is 6. |
The base manifest field is authoritative for tile generation and exact queries. See ARCHITECTURE
§8.36 and [`Standalone/Research/WorldAssemblerM3/Linux13/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux13/REPORT.md).
## 4. The density pipeline (most-edited hot path) ## 4. The density pipeline (most-edited hot path)
### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749 ### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749
@@ -235,7 +235,8 @@ namespace VoxelForgeCore
// L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles. // L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles.
inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256; inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256;
inline constexpr std::uint32_t WorldAssemblySchemaVersion = 1; inline constexpr std::uint32_t WorldAssemblySchemaVersion = 1;
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 5; // Version 6 binds every compiled tile page to the world's base density evaluator.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 6;
enum class FieldChannel : std::uint32_t enum class FieldChannel : std::uint32_t
{ {
@@ -1050,6 +1051,9 @@ namespace VoxelForgeCore
std::int32_t bandMaxZVoxel = 2147483647; std::int32_t bandMaxZVoxel = 2147483647;
bool hashDensity = false; bool hashDensity = false;
bool captureDensitySamples = false; bool captureDensitySamples = false;
// Diagnostic only; materialize the full density lattice even when block proofs
// establish that the tile has no surface.
bool forceFullDensityCapture = false;
bool skipUvAndColors = false; bool skipUvAndColors = false;
bool skipUv = false; bool skipUv = false;
bool skipColors = false; bool skipColors = false;
+31 -4
View File
@@ -478,9 +478,9 @@ public:
using Clock=std::chrono::steady_clock; using Clock=std::chrono::steady_clock;
Owner=&World;WorldAssembly=InWorldAssembly; Owner=&World;WorldAssembly=InWorldAssembly;
WorkerCount=1;DetailVariant=Variant;Scheduler=nullptr; WorkerCount=1;DetailVariant=Variant;Scheduler=nullptr;
// Region pages use the immutable manifest for conservative block proofs, while keeping // Analytic pages retain their bounded owner bins for route bookkeeping. Once published,
// the legacy SurfaceWorld density evaluator so existing tile hashes remain exact. // the Core world binds each page to its base shape as the single density evaluator.
bUseNativeManifestFields=false; bUseNativeManifestFields=true;
RoundTunnelsEnabled=bInRoundTunnels;bAnalyticOnly=true;bProfileDetailBand=false; RoundTunnelsEnabled=bInRoundTunnels;bAnalyticOnly=true;bProfileDetailBand=false;
for(int32 A=0;A<3;++A) for(int32 A=0;A<3;++A)
{ {
@@ -991,6 +991,9 @@ public:
} }
} }
void SetSharedDensitySource(const FStandaloneShapeWorld* Source)
{ SharedDensitySource=Source==this?nullptr:Source; }
bool HasEditTransaction() const { return !EditBrushes.empty(); } bool HasEditTransaction() const { return !EditBrushes.empty(); }
FIntVector GetEditBoundsMin() const { return EditBoundsMin; } FIntVector GetEditBoundsMin() const { return EditBoundsMin; }
FIntVector GetEditBoundsMax() const { return EditBoundsMax; } FIntVector GetEditBoundsMax() const { return EditBoundsMax; }
@@ -1017,6 +1020,7 @@ public:
// edge interpolation and normals to the existing mesher. // edge interpolation and normals to the existing mesher.
float DensityAt(float X,float Y,float Z) const float DensityAt(float X,float Y,float Z) const
{ {
if(SharedDensitySource)return SharedDensitySource->DensityAt(X,Y,Z);
if(bNativeOnly) if(bNativeOnly)
{ {
if(!NativeOnlyContains(X,Y,Z)) if(!NativeOnlyContains(X,Y,Z))
@@ -1050,6 +1054,7 @@ public:
float DensityAtLattice(int32 X,int32 Y,int32 Z) const float DensityAtLattice(int32 X,int32 Y,int32 Z) const
{ {
if(SharedDensitySource)return SharedDensitySource->DensityAtLattice(X,Y,Z);
if(bNativeOnly) if(bNativeOnly)
{ {
if(!NativeOnlyContains(static_cast<float>(X),static_cast<float>(Y), if(!NativeOnlyContains(static_cast<float>(X),static_cast<float>(Y),
@@ -1089,6 +1094,7 @@ public:
float DensityAtUnclamped(float X,float Y,float Z) const float DensityAtUnclamped(float X,float Y,float Z) const
{ {
if(SharedDensitySource)return SharedDensitySource->DensityAtUnclamped(X,Y,Z);
if(bNativeOnly) if(bNativeOnly)
{ {
if(!NativeOnlyContains(X,Y,Z)) if(!NativeOnlyContains(X,Y,Z))
@@ -1117,6 +1123,7 @@ public:
VoxelForgeCore::DetailFieldSample DetailSampleAt(float X,float Y,float Z) const VoxelForgeCore::DetailFieldSample DetailSampleAt(float X,float Y,float Z) const
{ {
if(SharedDensitySource)return SharedDensitySource->DetailSampleAt(X,Y,Z);
VoxelForgeCore::DetailFieldSample Sample; VoxelForgeCore::DetailFieldSample Sample;
if(bNativeOnly) if(bNativeOnly)
{RecordNativeOnlyViolation();return Sample;} {RecordNativeOnlyViolation();return Sample;}
@@ -1135,6 +1142,11 @@ public:
void DensityAtLatticeX8(int32 XStart,int32 XStep,int32 Y,int32 Z, void DensityAtLatticeX8(int32 XStart,int32 XStep,int32 Y,int32 Z,
int32 Count,float OutDensity[8]) const int32 Count,float OutDensity[8]) const
{ {
if(SharedDensitySource)
{
SharedDensitySource->DensityAtLatticeX8(XStart,XStep,Y,Z,Count,OutDensity);
return;
}
Count=std::clamp(Count,0,8); Count=std::clamp(Count,0,8);
if(Count==0)return; if(Count==0)return;
if(bNativeOnly) if(bNativeOnly)
@@ -1241,6 +1253,8 @@ private:
float* OutFloorInfluence=nullptr, float* OutFloorInfluence=nullptr,
bool bApplyEdits=true) const bool bApplyEdits=true) const
{ {
if(SharedDensitySource)return SharedDensitySource->AnalyticDensityAt(X,Y,Z,
bClampNearZero,OutDetailDisplacement,OutCaveInfluence,OutFloorInfluence,bApplyEdits);
if(OutDetailDisplacement)*OutDetailDisplacement=0.0f; if(OutDetailDisplacement)*OutDetailDisplacement=0.0f;
if(OutCaveInfluence)*OutCaveInfluence=0.0f; if(OutCaveInfluence)*OutCaveInfluence=0.0f;
if(OutFloorInfluence)*OutFloorInfluence=0.0f; if(OutFloorInfluence)*OutFloorInfluence=0.0f;
@@ -1303,6 +1317,8 @@ public:
bool GetNativeSurfaceHeightsAt(float X,float Y,int32 ChunkZ, bool GetNativeSurfaceHeightsAt(float X,float Y,int32 ChunkZ,
float& OutGroundZ,float& OutCeilingZ) const float& OutGroundZ,float& OutCeilingZ) const
{ {
if(SharedDensitySource)
return SharedDensitySource->GetNativeSurfaceHeightsAt(X,Y,ChunkZ,OutGroundZ,OutCeilingZ);
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
||!std::isfinite(X)||!std::isfinite(Y))return false; ||!std::isfinite(X)||!std::isfinite(Y))return false;
const std::int64_t chunkMinimum=static_cast<std::int64_t>(ChunkZ)*CHUNK_SIZE; const std::int64_t chunkMinimum=static_cast<std::int64_t>(ChunkZ)*CHUNK_SIZE;
@@ -1339,6 +1355,7 @@ public:
bool IsNativeSurfaceBox(const FIntVector& Origin,int32 Step,int32 Cells) const bool IsNativeSurfaceBox(const FIntVector& Origin,int32 Step,int32 Cells) const
{ {
if(SharedDensitySource)return SharedDensitySource->IsNativeSurfaceBox(Origin,Step,Cells);
if(!WorldAssembly||!Owner||!Owner->Manager||Step<=0||Cells<=0)return false; if(!WorldAssembly||!Owner||!Owner->Manager||Step<=0||Cells<=0)return false;
const int32 Pad=std::max(Step,1); const int32 Pad=std::max(Step,1);
const int32 BMin=Origin.Z-Pad; const int32 BMin=Origin.Z-Pad;
@@ -1377,6 +1394,8 @@ public:
FBoxClassification ClassifyBoxDetailed(const FIntVector& Origin,int32 Step,int32 Cells, FBoxClassification ClassifyBoxDetailed(const FIntVector& Origin,int32 Step,int32 Cells,
bool bUseNativeLatticeProof=false) const bool bUseNativeLatticeProof=false) const
{ {
if(SharedDensitySource)
return SharedDensitySource->ClassifyBoxDetailed(Origin,Step,Cells,bUseNativeLatticeProof);
using Clock=std::chrono::steady_clock; using Clock=std::chrono::steady_clock;
const auto Start=Clock::now(); const auto Start=Clock::now();
const int32 Pad=std::max(Step,1); const int32 Pad=std::max(Step,1);
@@ -1557,6 +1576,7 @@ public:
bool IsRock(int32 X,int32 Y,int32 Z) const bool IsRock(int32 X,int32 Y,int32 Z) const
{ {
if(SharedDensitySource)return SharedDensitySource->IsRock(X,Y,Z);
if(!Contains(X,Y,Z))return EvaluateFast(X,Y,Z); if(!Contains(X,Y,Z))return EvaluateFast(X,Y,Z);
const size_t Line=static_cast<size_t>(Y-Min[1])*Size[0] const size_t Line=static_cast<size_t>(Y-Min[1])*Size[0]
+static_cast<size_t>(X-Min[0]); +static_cast<size_t>(X-Min[0]);
@@ -2083,7 +2103,8 @@ private:
bool NativeFloatingIslandDensityAt(float X,float Y,float Z,float& OutDensity) const bool NativeFloatingIslandDensityAt(float X,float Y,float Z,float& OutDensity) const
{ {
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return false; ||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))
return false;
// Convert Core query Z back to the owner's legacy chunk coordinate. // Convert Core query Z back to the owner's legacy chunk coordinate.
// Convertir Z du Core vers la coordonnee de chunk legacy du proprietaire. // Convertir Z du Core vers la coordonnee de chunk legacy du proprietaire.
const double CoreVoxelsPerLegacyChunk=GetCoreVoxelsPerOwnerChunk(); const double CoreVoxelsPerLegacyChunk=GetCoreVoxelsPerOwnerChunk();
@@ -4823,6 +4844,11 @@ public:
void DensityAtLatticeZRun(int32 X,int32 Y,int32 ZStart,int32 ZStep, void DensityAtLatticeZRun(int32 X,int32 Y,int32 ZStart,int32 ZStep,
int32 Count,float* OutDensity) const int32 Count,float* OutDensity) const
{ {
if(SharedDensitySource)
{
SharedDensitySource->DensityAtLatticeZRun(X,Y,ZStart,ZStep,Count,OutDensity);
return;
}
if(Count<=0||OutDensity==nullptr)return; if(Count<=0||OutDensity==nullptr)return;
if(bNativeOnly) if(bNativeOnly)
{ {
@@ -5353,6 +5379,7 @@ private:
FStandaloneOwnerWorld* Owner=nullptr; FStandaloneOwnerWorld* Owner=nullptr;
const VoxelForgeCore::WorldAssemblyManifest* WorldAssembly=nullptr; const VoxelForgeCore::WorldAssemblyManifest* WorldAssembly=nullptr;
const FStandaloneShapeWorld* SharedDensitySource=nullptr;
int32 WorkerCount=6; int32 WorkerCount=6;
const VoxelForgeCore::JobScheduler* Scheduler=nullptr; const VoxelForgeCore::JobScheduler* Scheduler=nullptr;
bool RoundTunnelsEnabled=false; bool RoundTunnelsEnabled=false;
+4 -1
View File
@@ -1386,6 +1386,8 @@ namespace VoxelForgeCore
compiledRegions[i]=std::move(region); compiledRegions[i]=std::move(region);
} }
} }
for(const auto& region:compiledRegions)
if(region)region->SetSharedDensitySource(impl_->shape.get());
{ {
std::unordered_map<TileKey,std::shared_ptr<FStandaloneShapeWorld>,TileKeyHash> publish; std::unordered_map<TileKey,std::shared_ptr<FStandaloneShapeWorld>,TileKeyHash> publish;
publish.reserve(stats.tileKeysCovered); publish.reserve(stats.tileKeysCovered);
@@ -2021,7 +2023,8 @@ namespace VoxelForgeCore
MeshBandMinZVoxel,MeshBandMaxZVoxel,&sampleCount,nullptr,nullptr, MeshBandMinZVoxel,MeshBandMaxZVoxel,&sampleCount,nullptr,nullptr,
(options.hashDensity||options.captureDensitySamples)?&densityValues:nullptr, (options.hashDensity||options.captureDensitySamples)?&densityValues:nullptr,
options.profileMesherStages?&McStageTimings:nullptr, options.profileMesherStages?&McStageTimings:nullptr,
options.auditUniformBlockProofs?&BlockProofAudit:nullptr); options.auditUniformBlockProofs?&BlockProofAudit:nullptr,
options.forceFullDensityCapture);
if(options.auditUniformBlockProofs) if(options.auditUniformBlockProofs)
{ {
out.diagnostics.uniformBlockProofsChecked=BlockProofAudit.CheckedBlocks; out.diagnostics.uniformBlockProofsChecked=BlockProofAudit.CheckedBlocks;
@@ -0,0 +1,140 @@
# VoxelForge M3 Linux13 — route-invariant density
## Field decision and fix
The approved reference is the Core base shape built from the reviewed owner manifest: `Heightfield2D`
for SurfaceWorld and `FloatingIslandFieldV1` for FloatingIslands. L12's base route sampled that
field. Its analytic pages instead fell through to the copied legacy owner `GetDensityAt` evaluator,
so the same key could sample different values after the player crossed into a page. In the L12
SurfaceWorld audit, all 48 base-covered LOD1 candidates had different density; 10 also differed in
mesh, payload, and topology. A 214,375-sample L12 negative-control run measured max/mean density
delta `0.076171875 / 0.0133467594`, 29 sign changes, 170 edge-crossing changes, and up to 1.7778
voxels of surface displacement. The manifest field is the approved Core world and is the reference
kept here.
Changing the page manifest flag alone did not fix FloatingIslands: 8/8 page pairs still failed,
with max density delta `433.925781`, 262,676 sign changes, and 17,188 edge-crossing changes across
343,000 samples. The source fix binds each compiled page to its world's base `FStandaloneShapeWorld`
before publication. Page density, lattice, detail, classification, and solid queries now delegate
to that one evaluator; the legacy page-local evaluator is no longer an independent output route.
`WorldAssemblyEvaluatorVersion` is bumped from 5 to 6.
## Route parity
The L12 evaluator-v5 negative control fails as required: 5/5 selected base/page pairs mismatch. After the fix,
four audits passed: SurfaceWorld seeds 0, 1, and 17, plus FloatingIslands seed 0.
| Compared routes | Pairs | Mismatches |
|---|---:|---:|
| Base vs page (28 clipmap-requested pages; 26 base-covered page controls) | 54 | 0 |
| Base vs native-only shape-free route (SurfaceWorld LOD0) | 27 | 0 |
| Edited base vs edited page | 4 | 0 |
| Same key built in initial and moved-world history | 2 | 0 |
| Tile samples vs exact Core queries at LOD2–8 | 56 | 0 |
All 87 tile-generation pairs match density, mesh, payload, and topology hashes. The 56 higher-LOD
pairs compare the sampled tile lattice to direct `densityAt` / `densityAtLattice` queries; these
also match all sampled densities and solid/air signs. The owner fixture has
`full_res_clip_levels=2`, so analytic page routes exist only at LOD0–1. In total, page comparisons
covered 2,315,250 density samples with zero delta, sign, edge-crossing, or surface-root differences;
6,172,229 exact-query samples had zero mismatches. The audit exits nonzero on any output-hash,
sample, route-verification, exact-query, or proof-violation mismatch.
The history probe builds the same LOD0 key in a second Core world after a 96 m camera move. Both
SurfaceWorld and FloatingIslands match all four hashes across those two build histories. The edit
probe applies a sequence-1 density offset centered on a sampled sign crossing; it changes the field,
and edited base/page results still match.
### Page proof audit
The fill-and-check audit generated page tiles with full density capture and uniform-block proof
verification, so it checked the field those pages actually sample. Across the four audits it checked
1,274 blocks / 1,695,694 samples: 518 blocks used the exact fallback, 6 were unknown, and there were
zero false proofs or violations. SurfaceWorld walkability passed 5,642/5,642, 6,080/6,080, and
4,785/4,785 samples for seeds 0, 1, and 17; FloatingIslands passed 4,000/4,000. Shape readiness
passed 27/27 near-ring tiles where eligible. FloatingIslands has no eligible native-only tiles.
## Cost, hashing off
W12, seed 0, `--force-generate`, camera `0,-35,-487.94`, with the same crossing setup as L12:
| Move | Entering tiles | L12 crossing | L13 crossing | L13 peak RSS |
|---|---:|---:|---:|---:|
| 8 m | 144 | 0.0347 s | 0.0399 s | 468 MiB |
| 16 m | 288 | 0.1249 s | 0.0856 s | 513 MiB |
| 24 m | 432 | 0.1635 s | 0.1242 s | 512 MiB |
| 32 m | 576 | 0.1717 s | 0.1692 s | 511 MiB |
| 1 km | 2,260 | 1.2474 s | 0.7696 s | 673 MiB |
Three W12 spawn runs had medians of 157 ms first tile, 180 ms near ring, and 1.499 s whole view;
L12 medians were 146 ms, 161 ms, and 1.361 s. Each spawn run generated the same 2,553-tile
benchmark view. The final timings are in `Saved/Linux/l13-crossing-final-*.log` and
`Saved/Linux/l13-spawn-final-*.log`.
## Determinism and invariants
All 28 required configurations passed: SurfaceWorld and FloatingIslands seed 0; Clang
`-ffp-contract=off` and GCC default; W1/W8/W12, with five W12 repeats per compiler and recipe. Each
run matched all 12 rows (full detail, whole view, LOD0–8, exact queries) against L12/L11.
| Recipe | Full detail D/M/P/T | Whole view D/M/P/T | Exact density / unclamped / detail / collision |
|---|---|---|---|
| SurfaceWorld | `0x0ee0579bd15cbbe4 / 0x32e5d4964d610fee / 0x1932b96ee4b1d910 / 0x69743c6bad3447dc` | `0xc10697a8f48380c7 / 0xe75c9119a1498cd5 / 0x49a9a8d1835a6c8c / 0xedcb23288b5e8724` | `0xe4d4a8eb95b35933 / 0xe4d4a8eb95b35933 / 0xefcba20c0c70c415 / 0xe604823a249029bf` |
| FloatingIslands | `0x6d842d2878b08ef6 / 0x4b868a3184f08035 / 0x2cedf2236788752d / 0xeac17d5e0cb5044a` | `0x5be4d8cde79b2a76 / 0x96f75041f6861b3a / 0x3700a516cc89d50c / 0x6b99948d6eab4f21` | `0x61daded9c303becb / 0x61daded9c303becb / 0xefcba20c0c70c415 / 0x84d37463be9b0573` |
The crossing output changes as intended. The 24 m W1 and W12 moved-tile hashes match each other:
`0x337ca62131576728 / 0x7612f48e2ddbbaab / 0x69a67ed4add83b87 / 0xf11ac1ebd0f7ddb8` (D/M/P/T),
replacing L12's `0x174588abdc8c0d2c / 0x4c401e27d9d05dea / 0xeb10d9801c5ef125 / 0xf59d12304d0dcb4a`.
The L3 FP-contract preamble and runtime self-test, L4 `FLazy`, L7 shared column cache, L9/L12
proofs, and L11 native-only readiness/crash fixes were preserved. The L6 screen-space controls
still pass their six same-LOD checks and reject the missing/floating-surface, global-octave, and
stride-2 negative controls as required. Its whole gate still rejects the known far-field error over
the 1 px bound (exit 6); the route binding does not affect those LOD3–8 base-field comparisons.
The asynchronous MPSC/Epoch path and `ARCHITECTURE.md` §8.10 invariants are unchanged. No Unreal
adapter files were touched; the Core exact-query and collision-sign routes were checked, but Unreal
collision cooking was not built here. `ARCHITECTURE.md` §8.36 and `CODEMAP.md` §3.22 document the new
route law.
Builds and runs used CPUs 0–11, at most 12 workers, a 6 GiB address-space cap, and a 6,000,000,000
byte RSS monitor. The governor remained `powersave`. Peak sampled RSS was 904 MiB across runs
(673 MiB in the no-hash cost table); the GCC build process group peaked at 4.27 GiB. Clang and GCC
builds passed. No system changes or Unreal builds were made.
## Failed and retried runs
- `l13-route-baseline-s0-w12.log` exited 2 because the inferred binary-relative owner JSON path did
not exist; reruns used the explicit repository JSON. The first baseline capture used the wrong
camera, then an audit pass had empty proof-skipped density captures; the final L12 negative
control is `l13-route-baseline-s0-w12-r4.log`.
- `l13-route-fi-diagnostic.log` and `l13-route-fi-diagnostic-r2.log` intentionally exposed the
remaining FloatingIslands split before the shared-source binding; both exit 9 on 8/8 mismatches.
- `l13-route-edit-s0.log` exited 9 because its brush did not change the selected tile. Centering the
brush on a sampled sign crossing fixed the audit in `l13-route-edit-s0-r2.log`.
- `l13-route-history-sw-s0.log` exited 9 because the second-world probe exceeded the 4,096-node
region compiler envelope. The retry compiles one matching LOD0 anchor tile and passes.
- The first `l13-cost-*` measurements omitted `--force-generate` and used the owner JSON start;
those are not used above. The final crossing and spawn runs use L12's camera and force-generation
setting. The screen-space run's exit 6 is its expected far-field rejection, not a retried run.
- All final builds, the 28 hash runs, eight no-hash cost runs, and two crossing-hash runs completed
within their limits. No commit, push, or stash was made.
## Multiplayer note for the owner
Peers with the same manifest, seed, evaluator version 6, and tile key now reconstruct the same Core
density and tile output through each available base, page, or native-only route, regardless of
arrival history; terrain geometry still does not need to cross the network. Player edits remain an
explicit versioned diff that must be ordered and synchronized between peers.
## Orchestrator review (Claude)
- **Spawn cost re-run by me, 5 interleaved W12 pairs, no hashing:** whole view L12
1.385/1.405/1.419/1.443/1.460 s vs L13 1.401/1.448/1.430/1.435/1.451 s (median 1.419 → 1.435 s,
+1.1%, within noise); near ring 0.168 → 0.171 s. The +10% in the cost table above compares L13 runs
with L12 numbers from another session; interleaved, there is no measurable spawn regression.
- The fix is structural: pages are bound to their world's single base `FStandaloneShapeWorld`
evaluator before publication, so routes can't diverge by construction. The negative control fails
on L12 (5/5), and the 87 tile pairs, 56 exact-query pairs and 2.3M page samples show 0 mismatches
after. The page lifetime is safe because the base shape is owned by the `World` and outlives its pages.
- Crossing output changed, as intended (evaluator version 5 → 6); the spawn and island worlds are
unchanged.
@@ -43,6 +43,7 @@ namespace
bool AuditUniformBlockProofs=false; bool AuditUniformBlockProofs=false;
bool ProfileLodWork=false; bool ProfileLodWork=false;
bool AuditBasePageEquivalence=false; bool AuditBasePageEquivalence=false;
bool AuditRouteParity=false;
bool RegionCrossing=false; bool RegionCrossing=false;
bool AuditTileShapeReadiness=false; bool AuditTileShapeReadiness=false;
int DiagnosticSlowShapeCompileMs=0; int DiagnosticSlowShapeCompileMs=0;
@@ -122,6 +123,7 @@ namespace
" --audit-uniform-block-proofs (fill and check every interval-certified block)\n" " --audit-uniform-block-proofs (fill and check every interval-certified block)\n"
" --profile-lod-work (report per-LOD density sample counts)\n" " --profile-lod-work (report per-LOD density sample counts)\n"
" --audit-base-page-equivalence (hash one tile through both shape routes)\n" " --audit-base-page-equivalence (hash one tile through both shape routes)\n"
" --audit-route-parity (compare page, native-only, exact-query and mesh routes)\n"
" --audit-tile-shape-readiness (run a deliberately mis-marked tile against the native-only guard)\n" " --audit-tile-shape-readiness (run a deliberately mis-marked tile against the native-only guard)\n"
" --diagnostic-slow-shape-compile-ms=N (diagnostic overlap control; default 0)\n" " --diagnostic-slow-shape-compile-ms=N (diagnostic overlap control; default 0)\n"
" --render-distance-chunks=N (0 disables the extra far ring)\n" " --render-distance-chunks=N (0 disables the extra far ring)\n"
@@ -142,6 +144,7 @@ namespace
else if(arg=="--audit-uniform-block-proofs")options.AuditUniformBlockProofs=true; else if(arg=="--audit-uniform-block-proofs")options.AuditUniformBlockProofs=true;
else if(arg=="--profile-lod-work")options.ProfileLodWork=true; else if(arg=="--profile-lod-work")options.ProfileLodWork=true;
else if(arg=="--audit-base-page-equivalence")options.AuditBasePageEquivalence=true; else if(arg=="--audit-base-page-equivalence")options.AuditBasePageEquivalence=true;
else if(arg=="--audit-route-parity")options.AuditRouteParity=true;
else if(arg=="--region-crossing")options.RegionCrossing=true; else if(arg=="--region-crossing")options.RegionCrossing=true;
else if(arg=="--audit-tile-shape-readiness")options.AuditTileShapeReadiness=true; else if(arg=="--audit-tile-shape-readiness")options.AuditTileShapeReadiness=true;
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true; else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
@@ -373,5 +376,6 @@ int main(int argc,char** argv)
options.CameraPitchDegrees,options.ScreenSpaceGate,options.UseSharedColumnCache, options.CameraPitchDegrees,options.ScreenSpaceGate,options.UseSharedColumnCache,
cameraStepVoxels,options.AuditUniformBlockProofs,options.ProfileLodWork, cameraStepVoxels,options.AuditUniformBlockProofs,options.ProfileLodWork,
options.RegionCrossing,options.AuditTileShapeReadiness, options.RegionCrossing,options.AuditTileShapeReadiness,
options.DiagnosticSlowShapeCompileMs,options.AuditBasePageEquivalence); options.DiagnosticSlowShapeCompileMs,options.AuditBasePageEquivalence,
options.AuditRouteParity);
} }
+550 -1
View File
@@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <bit>
#include <chrono> #include <chrono>
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
@@ -23,6 +24,113 @@
namespace StandaloneStreamBenchmark namespace StandaloneStreamBenchmark
{ {
struct FRouteDensityComparison
{
std::uint64_t samples=0;
std::uint64_t signMismatches=0;
std::uint64_t crossingEdgeMismatches=0;
std::uint64_t sharedCrossingEdges=0;
std::uint64_t exactQuerySamples=0;
std::uint64_t exactQueryMismatches=0;
double maxAbsoluteDelta=0.0;
double sumAbsoluteDelta=0.0;
double maxSurfaceDisplacementVoxels=0.0;
double sumSurfaceDisplacementVoxels=0.0;
bool valid=false;
};
inline FRouteDensityComparison CompareRouteDensities(
const VoxelForgeCore::TileMesh& A,const VoxelForgeCore::TileMesh& B,
const VoxelForgeCore::World& World)
{
FRouteDensityComparison Result;
if(A.debugDensitySamples.empty()
||A.debugDensitySamples.size()!=B.debugDensitySamples.size())return Result;
const double Root=std::cbrt(static_cast<double>(A.debugDensitySamples.size()));
const std::int32_t Dim=static_cast<std::int32_t>(std::llround(Root));
if(Dim<4||static_cast<std::size_t>(Dim)*Dim*Dim!=A.debugDensitySamples.size())return Result;
const std::int32_t GridDim=Dim-3;
const std::int32_t Extent=CHUNK_SIZE<<A.key.lod;
if(GridDim<=0||Extent%GridDim!=0)return Result;
const std::int32_t Step=Extent/GridDim;
const FVoxelTileKey NativeKey(
FIntVector(A.key.coordinate.x,A.key.coordinate.y,A.key.coordinate.z),A.key.lod);
const FIntVector Origin=NativeKey.OriginVoxels();
const auto Index=[Dim](std::int32_t X,std::int32_t Y,std::int32_t Z)
{return (static_cast<std::size_t>(Z)*Dim+Y)*Dim+X;};
const auto IsSolid=[](float Density){return Density<0.0f;};
const auto EdgeCrosses=[&](const std::vector<float>& Values,
std::int32_t X0,std::int32_t Y0,std::int32_t Z0,
std::int32_t X1,std::int32_t Y1,std::int32_t Z1)
{
return IsSolid(Values[Index(X0,Y0,Z0)])!=IsSolid(Values[Index(X1,Y1,Z1)]);
};
for(std::int32_t Z=0;Z<Dim;++Z)
for(std::int32_t Y=0;Y<Dim;++Y)
for(std::int32_t X=0;X<Dim;++X)
{
const std::size_t I=Index(X,Y,Z);
const float DA=A.debugDensitySamples[I],DB=B.debugDensitySamples[I];
if(!std::isfinite(DA)||!std::isfinite(DB))return Result;
const double Delta=std::abs(static_cast<double>(DA)-DB);
Result.maxAbsoluteDelta=std::max(Result.maxAbsoluteDelta,Delta);
Result.sumAbsoluteDelta+=Delta;
Result.signMismatches+=IsSolid(DA)!=IsSolid(DB)?1u:0u;
++Result.samples;
const std::int32_t WorldX=Origin.X+(X-1)*Step;
const std::int32_t WorldY=Origin.Y+(Y-1)*Step;
const std::int32_t WorldZ=Origin.Z+(Z-1)*Step;
const VoxelForgeCore::Vec3i Lattice{WorldX,WorldY,WorldZ};
const float ExactLattice=World.densityAtLattice(Lattice);
const float ExactPoint=World.densityAt({static_cast<double>(WorldX),
static_cast<double>(WorldY),static_cast<double>(WorldZ)});
++Result.exactQuerySamples;
if(std::bit_cast<std::uint32_t>(DA)!=std::bit_cast<std::uint32_t>(ExactLattice)
||std::bit_cast<std::uint32_t>(DA)!=std::bit_cast<std::uint32_t>(ExactPoint))
++Result.exactQueryMismatches;
}
const auto CompareEdge=[&](std::int32_t X0,std::int32_t Y0,std::int32_t Z0,
std::int32_t X1,std::int32_t Y1,std::int32_t Z1)
{
const bool CrossA=EdgeCrosses(A.debugDensitySamples,X0,Y0,Z0,X1,Y1,Z1);
const bool CrossB=EdgeCrosses(B.debugDensitySamples,X0,Y0,Z0,X1,Y1,Z1);
if(CrossA!=CrossB)++Result.crossingEdgeMismatches;
if(!CrossA||!CrossB)return;
const float A0=A.debugDensitySamples[Index(X0,Y0,Z0)];
const float A1=A.debugDensitySamples[Index(X1,Y1,Z1)];
const float B0=B.debugDensitySamples[Index(X0,Y0,Z0)];
const float B1=B.debugDensitySamples[Index(X1,Y1,Z1)];
const double TA=static_cast<double>(A0)/(static_cast<double>(A0)-A1);
const double TB=static_cast<double>(B0)/(static_cast<double>(B0)-B1);
const double Displacement=std::abs(TA-TB)*Step;
Result.maxSurfaceDisplacementVoxels=std::max(
Result.maxSurfaceDisplacementVoxels,Displacement);
Result.sumSurfaceDisplacementVoxels+=Displacement;
++Result.sharedCrossingEdges;
};
for(std::int32_t Z=0;Z<Dim;++Z)
for(std::int32_t Y=0;Y<Dim;++Y)
for(std::int32_t X=0;X<Dim;++X)
{
if(X+1<Dim)CompareEdge(X,Y,Z,X+1,Y,Z);
if(Y+1<Dim)CompareEdge(X,Y,Z,X,Y+1,Z);
if(Z+1<Dim)CompareEdge(X,Y,Z,X,Y,Z+1);
}
Result.valid=true;
return Result;
}
inline bool SameTileOutput(const VoxelForgeCore::TileMesh& A,
const VoxelForgeCore::TileMesh& B)
{
return A.hasDensityHash&&B.hasDensityHash&&A.hasMeshHash&&B.hasMeshHash
&&A.hasPayloadHash&&B.hasPayloadHash&&A.hasTopologyHash&&B.hasTopologyHash
&&A.densityHash==B.densityHash&&A.meshHash==B.meshHash
&&A.payloadHash==B.payloadHash&&A.topologyHash==B.topologyHash;
}
struct FSceneExportWriter struct FSceneExportWriter
{ {
std::ofstream File; std::ofstream File;
@@ -145,7 +253,7 @@ namespace StandaloneStreamBenchmark
bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false, bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false,
bool bRegionCrossing=false, bool bRegionCrossing=false,
bool bAuditTileShapeReadiness=false,int DiagnosticSlowShapeCompileMs=0, bool bAuditTileShapeReadiness=false,int DiagnosticSlowShapeCompileMs=0,
bool bAuditBasePageEquivalence=false) bool bAuditBasePageEquivalence=false,bool bAuditRouteParity=false)
{ {
using Clock=std::chrono::steady_clock; using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld; FStandaloneOwnerWorld& World=*OwnerWorld;
@@ -472,6 +580,447 @@ namespace StandaloneStreamBenchmark
return 9; return 9;
} }
} }
if(bAuditRouteParity)
{
struct FRouteAuditCandidate
{
VoxelForgeCore::TileKey Key;
bool bWouldRequestPage=false;
};
struct FRouteAuditRow
{
FRouteAuditCandidate Candidate;
std::optional<VoxelForgeCore::TileMesh> Base;
};
VoxelForgeCore::TileGenerationOptions CaptureOptions;
CaptureOptions.hashDensity=true;
CaptureOptions.captureDensitySamples=true;
CaptureOptions.forceFullDensityCapture=true;
CaptureOptions.profileMesherStages=true;
std::vector<FRouteAuditRow> Rows;
Rows.reserve(static_cast<std::size_t>(World.FullResClipLevels)*8);
std::vector<VoxelForgeCore::TileKey> PageKeys;
PageKeys.reserve(Rows.capacity());
const int32 AuditPageLODs=std::min(World.FullResClipLevels,3);
std::vector<const FStandaloneDesiredTileSet*> CandidateSets{&Desired};
if(bHasCameraStep)CandidateSets.push_back(&MovedDesired);
for(int32 LOD=0;LOD<AuditPageLODs;++LOD)
{
for(const bool bPageRequested:{true,false})
{
int32 SurfaceCandidates=0;
bool bHaveFlatCandidate=false;
int32 Inspected=0;
for(const FStandaloneDesiredTileSet* CandidateSet:CandidateSets)
{
for(const FVoxelTileKey& Tile:CandidateSet->Tiles)
{
if(Tile.Level!=LOD)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
if(Shape.isTileShapeFree(Key)
||Shape.needsTileRegion(Key)!=bPageRequested)continue;
if(Inspected++>=256)break;
std::string BaseError;
auto Base=Shape.generateTile(Key,CaptureOptions,BaseError);
if(!Base)
{
std::printf("[RouteParityCandidate] route=%s key=(%d,%d,%d,lod%d) base=FAIL error=%s\n",
bPageRequested?"actual-page":"base-covered-page",Key.coordinate.x,
Key.coordinate.y,Key.coordinate.z,Key.lod,BaseError.c_str());
continue;
}
const bool bHasSurface=!Base->vertices.empty()&&!Base->indices.empty();
if(bHasSurface&&SurfaceCandidates<3)
{
Rows.push_back({{Key,bPageRequested},std::move(Base)});
PageKeys.push_back(Key);
++SurfaceCandidates;
}
else if(!bHasSurface&&!bHaveFlatCandidate)
{
Rows.push_back({{Key,bPageRequested},std::move(Base)});
PageKeys.push_back(Key);
bHaveFlatCandidate=true;
}
if(SurfaceCandidates>=3&&bHaveFlatCandidate)break;
}
if(SurfaceCandidates>=3&&bHaveFlatCandidate)break;
}
}
}
if(Rows.empty())
{
std::printf("[RouteParityAudit] status=UNAVAILABLE reason=no_page_route_candidates\n");
Streamer.Stop();
return 9;
}
VoxelForgeCore::TileGenerationOptions PageOptions=CaptureOptions;
PageOptions.auditUniformBlockProofs=true;
int32 BasePageMismatches=0,PageRoutesVerified=0;
std::uint64_t PageProofBlocks=0,PageProofSamples=0,PageProofFallbacks=0,
PageProofUnknown=0,PageProofViolations=0;
std::uint64_t PageExactSamples=0,PageExactMismatches=0;
double MaxDensityDelta=0.0,SumDensityDelta=0.0;
std::uint64_t ComparedDensitySamples=0,SignMismatches=0,
CrossingEdgeMismatches=0,SharedCrossingEdges=0;
double MaxSurfaceDisplacement=0.0,SumSurfaceDisplacement=0.0;
for(const FRouteAuditRow& Row:Rows)
if(Row.Base)
{
const FRouteDensityComparison Query=CompareRouteDensities(
*Row.Base,*Row.Base,Shape);
PageExactSamples+=Query.exactQuerySamples;
PageExactMismatches+=Query.exactQueryMismatches;
}
else ++BasePageMismatches;
VoxelForgeCore::TileRegionCompileStats PageStats;
std::size_t CoveredPageKeys=0;
std::string PageCompileError;
const bool bPagesCompiled=Shape.compileTileRegion(PageKeys,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
PageCompileError,&CoveredPageKeys,&PageStats,true,true);
if(!bPagesCompiled)
{
std::printf("[RouteParityAudit] page_compile=FAIL error=%s\n",PageCompileError.c_str());
Streamer.Stop();
return 9;
}
for(FRouteAuditRow& Row:Rows)
{
std::string Error;
const auto Page=Shape.generateTile(Row.Candidate.Key,PageOptions,Error);
const bool bVerifiedPage=Page&&Page->diagnostics.analyticRegionPageRoute;
PageRoutesVerified+=bVerifiedPage?1:0;
const bool bSame=Row.Base&&bVerifiedPage&&SameTileOutput(*Row.Base,*Page);
const FRouteDensityComparison Comparison=Page&&Row.Base
?CompareRouteDensities(*Page,*Row.Base,Shape):FRouteDensityComparison{};
if(!bSame||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++BasePageMismatches;
PageExactSamples+=Comparison.exactQuerySamples;
PageExactMismatches+=Comparison.exactQueryMismatches;
MaxDensityDelta=std::max(MaxDensityDelta,Comparison.maxAbsoluteDelta);
SumDensityDelta+=Comparison.sumAbsoluteDelta;
ComparedDensitySamples+=Comparison.samples;
SignMismatches+=Comparison.signMismatches;
CrossingEdgeMismatches+=Comparison.crossingEdgeMismatches;
SharedCrossingEdges+=Comparison.sharedCrossingEdges;
MaxSurfaceDisplacement=std::max(MaxSurfaceDisplacement,
Comparison.maxSurfaceDisplacementVoxels);
SumSurfaceDisplacement+=Comparison.sumSurfaceDisplacementVoxels;
if(Page)
{
PageProofBlocks+=Page->diagnostics.uniformBlockProofsChecked;
PageProofSamples+=Page->diagnostics.uniformBlockProofSamplesChecked;
PageProofFallbacks+=Page->diagnostics.uniformBlockProofFallbackBlocks;
PageProofUnknown+=Page->diagnostics.uniformBlockProofUnknownBlocks;
PageProofViolations+=Page->diagnostics.uniformBlockProofViolations;
}
std::printf("[RouteParityPair] route=base/page key=(%d,%d,%d,lod%d) page_requested=%d page_verified=%d same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu max_abs_density_delta=%.9g sign_mismatches=%llu edge_crossing_mismatches=%llu shared_surface_edges=%llu max_surface_delta_vox=%.9g exact_query_mismatches=%llu base_native_float=%llu page_native_float=%llu first_density=(%.9g,%.9g) status=%s error=%s\n",
Row.Candidate.Key.coordinate.x,Row.Candidate.Key.coordinate.y,
Row.Candidate.Key.coordinate.z,Row.Candidate.Key.lod,
Row.Candidate.bWouldRequestPage?1:0,bVerifiedPage?1:0,
Row.Base&&Page&&Row.Base->densityHash==Page->densityHash?1:0,
Row.Base&&Page&&Row.Base->meshHash==Page->meshHash?1:0,
Row.Base&&Page&&Row.Base->payloadHash==Page->payloadHash?1:0,
Row.Base&&Page&&Row.Base->topologyHash==Page->topologyHash?1:0,
static_cast<unsigned long long>(Comparison.samples),
Comparison.maxAbsoluteDelta,
static_cast<unsigned long long>(Comparison.signMismatches),
static_cast<unsigned long long>(Comparison.crossingEdgeMismatches),
static_cast<unsigned long long>(Comparison.sharedCrossingEdges),
Comparison.maxSurfaceDisplacementVoxels,
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
static_cast<unsigned long long>(Row.Base?Row.Base->diagnostics.floatFieldCalls:0),
static_cast<unsigned long long>(Page?Page->diagnostics.floatFieldCalls:0),
Row.Base&&!Row.Base->debugDensitySamples.empty()
?Row.Base->debugDensitySamples.front():0.0f,
Page&&!Page->debugDensitySamples.empty()?Page->debugDensitySamples.front():0.0f,
bSame&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Page?Error.c_str():Error.c_str());
}
int32 NativeMismatches=0,NativeRoutesVerified=0;
std::uint64_t NativeExactSamples=0,NativeExactMismatches=0;
int32 NativePairs=0;
VoxelForgeCore::TileGenerationOptions NativeOptions=CaptureOptions;
NativeOptions.diagnosticForceNativeOnly=true;
for(const FVoxelTileKey& Tile:ShapeFreeTiles)
{
if(NativePairs>=9)break;
if(!Neighborhood.contains(Tile))continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string BaseError,NativeError;
const auto Base=Shape.generateTile(Key,CaptureOptions,BaseError);
const auto Native=Shape.generateTile(Key,NativeOptions,NativeError);
++NativePairs;
const bool bVerifiedNative=Native&&Native->diagnostics.nativeOnlyRoute;
NativeRoutesVerified+=bVerifiedNative?1:0;
const bool bSame=Base&&bVerifiedNative&&SameTileOutput(*Base,*Native);
const FRouteDensityComparison Comparison=Base&&Native
?CompareRouteDensities(*Native,*Base,Shape):FRouteDensityComparison{};
NativeExactSamples+=Comparison.exactQuerySamples;
NativeExactMismatches+=Comparison.exactQueryMismatches;
if(!bSame||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++NativeMismatches;
std::printf("[RouteParityPair] route=compiled/native-only key=(%d,%d,%d,lod%d) native_verified=%d same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
bVerifiedNative?1:0,Base&&Native&&Base->densityHash==Native->densityHash?1:0,
Base&&Native&&Base->meshHash==Native->meshHash?1:0,
Base&&Native&&Base->payloadHash==Native->payloadHash?1:0,
Base&&Native&&Base->topologyHash==Native->topologyHash?1:0,
static_cast<unsigned long long>(Comparison.samples),
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
bSame&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Native?NativeError.c_str():NativeError.c_str());
}
int32 ExactQueryPairs=0,ExactQueryMismatches=0;
std::uint64_t ExactQuerySamples=0;
for(int32 LOD=World.FullResClipLevels;LOD<=World.MaxClipLevel&&LOD<9;++LOD)
{
int32 Added=0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
if(Tile.Level!=LOD||Added>=2)continue;
const VoxelForgeCore::TileKey Key{{Tile.Coord.X,Tile.Coord.Y,Tile.Coord.Z},Tile.Level};
std::string Error;
const auto Mesh=Shape.generateTile(Key,CaptureOptions,Error);
const FRouteDensityComparison Comparison=Mesh
?CompareRouteDensities(*Mesh,*Mesh,Shape):FRouteDensityComparison{};
++ExactQueryPairs;++Added;
ExactQuerySamples+=Comparison.exactQuerySamples;
if(!Mesh||!Comparison.valid||Comparison.exactQueryMismatches!=0)
++ExactQueryMismatches;
std::printf("[RouteParityPair] route=tile/exact-query key=(%d,%d,%d,lod%d) samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
static_cast<unsigned long long>(Comparison.exactQuerySamples),
static_cast<unsigned long long>(Comparison.exactQueryMismatches),
Mesh&&Comparison.valid&&Comparison.exactQueryMismatches==0?"PASS":"FAIL",
Error.c_str());
}
}
int32 EditPairs=0,EditMismatches=0;
const auto EditRow=std::find_if(Rows.begin(),Rows.end(),[](const FRouteAuditRow& Row)
{
return Row.Base&&!Row.Candidate.bWouldRequestPage&&Row.Candidate.Key.lod<=1
&&!Row.Base->vertices.empty()&&!Row.Base->indices.empty();
});
if(EditRow!=Rows.end())
{
VoxelForgeCore::World EditWorld(CoreSnapshot);
std::string EditCompileError;
if(!EditWorld.compile(ShapeRequest,Scheduler,EditCompileError))
{
++EditMismatches;
std::printf("[RouteParityEdit] status=FAIL stage=compile error=%s\n",
EditCompileError.c_str());
}
else
{
const VoxelForgeCore::TileKey Key=EditRow->Candidate.Key;
const std::int32_t Extent=CHUNK_SIZE<<Key.lod;
const std::array<VoxelForgeCore::TileKey,1> EditKeys={Key};
VoxelForgeCore::TileGenerationOptions EditOptions=CaptureOptions;
EditOptions.auditUniformBlockProofs=true;
std::string BeforeError,ApplyError,BaseError,PageCompileError,PageError;
const auto Before=EditWorld.generateTile(Key,EditOptions,BeforeError);
VoxelForgeCore::EditTransaction Transaction;
Transaction.sequence=1;
VoxelForgeCore::EditBrush Brush;
Brush.shape=VoxelForgeCore::EditBrush::Shape::sphere;
Brush.operation=VoxelForgeCore::EditBrush::Operation::densityOffset;
bool bSurfaceCenterFound=false;
if(Before&&!Before->debugDensitySamples.empty())
{
const std::int32_t Dim=static_cast<std::int32_t>(std::llround(
std::cbrt(static_cast<double>(Before->debugDensitySamples.size()))));
const std::int32_t GridDim=Dim-3;
if(Dim>=4&&static_cast<std::size_t>(Dim)*Dim*Dim
==Before->debugDensitySamples.size()&&GridDim>0&&Extent%GridDim==0)
{
const std::int32_t Step=Extent/GridDim;
const std::int32_t OriginX=Key.coordinate.x*Extent;
const std::int32_t OriginY=Key.coordinate.y*Extent;
const std::int32_t OriginZ=Key.coordinate.z*Extent;
const auto Index=[Dim](std::int32_t X,std::int32_t Y,std::int32_t Z)
{return (static_cast<std::size_t>(Z)*Dim+Y)*Dim+X;};
for(std::int32_t Z=0;Z<Dim&&!bSurfaceCenterFound;++Z)
for(std::int32_t Y=0;Y<Dim&&!bSurfaceCenterFound;++Y)
for(std::int32_t X=0;X<Dim&&!bSurfaceCenterFound;++X)
{
for(const std::array<std::int32_t,3>& Delta:
{std::array<std::int32_t,3>{1,0,0},
std::array<std::int32_t,3>{0,1,0},
std::array<std::int32_t,3>{0,0,1}})
{
const std::int32_t NX=X+Delta[0],NY=Y+Delta[1],NZ=Z+Delta[2];
if(NX>=Dim||NY>=Dim||NZ>=Dim)continue;
const float D0=Before->debugDensitySamples[Index(X,Y,Z)];
const float D1=Before->debugDensitySamples[Index(NX,NY,NZ)];
if((D0<0.0f)==(D1<0.0f))continue;
const double T=static_cast<double>(D0)
/(static_cast<double>(D0)-D1);
Brush.a={OriginX+(X-1+T*Delta[0])*Step,
OriginY+(Y-1+T*Delta[1])*Step,
OriginZ+(Z-1+T*Delta[2])*Step};
bSurfaceCenterFound=true;
break;
}
}
}
}
if(!bSurfaceCenterFound)
Brush.a={static_cast<double>(Key.coordinate.x*Extent)+Extent*0.5,
static_cast<double>(Key.coordinate.y*Extent)+Extent*0.5,
static_cast<double>(Key.coordinate.z*Extent)+Extent*0.5};
Brush.radius=10.0;
Brush.strength=-48.0f;
Transaction.brushes.push_back(Brush);
const auto Applied=Before?EditWorld.applyEditTransaction(Transaction,
EditKeys,ApplyError):std::optional<VoxelForgeCore::EditResult>{};
const auto EditedBase=Applied
?EditWorld.generateTile(Key,EditOptions,BaseError)
:std::optional<VoxelForgeCore::TileMesh>{};
VoxelForgeCore::TileRegionCompileStats EditPageStats;
std::size_t EditPageKeys=0;
const bool bEditPageBuilt=EditedBase&&EditWorld.compileTileRegion(EditKeys,
static_cast<std::uint32_t>(std::clamp(WorkerCount,1,16)),Scheduler,
PageCompileError,&EditPageKeys,&EditPageStats,true,true);
const auto EditedPage=bEditPageBuilt
?EditWorld.generateTile(Key,EditOptions,PageError)
:std::optional<VoxelForgeCore::TileMesh>{};
const FRouteDensityComparison EditComparison=EditedBase&&EditedPage
?CompareRouteDensities(*EditedPage,*EditedBase,EditWorld)
:FRouteDensityComparison{};
const bool bEditChanged=Before&&EditedBase
&&Before->densityHash!=EditedBase->densityHash;
const bool bEditPageVerified=EditedPage
&&EditedPage->diagnostics.analyticRegionPageRoute;
const bool bEditSame=EditedBase&&EditedPage&&bEditPageVerified
&&SameTileOutput(*EditedBase,*EditedPage);
const bool bEditPass=Before&&Applied&&EditedBase&&bEditPageBuilt
&&bEditPageVerified&&bEditChanged&&bEditSame&&EditComparison.valid
&&EditComparison.exactQueryMismatches==0;
++EditPairs;
if(!bEditPass)++EditMismatches;
if(EditedPage)
{
PageProofBlocks+=EditedPage->diagnostics.uniformBlockProofsChecked;
PageProofSamples+=EditedPage->diagnostics.uniformBlockProofSamplesChecked;
PageProofFallbacks+=EditedPage->diagnostics.uniformBlockProofFallbackBlocks;
PageProofUnknown+=EditedPage->diagnostics.uniformBlockProofUnknownBlocks;
PageProofViolations+=EditedPage->diagnostics.uniformBlockProofViolations;
}
std::printf("[RouteParityEdit] key=(%d,%d,%d,lod%d) sequence=%llu before_hash=0x%016llx edited_base_hash=0x%016llx edited_page_hash=0x%016llx edit_changed=%d page_verified=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu exact_query_mismatches=%llu status=%s error=%s\n",
Key.coordinate.x,Key.coordinate.y,Key.coordinate.z,Key.lod,
static_cast<unsigned long long>(Transaction.sequence),
static_cast<unsigned long long>(Before?Before->densityHash:0),
static_cast<unsigned long long>(EditedBase?EditedBase->densityHash:0),
static_cast<unsigned long long>(EditedPage?EditedPage->densityHash:0),
bEditChanged?1:0,bEditPageVerified?1:0,
EditedBase&&EditedPage&&EditedBase->meshHash==EditedPage->meshHash?1:0,
EditedBase&&EditedPage&&EditedBase->payloadHash==EditedPage->payloadHash?1:0,
EditedBase&&EditedPage&&EditedBase->topologyHash==EditedPage->topologyHash?1:0,
static_cast<unsigned long long>(EditComparison.samples),
static_cast<unsigned long long>(EditComparison.exactQueryMismatches),
bEditPass?"PASS":"FAIL",
!Before?BeforeError.c_str():!Applied?ApplyError.c_str():
!EditedBase?BaseError.c_str():!bEditPageBuilt?PageCompileError.c_str():
PageError.c_str());
}
}
int32 HistoryPairs=0,HistoryMismatches=0;
if(bHasCameraStep&&bRegionCrossing)
{
const auto MovedAnchor=std::find_if(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[](const FVoxelTileKey& Tile){return Tile.Level==0;});
const auto HistoryRow=std::find_if(Rows.begin(),Rows.end(),
[&](const FRouteAuditRow& Row)
{
if(!Row.Base||Row.Candidate.bWouldRequestPage)return false;
return std::none_of(MovedDesired.Tiles.begin(),MovedDesired.Tiles.end(),
[&](const FVoxelTileKey& Tile)
{
return Tile.Level==Row.Candidate.Key.lod
&&Tile.Coord.X==Row.Candidate.Key.coordinate.x
&&Tile.Coord.Y==Row.Candidate.Key.coordinate.y
&&Tile.Coord.Z==Row.Candidate.Key.coordinate.z;
});
});
if(HistoryRow!=Rows.end()&&MovedAnchor!=MovedDesired.Tiles.end())
{
VoxelForgeCore::ShapeBuildRequest MovedShapeRequest=ShapeRequest;
const FIntVector MovedOrigin=MovedAnchor->OriginVoxels();
const std::int32_t MovedExtent=MovedAnchor->ExtentVoxels();
MovedShapeRequest.minVoxel={MovedOrigin.X,MovedOrigin.Y,MovedOrigin.Z};
MovedShapeRequest.maxVoxel={MovedOrigin.X+MovedExtent,
MovedOrigin.Y+MovedExtent,MovedOrigin.Z+MovedExtent};
MovedShapeRequest.clipMinVoxel=MovedShapeRequest.minVoxel;
MovedShapeRequest.clipMaxVoxel=MovedShapeRequest.maxVoxel;
VoxelForgeCore::World MovedWorld(CoreSnapshot);
std::string MovedShapeError,MovedTileError;
const bool bMovedCompiled=MovedWorld.compile(MovedShapeRequest,Scheduler,
MovedShapeError);
const auto MovedTile=bMovedCompiled
?MovedWorld.generateTile(HistoryRow->Candidate.Key,CaptureOptions,MovedTileError)
:std::optional<VoxelForgeCore::TileMesh>{};
const FRouteDensityComparison HistoryComparison=MovedTile
?CompareRouteDensities(*MovedTile,*HistoryRow->Base,MovedWorld)
:FRouteDensityComparison{};
const bool bHistorySame=MovedTile
&&SameTileOutput(*MovedTile,*HistoryRow->Base)
&&HistoryComparison.valid&&HistoryComparison.exactQueryMismatches==0;
++HistoryPairs;
if(!bHistorySame)++HistoryMismatches;
std::printf("[RouteParityHistory] from=initial_base to=moved_world key=(%d,%d,%d,lod%d) same_density=%d same_mesh=%d same_payload=%d same_topology=%d samples=%llu max_abs_density_delta=%.9g exact_query_mismatches=%llu status=%s error=%s\n",
HistoryRow->Candidate.Key.coordinate.x,HistoryRow->Candidate.Key.coordinate.y,
HistoryRow->Candidate.Key.coordinate.z,HistoryRow->Candidate.Key.lod,
MovedTile&&MovedTile->densityHash==HistoryRow->Base->densityHash?1:0,
MovedTile&&MovedTile->meshHash==HistoryRow->Base->meshHash?1:0,
MovedTile&&MovedTile->payloadHash==HistoryRow->Base->payloadHash?1:0,
MovedTile&&MovedTile->topologyHash==HistoryRow->Base->topologyHash?1:0,
static_cast<unsigned long long>(HistoryComparison.samples),
HistoryComparison.maxAbsoluteDelta,
static_cast<unsigned long long>(HistoryComparison.exactQueryMismatches),
bHistorySame?"PASS":"FAIL",
!bMovedCompiled?MovedShapeError.c_str():MovedTileError.c_str());
}
}
const double MeanDensityDelta=ComparedDensitySamples
?SumDensityDelta/static_cast<double>(ComparedDensitySamples):0.0;
const double MeanSurfaceDisplacement=SharedCrossingEdges
?SumSurfaceDisplacement/static_cast<double>(SharedCrossingEdges):0.0;
const bool bRouteParityPassing=BasePageMismatches==0&&NativeMismatches==0
&&ExactQueryMismatches==0&&EditPairs==1&&EditMismatches==0
&&HistoryPairs==(bHasCameraStep&&bRegionCrossing?1:0)&&HistoryMismatches==0
&&PageRoutesVerified==static_cast<int32>(Rows.size())
&&NativeRoutesVerified==NativePairs&&PageProofViolations==0
&&PageExactMismatches==0&&NativeExactMismatches==0;
std::printf("[RouteParityAudit] seed=%d page_pairs=%zu page_verified=%d page_mismatches=%d native_only_pairs=%d native_verified=%d native_mismatches=%d higher_lod_exact_pairs=%d higher_lod_exact_mismatches=%d edit_pairs=%d edit_mismatches=%d history_pairs=%d history_mismatches=%d exact_query_samples=%llu exact_query_mismatches=%llu page_density_samples=%llu max_abs_density_delta=%.9g mean_abs_density_delta=%.9g sign_mismatches=%llu edge_crossing_mismatches=%llu shared_surface_edges=%llu max_surface_delta_vox=%.9g mean_surface_delta_vox=%.9g page_proof_blocks=%llu page_proof_samples=%llu page_proof_fallbacks=%llu page_proof_unknown=%llu page_proof_violations=%llu status=%s\n",
World.Seed,Rows.size(),PageRoutesVerified,BasePageMismatches,
NativePairs,NativeRoutesVerified,NativeMismatches,ExactQueryPairs,
ExactQueryMismatches,EditPairs,EditMismatches,HistoryPairs,HistoryMismatches,
static_cast<unsigned long long>(PageExactSamples
+NativeExactSamples+ExactQuerySamples),
static_cast<unsigned long long>(PageExactMismatches
+NativeExactMismatches+ExactQueryMismatches),
static_cast<unsigned long long>(ComparedDensitySamples),MaxDensityDelta,
MeanDensityDelta,static_cast<unsigned long long>(SignMismatches),
static_cast<unsigned long long>(CrossingEdgeMismatches),
static_cast<unsigned long long>(SharedCrossingEdges),MaxSurfaceDisplacement,
MeanSurfaceDisplacement,static_cast<unsigned long long>(PageProofBlocks),
static_cast<unsigned long long>(PageProofSamples),
static_cast<unsigned long long>(PageProofFallbacks),
static_cast<unsigned long long>(PageProofUnknown),
static_cast<unsigned long long>(PageProofViolations),
bRouteParityPassing?"PASS":"FAIL");
if(!bRouteParityPassing)
{
Streamer.Stop();
return 9;
}
}
const FStandaloneStreamingUpdate Update=Streamer.UpdateDesiredWithSet(Desired,{},0); const FStandaloneStreamingUpdate Update=Streamer.UpdateDesiredWithSet(Desired,{},0);
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size())) if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
{ {
@@ -122,7 +122,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const FVoxelSharedDensityGrid* InSharedDensityGrid, const FVoxelSharedDensityGrid* InSharedDensityGrid,
std::vector<float>* OutDebugDensitySamples, std::vector<float>* OutDebugDensitySamples,
FVoxelMarchingCubesStageTimings* OutStageTimings, FVoxelMarchingCubesStageTimings* OutStageTimings,
FVoxelUniformBlockProofAuditStats* OutBlockProofAudit) FVoxelUniformBlockProofAuditStats* OutBlockProofAudit,
bool bForceFullDensityCapture)
{ {
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_MesherGenerateMesh); TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_MesherGenerateMesh);
const uint64 StageMesherStartCycles=OutStageTimings?FPlatformTime::Cycles64():0; const uint64 StageMesherStartCycles=OutStageTimings?FPlatformTime::Cycles64():0;
@@ -865,7 +866,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
// allocating the density grid; no samples are skipped for a tile that can contain // allocating the density grid; no samples are skipped for a tile that can contain
// geometry, and the final geometry remains byte-identical because this path emits none. // geometry, and the final geometry remains byte-identical because this path emits none.
if (bHaveUniformBlock && bAllRelevantBlocksSame && bAllRelevantBlocksUniform if (bHaveUniformBlock && bAllRelevantBlocksSame && bAllRelevantBlocksUniform
&& !(Step == 2 && OutDebugDensitySamples != nullptr)) && !(Step == 2 && OutDebugDensitySamples != nullptr)
&& !(bForceFullDensityCapture && OutDebugDensitySamples != nullptr))
{ {
return MeshData; return MeshData;
} }
@@ -120,7 +120,8 @@ public:
const FVoxelSharedDensityGrid* InSharedDensityGrid = nullptr, const FVoxelSharedDensityGrid* InSharedDensityGrid = nullptr,
std::vector<float>* OutDebugDensitySamples = nullptr, std::vector<float>* OutDebugDensitySamples = nullptr,
FVoxelMarchingCubesStageTimings* OutStageTimings = nullptr, FVoxelMarchingCubesStageTimings* OutStageTimings = nullptr,
FVoxelUniformBlockProofAuditStats* OutBlockProofAudit = nullptr); FVoxelUniformBlockProofAuditStats* OutBlockProofAudit = nullptr,
bool bForceFullDensityCapture = false);
//========================================================================= //=========================================================================
// SERVICES (injectés par AVoxelWorld) // SERVICES (injectés par AVoxelWorld)