wip(assembler): M1 round 1 -- manifest format, block contract, bound audit, native Heightfield2D

Luna, M1 round 1 of 4 (plan in Standalone/ASSEMBLER_M1_REPORT.md):
- Versioned fixed-scale world manifest (the shipped plan format) and the Core block
  contract: point evaluation, interval-or-unknown, influence bound, detail envelope, channels.
- Interval audit: 256 boxes / 6,912 samples, 0 missed, 0 unknown; a deliberately false bound
  is detected (negative control).
- Native Heightfield2D with biome input: 4,096-point hash fae2721c052aec5c identical at
  W1/W8/W16; point queries 2.059 ms vs 62.115 ms legacy -- but NOT a match yet (mean density
  error 274 voxels, 2,261 sign mismatches vs the legacy surface). 45 mesh-free Core queries
  match direct evaluation exactly. Existing cave world unchanged (walkability, 64/64 tiles).
- Open: collision readiness, a valid full-view timing (viewer captures were occluded/empty;
  top-down height maps are the only usable pair).
Also carries the design doc's owner decisions (fixed water; player edits unrestricted, route
law for automatic changes only) and three plugin files + BuildHost scripts that earlier round
commits had missed (also fixed on unreal/core-integration as 2574b56).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-09 00:04:30 +02:00
1 parent d5ce5d675d
commit 874c796c65
20 files changed
+2880 -12

No files matched your search

+379
View File
@@ -1547,6 +1547,8 @@ namespace
bool bRoundTunnels=false;
bool bRoundTunnelEnhanced=true;
bool bShapeWorld=false;
bool bWorldAssemblerPrototype=false;
bool bWorldAssemblerAuditOnly=false;
bool bShapePipelineActive=false;
bool bNeighborhoodReadyReported=false;
bool bShapeAuditOnly=false;
@@ -7704,6 +7706,358 @@ float3 Lit=Rock*(Ambient+0.88*Diffuse)+float3(0.50,0.69,0.82)*Head*0.75;
return pass&&analyticDirectionsSame&&analyticForwardCovered==1
&&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 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));
}
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 double baseHeight=static_cast<double>(bottomVoxel)
+static_cast<double>(heightVoxels)*surface.BaseGroundRelative;
const double elevation=std::max(16.0,static_cast<double>(surface.ElevationRange));
const FBiomeMapParams& map=biomeContext.Map;
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);
VoxelForgeCore::WorldAssemblyBiomeProfileV1 lowland;
lowland.stableId=0x1001u;
lowland.baseHeightSubvoxels=WorldAssemblyFixed(baseHeight-elevation*0.15);
lowland.continentAmplitudeSubvoxels=WorldAssemblyFixed(elevation*0.45);
lowland.continentWavelengthSubvoxels=WorldAssemblyWavelength(surface.ContinentFrequency,800.0);
lowland.mountainAmplitudeSubvoxels=WorldAssemblyFixed(elevation*0.12*surface.MountainStrength);
lowland.mountainWavelengthSubvoxels=WorldAssemblyWavelength(surface.MountainFrequency,192.0);
lowland.detailAmplitudeSubvoxels=WorldAssemblyFixed(std::max(1.0,static_cast<double>(surface.SurfaceRoughness)));
lowland.detailWavelengthSubvoxels=WorldAssemblyWavelength(surface.DetailFrequency,24.0);
VoxelForgeCore::WorldAssemblyBiomeProfileV1 upland=lowland;
upland.stableId=0x1002u;
upland.baseHeightSubvoxels=WorldAssemblyFixed(baseHeight+elevation*0.20);
upland.continentAmplitudeSubvoxels=WorldAssemblyFixed(elevation*0.80);
upland.continentWavelengthSubvoxels=WorldAssemblyWavelength(surface.ContinentFrequency*0.72,1120.0);
upland.mountainAmplitudeSubvoxels=WorldAssemblyFixed(elevation*0.42*std::max(0.25,static_cast<double>(surface.MountainStrength)));
upland.mountainWavelengthSubvoxels=WorldAssemblyWavelength(surface.MountainFrequency*0.75,256.0);
upland.detailAmplitudeSubvoxels=WorldAssemblyFixed(std::max(2.0,static_cast<double>(surface.SurfaceRoughness)*1.5));
upland.detailWavelengthSubvoxels=WorldAssemblyWavelength(surface.DetailFrequency*0.8,30.0);
recipe.biomes={lowland,upland};
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;
stratum.capHeightSubvoxels=WorldAssemblyFixed(static_cast<double>(topChunkZ+1)*CHUNK_SIZE-4.0);
stratum.capUndulationSubvoxels=0;
stratum.capWavelengthSubvoxels=WorldAssemblyFixed(512.0);
manifest.plan.strates.push_back(std::move(stratum));
if(!manifest.finalize(error))return false;
const std::string manifestText=manifest.ToJson();
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=0 features=0\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));
return true;
}
int RunWorldAssemblerAudit(FStandaloneOwnerWorld& owner,
const VoxelForgeCore::ResolvedWorldSnapshot& snapshot,const std::string& captureDirectory)
{
const auto* manifest=snapshot.worldAssembly();
if(!manifest||manifest->plan.strates.empty())
{std::fprintf(stderr,"[WorldAssemblerAudit] no shipped world_assembly payload was resolved.\n");return 10;}
const auto& plan=manifest->plan.strates.front();
const VoxelForgeCore::Heightfield2D block(manifest->recipe,plan);
if(!block.isValid())
{std::fprintf(stderr,"[WorldAssemblerAudit] Heightfield2D rejected its recipe or plan.\n");return 10;}
const auto contract=block.contract();
const auto influence=block.influenceBounds();
const auto detail=block.detailEnvelope();
const auto bounds=VoxelForgeCore::AuditHeightfieldBounds(block,256,
0x574f524c44415331ull^manifest->contentHash);
std::printf("[WorldAssemblerBlock] name=Heightfield2D evaluator=%u reads=biome writes=height,rock influence_xy=global influence_z_q=%lld..%lld detail_envelope_q=%lld minimum_feature_q=%lld status=%s\n",
contract.evaluatorVersion,static_cast<long long>(influence.minimumZSubvoxels),
static_cast<long long>(influence.maximumZSubvoxels),
static_cast<long long>(detail.maximumAbsoluteDisplacementSubvoxels),
static_cast<long long>(detail.minimumFeatureSizeSubvoxels),bounds.passed?"PASS":"FAIL");
std::printf("[WorldAssemblerBoundAudit] boxes=%llu point_samples=%llu missed_bounds=%llu unknown_bounds=%llu deliberately_wrong_bound_detected=%s status=%s\n",
static_cast<unsigned long long>(bounds.boxesTested),
static_cast<unsigned long long>(bounds.pointSamples),
static_cast<unsigned long long>(bounds.missedBounds),
static_cast<unsigned long long>(bounds.unknownBounds),
bounds.negativeControlDetected?"true":"false",bounds.passed?"PASS":"FAIL");
struct Query {std::int64_t x=0,y=0,z=0;};
constexpr int side=64;
std::vector<Query> queries;
queries.reserve(side*side);
for(int y=0;y<side;++y)
for(int x=0;x<side;++x)
{
const std::int64_t xq=(static_cast<std::int64_t>(x)-side/2)*128
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const std::int64_t yq=(static_cast<std::int64_t>(y)-side/2)*128
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const auto column=block.point(xq,yq,0);
const std::int64_t offset=(static_cast<std::int64_t>((x+3*y)%9)-4)
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
queries.push_back({xq,yq,column.groundHeightSubvoxels+offset});
}
std::vector<VoxelForgeCore::HeightfieldPointSample> oneWorker(queries.size());
const auto evaluate=[&](std::uint32_t workers,
std::vector<VoxelForgeCore::HeightfieldPointSample>& output)
{
const auto begin=std::chrono::steady_clock::now();
std::vector<std::thread> threads;
for(std::uint32_t worker=0;worker<workers;++worker)
{
const std::size_t first=queries.size()*worker/workers;
const std::size_t last=queries.size()*(worker+1)/workers;
auto task=[&,first,last]
{
for(std::size_t i=first;i<last;++i)
output[i]=block.point(queries[i].x,queries[i].y,queries[i].z);
};
if(workers==1)task();
else threads.emplace_back(std::move(task));
}
for(auto& thread:threads)thread.join();
return std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-begin).count();
};
const auto hashSamples=[](const std::vector<VoxelForgeCore::HeightfieldPointSample>& samples)
{
std::uint64_t hash=14695981039346656037ull;
const auto add=[&](std::uint64_t value,int bytes)
{
for(int i=0;i<bytes;++i){hash^=static_cast<uint8>(value>>(8*i));hash*=1099511628211ull;}
};
for(const auto& sample:samples)
{
add(static_cast<std::uint64_t>(sample.groundHeightSubvoxels),8);
add(static_cast<std::uint64_t>(sample.capHeightSubvoxels),8);
add(sample.biomeId,4);add(sample.neighborBiomeId,4);add(sample.biomeWeightQ16,4);
add(static_cast<std::uint64_t>(sample.densitySubvoxels),8);
}
return hash;
};
const double time1=evaluate(1,oneWorker);
const std::uint64_t hash1=hashSamples(oneWorker);
std::vector<VoxelForgeCore::HeightfieldPointSample> eightWorkers(queries.size());
const double time8=evaluate(8,eightWorkers);
const std::uint64_t hash8=hashSamples(eightWorkers);
std::vector<VoxelForgeCore::HeightfieldPointSample> sixteenWorkers(queries.size());
const double time16=evaluate(16,sixteenWorkers);
const std::uint64_t hash16=hashSamples(sixteenWorkers);
const bool deterministic=hash1==hash8&&hash1==hash16;
std::printf("[WorldAssemblerEvaluatorHash] samples=%zu W1=%016llx W8=%016llx W16=%016llx deterministic=%s\n",
queries.size(),static_cast<unsigned long long>(hash1),
static_cast<unsigned long long>(hash8),static_cast<unsigned long long>(hash16),
deterministic?"true":"false");
std::printf("[WorldAssemblerQueryTiming] samples=%zu native_W1_ms=%.3f native_W8_ms=%.3f native_W16_ms=%.3f scope=point_evaluation_only\n",
queries.size(),time1,time8,time16);
double absoluteSum=0.0,maximumError=0.0;
std::uint64_t signMismatches=0;
const auto legacyStart=std::chrono::steady_clock::now();
for(std::size_t i=0;i<queries.size();++i)
{
const float x=static_cast<float>(queries[i].x
/static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
const float y=static_cast<float>(queries[i].y
/static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
const float z=static_cast<float>(queries[i].z
/static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
const float legacyDensity=owner.Generator->GetDensityAt(x,y,z);
const double error=std::abs(static_cast<double>(oneWorker[i].densitySubvoxels
/static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel))-legacyDensity);
absoluteSum+=error;maximumError=std::max(maximumError,error);
if((oneWorker[i].densitySubvoxels<0)!=(legacyDensity<0.0f))
++signMismatches;
}
const double legacyMs=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-legacyStart).count();
std::printf("[WorldAssemblerLegacyCompare] samples=%zu mean_abs_density_error=%.4f max_abs_density_error=%.4f sign_mismatches=%llu legacy_point_queries_ms=%.3f status=MEASURED_NOT_PARITY_GATE\n",
queries.size(),absoluteSum/queries.size(),maximumError,
static_cast<unsigned long long>(signMismatches),legacyMs);
const auto centerColumn=block.point(0,0,0);
const int32 centerGroundVoxel=static_cast<int32>(std::llround(
static_cast<double>(centerColumn.groundHeightSubvoxels)
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));
VoxelForgeCore::World coreWorld(snapshot);
VoxelForgeCore::ShapeBuildRequest coreBuild;
coreBuild.minVoxel={-32,-32,centerGroundVoxel-32};
coreBuild.maxVoxel={32,32,centerGroundVoxel+32};
coreBuild.clipMinVoxel=coreBuild.minVoxel;
coreBuild.clipMaxVoxel=coreBuild.maxVoxel;
coreBuild.workerLimit=1;
coreBuild.validatePassageRoutes=false;
FStandaloneCoreScheduler scheduler;
std::string coreError;
const auto coreCompileStart=std::chrono::steady_clock::now();
const bool coreCompiled=coreWorld.compile(coreBuild,scheduler,coreError);
const double coreCompileMs=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-coreCompileStart).count();
double coreQueryMaximumError=0.0;
std::uint64_t coreQuerySamples=0;
if(coreCompiled)
{
for(const std::int64_t dx:{-24ll,0ll,24ll})
for(const std::int64_t dy:{-24ll,0ll,24ll})
for(const std::int64_t dz:{-8ll,-1ll,0ll,1ll,8ll})
{
const std::int64_t xq=dx*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const std::int64_t yq=dy*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const std::int64_t zq=centerColumn.groundHeightSubvoxels
+dz*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double expected=static_cast<double>(block.point(xq,yq,zq).densitySubvoxels)
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const double actual=coreWorld.densityAt({static_cast<double>(xq)
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
static_cast<double>(yq)/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
static_cast<double>(zq)/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel});
coreQueryMaximumError=std::max(coreQueryMaximumError,std::abs(expected-actual));
++coreQuerySamples;
}
}
const bool coreQueryPass=coreCompiled&&coreQuerySamples==45&&coreQueryMaximumError<=1.0/256.0;
std::printf("[WorldAssemblerCoreQuery] compiled=%s compile_ms=%.3f samples=%llu max_abs_error=%.8f render_meshes_generated=0 readiness=%s status=%s error=%s\n",
coreCompiled?"true":"false",coreCompileMs,
static_cast<unsigned long long>(coreQuerySamples),coreQueryMaximumError,
coreQueryPass?"field_ready_without_meshes":"unavailable",coreQueryPass?"PASS":"FAIL",
coreError.empty()?"none":coreError.c_str());
if(!captureDirectory.empty())
{
constexpr int width=320,height=200;
constexpr double spanVoxels=3200.0;
const std::size_t columnCount=static_cast<std::size_t>(width)*height;
std::vector<std::uint8_t> ownerPixels(columnCount*3,0);
std::vector<std::uint8_t> nativePixels(ownerPixels.size(),0);
std::vector<double> ownerHeights(columnCount,std::numeric_limits<double>::quiet_NaN());
std::vector<double> nativeHeights(columnCount,0.0);
double minimumHeight=std::numeric_limits<double>::max();
double maximumHeight=std::numeric_limits<double>::lowest();
std::uint64_t ownerColumns=0;
for(int y=0;y<height;++y)
for(int x=0;x<width;++x)
{
const double xVoxel=(static_cast<double>(x)/(width-1)-0.5)*spanVoxels;
const double yVoxel=(static_cast<double>(y)/(height-1)-0.5)*spanVoxels;
const std::size_t column=static_cast<std::size_t>(y)*width+x;
float ownerGround=0.0f,ownerCap=0.0f;
if(owner.Generator->GetSurfaceHeightAt(static_cast<float>(xVoxel),
static_cast<float>(yVoxel),plan.topChunkZ,ownerGround,ownerCap))
{
if(std::isfinite(ownerGround))
{
ownerHeights[column]=ownerGround;
minimumHeight=std::min(minimumHeight,static_cast<double>(ownerGround));
maximumHeight=std::max(maximumHeight,static_cast<double>(ownerGround));
++ownerColumns;
}
}
const auto native=block.point(
static_cast<std::int64_t>(std::llround(xVoxel*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)),
static_cast<std::int64_t>(std::llround(yVoxel*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)),0);
nativeHeights[column]=static_cast<double>(native.groundHeightSubvoxels)
/VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
minimumHeight=std::min(minimumHeight,nativeHeights[column]);
maximumHeight=std::max(maximumHeight,nativeHeights[column]);
}
const auto colorHeight=[&](double heightValue,std::vector<std::uint8_t>& pixels,std::size_t offset)
{
const double t=std::clamp((heightValue-minimumHeight)
/std::max(1.0,maximumHeight-minimumHeight),0.0,1.0);
const std::array<std::array<double,3>,4> stops={{{24,68,78},{61,128,75},
{166,143,83},{232,229,209}}};
const double scaled=t*3.0;
const int segment=std::min(2,static_cast<int>(scaled));
const double blend=scaled-segment;
for(int channel=0;channel<3;++channel)
pixels[offset+channel]=static_cast<std::uint8_t>(std::clamp(std::lround(
stops[segment][channel]*(1.0-blend)+stops[segment+1][channel]*blend),0l,255l));
};
for(std::size_t column=0;column<columnCount;++column)
{
const std::size_t offset=column*3;
if(std::isfinite(ownerHeights[column]))
colorHeight(ownerHeights[column],ownerPixels,offset);
colorHeight(nativeHeights[column],nativePixels,offset);
}
std::error_code directoryError;
std::filesystem::create_directories(captureDirectory,directoryError);
const auto writePpm=[&](const std::filesystem::path& path,const std::vector<std::uint8_t>& pixels)
{
std::ofstream output(path,std::ios::binary);
if(!output)return false;
output<<"P6\n"<<width<<' '<<height<<"\n255\n";
output.write(reinterpret_cast<const char*>(pixels.data()),
static_cast<std::streamsize>(pixels.size()));
return static_cast<bool>(output);
};
const bool ownerSaved=!directoryError&&writePpm(
std::filesystem::path(captureDirectory)/"owner-reference-height.ppm",ownerPixels);
const bool nativeSaved=!directoryError&&writePpm(
std::filesystem::path(captureDirectory)/"native-prototype-height.ppm",nativePixels);
std::printf("[WorldAssemblerCapturePair] resolution=%dx%d xy_span_vox=%.0f height_range=[%.2f,%.2f] owner_columns=%llu owner_saved=%s native_saved=%s files=owner-reference-height.ppm,native-prototype-height.ppm status=%s\n",
width,height,spanVoxels,minimumHeight,maximumHeight,static_cast<unsigned long long>(ownerColumns),
ownerSaved?"true":"false",nativeSaved?"true":"false",
ownerSaved&&nativeSaved?"PASS":"FAIL");
}
std::printf("[WorldAssemblerFullViewTiming] status=NOT_MEASURED_IN_AUDIT_MODE; capture_viewer_runs_report_separately\n");
return bounds.passed&&deterministic&&coreQueryPass?0:11;
}
}
int main(int Argc,char** Argv)
@@ -7805,6 +8159,8 @@ int main(int Argc,char** Argv)
int32 MaxClipLevelOverride=-1;
int32 ShapeCompareLevel=-1,ShapeCompareTileLimit=0;
std::string ShapeCompareArea="unlabeled";
std::string WorldAssemblyCaptureDir;
std::string WorldAssemblyManifestOutputPath;
bool bStreamBenchmark=false;
bool bStreamPipeline=false;
bool bProfileDetailBand=false;
@@ -7848,6 +8204,16 @@ int main(int Argc,char** Argv)
else if(Arg=="--parity-only")App.bParityOnly=true;
else if(Arg=="--density-hash")App.bDensityHash=true;
else if(Arg=="--shape-world")App.bShapeWorld=true;
else if(Arg=="--world-assembler-prototype")
{App.bWorldAssemblerPrototype=true;App.bShapeWorld=true;}
else if(Arg=="--world-assembler-audit")
{App.bWorldAssemblerPrototype=true;App.bWorldAssemblerAuditOnly=true;}
else if(Arg.starts_with("--world-assembler-capture-dir="))
WorldAssemblyCaptureDir=std::string(Arg.substr(
std::string_view("--world-assembler-capture-dir=").size()));
else if(Arg.starts_with("--world-assembler-manifest-output="))
WorldAssemblyManifestOutputPath=std::string(Arg.substr(
std::string_view("--world-assembler-manifest-output=").size()));
else if(Arg=="--gpu-far")
App.bGpuFarEnabled=true,App.bGpuFarShaderPrewarm=true,App.bShapeWorld=true,App.bForceGenerate=true,
App.bPresentCpuFrameBeforeGpu=true,App.bHoldCpuFrameDuringGpuWarmup=true;
@@ -8057,6 +8423,19 @@ int main(int Argc,char** Argv)
std::printf("Standalone max clip level override: exported=%d -> max_level=%d.\n",
ExportMaxClipLevel,MaxClipLevelOverride);
}
if(App.bWorldAssemblerPrototype
&&!AttachRound1WorldAssemblyPrototype(*App.World,App.OwnerJsonRoot,Error,
WorldAssemblyManifestOutputPath))
{std::fprintf(stderr,"World assembler prototype setup failed: %s\n",Error.c_str());return 2;}
if(App.bWorldAssemblerAuditOnly)
{
App.Snapshot=VoxelForgeCore::MakeStandaloneSnapshotFromParsedJson(App.OwnerJsonRoot,
App.Seed,App.ClipRadius,App.MaxClipLevelOverride,App.bRoundTunnels,
App.bRoundTunnelEnhanced,Error);
if(!App.Snapshot)
{std::fprintf(stderr,"World assembler snapshot setup failed: %s\n",Error.c_str());return 2;}
return RunWorldAssemblerAudit(*App.World,App.Snapshot,WorldAssemblyCaptureDir);
}
const bool bNeedFarShapeWorld=bStreamBenchmark
?(StreamBenchmarkMaxLevel<0||StreamBenchmarkMaxLevel>=App.World->FullResClipLevels)
:(App.bShapeCompare?ShapeCompareLevel>=App.World->FullResClipLevels