wip(unreal): round 5 (stopped early) -- all 15 passage/strate probes walkable

Luna, round 5 goal 1 only (stopped by owner decision before the SurfaceWorld port):
- Worm and Cascading passages now pass walkability; the wide floor stays clipped while the
  narrow route core stays open.
- Hidden third failure found and fixed: long VerticalShafts diagonal legs were dropped from
  Core's spatial bins by a 100,000-bin safety cutoff (invisible to density queries);
  conservative bins restore them (18,570/18,570).
- All 15 saved probes pass a walkability-only gate; build-time walkability gate added.
NOT re-verified before the stop: W1/W8/W16 hashes, BuildHost UBT/actor run.

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-08 22:50:54 +02:00
1 parent d696463c68
commit 7661fe9d24
3 files changed
+120 -14

No files matched your search

+99 -13
View File
@@ -341,7 +341,11 @@ public:
// Route validation is world-wide. Detail regions reuse the same authored route data and // Route validation is world-wide. Detail regions reuse the same authored route data and
// do not need to repeat the 5,642-point world audit for every entering tile group. // do not need to repeat the 5,642-point world audit for every entering tile group.
Substage=Clock::now(); Substage=Clock::now();
if(bValidatePassageRoutes)ValidatePassageRoutes(); if(bValidatePassageRoutes&&!ValidatePassageRoutes())
{
Error="compiled shape world contains a solid passage centreline sample";
return false;
}
Stats.PassageValidationSeconds=std::chrono::duration<double>(Clock::now()-Substage).count(); Stats.PassageValidationSeconds=std::chrono::duration<double>(Clock::now()-Substage).count();
Substage=Clock::now(); Substage=Clock::now();
RebuildSharedFieldPrimitives(); RebuildSharedFieldPrimitives();
@@ -2640,14 +2644,16 @@ private:
const float CoreRadiusB=std::min(2.5f,RadiusB*0.45f); const float CoreRadiusB=std::min(2.5f,RadiusB*0.45f);
const double CoreSlopeA=CoreRadiusA<2.5f-1.0e-4?RadiusSlopeA*0.45:0.0; const double CoreSlopeA=CoreRadiusA<2.5f-1.0e-4?RadiusSlopeA*0.45:0.0;
const double CoreSlopeB=CoreRadiusB<2.5f-1.0e-4?RadiusSlopeB*0.45:0.0; const double CoreSlopeB=CoreRadiusB<2.5f-1.0e-4?RadiusSlopeB*0.45:0.0;
// Keep a narrow, un-clipped air core through every authored control segment.
// The larger outer tube owns the D-section floor; its interpolated floor curve
// can bow above the path on sharp drops, so clipping this safety bore would
// close the passage precisely where Cascading/Worm need the continuity repair.
// Garder un petit noyau d'air sans coupe de plancher dans chaque segment.
// Le tube large porte le plancher en D; sa courbe peut depasser l'axe dans les
// chutes brusques et fermer la route si ce noyau herite de la meme coupe.
AddTaperedCapsule(Points[I],Points[I+1],CoreRadiusA, AddTaperedCapsule(Points[I],Points[I+1],CoreRadiusA,
CoreRadiusB,true,true,true,ZA,ZB, CoreRadiusB,true,true,false,ZA,ZB,
CoreExtendStart,CoreExtendEnd); CoreExtendStart,CoreExtendEnd);
SetCurvedFloorClip(Primitives.back(),Points[I],Points[I+1],ZA,ZB,
FloorTangents[static_cast<size_t>(I)],FloorTangents[static_cast<size_t>(I+1)]);
++Stats.CurvedFloorSegments;
Stats.MaxFloorCurveDeviation=std::max(Stats.MaxFloorCurveDeviation,
Primitives.back().FloorCurveMaxDeviation);
FitCapsuleRadiiAtEndpoints(Primitives.back(),Points[I],CoreRadiusA, FitCapsuleRadiiAtEndpoints(Primitives.back(),Points[I],CoreRadiusA,
Points[I+1],CoreRadiusB); Points[I+1],CoreRadiusB);
SetCapsuleRadiusProfile(Primitives.back(),Points[I],CoreRadiusA,CoreSlopeA, SetCapsuleRadiusProfile(Primitives.back(),Points[I],CoreRadiusA,CoreSlopeA,
@@ -2869,7 +2875,59 @@ private:
const int32 X0=FloorDiv(P.Min[0]-DetailBand,BinResolution),X1=FloorDiv(P.Max[0]+DetailBand,BinResolution); const int32 X0=FloorDiv(P.Min[0]-DetailBand,BinResolution),X1=FloorDiv(P.Max[0]+DetailBand,BinResolution);
const int32 Y0=FloorDiv(P.Min[1]-DetailBand,BinResolution),Y1=FloorDiv(P.Max[1]+DetailBand,BinResolution); const int32 Y0=FloorDiv(P.Min[1]-DetailBand,BinResolution),Y1=FloorDiv(P.Max[1]+DetailBand,BinResolution);
const int32 Z0=FloorDiv(P.Min[2]-DetailBand,BinResolution),Z1=FloorDiv(P.Max[2]+DetailBand,BinResolution); const int32 Z0=FloorDiv(P.Min[2]-DetailBand,BinResolution),Z1=FloorDiv(P.Max[2]+DetailBand,BinResolution);
if(static_cast<int64>(X1-X0+1)*(Y1-Y0+1)*(Z1-Z0+1)>100000)continue; const int64 BoundingBinCount=static_cast<int64>(X1-X0+1)*(Y1-Y0+1)*(Z1-Z0+1);
if(BoundingBinCount>100000)
{
// Long diagonal passages have a huge AABB even though their capsule is narrow.
// Rasterize the centerline with a conservative bin halo instead of dropping the
// primitive from analytic queries outside the packed near region.
// Les longues galeries diagonales ont une grande AABB mais un tube fin.
// Echantillonner l'axe avec une marge prudente garde les requetes analytiques.
if(!P.bCapsule)continue;
const double BinWidth=static_cast<double>(BinResolution);
const double AxisStep=std::max(1.0,BinWidth*0.5);
const int32 AxisSamples=std::max(1,static_cast<int32>(std::ceil(
P.CapsuleAxisLength/AxisStep)));
const double CapsuleRadius=std::max(P.CapsuleStartRadius,P.CapsuleEndRadius);
const int32 Halo=std::clamp(static_cast<int32>(std::ceil(
(CapsuleRadius+DetailBand)/BinWidth))+1,1,8);
std::vector<FBinKey> PrimitiveBins;
const int64 HaloWidth=2*Halo+1;
const uint64 Reserve=std::min<uint64>(
static_cast<uint64>(AxisSamples+1)*HaloWidth*HaloWidth*HaloWidth,
1000000ull);
PrimitiveBins.reserve(static_cast<size_t>(Reserve));
for(int32 Sample=0;Sample<=AxisSamples;++Sample)
{
const double T=static_cast<double>(Sample)/AxisSamples;
const int32 CX=static_cast<int32>(std::floor(P.CapsuleStartWorld[0]
+P.CapsuleAxisDelta[0]*T));
const int32 CY=static_cast<int32>(std::floor(P.CapsuleStartWorld[1]
+P.CapsuleAxisDelta[1]*T));
const int32 CZ=static_cast<int32>(std::floor(P.CapsuleStartWorld[2]
+P.CapsuleAxisDelta[2]*T));
const int32 BX=FloorDiv(CX,BinResolution),BY=FloorDiv(CY,BinResolution);
const int32 BZ=FloorDiv(CZ,BinResolution);
for(int32 DZ=-Halo;DZ<=Halo;++DZ)
for(int32 DY=-Halo;DY<=Halo;++DY)
for(int32 DX=-Halo;DX<=Halo;++DX)
PrimitiveBins.push_back({BX+DX,BY+DY,BZ+DZ});
}
std::sort(PrimitiveBins.begin(),PrimitiveBins.end(),[](const FBinKey& A,const FBinKey& B)
{
if(A.X!=B.X)return A.X<B.X;
if(A.Y!=B.Y)return A.Y<B.Y;
return A.Z<B.Z;
});
PrimitiveBins.erase(std::unique(PrimitiveBins.begin(),PrimitiveBins.end()),
PrimitiveBins.end());
for(const FBinKey& Key:PrimitiveBins)
{
SpatialBins[Key].push_back(Id);
if(bCriticalAir)CriticalAirBins[Key].push_back(Id);
}
continue;
}
for(int32 Z=Z0;Z<=Z1;++Z)for(int32 Y=Y0;Y<=Y1;++Y)for(int32 X=X0;X<=X1;++X) for(int32 Z=Z0;Z<=Z1;++Z)for(int32 Y=Y0;Y<=Y1;++Y)for(int32 X=X0;X<=X1;++X)
{ {
const FBinKey Key{X,Y,Z}; const FBinKey Key{X,Y,Z};
@@ -4660,28 +4718,55 @@ private:
return RockDistance>=0.0f; return RockDistance>=0.0f;
} }
void ValidatePassageRoutes() bool ValidatePassageRoutes()
{ {
constexpr double SampleStep=0.5; constexpr double SampleStep=0.5;
uint32 PassageIndex=0;
for(const FVoxelPassage& P:Owner->Manager->GetPassages()) for(const FVoxelPassage& P:Owner->Manager->GetPassages())
{ {
const auto& Points=P.ControlPoints; const auto& Points=P.ControlPoints;
if(Points.Num()<2)continue; if(Points.Num()<2){++PassageIndex;continue;}
uint64 RouteSamples=0,RouteFailures=0,RouteCritical=0;
int32 FirstFailure[3]={0,0,0};bool bFirstFailureCritical=false;
for(int32 I=0;I+1<Points.Num();++I) for(int32 I=0;I+1<Points.Num();++I)
{ {
const FVector A=Points[I],B=Points[I+1]; const FVector A=Points[I],B=Points[I+1];
const double L=std::sqrt((B.X-A.X)*(B.X-A.X)+(B.Y-A.Y)*(B.Y-A.Y)+(B.Z-A.Z)*(B.Z-A.Z)); const double L=std::sqrt((B.X-A.X)*(B.X-A.X)+(B.Y-A.Y)*(B.Y-A.Y)+(B.Z-A.Z)*(B.Z-A.Z));
const int32 Count=std::max(1,static_cast<int32>(std::ceil(L/SampleStep))); const int32 Count=std::max(1,static_cast<int32>(std::ceil(L/SampleStep)));
uint64 SegmentSamples=0,SegmentFailures=0,SegmentCritical=0;
for(int32 J=0;J<=Count;++J) for(int32 J=0;J<=Count;++J)
{ {
const double T=static_cast<double>(J)/Count; const double T=static_cast<double>(J)/Count;
const double X=A.X+(B.X-A.X)*T,Y=A.Y+(B.Y-A.Y)*T,Z=A.Z+(B.Z-A.Z)*T; const double X=A.X+(B.X-A.X)*T,Y=A.Y+(B.Y-A.Y)*T,Z=A.Z+(B.Z-A.Z)*T;
++Stats.WalkSamples; ++Stats.WalkSamples;
if(IsRock(static_cast<int32>(std::lround(X)), ++RouteSamples;++SegmentSamples;
static_cast<int32>(std::lround(Y)),static_cast<int32>(std::lround(Z)))) const int32 VX=static_cast<int32>(std::lround(X));
++Stats.WalkFailures; const int32 VY=static_cast<int32>(std::lround(Y));
const int32 VZ=static_cast<int32>(std::lround(Z));
const bool bCritical=IsInsideCriticalAir(VX,VY,VZ);
if(bCritical){++RouteCritical;++SegmentCritical;}
if(IsRock(VX,VY,VZ))
{
++Stats.WalkFailures;++RouteFailures;++SegmentFailures;
if(RouteFailures==1)
{FirstFailure[0]=VX;FirstFailure[1]=VY;FirstFailure[2]=VZ;bFirstFailureCritical=bCritical;}
}
} }
if(SegmentFailures)
std::fprintf(stderr,"[WalkabilitySegment] passage=%u segment=%d failures=%llu/%llu critical=%llu length=%.2f start=(%.2f,%.2f,%.2f) end=(%.2f,%.2f,%.2f)\n",
PassageIndex,I,static_cast<unsigned long long>(SegmentFailures),
static_cast<unsigned long long>(SegmentSamples),
static_cast<unsigned long long>(SegmentCritical),L,
A.X,A.Y,A.Z,B.X,B.Y,B.Z);
} }
if(RouteFailures)
std::fprintf(stderr,"[WalkabilityRoute] passage=%u type=%u points=%d failures=%llu/%llu critical_centerline=%llu first_solid=(%d,%d,%d) critical=%u\n",
PassageIndex,static_cast<uint32>(P.PassageType),Points.Num(),
static_cast<unsigned long long>(RouteFailures),
static_cast<unsigned long long>(RouteSamples),
static_cast<unsigned long long>(RouteCritical),FirstFailure[0],
FirstFailure[1],FirstFailure[2],bFirstFailureCritical?1u:0u);
++PassageIndex;
} }
if(Stats.WalkFailures) if(Stats.WalkFailures)
std::fprintf(stderr,"[Walkability] FAIL %llu/%llu passage centerline samples are solid\n", std::fprintf(stderr,"[Walkability] FAIL %llu/%llu passage centerline samples are solid\n",
@@ -4689,6 +4774,7 @@ private:
else else
std::printf("[Walkability] PASS %llu/%llu passage centerline samples remain open; native landing floors retained\n", std::printf("[Walkability] PASS %llu/%llu passage centerline samples remain open; native landing floors retained\n",
static_cast<unsigned long long>(Stats.WalkSamples),static_cast<unsigned long long>(Stats.WalkSamples)); static_cast<unsigned long long>(Stats.WalkSamples),static_cast<unsigned long long>(Stats.WalkSamples));
return Stats.WalkFailures==0;
} }
static double DetailAutocorrelation(EDetailVariant Variant) static double DetailAutocorrelation(EDetailVariant Variant)
@@ -459,3 +459,20 @@ beaches, and biome transitions, then check the opening room and landing. The ful
work are in Standalone/UNREAL_INTEGRATION_REPORT.md. work are in Standalone/UNREAL_INTEGRATION_REPORT.md.
— Luna — Luna
## Claude, after Unreal round 4 (2026-10-08, night)
Thank you. That coverage matrix is the most honest picture we've had of what Core actually is: a fast
re-expression of TunnelNetwork-style caves, not the owner's full generator. Saved as `d696463`; I
rebuilt the owner's project.
Two things I take from it:
- **Cascading and Worm failing walkability is the most urgent finding.** Entrance-to-exit walkability is
the owner's primordial law; nothing ships with a strate a player can't cross.
- **The SurfaceWorld bridge is exact, but it brings back legacy cost** (23 s full view vs 0.8 s). It's
right as a correctness reference, but speed was the reason for Core. Next: a native Core SurfaceWorld
that stays close to the bridge, verified against it.
I'm putting the bigger question to the owner: port every type natively, or accept the bridge for the
rare ones.
— Claude
+4 -1
View File
@@ -1551,6 +1551,7 @@ namespace
bool bNeighborhoodReadyReported=false; bool bNeighborhoodReadyReported=false;
bool bShapeAuditOnly=false; bool bShapeAuditOnly=false;
bool bShapeCompare=false; bool bShapeCompare=false;
bool bWalkabilityAuditOnly=false;
bool bFarShapeStagePending=false; bool bFarShapeStagePending=false;
bool bGpuFarEnabled=false; bool bGpuFarEnabled=false;
bool bGpuFarPipelineInitialized=false; bool bGpuFarPipelineInitialized=false;
@@ -7889,6 +7890,7 @@ int main(int Argc,char** Argv)
else if(Arg=="--gpu-far-audit") else if(Arg=="--gpu-far-audit")
{App.bGpuFarEnabled=true;App.bGpuFarAuditEnabled=true;App.bShapeWorld=true;App.bForceGenerate=true;App.bQuitAfterClipmap=true;} {App.bGpuFarEnabled=true;App.bGpuFarAuditEnabled=true;App.bShapeWorld=true;App.bForceGenerate=true;App.bQuitAfterClipmap=true;}
else if(Arg=="--shape-audit")App.bShapeWorld=true,App.bShapeAuditOnly=true; else if(Arg=="--shape-audit")App.bShapeWorld=true,App.bShapeAuditOnly=true;
else if(Arg=="--walkability-audit")App.bShapeWorld=true,App.bWalkabilityAuditOnly=true;
else if(Arg=="--grid-stair-audit")bGridStairAudit=true,App.bShapeWorld=true; else if(Arg=="--grid-stair-audit")bGridStairAudit=true,App.bShapeWorld=true;
else if(Arg=="--tile-path-hash-audit")bTilePathHashAudit=true,App.bShapeWorld=true; else if(Arg=="--tile-path-hash-audit")bTilePathHashAudit=true,App.bShapeWorld=true;
else if(Arg=="--passage-wall-detail-audit") else if(Arg=="--passage-wall-detail-audit")
@@ -8059,7 +8061,7 @@ int main(int Argc,char** Argv)
?(StreamBenchmarkMaxLevel<0||StreamBenchmarkMaxLevel>=App.World->FullResClipLevels) ?(StreamBenchmarkMaxLevel<0||StreamBenchmarkMaxLevel>=App.World->FullResClipLevels)
:(App.bShapeCompare?ShapeCompareLevel>=App.World->FullResClipLevels :(App.bShapeCompare?ShapeCompareLevel>=App.World->FullResClipLevels
:(BenchmarkLevel>=App.World->FullResClipLevels)); :(BenchmarkLevel>=App.World->FullResClipLevels));
if(App.bShapeWorld&&(App.bShapeAuditOnly||bGridStairAudit||bTilePathHashAudit||App.bShapeCompare||bStreamBenchmark||BenchmarkLevel>=0) if(App.bShapeWorld&&(App.bShapeAuditOnly||App.bWalkabilityAuditOnly||bGridStairAudit||bTilePathHashAudit||App.bShapeCompare||bStreamBenchmark||BenchmarkLevel>=0)
&&!bStreamPipeline &&!bStreamPipeline
&&!App.BuildShapeWorldForCamera(Error,bNeedFarShapeWorld)) &&!App.BuildShapeWorldForCamera(Error,bNeedFarShapeWorld))
{std::fprintf(stderr,"Shape interval build failed: %s\n",Error.c_str());return 2;} {std::fprintf(stderr,"Shape interval build failed: %s\n",Error.c_str());return 2;}
@@ -8071,6 +8073,7 @@ int main(int Argc,char** Argv)
if(!App.Snapshot) if(!App.Snapshot)
{std::fprintf(stderr,"Shape interval build failed: %s\n",Error.c_str());return 2;} {std::fprintf(stderr,"Shape interval build failed: %s\n",Error.c_str());return 2;}
} }
if(App.bWalkabilityAuditOnly)return 0;
if(App.bShapeAuditOnly) if(App.bShapeAuditOnly)
{ {
if(bPassageDetailAuditOnly) if(bPassageDetailAuditOnly)