wip(assembler): round L1 -- Linux baseline on abyss: Linux world identical to Windows

Headless Linux benchmark/hash tool (Clang 19 / GCC 14) sharing the viewer's plan builder and
streaming pipeline (moved verbatim into StreamBenchmarkPipeline.h / WorldAssemblyPrototype.h).
Owner Round17 view: density/mesh/payload/topology hashes equal the Windows S13 reference at
W1/W8/W12 (Clang, 3 runs each) and W8 (GCC), with -ffp-contract=off. No output change.
Baseline (i9-12900H, CPUs 0-11, powersave/balance_performance): whole view W8 3.562 s median,
W12 3.512 s, W1 16.555 s; peak RSS < 605 MiB.
Review: the default-stack crash is 17.3 MiB of static TLS per thread (glibc puts it in the
thread stack; HeightfieldColumnCache 6.8 MB), not recursion -- open, after S14.
MSVC compile of the viewer refactor not verified (no MSVC here).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 18:18:34 +02:00
1 parent ec2afe9c93
commit 1276fd11e3
11 files changed
+1308 -760

No files matched your search

+7 -758
View File
@@ -1,5 +1,7 @@
#include "OwnerWorldLoader.h"
#include "StreamingWorld.h"
#include "StreamBenchmarkPipeline.h"
#include "WorldAssemblyPrototype.h"
#include "StandaloneCoreScheduler.h"
#include "../Core/src/StandaloneSnapshotAdapter.h"
#include "../Research/OwnerShapeWorld/gpu_field_port/GpuFarViewer.h"
@@ -52,6 +54,9 @@
namespace
{
using StandaloneStreamBenchmark::FHashedTile;
using StandaloneStreamBenchmark::HashTileRows;
struct V3 { float X=0.0f,Y=0.0f,Z=0.0f; };
V3 Add(V3 A,V3 B){return {A.X+B.X,A.Y+B.Y,A.Z+B.Z};}
V3 Sub(V3 A,V3 B){return {A.X-B.X,A.Y-B.Y,A.Z-B.Z};}
@@ -6932,354 +6937,6 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
return TotalSamples>0&&LegacyToDetailed.Unmatched+DetailedToLegacy.Unmatched==0?0:10;
}
void HashWord(uint64& Hash,uint64 Word,int32 Bytes=8)
{
for(int32 I=0;I<Bytes;++I)
{
Hash^=static_cast<uint8>(Word>>(I*8));
Hash*=1099511628211ull;
}
}
struct FHashedTile
{
FVoxelTileKey Key;
uint64 Hash=14695981039346656037ull;
};
bool TileKeyLessForHash(const FVoxelTileKey& A,const FVoxelTileKey& B)
{
if(A.Level!=B.Level)return A.Level<B.Level;
if(A.Coord.Z!=B.Coord.Z)return A.Coord.Z<B.Coord.Z;
if(A.Coord.Y!=B.Coord.Y)return A.Coord.Y<B.Coord.Y;
return A.Coord.X<B.Coord.X;
}
uint64 HashTileRows(std::vector<FHashedTile>& Rows)
{
std::sort(Rows.begin(),Rows.end(),[](const FHashedTile& A,const FHashedTile& B)
{return TileKeyLessForHash(A.Key,B.Key);});
uint64 Hash=14695981039346656037ull;
for(const FHashedTile& Row:Rows)
{
HashWord(Hash,static_cast<uint32>(Row.Key.Level),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.X),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Y),4);
HashWord(Hash,static_cast<uint32>(Row.Key.Coord.Z),4);
HashWord(Hash,Row.Hash);
}
return Hash;
}
int RunPipelinedStreamingBenchmark(std::shared_ptr<FStandaloneOwnerWorld> OwnerWorld,
const VoxelForgeCore::ResolvedWorldSnapshot& CoreSnapshot,
const FVector& CameraPositionVoxels,int32 WorkerCount,int32 MaxLevel,
VoxelForgeCore::DetailVariant DetailVariant,const VoxelForgeCore::JobScheduler& Scheduler,
bool bHashDensity,bool bSkipUvAndColors,bool bSkipMaterialGroups,bool bSkipUV,bool bSkipColors,
std::chrono::steady_clock::time_point ColdStart,bool bProfileColumnOverlap,
int32 FarHorizonLOD8InteriorStepVoxels)
{
using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld;
const bool bRoundTunnels=World.Generator->bStandaloneResearchRoundTunnels;
const bool bEnhancedTunnelWalls=World.Generator->bStandaloneResearchEnhancedWalls;
VoxelForgeCore::World Shape(CoreSnapshot);
FStandaloneDesiredTileSet Desired=StandaloneWorldMesher::BuildDesiredSet(World,CameraPositionVoxels);
const auto CoreTiles=Shape.desiredTiles(
{CameraPositionVoxels.X,CameraPositionVoxels.Y,CameraPositionVoxels.Z});
Desired.Tiles.clear();Desired.Tiles.reserve(CoreTiles.size());
for(const auto& Key:CoreTiles)
Desired.Tiles.emplace_back(FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
if(MaxLevel>=0)
Desired.Tiles.erase(std::remove_if(Desired.Tiles.begin(),Desired.Tiles.end(),
[&](const FVoxelTileKey& Tile){return Tile.Level>MaxLevel;}),Desired.Tiles.end());
FIntVector FineMin(INT32_MAX,INT32_MAX,INT32_MAX),FineMax(INT32_MIN,INT32_MIN,INT32_MIN);
FIntVector ClipMin(INT32_MAX,INT32_MAX,INT32_MAX),ClipMax(INT32_MIN,INT32_MIN,INT32_MIN);
for(const FVoxelTileKey& Tile:Desired.Tiles)
{
const FIntVector Origin=Tile.OriginVoxels();const int32 Extent=Tile.ExtentVoxels();
ClipMin.X=std::min(ClipMin.X,Origin.X);ClipMin.Y=std::min(ClipMin.Y,Origin.Y);ClipMin.Z=std::min(ClipMin.Z,Origin.Z);
ClipMax.X=std::max(ClipMax.X,Origin.X+Extent);ClipMax.Y=std::max(ClipMax.Y,Origin.Y+Extent);ClipMax.Z=std::max(ClipMax.Z,Origin.Z+Extent);
if(Tile.Level<World.FullResClipLevels)
{
FineMin.X=std::min(FineMin.X,Origin.X);FineMin.Y=std::min(FineMin.Y,Origin.Y);FineMin.Z=std::min(FineMin.Z,Origin.Z);
FineMax.X=std::max(FineMax.X,Origin.X+Extent);FineMax.Y=std::max(FineMax.Y,Origin.Y+Extent);FineMax.Z=std::max(FineMax.Z,Origin.Z+Extent);
}
}
if(FineMin.X==INT32_MAX||ClipMin.X==INT32_MAX)
{std::fprintf(stderr,"[StreamPipeline] no desired detail or clipmap tiles.\n");return 7;}
const FIntVector CenterChunk=Desired.CenterChunk;
std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash> Neighborhood;
Neighborhood.reserve(32);
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level==0&&std::abs(Tile.Coord.X-CenterChunk.X)<=1
&&std::abs(Tile.Coord.Y-CenterChunk.Y)<=1&&std::abs(Tile.Coord.Z-CenterChunk.Z)<=1)
Neighborhood.insert(Tile);
if(Neighborhood.size()!=27)
{std::fprintf(stderr,"[StreamPipeline] expected 27 player-neighborhood tiles, found %zu.\n",Neighborhood.size());return 7;}
// The initial desired set now owns all clipmap metadata needed by this Core-only run.
// Release the separate compatibility-world generation graph before compiling Core.
World.Generator.reset();
World.Manager.reset();
World.DefinitionStorage.clear();
World.BiomeStorage.clear();
World.OperationStorage.clear();
World.DensitySamples.clear();
std::string BuildError;
const bool bIncludeFarWorld=MaxLevel<0||MaxLevel>=World.FullResClipLevels;
const auto ShapeBuildStart=Clock::now();
VoxelForgeCore::ShapeBuildRequest ShapeRequest;
ShapeRequest.minVoxel={FineMin.X,FineMin.Y,FineMin.Z};
ShapeRequest.maxVoxel={FineMax.X,FineMax.Y,FineMax.Z};
ShapeRequest.clipMinVoxel={ClipMin.X,ClipMin.Y,ClipMin.Z};
ShapeRequest.clipMaxVoxel={ClipMax.X,ClipMax.Y,ClipMax.Z};
ShapeRequest.workerLimit=static_cast<uint32>(std::clamp(WorkerCount,1,16));
ShapeRequest.detail=DetailVariant;ShapeRequest.includeFarWorld=bIncludeFarWorld;
ShapeRequest.roundTunnels=bRoundTunnels;
ShapeRequest.enhancedTunnelWalls=bEnhancedTunnelWalls;
if(!Shape.compile(ShapeRequest,Scheduler,BuildError))
{std::fprintf(stderr,"[StreamPipeline] full shape build failed: %s\n",BuildError.c_str());return 2;}
const auto ShapeReady=Clock::now();
const double ShapeSeconds=std::chrono::duration<double>(ShapeReady-ShapeBuildStart).count();
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
FarHorizonLOD8InteriorStepVoxels);
const auto StreamStart=Clock::now();
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
if(Update.DesiredTiles!=static_cast<int32>(Desired.Tiles.size()))
{
Streamer.Stop();
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles but queued %d.\n",
Desired.Tiles.size(),Update.DesiredTiles);return 7;
}
std::vector<FHashedTile> DensityRows,MeshRows,PayloadRows,TopologyRows;
int32 Finished=0,NeighborhoodFinished=0,FullDetailFinished=0;
int32 FullDetailExpected=0;
struct FColumnXY
{
std::int64_t X=0,Y=0;
bool operator==(const FColumnXY&)const=default;
};
struct FColumnXYHash
{
std::size_t operator()(const FColumnXY& Value)const noexcept
{
const std::size_t X=std::hash<std::int64_t>{}(Value.X);
const std::size_t Y=std::hash<std::int64_t>{}(Value.Y);
return X^(Y+static_cast<std::size_t>(0x9E3779B9u)+(X<<6)+(X>>2));
}
};
struct FFirstColumnUse
{
FVoxelTileKey Tile;
std::uint64_t WorkerHash=0;
};
std::array<std::unordered_map<FColumnXY,std::vector<FFirstColumnUse>,FColumnXYHash>,9> ColumnUsesByLOD;
std::array<std::uint64_t,9> ColumnDuplicateEventsByLOD{},NeighbourDuplicateEventsByLOD{};
std::array<std::uint64_t,9> CrossWorkerNeighbourDuplicateEventsByLOD{};
std::array<std::uint64_t,9> ColumnCaptureTilesByLOD{},ExpectedTilesByLOD{};
std::array<bool,9> ColumnCaptureCompleteByLOD{};
ColumnCaptureCompleteByLOD.fill(true);
std::array<double,9> WorkerSecondsByLOD{};
std::array<double,9> ColumnEvalMsByLOD{},MarchingExclusiveMsByLOD{};
std::array<double,9> GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{};
std::array<double,9> MeshAssemblyMsByLOD{};
std::array<std::uint64_t,9> TileCountByLOD{};
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level>=0&&Tile.Level<static_cast<int32>(ExpectedTilesByLOD.size()))
++ExpectedTilesByLOD[static_cast<std::size_t>(Tile.Level)];
const auto AreSameLODNeighbours=[](const FVoxelTileKey& A,const FVoxelTileKey& B)
{
if(A.Level!=B.Level)return false;
const std::int64_t DX=std::abs(static_cast<std::int64_t>(A.Coord.X)-B.Coord.X);
const std::int64_t DY=std::abs(static_cast<std::int64_t>(A.Coord.Y)-B.Coord.Y);
const std::int64_t DZ=std::abs(static_cast<std::int64_t>(A.Coord.Z)-B.Coord.Z);
return std::max({DX,DY,DZ})<=1&&(DX+DY+DZ)>0;
};
uint64 NativeSolidBoxes=0,NativeAirBoxes=0,NativeMixedBoxes=0,NativeUnknownBoxes=0;
uint64 NativeFieldCalls=0,NativeColumnHits=0,NativeColumnMisses=0,NativeMeshingSkips=0;
double NativeClassificationMilliseconds=0.0,NativeColumnComputeMilliseconds=0.0;
double NativeMeshingMilliseconds=0.0;
for(const FVoxelTileKey& Tile:Desired.Tiles)
if(Tile.Level<World.FullResClipLevels)++FullDetailExpected;
Clock::time_point NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
bool bNeighborhoodReported=false,bFullDetailReported=false;
while(Finished<Update.DesiredTiles)
{
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
if(Ready.empty()){std::this_thread::sleep_for(std::chrono::milliseconds(1));continue;}
for(const FStandaloneCpuTile& Tile:Ready)
{
++Finished;
if(Tile.Key.Level>=0&&Tile.Key.Level<static_cast<int32>(TileCountByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++TileCountByLOD[LOD];
WorkerSecondsByLOD[LOD]+=Tile.WorkerSeconds;
ColumnEvalMsByLOD[LOD]+=Tile.CoreDiagnostics.columnEvaluationExclusiveMilliseconds;
MarchingExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesExclusiveMilliseconds;
GroundRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.groundRefinementExclusiveMilliseconds;
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
}
if(bProfileColumnOverlap&&Tile.Key.Level>=0
&&Tile.Key.Level<static_cast<int32>(ColumnCaptureTilesByLOD.size()))
{
const std::size_t LOD=static_cast<std::size_t>(Tile.Key.Level);
++ColumnCaptureTilesByLOD[LOD];
ColumnCaptureCompleteByLOD[LOD]=ColumnCaptureCompleteByLOD[LOD]
&&Tile.CoreDiagnostics.columnCoordinateCaptureComplete;
std::vector<std::array<std::int64_t,2>> Coordinates=
Tile.CoreDiagnostics.evaluatedColumnCoordinates;
std::sort(Coordinates.begin(),Coordinates.end());
Coordinates.erase(std::unique(Coordinates.begin(),Coordinates.end()),Coordinates.end());
for(const auto& Coordinate:Coordinates)
{
const FColumnXY XY{Coordinate[0],Coordinate[1]};
auto [Uses,Inserted]=ColumnUsesByLOD[LOD].try_emplace(XY);
std::vector<FFirstColumnUse>& PriorUses=Uses->second;
if(Inserted)
{
PriorUses.push_back({Tile.Key,Tile.CoreDiagnostics.columnEvaluationWorkerHash});
continue;
}
++ColumnDuplicateEventsByLOD[LOD];
bool bHasNeighbourDuplicate=false,bHasCrossWorkerNeighbourDuplicate=false;
for(const FFirstColumnUse& Prior:PriorUses)
{
if(!AreSameLODNeighbours(Prior.Tile,Tile.Key))continue;
bHasNeighbourDuplicate=true;
bHasCrossWorkerNeighbourDuplicate=bHasCrossWorkerNeighbourDuplicate
||Prior.WorkerHash!=Tile.CoreDiagnostics.columnEvaluationWorkerHash;
}
if(bHasNeighbourDuplicate)++NeighbourDuplicateEventsByLOD[LOD];
if(bHasCrossWorkerNeighbourDuplicate)
++CrossWorkerNeighbourDuplicateEventsByLOD[LOD];
PriorUses.push_back({Tile.Key,Tile.CoreDiagnostics.columnEvaluationWorkerHash});
}
}
WholeViewReady=std::max(WholeViewReady,Tile.CompletedAt);
if(Neighborhood.contains(Tile.Key))
{
++NeighborhoodFinished;
NeighborhoodReady=std::max(NeighborhoodReady,Tile.CompletedAt);
}
if(Tile.Key.Level<World.FullResClipLevels)
{
++FullDetailFinished;
FullDetailReady=std::max(FullDetailReady,Tile.CompletedAt);
NativeSolidBoxes+=Tile.CoreDiagnostics.solidBoxes;
NativeAirBoxes+=Tile.CoreDiagnostics.airBoxes;
NativeMixedBoxes+=Tile.CoreDiagnostics.mixedBoxes;
NativeUnknownBoxes+=Tile.CoreDiagnostics.unknownBoxes;
NativeFieldCalls+=Tile.CoreDiagnostics.fieldCalls;
NativeColumnHits+=Tile.CoreDiagnostics.columnCacheHits;
NativeColumnMisses+=Tile.CoreDiagnostics.columnCacheMisses;
NativeMeshingSkips+=Tile.CoreDiagnostics.meshingSkipped?1u:0u;
NativeClassificationMilliseconds+=Tile.CoreDiagnostics.classificationMilliseconds;
NativeColumnComputeMilliseconds+=Tile.CoreDiagnostics.columnComputeMilliseconds;
NativeMeshingMilliseconds+=Tile.CoreDiagnostics.meshingMilliseconds;
}
if(bHashDensity)
{
if(Tile.bHasDensityHash)DensityRows.push_back({Tile.Key,Tile.DensityHash});
if(Tile.bHasMeshHash)MeshRows.push_back({Tile.Key,Tile.MeshHash});
if(Tile.bHasPayloadHash)PayloadRows.push_back({Tile.Key,Tile.PayloadHash});
if(Tile.bHasTopologyHash)TopologyRows.push_back({Tile.Key,Tile.TopologyHash});
}
}
if(!bNeighborhoodReported&&NeighborhoodFinished==static_cast<int32>(Neighborhood.size()))
{
std::printf("[PipelineMilestone] neighborhood_ready=%.3fs generated=%d/27\n",
std::chrono::duration<double>(NeighborhoodReady-ColdStart).count(),NeighborhoodFinished);
bNeighborhoodReported=true;
}
if(!bFullDetailReported&&FullDetailFinished==FullDetailExpected)
{
std::printf("[PipelineMilestone] full_detail_ready=%.3fs generated=%d/%d\n",
std::chrono::duration<double>(FullDetailReady-ColdStart).count(),
FullDetailFinished,FullDetailExpected);
bFullDetailReported=true;
}
}
Streamer.Stop();
bool bColumnOverlapCapturePassing=true;
if(bProfileColumnOverlap)
{
for(std::size_t LOD=0;LOD<ColumnCaptureTilesByLOD.size();++LOD)
{
const bool bLODComplete=ColumnCaptureCompleteByLOD[LOD]
&&ColumnCaptureTilesByLOD[LOD]==ExpectedTilesByLOD[LOD];
bColumnOverlapCapturePassing=bColumnOverlapCapturePassing&&bLODComplete;
std::printf("[WorldAssemblerLODColumnOverlap] lod=%zu tiles=%llu expected_tiles=%llu unique_xy_columns=%zu repeated_tile_evaluations=%llu neighbouring_duplicate_evaluations=%llu cross_worker_neighbouring_duplicates=%llu capture_complete=%d\n",
LOD,static_cast<unsigned long long>(ColumnCaptureTilesByLOD[LOD]),
static_cast<unsigned long long>(ExpectedTilesByLOD[LOD]),
ColumnUsesByLOD[LOD].size(),
static_cast<unsigned long long>(ColumnDuplicateEventsByLOD[LOD]),
static_cast<unsigned long long>(NeighbourDuplicateEventsByLOD[LOD]),
static_cast<unsigned long long>(CrossWorkerNeighbourDuplicateEventsByLOD[LOD]),
bLODComplete?1:0);
}
}
for(std::size_t LOD=0;LOD<TileCountByLOD.size();++LOD)
{
std::printf("[WorldAssemblerLODWorker] lod=%zu tiles=%llu worker_sum_s=%.6f column_eval_exclusive_ms=%.3f mc_exclusive_ms=%.3f ground_refine_exclusive_ms=%.3f cap_refine_exclusive_ms=%.3f mesh_assembly_ms=%.3f\n",
LOD,static_cast<unsigned long long>(TileCountByLOD[LOD]),WorkerSecondsByLOD[LOD],
ColumnEvalMsByLOD[LOD],MarchingExclusiveMsByLOD[LOD],
GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD],MeshAssemblyMsByLOD[LOD]);
}
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
const double NeighborhoodMeshSeconds=std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count();
const double FullDetailSeconds=std::chrono::duration<double>(FullDetailReady-ColdStart).count();
const double WholeViewSeconds=std::chrono::duration<double>(WholeViewReady-ColdStart).count();
const double StreamSeconds=std::chrono::duration<double>(WholeViewReady-StreamStart).count();
std::printf("[StreamPipeline] workers=%d shape=%.3fs neighborhood_mesh=%.3fs neighborhood_ready=%.3fs full_detail_ready=%.3fs whole_view_ready=%.3fs neighborhood_tiles=%d/27 full_detail_tiles=%d/%d whole_tiles=%d/%zu stream_wall=%.3fs cache_hits=0 full_payload=1\n",
WorkerCount,ShapeSeconds,NeighborhoodMeshSeconds,NeighborhoodSeconds,
FullDetailSeconds,WholeViewSeconds,NeighborhoodFinished,
FullDetailFinished,FullDetailExpected,Finished,Desired.Tiles.size(),StreamSeconds);
std::printf("[WorldAssemblerTilePipeline] full_detail_tiles=%d solid_boxes=%llu air_boxes=%llu mixed_boxes=%llu unknown_boxes=%llu whole_tile_skips=%llu field_calls=%llu column_cache_hits=%llu column_cache_misses=%llu column_compute_worker_ms=%.3f classification_worker_ms=%.3f meshing_worker_ms=%.3f\n",
FullDetailExpected,static_cast<unsigned long long>(NativeSolidBoxes),
static_cast<unsigned long long>(NativeAirBoxes),
static_cast<unsigned long long>(NativeMixedBoxes),
static_cast<unsigned long long>(NativeUnknownBoxes),
static_cast<unsigned long long>(NativeMeshingSkips),
static_cast<unsigned long long>(NativeFieldCalls),
static_cast<unsigned long long>(NativeColumnHits),
static_cast<unsigned long long>(NativeColumnMisses),
NativeColumnComputeMilliseconds,NativeClassificationMilliseconds,
NativeMeshingMilliseconds);
bool bHashesPassing=true;
if(bHashDensity)
{
bHashesPassing=DensityRows.size()==Desired.Tiles.size()
&&MeshRows.size()==Desired.Tiles.size()
&&PayloadRows.size()==Desired.Tiles.size()
&&TopologyRows.size()==Desired.Tiles.size();
std::vector<FHashedTile> FullDensity,FullMesh,FullPayload,FullTopology;
for(const FHashedTile& Row:DensityRows)if(Row.Key.Level<World.FullResClipLevels)FullDensity.push_back(Row);
for(const FHashedTile& Row:MeshRows)if(Row.Key.Level<World.FullResClipLevels)FullMesh.push_back(Row);
for(const FHashedTile& Row:PayloadRows)if(Row.Key.Level<World.FullResClipLevels)FullPayload.push_back(Row);
for(const FHashedTile& Row:TopologyRows)if(Row.Key.Level<World.FullResClipLevels)FullTopology.push_back(Row);
std::printf("[PipelineFullDetailHash] tiles=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
FullDetailExpected,static_cast<unsigned long long>(HashTileRows(FullDensity)),
static_cast<unsigned long long>(HashTileRows(FullMesh)),
static_cast<unsigned long long>(HashTileRows(FullPayload)),
static_cast<unsigned long long>(HashTileRows(FullTopology)));
std::printf("[PipelineWholeViewHash] tiles=%zu density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx\n",
Desired.Tiles.size(),static_cast<unsigned long long>(HashTileRows(DensityRows)),
static_cast<unsigned long long>(HashTileRows(MeshRows)),
static_cast<unsigned long long>(HashTileRows(PayloadRows)),
static_cast<unsigned long long>(HashTileRows(TopologyRows)));
}
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)?0:6;
}
int RunStreamingBenchmark(FStandaloneOwnerWorld& World,VoxelForgeCore::World* CoreWorld,
const FVector& CameraPositionVoxels,
int32 WorkerCount,int32 MaxLevel,bool bRoundTunnels,
@@ -8132,414 +7789,6 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
&&analyticReverseCovered==1&&packedAnalyticRenderSame?0:12;
}
std::int64_t WorldAssemblyFixed(double voxels)
{return static_cast<std::int64_t>(std::llround(voxels*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));}
std::int64_t WorldAssemblyQ16(double value)
{return static_cast<std::int64_t>(std::llround(value*65536.0));}
std::int64_t WorldAssemblyWavelength(double frequency,double fallbackVoxels)
{
const double wavelength=std::isfinite(frequency)&&frequency>0.0?1.0/frequency:fallbackVoxels;
return std::max<std::int64_t>(1,WorldAssemblyFixed(wavelength));
}
uint64 WorldAssemblyFeatureId(uint32 seed,int64 x,int64 y,uint32 kind)
{
uint64 hash=14695981039346656037ull;
const auto add=[&](uint64 value,int bytes)
{
for(int i=0;i<bytes;++i){hash^=static_cast<uint8>(value>>(8*i));hash*=1099511628211ull;}
};
add(seed,4);add(static_cast<uint64>(x),8);add(static_cast<uint64>(y),8);add(kind,4);
return hash?hash:1;
}
bool BuildFiniteStrateRoute(VoxelForgeCore::WorldAssemblyRecipeV1& recipe,
VoxelForgeCore::WorldAssemblyStratumPlanV1& stratum,std::uint64_t& tested,
std::uint64_t& gradeRejected,std::uint64_t& sweepRejected,std::string& error)
{
using namespace VoxelForgeCore;
constexpr std::int64_t PlayerRadiusQ=348; // 0.34 m in Core's 0.25 m voxel scale.
constexpr std::int64_t PlayerHeightQ=1802; // 1.76 m in Core's 0.25 m voxel scale.
constexpr std::int64_t HalfHeightQ=PlayerHeightQ/2;
constexpr std::int64_t StepQ=128; // 0.5 Core voxel, finer than the density lattice.
constexpr std::int64_t ProbeRadiusQ=174;
constexpr std::int64_t SupportDepthQ=256;
constexpr std::int64_t GradeQ16=17560; // tan(15 degrees), rounded upward.
constexpr std::int64_t RouteRadiusQ=4*WorldAssemblySubvoxelsPerVoxel;
struct Direction {std::int32_t x,y;};
constexpr std::array<Direction,8> directions{{
{65536,0},{46341,46341},{0,65536},{-46341,46341},
{-65536,0},{-46341,-46341},{0,-65536},{46341,-46341}}};
struct Candidate
{
std::int64_t score=0;
std::int32_t centerX=0,centerY=0,direction=0;
std::vector<WorldAssemblyRoutePointV1> points;
};
auto& constraints=stratum.routeConstraints;
constraints.version=1;
constraints.capsuleRadiusSubvoxels=PlayerRadiusQ;
constraints.capsuleHeightSubvoxels=PlayerHeightQ;
constraints.maximumGradeQ16=GradeQ16;
constraints.sweepSpacingSubvoxels=StepQ;
constraints.supportProbeRadiusSubvoxels=ProbeRadiusQ;
constraints.supportSearchDepthSubvoxels=SupportDepthQ;
constraints.minimumClearanceSubvoxels=8;
constraints.minimumSupportProbes=3;
const Heightfield2D finalField(recipe,stratum);
if(!finalField.isValid())
{error="route planner received an invalid final composed field";return false;}
std::vector<Candidate> candidates;
constexpr std::int32_t halfLength=128;
constexpr std::int32_t waypointSpacing=8;
for(std::int32_t centerY=-256;centerY<=256;centerY+=64)
for(std::int32_t centerX=-256;centerX<=256;centerX+=64)
for(std::int32_t directionIndex=0;directionIndex<static_cast<std::int32_t>(directions.size());++directionIndex)
{
Candidate candidate;
candidate.centerX=centerX;candidate.centerY=centerY;candidate.direction=directionIndex;
candidate.points.reserve(33);
std::int64_t previousGround=0,previousX=0,previousY=0;
bool gradePass=true;
for(std::int32_t index=0;index<=32;++index)
{
const std::int64_t along=(index-16)*waypointSpacing;
const std::int64_t x=centerX+std::llround(
static_cast<double>(along)*directions[directionIndex].x/65536.0);
const std::int64_t y=centerY+std::llround(
static_cast<double>(along)*directions[directionIndex].y/65536.0);
const auto column=finalField.point(WorldAssemblyFixed(static_cast<double>(x)),
WorldAssemblyFixed(static_cast<double>(y)),0);
const std::int64_t horizontalQ=static_cast<std::int64_t>(std::llround(
std::hypot(static_cast<double>(x-previousX),static_cast<double>(y-previousY))
*WorldAssemblySubvoxelsPerVoxel));
if(index>0)
{
const std::int64_t riseQ=std::abs(column.groundHeightSubvoxels-previousGround);
if(horizontalQ==0||riseQ*65536>horizontalQ*GradeQ16)
{gradePass=false;break;}
candidate.score+=riseQ*65536/std::max<std::int64_t>(1,horizontalQ);
}
WorldAssemblyRoutePointV1 point;
point.positionSubvoxels={WorldAssemblyFixed(static_cast<double>(x)),
WorldAssemblyFixed(static_cast<double>(y)),column.groundHeightSubvoxels+HalfHeightQ};
point.radiusSubvoxels=RouteRadiusQ;
point.stableFeatureId=WorldAssemblyFeatureId(recipe.seed,
static_cast<std::int64_t>(x),static_cast<std::int64_t>(y),
0x52540000u+static_cast<std::uint32_t>(index));
candidate.points.push_back(point);
previousGround=column.groundHeightSubvoxels;previousX=x;previousY=y;
}
++tested;
if(gradePass)candidates.push_back(std::move(candidate));
else ++gradeRejected;
}
std::stable_sort(candidates.begin(),candidates.end(),[](const Candidate& a,const Candidate& b)
{
if(a.score!=b.score)return a.score<b.score;
if(a.centerY!=b.centerY)return a.centerY<b.centerY;
if(a.centerX!=b.centerX)return a.centerX<b.centerX;
return a.direction<b.direction;
});
std::uint64_t sweepAttempt=0,repairAttempt=0;
VoxelForgeCore::WorldAssemblyRouteAuditResult lastAudit{};
for(auto& candidate:candidates)
{
stratum.route=candidate.points;
std::int64_t liftQ=0;
constexpr std::int64_t RepairStepQ=64;
constexpr std::int64_t MaximumRepairLiftQ=SupportDepthQ-RepairStepQ;
for(;;)
{
if(liftQ>0)
for(std::size_t pointIndex=0;pointIndex<stratum.route.size();++pointIndex)
stratum.route[pointIndex].positionSubvoxels[2]
=candidate.points[pointIndex].positionSubvoxels[2]+liftQ;
const Heightfield2D candidateField(recipe,stratum);
const auto audit=AuditHeightfieldRoute(candidateField);
lastAudit=audit;
if(audit.passed)
{
if(liftQ>0)
std::printf("[WorldAssemblerRouteRepaired] uniform_lift_q=%lld support_limit_q=%lld\n",
static_cast<long long>(liftQ),static_cast<long long>(SupportDepthQ));
return true;
}
if(audit.blockedCapsuleSamples==0||liftQ>=MaximumRepairLiftQ)break;
const std::int64_t needed=std::max<std::int64_t>(1,
constraints.minimumClearanceSubvoxels-audit.minimumClearanceSubvoxels);
const std::int64_t steps=(needed+RepairStepQ-1)/RepairStepQ;
const std::int64_t nextLift=std::max(liftQ+RepairStepQ,liftQ+steps*RepairStepQ);
if(nextLift>MaximumRepairLiftQ)break;
liftQ=nextLift;
++repairAttempt;
}
if(sweepAttempt<3)
std::printf("[WorldAssemblerRouteCandidateRejected] ordinal=%llu blocked=%llu unsupported=%llu grade_failures=%llu minimum_clearance_q=%lld\n",
static_cast<unsigned long long>(sweepAttempt),
static_cast<unsigned long long>(lastAudit.blockedCapsuleSamples),
static_cast<unsigned long long>(lastAudit.unsupportedCenterSamples),
static_cast<unsigned long long>(lastAudit.gradeFailures),
static_cast<long long>(lastAudit.minimumClearanceSubvoxels));
++sweepAttempt;
++sweepRejected;
}
std::printf("[WorldAssemblerRouteSearchFailed] tested=%llu grade_rejected=%llu sweepable_candidates=%llu sweep_rejected=%llu last_blocked=%llu last_unsupported=%llu last_grade_failures=%llu\n",
static_cast<unsigned long long>(tested),static_cast<unsigned long long>(gradeRejected),
static_cast<unsigned long long>(candidates.size()),static_cast<unsigned long long>(sweepRejected),
static_cast<unsigned long long>(lastAudit.blockedCapsuleSamples),
static_cast<unsigned long long>(lastAudit.unsupportedCenterSamples),
static_cast<unsigned long long>(lastAudit.gradeFailures));
std::printf("[WorldAssemblerRouteRepairSummary] repair_attempts=%llu\n",
static_cast<unsigned long long>(repairAttempt));
stratum.route.clear();
error="finite-strate route candidates failed the composed-field capsule and support sweep";
return false;
}
bool AttachRound1WorldAssemblyPrototype(FStandaloneOwnerWorld& owner,VFJson::Value& root,
std::string& error,const std::string& manifestOutputPath)
{
if(!owner.Manager||!owner.Generator)
{error="world assembler prototype needs the resolved standalone owner world";return false;}
int32 surfaceChunkZ=0,topChunkZ=0,bottomChunkZ=0;
bool foundSurface=false;
for(int32 chunkZ=1024;chunkZ>=-4096;--chunkZ)
{
if(owner.Manager->GetGeneratorTypeForChunk(FIntVector(0,0,chunkZ))
!=ECaveGeneratorType::SurfaceWorld)continue;
surfaceChunkZ=chunkZ;
foundSurface=owner.Manager->GetStrateChunkZBounds(chunkZ,topChunkZ,bottomChunkZ);
break;
}
if(!foundSurface)
{error="world assembler prototype could not find a finite SurfaceWorld strate";return false;}
const FIntVector chunk(0,0,surfaceChunkZ);
const FSurfaceGenerationParams surface=owner.Manager->GetSurfaceParamsForChunk(chunk);
const FBiomeContext biomeContext=owner.Manager->GetBiomeContextForChunk(chunk);
const std::int64_t bottomVoxel=static_cast<std::int64_t>(bottomChunkZ)*CHUNK_SIZE;
const std::int64_t heightVoxels=static_cast<std::int64_t>(topChunkZ-bottomChunkZ+1)*CHUNK_SIZE;
const FBiomeMapParams& map=biomeContext.Map;
const UVoxelStrateDefinition* definition=owner.Manager->GetStrateForChunk(chunk);
VoxelForgeCore::WorldAssemblyManifest manifest;
auto& recipe=manifest.recipe;
recipe.seed=static_cast<uint32>(owner.Seed);
recipe.biomeCellSizeSubvoxels=WorldAssemblyFixed(map.CellSize);
recipe.biomeWarpSubvoxels=WorldAssemblyFixed(map.WarpStrength);
recipe.biomeWarpWavelengthSubvoxels=WorldAssemblyWavelength(map.WarpFrequency,556.0);
recipe.biomeBorderBlendSubvoxels=WorldAssemblyFixed(map.BorderBlend);
recipe.biomeClimateReliefWavelengthSubvoxels=WorldAssemblyWavelength(map.ReliefFrequency,3333.0);
recipe.biomeClimateMoistureWavelengthSubvoxels=WorldAssemblyWavelength(map.MoistureFrequency,2500.0);
recipe.biomeClimateReliefContrastQ16=WorldAssemblyQ16(map.ReliefContrast);
const auto makeProfile=[&](uint32 stableId,const FSurfaceGenerationParams& params,
const FBiomeResolved* climate)
{
VoxelForgeCore::WorldAssemblyBiomeProfileV1 profile;
profile.stableId=stableId;
profile.baseHeightSubvoxels=WorldAssemblyFixed(static_cast<double>(bottomVoxel)
+static_cast<double>(heightVoxels)*params.BaseGroundRelative);
profile.continentAmplitudeSubvoxels=WorldAssemblyFixed(params.ElevationRange);
profile.continentWavelengthSubvoxels=WorldAssemblyWavelength(params.ContinentFrequency,1000.0);
profile.mountainAmplitudeSubvoxels=WorldAssemblyFixed(params.ElevationRange*params.MountainStrength);
profile.mountainWavelengthSubvoxels=WorldAssemblyWavelength(params.MountainFrequency,500.0);
profile.detailAmplitudeSubvoxels=WorldAssemblyFixed(params.SurfaceRoughness);
profile.detailWavelengthSubvoxels=WorldAssemblyWavelength(params.DetailFrequency,25.0);
profile.reliefMinimumQ16=climate?WorldAssemblyQ16(climate->ReliefMin):0;
profile.reliefMaximumQ16=climate?WorldAssemblyQ16(climate->ReliefMax):65536;
profile.moistureMinimumQ16=climate?WorldAssemblyQ16(climate->MoistureMin):0;
profile.moistureMaximumQ16=climate?WorldAssemblyQ16(climate->MoistureMax):65536;
profile.reliefStrengthQ16=WorldAssemblyQ16(params.ReliefStrength);
profile.reliefContrastQ16=WorldAssemblyQ16(params.ReliefContrast);
profile.reliefWavelengthSubvoxels=WorldAssemblyWavelength(params.ReliefFrequency,667.0);
profile.heightWarpStrengthSubvoxels=WorldAssemblyFixed(params.HeightWarpStrength);
profile.heightWarpWavelengthSubvoxels=WorldAssemblyWavelength(params.HeightWarpFrequency,125.0);
profile.beachWidthSubvoxels=WorldAssemblyFixed(params.BeachWidth);
profile.cliffStrengthQ16=WorldAssemblyQ16(params.CliffStrength);
profile.cliffSlopeThresholdQ16=std::max<std::int64_t>(1,WorldAssemblyQ16(params.CliffSlopeThreshold));
profile.cliffSharpnessQ16=WorldAssemblyQ16(params.CliffSharpness);
profile.cliffSampleDistanceSubvoxels=WorldAssemblyFixed(std::max(0.5f,params.CliffSampleDist));
const double structuralAbsBound=static_cast<double>(params.ElevationRange)
+static_cast<double>(params.ElevationRange)*params.MountainStrength
+2.0*params.SurfaceRoughness;
const double cliffAbsBound=2.0*structuralAbsBound*params.CliffStrength*params.CliffSharpness;
profile.cliffMaximumDisplacementSubvoxels=WorldAssemblyFixed(params.CliffStrength>0.0f
?std::max(1.0,cliffAbsBound):0.0);
profile.hasCapProfile=true;
profile.capHeightSubvoxels=WorldAssemblyFixed(static_cast<double>(bottomVoxel)
+static_cast<double>(heightVoxels)*params.CeilingRelative);
profile.capWarpStrengthSubvoxels=WorldAssemblyFixed(params.CeilingWarpStrength);
profile.capWarpWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingWarpFrequency,100.0);
profile.capUndulationSubvoxels=WorldAssemblyFixed(params.CeilingUndulation);
profile.capWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingUndulationFrequency,500.0);
profile.capDetailAmplitudeSubvoxels=WorldAssemblyFixed(params.CeilingRoughness);
profile.capDetailWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingRoughnessFrequency,25.0);
profile.capRidgeAmplitudeSubvoxels=WorldAssemblyFixed(params.CeilingRidgeStrength);
profile.capRidgeWavelengthSubvoxels=WorldAssemblyWavelength(params.CeilingRidgeFrequency,50.0);
return profile;
};
if(biomeContext.IsValid()&&definition)
{
for(const FBiomeResolved& resolved:biomeContext.Biomes)
{
const UVoxelBiomeDefinition* biome=definition->Biomes.IsValidIndex(resolved.Index)
?definition->Biomes[resolved.Index]:nullptr;
FSurfaceGenerationParams params=surface;
if(biome&&biome->bOverrideTerrain&&biome->GeneratorType==ECaveGeneratorType::SurfaceWorld)
{
params=biome->SurfaceParams;
params.StrateTopWorldZ=surface.StrateTopWorldZ;
params.StrateBottomWorldZ=surface.StrateBottomWorldZ;
params.BoundarySealThickness=surface.BoundarySealThickness;
params.BaseDensity=surface.BaseDensity;
params.WaterLevelRelative=surface.WaterLevelRelative;
}
recipe.biomes.push_back(makeProfile(0x1001u+static_cast<uint32>(resolved.Index),params,&resolved));
}
}
if(recipe.biomes.empty())recipe.biomes.push_back(makeProfile(0x1001u,surface,nullptr));
VoxelForgeCore::WorldAssemblyStratumPlanV1 stratum;
stratum.strateIndex=owner.Manager->GetStrateIndex(
static_cast<float>((static_cast<double>(surfaceChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE));
stratum.topChunkZ=topChunkZ;
stratum.bottomChunkZ=bottomChunkZ;
const double strateBottom=static_cast<double>(bottomVoxel);
const double strateHeight=static_cast<double>(heightVoxels);
stratum.capHeightSubvoxels=WorldAssemblyFixed(strateBottom+strateHeight*surface.CeilingRelative);
stratum.capUndulationSubvoxels=WorldAssemblyFixed(surface.CeilingUndulation);
stratum.capWavelengthSubvoxels=WorldAssemblyWavelength(surface.CeilingUndulationFrequency,250.0);
stratum.capDetailAmplitudeSubvoxels=WorldAssemblyFixed(surface.CeilingRoughness);
stratum.capDetailWavelengthSubvoxels=WorldAssemblyWavelength(surface.CeilingRoughnessFrequency,25.0);
stratum.capRidgeAmplitudeSubvoxels=WorldAssemblyFixed(surface.CeilingRidgeStrength);
stratum.capRidgeWavelengthSubvoxels=WorldAssemblyWavelength(surface.CeilingRidgeFrequency,50.0);
stratum.waterSurfaceSubvoxels=WorldAssemblyFixed(strateBottom+strateHeight*surface.WaterLevelRelative);
stratum.waterEnabled=definition&&definition->bHasWater&&surface.WaterLevelRelative>0.0f;
// Select a deterministic steep edge in the resolved owner field for a bounded shelf.
// Selection d'une pente deterministe dans le champ resolu pour une saillie bornee.
constexpr int probeSide=49,probeStep=32;
std::array<float,probeSide*probeSide> heights{};
std::array<uint8,probeSide*probeSide> valid{};
for(int y=0;y<probeSide;++y)
for(int x=0;x<probeSide;++x)
{
const float px=static_cast<float>((x-probeSide/2)*probeStep);
const float py=static_cast<float>((y-probeSide/2)*probeStep);
float ceiling=0.0f;
const std::size_t index=static_cast<std::size_t>(y)*probeSide+x;
valid[index]=owner.Generator->GetSurfaceHeightAt(px,py,topChunkZ,heights[index],ceiling)?1u:0u;
}
double steepest=0.0;int cliffX=0,cliffY=0;bool xAxis=true;int downhill=1;
for(int y=1;y<probeSide-1;++y)
for(int x=1;x<probeSide-1;++x)
{
const std::size_t center=static_cast<std::size_t>(y)*probeSide+x;
if(!valid[center]||!valid[center-1]||!valid[center+1]||!valid[center-probeSide]||!valid[center+probeSide])continue;
const double dx=static_cast<double>(heights[center+1]-heights[center-1]);
const double dy=static_cast<double>(heights[center+probeSide]-heights[center-probeSide]);
const double slope=(std::abs(dx)+std::abs(dy))/(4.0*probeStep);
if(slope>steepest){steepest=slope;cliffX=(x-probeSide/2)*probeStep;cliffY=(y-probeSide/2)*probeStep;
xAxis=std::abs(dx)>=std::abs(dy);downhill=(xAxis?dx:dy)>=0.0?-1:1;}
}
if(steepest>0.05)
{
float ground=0.0f,ceiling=0.0f;
if(owner.Generator->GetSurfaceHeightAt(static_cast<float>(cliffX),static_cast<float>(cliffY),
topChunkZ,ground,ceiling))
{
VoxelForgeCore::WorldAssemblyFeatureV1 shelf;
shelf.stableId=WorldAssemblyFeatureId(recipe.seed,cliffX,cliffY,0x4f564552u);
shelf.type=4;
constexpr int reach=72,width=36,height=64,feather=8;
const int dirX=xAxis?downhill:0,dirY=xAxis?0:downhill;
const int minX=xAxis?(dirX>0?cliffX-feather:cliffX-reach-feather)
:cliffX-width-feather;
const int maxX=xAxis?(dirX>0?cliffX+reach+feather:cliffX+feather)
:cliffX+width+feather;
const int minY=xAxis?cliffY-width-feather
:(dirY>0?cliffY-feather:cliffY-reach-feather);
const int maxY=xAxis?cliffY+width+feather
:(dirY>0?cliffY+reach+feather:cliffY+feather);
VoxelForgeCore::Heightfield2D baseField(recipe,stratum);
double lowestGround=std::numeric_limits<double>::infinity();
double highestGround=-std::numeric_limits<double>::infinity();
for(int sampleY=minY;sampleY<=maxY;sampleY+=4)
for(int sampleX=minX;sampleX<=maxX;sampleX+=4)
{
const auto sample=baseField.point(WorldAssemblyFixed(sampleX),
WorldAssemblyFixed(sampleY),0);
const double heightQ=static_cast<double>(sample.groundHeightSubvoxels)
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
lowestGround=std::min(lowestGround,heightQ);
highestGround=std::max(highestGround,heightQ);
}
if(!std::isfinite(lowestGround)||!std::isfinite(highestGround))
{error="world assembler cliff shelf could not bound its terrain columns";return false;}
shelf.minimumSubvoxels={WorldAssemblyFixed(minX),WorldAssemblyFixed(minY),
WorldAssemblyFixed(std::max<double>(bottomVoxel,lowestGround-4.0))};
shelf.maximumSubvoxels={WorldAssemblyFixed(maxX),WorldAssemblyFixed(maxY),
WorldAssemblyFixed(std::min<double>((topChunkZ+1)*CHUNK_SIZE,
highestGround+height+4.0))};
shelf.parametersSubvoxels={WorldAssemblyFixed(dirX),WorldAssemblyFixed(dirY),
WorldAssemblyFixed(height),WorldAssemblyFixed(reach)};
stratum.features.push_back(shelf);
}
}
std::uint64_t routeCandidates=0,routeGradeRejected=0,routeSweepRejected=0;
if(!BuildFiniteStrateRoute(recipe,stratum,routeCandidates,routeGradeRejected,
routeSweepRejected,error))return false;
std::printf("[WorldAssemblerRoutePlan] candidates=%llu grade_rejected=%llu sweep_rejected=%llu accepted_points=%zu capsule_m=0.34x1.76 corridor_radius_vox=4 support_probe_points=5 minimum_support_probes=%u status=PASS\n",
static_cast<unsigned long long>(routeCandidates),
static_cast<unsigned long long>(routeGradeRejected),
static_cast<unsigned long long>(routeSweepRejected),stratum.route.size(),
stratum.routeConstraints.minimumSupportProbes);
manifest.plan.strates.push_back(std::move(stratum));
if(!manifest.finalize(error))return false;
const std::string manifestText=manifest.ToJson();
const auto roundTrip=VoxelForgeCore::WorldAssemblyManifest::FromJson(manifestText,error);
if(!roundTrip||!roundTrip->validate(error)||roundTrip->ToJson()!=manifestText
||roundTrip->contentHash!=manifest.contentHash)
{if(error.empty())error="world assembly canonical plan serialization did not round-trip";return false;}
std::printf("[WorldAssemblerPlanSerialization] bytes=%zu canonical_round_trip=true route_points=%zu plan_hash=%016llx manifest_hash=%016llx status=PASS\n",
manifestText.size(),manifest.plan.strates.front().route.size(),
static_cast<unsigned long long>(manifest.plan.contentHash),
static_cast<unsigned long long>(manifest.contentHash));
if(!manifestOutputPath.empty())
{
const std::filesystem::path outputPath(manifestOutputPath);
std::error_code directoryError;
if(!outputPath.parent_path().empty())
std::filesystem::create_directories(outputPath.parent_path(),directoryError);
if(directoryError)
{error="could not create the world assembly manifest output directory";return false;}
std::ofstream output(outputPath,std::ios::binary);
if(!output)
{error="could not open the world assembly manifest output path";return false;}
output.write(manifestText.data(),static_cast<std::streamsize>(manifestText.size()));
if(!output)
{error="could not write the world assembly manifest payload";return false;}
}
VFJson::Value manifestJson;
if(!VFJson::Parser(manifestText).Parse(manifestJson,error))return false;
auto* rootObject=std::get_if<VFJson::Value::Object>(&root.Data);
if(!rootObject)
{error="owner snapshot root is not a JSON object";return false;}
(*rootObject)["world_assembly"]=std::move(manifestJson);
std::printf("[WorldAssemblerPrototype] recipe_version=%u evaluator_version=%u strata=%zu biomes=%zu strate_index=%d chunk_z=%d..%d serialized_bytes=%zu recipe_hash=%016llx plan_hash=%016llx manifest_hash=%016llx source=owner_surface_params_and_biome_map route_points=%zu features=%zu\n",
manifest.recipe.schemaVersion,manifest.recipe.evaluatorVersion,manifest.plan.strates.size(),
manifest.recipe.biomes.size(),manifest.plan.strates.front().strateIndex,topChunkZ,bottomChunkZ,
manifestText.size(),static_cast<unsigned long long>(manifest.recipe.contentHash),
static_cast<unsigned long long>(manifest.plan.contentHash),
static_cast<unsigned long long>(manifest.contentHash),manifest.plan.strates.front().route.size(),
manifest.plan.strates.front().features.size());
return true;
}
bool RunWorldAssemblerCapAudit(FStandaloneOwnerWorld& owner,
const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,VoxelForgeCore::World& world,
VoxelForgeCore::Vec3d walkCameraVoxels)
@@ -9916,7 +9165,7 @@ int main(int Argc,char** Argv)
if(App.bWorldAssemblerPrototype)
{
const auto PlanStart=std::chrono::steady_clock::now();
const bool bPlanReady=AttachRound1WorldAssemblyPrototype(*App.World,App.OwnerJsonRoot,
const bool bPlanReady=StandaloneWorldAssemblyPrototype::AttachRound1WorldAssemblyPrototype(*App.World,App.OwnerJsonRoot,
Error,WorldAssemblyManifestOutputPath);
const double PlanMilliseconds=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-PlanStart).count();
@@ -9978,7 +9227,7 @@ int main(int Argc,char** Argv)
if(bStreamBenchmark)
{
if(bStreamPipeline)
return RunPipelinedStreamingBenchmark(App.World,App.Snapshot,
return StandaloneStreamBenchmark::RunPipelinedStreamingBenchmark(App.World,App.Snapshot,
FVector(App.Position.X*4.0,App.Position.Y*4.0,App.Position.Z*4.0),
App.WorkerCount,StreamBenchmarkMaxLevel,App.ShapeDetailVariant,App.CoreScheduler,
bStreamHash||!BakeMeshCachePath.empty(),bSkipUvAndColors,bSkipMaterialGroups,