wip(L17, side branch): FloatingIslands seal-cap fix + owner/Core chunk-scale change (breaks SurfaceWorld)

Not for assembler/world: the 8 m -> 4 m strate chunk change moves every stratum, so the SurfaceWorld
spawn camera floats in a void and the L1 mesh export shrank 58.7 -> 31.7 MB. Kept for its
diagnostics, the boundarySeal finding and the readable capture shading. See Linux17/REPORT.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-20 05:52:59 +02:00
1 parent 9a7c87e47b
commit 34ae1d7187
30 files changed
+1353 -70

No files matched your search

@@ -249,8 +249,8 @@ namespace VoxelForgeCore
// L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles.
inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256;
inline constexpr std::uint32_t WorldAssemblySchemaVersion = 1;
// Version 6 binds every compiled tile page to the world's base density evaluator.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 6;
// Version 7 fixes owner/Core chunk mapping and native adjacent-stratum boundaries.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 7;
enum class FieldChannel : std::uint32_t
{
+144 -51
View File
@@ -47,6 +47,18 @@ public:
return static_cast<double>(CHUNK_SIZE) * OwnerVoxelSizeCm / GetCoreVoxelSizeCm();
}
int32 OwnerChunkLowerBoundaryCoreVoxel(int32 ChunkZ) const
{
return static_cast<int32>(std::floor(
static_cast<double>(ChunkZ) * GetCoreVoxelsPerOwnerChunk()));
}
int32 OwnerChunkUpperBoundaryCoreVoxel(int32 ChunkZ) const
{
return static_cast<int32>(std::ceil(
static_cast<double>(ChunkZ) * GetCoreVoxelsPerOwnerChunk()));
}
enum class EDetailVariant : uint8 { Coherent, Smooth, PerVoxel };
struct FBoxClassification
{
@@ -712,14 +724,21 @@ public:
if(Owner&&Owner->Manager)
{
const double TileZ0=Origin.Z,TileZ1=Origin.Z+static_cast<double>(Cells)*Step;
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
for(const FStrateSlot& Slot:Owner->Manager->GetLayout())
{
const int32 MidChunkZ=(Slot.TopChunkZ+Slot.BottomChunkZ)/2;
if(bUseNativeManifestFields
&&Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,MidChunkZ))
==ECaveGeneratorType::FloatingIslands)
continue;
const FStrateGenerationParams Params=Owner->Manager->GetGenerationParams(
FIntVector(0,0,(Slot.TopChunkZ+Slot.BottomChunkZ)/2));
FIntVector(0,0,MidChunkZ));
const float HalfWidth=static_cast<float>(std::max(8.0,
static_cast<double>(Params.BoundarySealThickness)+8.0));
const float Boundaries[2]={static_cast<float>(Slot.BottomChunkZ)*CHUNK_SIZE,
static_cast<float>(Slot.TopChunkZ+1)*CHUNK_SIZE};
const float Boundaries[2]={
static_cast<float>(static_cast<double>(Slot.BottomChunkZ)*CoreVoxelsPerOwnerChunk),
static_cast<float>(static_cast<double>(Slot.TopChunkZ+1)*CoreVoxelsPerOwnerChunk)};
for(const float Z:Boundaries)
if(Z+HalfWidth>=TileZ0&&Z-HalfWidth<=TileZ1)
Out.stratumBoundaries.push_back({Z,HalfWidth});
@@ -1028,19 +1047,21 @@ public:
float NativeDensity=0.0f;
if(!NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{RecordNativeOnlyViolation();return 0.0f;}
return NativeDensity;
return ApplyAdjacentStratumBoundary(X,Y,Z,NativeDensity,false);
}
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
{
++ThreadClassificationStats().NativeFloatFieldCalls;
return ApplyEditBrushes(IslandDensity,X,Y,Z);
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
X,Y,Z,IslandDensity,true),X,Y,Z);
}
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{
++ThreadClassificationStats().NativeFloatFieldCalls;
return ApplyEditBrushes(NativeDensity,X,Y,Z);
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
X,Y,Z,NativeDensity,false),X,Y,Z);
}
if(UsesLegacySurfaceField(X,Y,Z))
return LegacySurfaceDensityAt(X,Y,Z);
@@ -1064,21 +1085,27 @@ public:
if(!NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z),NativeDensity))
{RecordNativeOnlyViolation();return 0.0f;}
return NativeDensity;
return ApplyAdjacentStratumBoundary(
static_cast<float>(X),static_cast<float>(Y),static_cast<float>(Z),
NativeDensity,false);
}
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);
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
static_cast<float>(X),static_cast<float>(Y),static_cast<float>(Z),
IslandDensity,true),X,Y,Z);
}
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z),NativeDensity))
{
++ThreadClassificationStats().NativeLatticeFieldCalls;
return ApplyEditBrushes(NativeDensity,X,Y,Z);
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
static_cast<float>(X),static_cast<float>(Y),static_cast<float>(Z),
NativeDensity,false),X,Y,Z);
}
if(UsesLegacySurfaceField(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z)))
@@ -1102,19 +1129,21 @@ public:
float NativeDensity=0.0f;
if(!NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{RecordNativeOnlyViolation();return 0.0f;}
return NativeDensity;
return ApplyAdjacentStratumBoundary(X,Y,Z,NativeDensity,false);
}
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
{
++ThreadClassificationStats().NativeUnclampedFieldCalls;
return ApplyEditBrushes(IslandDensity,X,Y,Z);
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
X,Y,Z,IslandDensity,true),X,Y,Z);
}
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{
++ThreadClassificationStats().NativeUnclampedFieldCalls;
return ApplyEditBrushes(NativeDensity,X,Y,Z);
return ApplyEditBrushes(ApplyAdjacentStratumBoundary(
X,Y,Z,NativeDensity,false),X,Y,Z);
}
if(UsesLegacySurfaceField(X,Y,Z))
return LegacySurfaceDensityAt(X,Y,Z);
@@ -1260,12 +1289,18 @@ private:
if(OutFloorInfluence)*OutFloorInfluence=0.0f;
float IslandDensity=0.0f;
if(NativeFloatingIslandDensityAt(X,Y,Z,IslandDensity))
{
IslandDensity=ApplyAdjacentStratumBoundary(X,Y,Z,IslandDensity,true);
return bApplyEdits?ApplyEditBrushes(IslandDensity,X,Y,Z):IslandDensity;
}
if(UsesLegacySurfaceField(X,Y,Z))
{
float NativeDensity=0.0f;
if(NativeSurfaceDensityAt(X,Y,Z,NativeDensity))
{
NativeDensity=ApplyAdjacentStratumBoundary(X,Y,Z,NativeDensity,false);
return bApplyEdits?ApplyEditBrushes(NativeDensity,X,Y,Z):NativeDensity;
}
const float Density=Owner->Generator->GetDensityAt(X,Y,Z);
return bApplyEdits?ApplyEditBrushes(Density,X,Y,Z):Density;
}
@@ -1321,8 +1356,11 @@ public:
return SharedDensitySource->GetNativeSurfaceHeightsAt(X,Y,ChunkZ,OutGroundZ,OutCeilingZ);
if(!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
||!std::isfinite(X)||!std::isfinite(Y))return false;
const std::int64_t chunkMinimum=static_cast<std::int64_t>(ChunkZ)*CHUNK_SIZE;
const std::int64_t chunkMaximum=chunkMinimum+CHUNK_SIZE;
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
const std::int64_t chunkMinimum=static_cast<std::int64_t>(std::floor(
static_cast<double>(ChunkZ)*CoreVoxelsPerOwnerChunk));
const std::int64_t chunkMaximum=static_cast<std::int64_t>(std::ceil(
static_cast<double>(ChunkZ+1)*CoreVoxelsPerOwnerChunk));
if(bNativeOnly&&(!NativeOnlyContainsColumn(X,Y)
||chunkMaximum<NativeOnlyMinimum.Z||chunkMinimum>NativeOnlyMaximum.Z
||Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
@@ -1344,7 +1382,8 @@ public:
const VoxelForgeCore::Heightfield2D Block(WorldAssembly->recipe,*Plan);
if(!Block.isValid())return false;
const auto Column=Block.point(ToFixed(X),ToFixed(Y),
static_cast<int64>(ChunkZ)*CHUNK_SIZE*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
static_cast<int64>(std::llround(static_cast<double>(ChunkZ)
*CoreVoxelsPerOwnerChunk*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)));
OutGroundZ=static_cast<float>(Column.groundHeightSubvoxels/Scale);
OutCeilingZ=static_cast<float>(Column.capHeightSubvoxels/Scale);
return std::isfinite(OutGroundZ)&&std::isfinite(OutCeilingZ);
@@ -1360,10 +1399,11 @@ public:
const int32 Pad=std::max(Step,1);
const int32 BMin=Origin.Z-Pad;
const int32 BMax=Origin.Z+(Cells+1)*Step;
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin)
/static_cast<float>(CHUNK_SIZE));
/static_cast<float>(CoreVoxelsPerOwnerChunk));
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax)
/static_cast<float>(CHUNK_SIZE));
/static_cast<float>(CoreVoxelsPerOwnerChunk));
const VoxelForgeCore::WorldAssemblyStratumPlanV1* Plan=nullptr;
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
{
@@ -1407,12 +1447,13 @@ public:
bool bIslandOtherStrateOverlap=false,bBadPlan=false;
if(Owner&&Owner->Manager)
{
// Keep the delivered SurfaceWorld chunk mapping unchanged.
// Conserver le mapping de chunks SurfaceWorld deja livre.
// All manifest strata use the same resolved owner-chunk to Core-voxel scale.
// Toutes les strates du manifeste partagent l'echelle owner/Core resolue.
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin[2])
/static_cast<float>(CHUNK_SIZE));
/static_cast<float>(CoreVoxelsPerOwnerChunk));
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax[2])
/static_cast<float>(CHUNK_SIZE));
/static_cast<float>(CoreVoxelsPerOwnerChunk));
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
{
const ECaveGeneratorType Type=Owner->Manager->GetGeneratorTypeForChunk(
@@ -1544,19 +1585,6 @@ public:
{
if(!IslandPlan)return Finish(EVoxelTileClass::Mixed,true);
constexpr std::int64_t Scale=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
const std::int64_t Bottom=IslandPlan->manifest.recipe.layoutMinimumZSubvoxels;
const std::int64_t Top=IslandPlan->manifest.recipe.layoutMaximumZSubvoxels;
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);
@@ -2079,7 +2107,8 @@ private:
{
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager||!Owner->Generator
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return false;
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CHUNK_SIZE));
const int32 ChunkZ=FMath::FloorToInt(Z
/static_cast<float>(GetCoreVoxelsPerOwnerChunk()));
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
!=ECaveGeneratorType::SurfaceWorld)return false;
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
@@ -2125,23 +2154,79 @@ private:
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));
const std::int64_t Bottom=Plan->manifest.recipe.layoutMinimumZSubvoxels;
const std::int64_t Top=Plan->manifest.recipe.layoutMaximumZSubvoxels;
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));
// The recipe's boundary seal is a feature margin, not a horizontal solid cap.
// La marge de scellement du plan borne ses formes, sans remplir tout le plan XY.
const std::int64_t Density=Field.densitySubvoxels(ToFixed(X),ToFixed(Y),ToFixed(Z));
OutDensity=static_cast<float>(static_cast<double>(Density)/Scale);
return std::isfinite(OutDensity);
}
float ApplyAdjacentStratumBoundary(float X,float Y,float Z,float Density,
bool bFloatingIsland) const
{
if(!bUseNativeManifestFields||!WorldAssembly||!Owner||!Owner->Manager
||!std::isfinite(X)||!std::isfinite(Y)||!std::isfinite(Z))return Density;
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
const int32 ChunkZ=FMath::FloorToInt(Z/static_cast<float>(CoreVoxelsPerOwnerChunk));
const ECaveGeneratorType CurrentType=Owner->Manager->GetGeneratorTypeForChunk(
FIntVector(0,0,ChunkZ));
if(bFloatingIsland&&CurrentType==ECaveGeneratorType::FloatingIslands)
{
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 Density;
const int32 LowerChunk=Plan->bottomChunkZ-1;
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,LowerChunk))
!=ECaveGeneratorType::SurfaceWorld)return Density;
const double Boundary=static_cast<double>(Plan->bottomChunkZ)
*CoreVoxelsPerOwnerChunk;
float LowerDensity=0.0f,UpperDensity=0.0f;
if(!NativeSurfaceDensityAt(X,Y,static_cast<float>(Boundary-0.5),LowerDensity)
||!NativeFloatingIslandDensityAt(X,Y,static_cast<float>(Boundary+0.5),UpperDensity)
||(LowerDensity<0.0f)==(UpperDensity<0.0f))return Density;
// Clip the two signed-distance fields to their shared owner-stratum plane.
// This keeps a solid-below/air-above seam continuous at every mesh sample step.
// Les deux champs sont limites au plan commun, quel que soit le pas de maillage.
const float Plane=static_cast<float>(static_cast<double>(Z)-Boundary);
return LowerDensity<0.0f?std::min(Density,Plane)
:std::max(Density,-Plane);
}
if(!bFloatingIsland&&CurrentType==ECaveGeneratorType::SurfaceWorld)
{
const int32 StrateIndex=Owner->Manager->GetStrateIndex(
static_cast<float>((static_cast<double>(ChunkZ)*CHUNK_SIZE+CHUNK_SIZE/2)*VOXEL_SIZE));
const auto* Plan=FindWorldAssemblyStratum(StrateIndex,ChunkZ);
if(!Plan)return Density;
const int32 UpperChunk=Plan->topChunkZ+1;
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,UpperChunk))
!=ECaveGeneratorType::FloatingIslands)return Density;
const auto* UpperPlan=FindWorldAssemblyFloatingIslandStratum(
Owner->Manager->GetStrateIndex(static_cast<float>((
static_cast<double>(UpperChunk)*CHUNK_SIZE+CHUNK_SIZE/2)*VOXEL_SIZE)),UpperChunk);
if(!UpperPlan)return Density;
const double Boundary=static_cast<double>(UpperPlan->bottomChunkZ)
*CoreVoxelsPerOwnerChunk;
float LowerDensity=0.0f,UpperDensity=0.0f;
if(!NativeSurfaceDensityAt(X,Y,static_cast<float>(Boundary-0.5),LowerDensity)
||!NativeFloatingIslandDensityAt(X,Y,static_cast<float>(Boundary+0.5),UpperDensity)
||(LowerDensity<0.0f)==(UpperDensity<0.0f))return Density;
const float Plane=static_cast<float>(static_cast<double>(Z)-Boundary);
return LowerDensity<0.0f?std::max(Density,Plane)
:std::min(Density,-Plane);
}
return Density;
}
bool UsesLegacySurfaceField(float X,float Y,float Z) const
{
if(!Owner||!Owner->Manager||!Owner->Generator)return false;
const FIntVector ChunkCoord(FMath::FloorToInt(X/static_cast<float>(CHUNK_SIZE)),
FMath::FloorToInt(Y/static_cast<float>(CHUNK_SIZE)),
FMath::FloorToInt(Z/static_cast<float>(CHUNK_SIZE)));
const float CoreVoxelsPerOwnerChunk=static_cast<float>(GetCoreVoxelsPerOwnerChunk());
const FIntVector ChunkCoord(FMath::FloorToInt(X/CoreVoxelsPerOwnerChunk),
FMath::FloorToInt(Y/CoreVoxelsPerOwnerChunk),
FMath::FloorToInt(Z/CoreVoxelsPerOwnerChunk));
return Owner->Manager->GetGeneratorTypeForChunk(ChunkCoord)
==ECaveGeneratorType::SurfaceWorld;
}
@@ -2351,19 +2436,26 @@ private:
int32 Top=MIN_int32,Bottom=MAX_int32;
for(const FStrateSlot& Slot:Layout)
{
const int32 MidChunkZ=(Slot.TopChunkZ+Slot.BottomChunkZ)/2;
// A manifest-backed FloatingIslands stratum supplies its own sparse island
// field; it must not extend the legacy solid envelope across the open sky.
if(bUseNativeManifestFields
&&Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,MidChunkZ))
==ECaveGeneratorType::FloatingIslands)
continue;
Top=std::max(Top,Slot.TopChunkZ);Bottom=std::min(Bottom,Slot.BottomChunkZ);
if(!Slot.Definition)continue;
const int32 MidChunkZ=(Slot.TopChunkZ+Slot.BottomChunkZ)/2;
FLayerField Field;
Field.Lo=Slot.BottomChunkZ*CHUNK_SIZE;
Field.Hi=(Slot.TopChunkZ+1)*CHUNK_SIZE;
Field.Lo=OwnerChunkLowerBoundaryCoreVoxel(Slot.BottomChunkZ);
Field.Hi=OwnerChunkUpperBoundaryCoreVoxel(Slot.TopChunkZ+1);
Field.StrateIndex=Slot.StrateIndex;
Field.Params=Owner->Manager->GetGenerationParams(FIntVector(0,0,MidChunkZ));
LayerFields.push_back(std::move(Field));
}
if(Top>=Bottom)
{
LayerRanges.push_back({Bottom*CHUNK_SIZE,(Top+1)*CHUNK_SIZE});
LayerRanges.push_back({OwnerChunkLowerBoundaryCoreVoxel(Bottom),
OwnerChunkUpperBoundaryCoreVoxel(Top+1)});
}
}
@@ -3474,8 +3566,9 @@ private:
auto Unit=[&](uint32 H){return static_cast<double>(Hash(H)>>8)*(1.0/16777216.0);};
for(const FStrateSlot& Slot:Layout)
{
const double ZBottom=static_cast<double>(Slot.BottomChunkZ)*CHUNK_SIZE;
const double ZTop=static_cast<double>(Slot.TopChunkZ+1)*CHUNK_SIZE;
const double CoreVoxelsPerOwnerChunk=GetCoreVoxelsPerOwnerChunk();
const double ZBottom=static_cast<double>(Slot.BottomChunkZ)*CoreVoxelsPerOwnerChunk;
const double ZTop=static_cast<double>(Slot.TopChunkZ+1)*CoreVoxelsPerOwnerChunk;
for(int32 GY=GY0;GY<=GY1;++GY)for(int32 GX=GX0;GX<=GX1;++GX)
{
uint32 H=Hash(Seed^static_cast<uint32>(GX)*0x9E3779B9u
+7 -5
View File
@@ -1162,8 +1162,13 @@ namespace VoxelForgeCore
const std::int64_t tileMinimum[3]={boundsMin.X,boundsMin.Y,boundsMin.Z};
const std::int64_t tileMaximum[3]={boundsMax.X,boundsMax.Y,boundsMax.Z};
const int32 firstSurfaceChunk=FloorDiv(boundsMin.Z,CHUNK_SIZE);
const int32 lastSurfaceChunk=FloorDiv(boundsMax.Z,CHUNK_SIZE);
const double coreVoxelsPerOwnerChunk=static_cast<double>(CHUNK_SIZE)
*static_cast<double>(impl_->owner->OwnerVoxelSizeMicrons)
/static_cast<double>(std::max(1u,impl_->owner->CoreVoxelSizeMicrons));
const int32 firstSurfaceChunk=FMath::FloorToInt(
static_cast<double>(boundsMin.Z)/coreVoxelsPerOwnerChunk);
const int32 lastSurfaceChunk=FMath::FloorToInt(
static_cast<double>(boundsMax.Z)/coreVoxelsPerOwnerChunk);
const WorldAssemblyStratumPlanV1* selectedPlan=nullptr;
for(int32 chunkZ=firstSurfaceChunk;chunkZ<=lastSurfaceChunk;++chunkZ)
{
@@ -1183,9 +1188,6 @@ namespace VoxelForgeCore
if(!selectedPlan||!Heightfield2D(impl_->worldAssembly->recipe,*selectedPlan).isValid())
return false;
const double coreVoxelsPerOwnerChunk=static_cast<double>(CHUNK_SIZE)
*static_cast<double>(impl_->owner->OwnerVoxelSizeMicrons)
/static_cast<double>(std::max(1u,impl_->owner->CoreVoxelSizeMicrons));
const int32 firstIslandChunk=FMath::FloorToInt(
static_cast<double>(boundsMin.Z)/coreVoxelsPerOwnerChunk);
const int32 lastIslandChunk=FMath::FloorToInt(