wip(assembler): M3 round 3 -- separated islands + Unreal island route (owner build 18:46)

Islands read as separate (91.89% open sky at mid-height), underside cavity closed,
rim teeth were capture shading. Island manifest import + BuildHost proof passed on the
pre-cache tree; M1 SurfaceWorld and M2 V1/V2 gates passed.

Known open: final XY-column cache compiled in the owner build but is unverified;
island LOD0 p95 ~155 ms misses the 133 ms sprint deadline (legacy ~43 ms); the island
manifest only fits the BuildHost fixture layout (owner's world: Core init fails,
empty world) -> round 4 builds plans inside Unreal.

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-10 20:53:03 +02:00
1 parent 4afea7c802
commit 48fa028086
37 files changed
+3788 -107

No files matched your search

+154 -10
View File
@@ -936,6 +936,12 @@ public:
// edge interpolation and normals to the existing mesher.
float DensityAt(float X,float Y,float Z) const
{
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
{
++ThreadClassificationStats().NativeFloatFieldCalls;
return ApplyEditBrushes(IslandDensity,X,Y,Z);
}
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{
@@ -954,6 +960,13 @@ public:
float DensityAtLattice(int32 X,int32 Y,int32 Z) const
{
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z),IslandDensity))
{
++ThreadClassificationStats().NativeLatticeFieldCalls;
return ApplyEditBrushes(IslandDensity,X,Y,Z);
}
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z),NativeDensity))
@@ -975,6 +988,12 @@ public:
float DensityAtUnclamped(float X,float Y,float Z) const
{
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
{
++ThreadClassificationStats().NativeUnclampedFieldCalls;
return ApplyEditBrushes(IslandDensity,X,Y,Z);
}
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{
@@ -1007,11 +1026,18 @@ public:
Count=std::clamp(Count,0,8);
if(Count==0)return;
bool bHasLegacySurfaceSample=false;
bool bHasNativeIslandSample=false;
for(int32 Lane=0;Lane<Count;++Lane)
bHasLegacySurfaceSample|=UsesLegacySurfaceField(
static_cast<float>(XStart+Lane*XStep),static_cast<float>(Y),
static_cast<float>(Z));
if(bHasLegacySurfaceSample)
{
const float SampleX=static_cast<float>(XStart+Lane*XStep);
const float SampleY=static_cast<float>(Y);
const float SampleZ=static_cast<float>(Z);
bHasLegacySurfaceSample|=UsesLegacySurfaceField(SampleX,SampleY,SampleZ);
float IslandDensity=0.0f;
bHasNativeIslandSample|=NativeFloatingIslandDensityAt(
SampleX,SampleY,SampleZ,IslandDensity);
}
if(bHasLegacySurfaceSample||bHasNativeIslandSample)
{
for(int32 Lane=0;Lane<Count;++Lane)
OutDensity[Lane]=DensityAtLattice(XStart+Lane*XStep,Y,Z);
@@ -1100,6 +1126,9 @@ private:
if(OutDetailDisplacement)*OutDetailDisplacement=0.0f;
if(OutCaveInfluence)*OutCaveInfluence=0.0f;
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
return bApplyEdits?ApplyEditBrushes(IslandDensity,X,Y,Z):IslandDensity;
if(UsesLegacySurfaceField(X,Y,Z))
{
float NativeDensity=0.0f;
@@ -1191,17 +1220,22 @@ public:
int32 BMin[3]={Origin.X-Pad,Origin.Y-Pad,Origin.Z-Pad};
int32 BMax[3]={Origin.X+(Cells+1)*Step,Origin.Y+(Cells+1)*Step,Origin.Z+(Cells+1)*Step};
const VoxelForgeCore::WorldAssemblyStratumPlanV1* SurfacePlan=nullptr;
bool bSurfaceOverlap=false,bOtherStrateOverlap=false,bBadPlan=false;
const VoxelForgeCore::WorldAssemblyFloatingIslandPlanV1* IslandPlan=nullptr;
bool bSurfaceOverlap=false,bIslandOverlap=false,bOtherStrateOverlap=false;
bool bIslandOtherStrateOverlap=false,bBadPlan=false;
if(Owner&&Owner->Manager)
{
// Keep the delivered SurfaceWorld chunk mapping unchanged.
// Conserver le mapping de chunks SurfaceWorld deja livre.
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
/static_cast<float>(CHUNK_SIZE));
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax[2])
/static_cast<float>(CHUNK_SIZE));
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
{
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
==ECaveGeneratorType::SurfaceWorld)
const ECaveGeneratorType Type=Owner->Manager->GetGeneratorTypeForChunk(
FIntVector(0,0,ChunkZ));
if(Type==ECaveGeneratorType::SurfaceWorld)
{
bSurfaceOverlap=true;
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
@@ -1211,12 +1245,39 @@ public:
bBadPlan=true;
SurfacePlan=Candidate;
}
else bOtherStrateOverlap=true;
else if(Type!=ECaveGeneratorType::FloatingIslands)
bOtherStrateOverlap=true;
}
// Floating islands use the explicit 12.5 cm owner to 25 cm Core mapping:
// one legacy 4 m chunk occupies 16 Core voxels.
// Les iles flottantes suivent l'echelle explicite proprietaire/Core: 16 voxels Core.
constexpr int32 CoreVoxelsPerIslandChunk=CHUNK_SIZE/2;
const int32 FirstIslandChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
/static_cast<float>(CoreVoxelsPerIslandChunk));
const int32 LastIslandChunk=FMath::FloorToInt(static_cast<float>(BMax[2])
/static_cast<float>(CoreVoxelsPerIslandChunk));
for(int32 ChunkZ=FirstIslandChunk;ChunkZ<=LastIslandChunk;++ChunkZ)
{
const ECaveGeneratorType Type=Owner->Manager->GetGeneratorTypeForChunk(
FIntVector(0,0,ChunkZ));
if(Type==ECaveGeneratorType::FloatingIslands)
{
bIslandOverlap=true;
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
static_cast<float>((static_cast<double>(ChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE));
const auto* Candidate=FindWorldAssemblyFloatingIslandStratum(StrateIndex,ChunkZ);
if(!Candidate||(IslandPlan&&IslandPlan!=Candidate))bBadPlan=true;
IslandPlan=Candidate;
}
else bIslandOtherStrateOverlap=true;
}
}
const auto Finish=[&](EVoxelTileClass Verdict,bool bUnknown=false)
{
FBoxClassification Result{Verdict,bSurfaceOverlap&&!bOtherStrateOverlap,bUnknown};
const bool bNative=(bSurfaceOverlap&&!bOtherStrateOverlap)
||(bIslandOverlap&&!bIslandOtherStrateOverlap);
FBoxClassification Result{Verdict,bNative,bUnknown};
auto& Counts=ThreadClassificationStats();
Counts.Milliseconds+=std::chrono::duration<double,std::milli>(Clock::now()-Start).count();
if(!Result.bNativeSurface||bUnknown)++Counts.UnknownBoxes;
@@ -1227,7 +1288,9 @@ public:
};
// A box crossing recipes cannot use one field interval; unknown composition stays Mixed.
// Une boite qui traverse plusieurs recettes reste Mixed, car l'intervalle d'un seul champ ne suffit pas.
if(bBadPlan|| (bSurfaceOverlap&&bOtherStrateOverlap))
if(bBadPlan||(bSurfaceOverlap&&(bIslandOverlap||bOtherStrateOverlap))
||(bIslandOverlap&&(bIslandOtherStrateOverlap
||(!bSurfaceOverlap&&bOtherStrateOverlap))))
return Finish(EVoxelTileClass::Mixed,true);
if(!EditBrushes.empty()&&EditBoundsMin.X<=BMax[0]&&EditBoundsMax.X>=BMin[0]
&&EditBoundsMin.Y<=BMax[1]&&EditBoundsMax.Y>=BMin[1]
@@ -1273,6 +1336,38 @@ public:
default:return Finish(EVoxelTileClass::Mixed,true);
}
}
if(bIslandOverlap)
{
if(!IslandPlan)return Finish(EVoxelTileClass::Mixed,true);
constexpr std::int64_t Scale=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
constexpr std::int64_t CoreVoxelsPerLegacyChunk=CHUNK_SIZE/2;
const std::int64_t Bottom=static_cast<std::int64_t>(IslandPlan->bottomChunkZ)
*CoreVoxelsPerLegacyChunk*Scale;
const std::int64_t Top=(static_cast<std::int64_t>(IslandPlan->topChunkZ)+1)
*CoreVoxelsPerLegacyChunk*Scale;
const std::int64_t Seal=IslandPlan->manifest.recipe.boundarySealSubvoxels;
const std::int64_t BoxBottom=static_cast<std::int64_t>(BMin[2])*Scale;
const std::int64_t BoxTop=static_cast<std::int64_t>(BMax[2])*Scale;
const bool bBottomSealOverlap=BoxBottom<Bottom+Seal&&BoxTop>=Bottom;
const bool bTopSealOverlap=BoxBottom<=Top&&BoxTop>Top-Seal;
if(bBottomSealOverlap)
return Finish(BoxBottom>=Bottom&&BoxTop<=Bottom+Seal
?EVoxelTileClass::AllSolid:EVoxelTileClass::Mixed);
if(bTopSealOverlap)
return Finish(BoxBottom>=Top-Seal&&BoxTop<=Top
?EVoxelTileClass::AllSolid:EVoxelTileClass::Mixed);
const VoxelForgeCore::FloatingIslandFieldV1 Block(
IslandPlan->manifest.recipe,IslandPlan->manifest.plan);
if(!Block.isValid())return Finish(EVoxelTileClass::Mixed,true);
const auto Interval=Block.interval(static_cast<int64>(BMin[0])*Scale,
static_cast<int64>(BMin[1])*Scale,static_cast<int64>(BMin[2])*Scale,
static_cast<int64>(BMax[0])*Scale,static_cast<int64>(BMax[1])*Scale,
static_cast<int64>(BMax[2])*Scale);
if(!Interval.known)return Finish(EVoxelTileClass::Mixed,true);
if(Interval.minimumDensitySubvoxels>=0)return Finish(EVoxelTileClass::AllAir);
if(Interval.maximumDensitySubvoxels<0)return Finish(EVoxelTileClass::AllSolid);
return Finish(EVoxelTileClass::Mixed);
}
const bool bRock=EvaluateFast((BMin[0]+BMax[0])*0.5,
(BMin[1]+BMax[1])*0.5,(BMin[2]+BMax[2])*0.5);
return Finish(bRock?EVoxelTileClass::AllSolid:EVoxelTileClass::AllAir);
@@ -1753,6 +1848,16 @@ private:
return It==WorldAssembly->plan.strates.end()?nullptr:&*It;
}
const VoxelForgeCore::WorldAssemblyFloatingIslandPlanV1* FindWorldAssemblyFloatingIslandStratum(
int32 StrateIndex,int32 ChunkZ) const
{
if(!WorldAssembly||StrateIndex<0)return nullptr;
const auto It=std::find_if(WorldAssembly->floatingIslands.begin(),
WorldAssembly->floatingIslands.end(),[StrateIndex,ChunkZ](const auto& Entry)
{return Entry.strateIndex==StrateIndex&&ChunkZ<=Entry.topChunkZ&&ChunkZ>=Entry.bottomChunkZ;});
return It==WorldAssembly->floatingIslands.end()?nullptr:&*It;
}
bool NativeSurfaceDensityAt(float X,float Y,float Z,float& OutDensity) const
{
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
@@ -1778,6 +1883,45 @@ private:
return true;
}
bool NativeFloatingIslandDensityAt(float X,float Y,float Z,float& OutDensity) const
{
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
||!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.
constexpr int32 CoreVoxelsPerLegacyChunk=CHUNK_SIZE/2;
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CoreVoxelsPerLegacyChunk));
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
!=ECaveGeneratorType::FloatingIslands)return false;
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
static_cast<float>((static_cast<double>(ChunkZ*CHUNK_SIZE+CHUNK_SIZE/2))*VOXEL_SIZE));
const auto* Plan=FindWorldAssemblyFloatingIslandStratum(StrateIndex,ChunkZ);
if(!Plan)return false;
constexpr double Scale=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
constexpr double Maximum=1000000000000.0/Scale;
if(std::abs(static_cast<double>(X))>Maximum||std::abs(static_cast<double>(Y))>Maximum
||std::abs(static_cast<double>(Z))>Maximum)return false;
const auto ToFixed=[](float Value)
{return static_cast<int64>(std::llround(static_cast<double>(Value)
*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel));};
const VoxelForgeCore::FloatingIslandFieldV1 Field(
Plan->manifest.recipe,Plan->manifest.plan);
if(!Field.isValid())return false;
std::int64_t Density=Field.densitySubvoxels(ToFixed(X),ToFixed(Y),ToFixed(Z));
// A legacy 4 m chunk is 16 Core voxels at the published 12.5 cm to 25 cm scale.
// Un chunk legacy de 4 m represente 16 voxels Core avec l'echelle publiee.
const std::int64_t Bottom=static_cast<std::int64_t>(Plan->bottomChunkZ)
*CoreVoxelsPerLegacyChunk*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const std::int64_t Top=(static_cast<std::int64_t>(Plan->topChunkZ)+1)
*CoreVoxelsPerLegacyChunk*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const std::int64_t Seal=Plan->manifest.recipe.boundarySealSubvoxels;
const std::int64_t Zq=ToFixed(Z);
if(Zq>=Bottom&&Zq<Bottom+Seal)Density=std::min(Density,-std::max<std::int64_t>(1,Zq-Bottom));
if(Zq<=Top&&Zq>Top-Seal)Density=std::min(Density,-std::max<std::int64_t>(1,Top-Zq));
OutDensity=static_cast<float>(static_cast<double>(Density)/Scale);
return std::isfinite(OutDensity);
}
bool UsesLegacySurfaceField(float X,float Y,float Z) const
{
if(!Owner||!Owner->Manager||!Owner->Generator)return false;