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:
1 parent
32b8670833
commit
976d012a86
10 files changed
+767
-11
No files matched your search
@@ -478,9 +478,9 @@ public:
|
||||
using Clock=std::chrono::steady_clock;
|
||||
Owner=&World;WorldAssembly=InWorldAssembly;
|
||||
WorkerCount=1;DetailVariant=Variant;Scheduler=nullptr;
|
||||
// Region pages use the immutable manifest for conservative block proofs, while keeping
|
||||
// the legacy SurfaceWorld density evaluator so existing tile hashes remain exact.
|
||||
bUseNativeManifestFields=false;
|
||||
// Analytic pages retain their bounded owner bins for route bookkeeping. Once published,
|
||||
// the Core world binds each page to its base shape as the single density evaluator.
|
||||
bUseNativeManifestFields=true;
|
||||
RoundTunnelsEnabled=bInRoundTunnels;bAnalyticOnly=true;bProfileDetailBand=false;
|
||||
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(); }
|
||||
FIntVector GetEditBoundsMin() const { return EditBoundsMin; }
|
||||
FIntVector GetEditBoundsMax() const { return EditBoundsMax; }
|
||||
@@ -1017,6 +1020,7 @@ public:
|
||||
// edge interpolation and normals to the existing mesher.
|
||||
float DensityAt(float X,float Y,float Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DensityAt(X,Y,Z);
|
||||
if(bNativeOnly)
|
||||
{
|
||||
if(!NativeOnlyContains(X,Y,Z))
|
||||
@@ -1050,6 +1054,7 @@ public:
|
||||
|
||||
float DensityAtLattice(int32 X,int32 Y,int32 Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DensityAtLattice(X,Y,Z);
|
||||
if(bNativeOnly)
|
||||
{
|
||||
if(!NativeOnlyContains(static_cast<float>(X),static_cast<float>(Y),
|
||||
@@ -1089,6 +1094,7 @@ public:
|
||||
|
||||
float DensityAtUnclamped(float X,float Y,float Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DensityAtUnclamped(X,Y,Z);
|
||||
if(bNativeOnly)
|
||||
{
|
||||
if(!NativeOnlyContains(X,Y,Z))
|
||||
@@ -1117,6 +1123,7 @@ public:
|
||||
|
||||
VoxelForgeCore::DetailFieldSample DetailSampleAt(float X,float Y,float Z) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->DetailSampleAt(X,Y,Z);
|
||||
VoxelForgeCore::DetailFieldSample Sample;
|
||||
if(bNativeOnly)
|
||||
{RecordNativeOnlyViolation();return Sample;}
|
||||
@@ -1135,6 +1142,11 @@ public:
|
||||
void DensityAtLatticeX8(int32 XStart,int32 XStep,int32 Y,int32 Z,
|
||||
int32 Count,float OutDensity[8]) const
|
||||
{
|
||||
if(SharedDensitySource)
|
||||
{
|
||||
SharedDensitySource->DensityAtLatticeX8(XStart,XStep,Y,Z,Count,OutDensity);
|
||||
return;
|
||||
}
|
||||
Count=std::clamp(Count,0,8);
|
||||
if(Count==0)return;
|
||||
if(bNativeOnly)
|
||||
@@ -1241,6 +1253,8 @@ private:
|
||||
float* OutFloorInfluence=nullptr,
|
||||
bool bApplyEdits=true) const
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->AnalyticDensityAt(X,Y,Z,
|
||||
bClampNearZero,OutDetailDisplacement,OutCaveInfluence,OutFloorInfluence,bApplyEdits);
|
||||
if(OutDetailDisplacement)*OutDetailDisplacement=0.0f;
|
||||
if(OutCaveInfluence)*OutCaveInfluence=0.0f;
|
||||
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
|
||||
@@ -1303,6 +1317,8 @@ public:
|
||||
bool GetNativeSurfaceHeightsAt(float X,float Y,int32 ChunkZ,
|
||||
float& OutGroundZ,float& OutCeilingZ) const
|
||||
{
|
||||
if(SharedDensitySource)
|
||||
return SharedDensitySource->GetNativeSurfaceHeightsAt(X,Y,ChunkZ,OutGroundZ,OutCeilingZ);
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
|
||||
||!std::isfinite(X)||!std::isfinite(Y))return false;
|
||||
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
|
||||
{
|
||||
if(SharedDensitySource)return SharedDensitySource->IsNativeSurfaceBox(Origin,Step,Cells);
|
||||
if(!WorldAssembly||!Owner||!Owner->Manager||Step<=0||Cells<=0)return false;
|
||||
const int32 Pad=std::max(Step,1);
|
||||
const int32 BMin=Origin.Z-Pad;
|
||||
@@ -1377,6 +1394,8 @@ public:
|
||||
FBoxClassification ClassifyBoxDetailed(const FIntVector& Origin,int32 Step,int32 Cells,
|
||||
bool bUseNativeLatticeProof=false) const
|
||||
{
|
||||
if(SharedDensitySource)
|
||||
return SharedDensitySource->ClassifyBoxDetailed(Origin,Step,Cells,bUseNativeLatticeProof);
|
||||
using Clock=std::chrono::steady_clock;
|
||||
const auto Start=Clock::now();
|
||||
const int32 Pad=std::max(Step,1);
|
||||
@@ -1557,6 +1576,7 @@ public:
|
||||
|
||||
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);
|
||||
const size_t Line=static_cast<size_t>(Y-Min[1])*Size[0]
|
||||
+static_cast<size_t>(X-Min[0]);
|
||||
@@ -2083,7 +2103,8 @@ private:
|
||||
bool NativeFloatingIslandDensityAt(float X,float Y,float Z,float& OutDensity) const
|
||||
{
|
||||
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.
|
||||
// Convertir Z du Core vers la coordonnee de chunk legacy du proprietaire.
|
||||
const double CoreVoxelsPerLegacyChunk=GetCoreVoxelsPerOwnerChunk();
|
||||
@@ -4823,6 +4844,11 @@ public:
|
||||
void DensityAtLatticeZRun(int32 X,int32 Y,int32 ZStart,int32 ZStep,
|
||||
int32 Count,float* OutDensity) const
|
||||
{
|
||||
if(SharedDensitySource)
|
||||
{
|
||||
SharedDensitySource->DensityAtLatticeZRun(X,Y,ZStart,ZStep,Count,OutDensity);
|
||||
return;
|
||||
}
|
||||
if(Count<=0||OutDensity==nullptr)return;
|
||||
if(bNativeOnly)
|
||||
{
|
||||
@@ -5353,6 +5379,7 @@ private:
|
||||
|
||||
FStandaloneOwnerWorld* Owner=nullptr;
|
||||
const VoxelForgeCore::WorldAssemblyManifest* WorldAssembly=nullptr;
|
||||
const FStandaloneShapeWorld* SharedDensitySource=nullptr;
|
||||
int32 WorkerCount=6;
|
||||
const VoxelForgeCore::JobScheduler* Scheduler=nullptr;
|
||||
bool RoundTunnelsEnabled=false;
|
||||
|
||||
Reference in new issue
Block a user