standalone: far-survival audit + LOD8 default with explicit far shells; neighbourhood-first viewer

- FarSurvivalAudit: checks every stratum top/bottom boundary (4x4 columns per far tile) and every
  in-view far connector (sections <=128 voxels, 4 radial rays) against the emitted mesh. Falsified:
  removing one tile's shell triangles -> 16 missing, 16 holes, exit 14. Passes at LOD6/7/8.
- Far connectors follow source radial crossings; strata patches emitted at LOD7/8. Default LOD8.
- Viewer: separate near ShapeWorld for the 27 player tiles, full world built on its own thread;
  27/27 tiles hash-identical to the direct build. W1/W8 60 hash fields equal; routes 5642/5642.
Cost, measured by me head to head (8 workers, cold, BelowNormal 0xFF00): LOD8 without the shells
1.17-1.25 s, LOD8 with the shells 1.80 s; payload 92.6 -> 276.7 MiB. The shells are far too
expensive, and the pipelined benchmark whole view is 2.92 s (shape compiled twice): both to fix.

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-04 22:51:44 +02:00
1 parent 5602a281b9
commit a40b0454b3
7 files changed
+1350 -17

No files matched your search

+83
View File
@@ -21,6 +21,7 @@
#include <thread>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// Standalone-only world compiler. It compiles the runtime room/tunnel/passages into
@@ -30,6 +31,12 @@ class FStandaloneShapeWorld
{
public:
enum class EDetailVariant : uint8 { Coherent, Smooth, PerVoxel };
struct FFarConnectorSegment
{
FVector Start=FVector::ZeroVector;
FVector End=FVector::ZeroVector;
float Radius=0.0f;
};
struct FEditBrush
{
enum class EShape : uint8 { Sphere, Capsule, RoundedBox };
@@ -393,6 +400,64 @@ public:
const FBuildStats& GetStats() const { return Stats; }
bool IsBuilt() const { return Built; }
bool HasFarWorld() const { return FarBuilt; }
const std::vector<FFarConnectorSegment>& GetFarConnectorSegments() const
{ return FarConnectorSegments; }
size_t BuildFarConnectorAirSamples(const FIntVector& TileOrigin,int32 Step,int32 Cells,
std::unordered_set<uint64>& OutSamples) const
{
OutSamples.clear();
if(FarConnectorSegments.empty()||Step<=0||Cells<=0)return 0;
const double Pad=Step;
const double TileMin[3]={TileOrigin.X-Pad,TileOrigin.Y-Pad,TileOrigin.Z-Pad};
const double TileMax[3]={TileOrigin.X+(Cells+1)*Step,TileOrigin.Y+(Cells+1)*Step,
TileOrigin.Z+(Cells+1)*Step};
for(const FFarConnectorSegment& Connector:FarConnectorSegments)
{
const double Start[3]={Connector.Start.X,Connector.Start.Y,Connector.Start.Z};
const double End[3]={Connector.End.X,Connector.End.Y,Connector.End.Z};
bool bOverlaps=true;
for(int32 Axis=0;Axis<3;++Axis)
bOverlaps &= std::min(Start[Axis],End[Axis])-Connector.Radius<=TileMax[Axis]
&&std::max(Start[Axis],End[Axis])+Connector.Radius>=TileMin[Axis];
if(!bOverlaps)continue;
const double Delta[3]={End[0]-Start[0],End[1]-Start[1],End[2]-Start[2]};
const double Length=std::sqrt(Delta[0]*Delta[0]+Delta[1]*Delta[1]+Delta[2]*Delta[2]);
if(Length<=1.0e-6)continue;
const int32 Samples=std::max(1,static_cast<int32>(std::ceil(Length/(Step*0.25))));
for(int32 I=0;I<=Samples;++I)
{
const double T=static_cast<double>(I)/Samples;
const double P[3]={Start[0]+Delta[0]*T,Start[1]+Delta[1]*T,Start[2]+Delta[2]*T};
if(P[0]<TileMin[0]||P[0]>TileMax[0]||P[1]<TileMin[1]||P[1]>TileMax[1]
||P[2]<TileMin[2]||P[2]>TileMax[2])continue;
int32 Base[3];
for(int32 Axis=0;Axis<3;++Axis)
Base[Axis]=static_cast<int32>(std::floor((P[Axis]-(&TileOrigin.X)[Axis])/Step));
for(int32 DZ=0;DZ<=1;++DZ)for(int32 DY=0;DY<=1;++DY)for(int32 DX=0;DX<=1;++DX)
{
const int32 IX=Base[0]+DX,IY=Base[1]+DY,IZ=Base[2]+DZ;
if(IX<0||IY<0||IZ<0||IX>Cells||IY>Cells||IZ>Cells)continue;
OutSamples.insert(PackLatticeKey(TileOrigin.X+IX*Step,
TileOrigin.Y+IY*Step,TileOrigin.Z+IZ*Step));
}
}
}
return OutSamples.size();
}
class FScopedForcedFarAirSamples
{
public:
explicit FScopedForcedFarAirSamples(const std::unordered_set<uint64>* AirSamples)
:PreviousAir(ForcedFarAirSamples)
{ ForcedFarAirSamples=AirSamples; }
~FScopedForcedFarAirSamples(){ForcedFarAirSamples=PreviousAir;}
FScopedForcedFarAirSamples(const FScopedForcedFarAirSamples&)=delete;
FScopedForcedFarAirSamples& operator=(const FScopedForcedFarAirSamples&)=delete;
private:
const std::unordered_set<uint64>* PreviousAir=nullptr;
};
bool DebugCriticalAirAt(double X,double Y,double Z) const { return IsInsideCriticalAir(X,Y,Z); }
bool DebugSolidOverlayAt(double X,double Y,double Z) const { return IsInsideSolidOverlay(X,Y,Z); }
@@ -451,6 +516,7 @@ public:
{
int32 IX=0,IY=0,IZ=0;
const bool bInteger=NearInteger(X,IX)&&NearInteger(Y,IY)&&NearInteger(Z,IZ);
if(bInteger&&IsForcedFarAirSample(IX,IY,IZ))return 0.05f;
const bool bPacked=bInteger&&Contains(IX,IY,IZ);
if(bPacked)
return PackedDensityAt(IX,IY,IZ,IsRock(IX,IY,IZ),X,Y,Z);
@@ -459,6 +525,7 @@ public:
float DensityAtLattice(int32 X,int32 Y,int32 Z) const
{
if(IsForcedFarAirSample(X,Y,Z))return 0.05f;
const bool bPacked=Contains(X,Y,Z);
if(bPacked)
return PackedDensityAt(X,Y,Z,IsRock(X,Y,Z),static_cast<float>(X),
@@ -468,6 +535,18 @@ public:
}
private:
static uint64 PackLatticeKey(int32 X,int32 Y,int32 Z)
{
constexpr uint64 Mask=0x1FFFFFull;
return (static_cast<uint64>(static_cast<uint32>(X)&Mask)<<42)
|(static_cast<uint64>(static_cast<uint32>(Y)&Mask)<<21)
|(static_cast<uint64>(static_cast<uint32>(Z)&Mask));
}
static bool IsForcedFarAirSample(int32 X,int32 Y,int32 Z)
{
const auto* Samples=ForcedFarAirSamples;
return Samples&&Samples->contains(PackLatticeKey(X,Y,Z));
}
float PackedDensityAt(int32 X,int32 Y,int32 Z,bool bRock,float FX,float FY,float FZ) const
{
const size_t Column=static_cast<size_t>(Y-Min[1])*Size[0]+static_cast<size_t>(X-Min[0]);
@@ -1970,6 +2049,7 @@ private:
void BuildFarParentShapes()
{
constexpr int32 ParentPitch=2048;
FarConnectorSegments.clear();
struct FParent { int32 GX=0,GY=0,Strate=0; FVector Center; double Rx=0,Ry=0,Rz=0; };
const int32 GX0=FloorDiv(ClipMin[0],ParentPitch)-1,GY0=FloorDiv(ClipMin[1],ParentPitch)-1;
const int32 GX1=FloorDiv(ClipMax[0],ParentPitch)+1,GY1=FloorDiv(ClipMax[1],ParentPitch)+1;
@@ -2024,6 +2104,7 @@ private:
if(MaxX>=Min[0]&&MinX<=Max[0]&&MaxY>=Min[1]&&MinY<=Max[1])continue;
AddTaperedCapsule(A,B,64.0f,64.0f,true);
Primitives.back().BlendRadius=0.0;
FarConnectorSegments.push_back({A,B,64.0f});
}
}
if(!Parents.empty())
@@ -3154,6 +3235,7 @@ private:
std::vector<FInterval> LayerRanges;
std::vector<FLayerField> LayerFields;
std::vector<FPrimitive> Primitives;
std::vector<FFarConnectorSegment> FarConnectorSegments;
std::vector<FEditBrush> EditBrushes;
std::array<FAxisBins,3> AxisBins;
std::unordered_map<FBinKey,FBinItems,FBinHash> SpatialBins;
@@ -3164,6 +3246,7 @@ private:
std::array<std::vector<uint64>,3> CandidateAxisWords;
std::vector<uint64> CandidateWords;
FBuildStats Stats;
inline static thread_local const std::unordered_set<uint64>* ForcedFarAirSamples=nullptr;
};
namespace FStandaloneShapeWorldAccess