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

@@ -128,6 +128,110 @@ struct FCoreSurfaceSnapshot
}
};
struct FCoreFloatingIslandFieldSnapshot
{
VoxelForgeCore::FloatingIslandRecipeV1 Recipe;
VoxelForgeCore::FloatingIslandPlanV1 Plan;
TUniquePtr<VoxelForgeCore::FloatingIslandFieldV1> Field;
};
struct FCoreFloatingIslandSnapshot
{
TMap<int32, TSharedPtr<const FCoreFloatingIslandFieldSnapshot, ESPMode::ThreadSafe>> Fields;
const FCoreFloatingIslandFieldSnapshot* FindField(int32 StrateIndex) const
{
const auto* Found = Fields.Find(StrateIndex);
return Found != nullptr && Found->IsValid() ? Found->Get() : nullptr;
}
bool GetDensity(int32 StrateIndex, float LegacyVoxelX, float LegacyVoxelY,
float LegacyVoxelZ, float& OutDensity) const
{
OutDensity = 1.0f;
const FCoreFloatingIslandFieldSnapshot* Entry = FindField(StrateIndex);
if (Entry == nullptr || !Entry->Field.IsValid()
|| !FMath::IsFinite(LegacyVoxelX) || !FMath::IsFinite(LegacyVoxelY)
|| !FMath::IsFinite(LegacyVoxelZ))
{
return false;
}
// A legacy voxel is 128 subvoxels at 12.5 cm; Core field distances are converted back to legacy units.
// Un voxel historique vaut 128 sous-voxels a 12,5 cm ; la distance Core revient en unites historiques.
constexpr double LegacyVoxelSubvoxels = 128.0;
constexpr double MaximumInput = static_cast<double>(MAX_int64) / LegacyVoxelSubvoxels;
if (FMath::Abs(static_cast<double>(LegacyVoxelX)) > MaximumInput
|| FMath::Abs(static_cast<double>(LegacyVoxelY)) > MaximumInput
|| FMath::Abs(static_cast<double>(LegacyVoxelZ)) > MaximumInput)
{
return false;
}
const int64 Density = Entry->Field->densitySubvoxels(
static_cast<int64>(std::llround(static_cast<double>(LegacyVoxelX) * LegacyVoxelSubvoxels)),
static_cast<int64>(std::llround(static_cast<double>(LegacyVoxelY) * LegacyVoxelSubvoxels)),
static_cast<int64>(std::llround(static_cast<double>(LegacyVoxelZ) * LegacyVoxelSubvoxels)));
OutDensity = static_cast<float>(static_cast<double>(Density) / LegacyVoxelSubvoxels);
return FMath::IsFinite(OutDensity);
}
bool GetTopAnchor(int32 StrateIndex, const FVector2D& LocalXYCm,
float& OutGroundLocalZCm) const
{
OutGroundLocalZCm = 0.0f;
const FCoreFloatingIslandFieldSnapshot* Entry = FindField(StrateIndex);
if (Entry == nullptr || !Entry->Field.IsValid()
|| Entry->Plan.islands.empty()
|| !FMath::IsFinite(LocalXYCm.X) || !FMath::IsFinite(LocalXYCm.Y))
{
return false;
}
constexpr double SubvoxelsPerCoreVoxel = 256.0;
constexpr double CentimetersPerCoreVoxel = 25.0;
const double XSubvoxels = static_cast<double>(LocalXYCm.X)
* SubvoxelsPerCoreVoxel / CentimetersPerCoreVoxel;
const double YSubvoxels = static_cast<double>(LocalXYCm.Y)
* SubvoxelsPerCoreVoxel / CentimetersPerCoreVoxel;
constexpr double MaximumInput = static_cast<double>(MAX_int64) - 1024.0;
if (FMath::Abs(XSubvoxels) > MaximumInput || FMath::Abs(YSubvoxels) > MaximumInput)
{
return false;
}
const int64 X = static_cast<int64>(std::llround(XSubvoxels));
const int64 Y = static_cast<int64>(std::llround(YSubvoxels));
int64 SearchTop = Entry->Plan.islands.front().topZSubvoxels;
int64 SearchBottom = Entry->Plan.islands.front().bottomZSubvoxels;
for (const auto& Island : Entry->Plan.islands)
{
SearchTop = FMath::Max(SearchTop, Island.topZSubvoxels);
SearchBottom = FMath::Min(SearchBottom, Island.bottomZSubvoxels);
}
SearchTop += 4 * 256;
SearchBottom -= 4 * 256;
constexpr int64 ScanStepSubvoxels = 128;
int64 PreviousZ = SearchTop;
int64 PreviousDensity = Entry->Field->densitySubvoxels(X, Y, PreviousZ);
if (PreviousDensity < 0) return false;
for (int64 Z = SearchTop - ScanStepSubvoxels; Z >= SearchBottom; Z -= ScanStepSubvoxels)
{
const int64 Density = Entry->Field->densitySubvoxels(X, Y, Z);
if (PreviousDensity >= 0 && Density < 0)
{
const double Denominator = static_cast<double>(PreviousDensity - Density);
const double Alpha = Denominator > 0.0
? static_cast<double>(PreviousDensity) / Denominator : 0.5;
const double SurfaceSubvoxels = static_cast<double>(PreviousZ)
+ static_cast<double>(Z - PreviousZ) * Alpha;
OutGroundLocalZCm = static_cast<float>(SurfaceSubvoxels
* CentimetersPerCoreVoxel / SubvoxelsPerCoreVoxel);
return FMath::IsFinite(OutGroundLocalZCm);
}
PreviousZ = Z;
PreviousDensity = Density;
}
return false;
}
};
// Global safety cap on spawned decoration ACTORS per cell (across all entries).
// HISM instances are exempt — they're batched render data, capped per entry by MaxPerChunk.
static constexpr int32 GMaxDecorationActorsPerCell = 400;
@@ -174,6 +278,7 @@ void UVoxelContentManager::Initialize(AActor* InOwner, UVoxelStrateManager* InSt
Settings = InSettings;
Seed = InSeed;
NativeSurfaceSnapshot.Reset();
NativeFloatingIslandSnapshot.Reset();
if (Settings)
{
@@ -196,6 +301,33 @@ void UVoxelContentManager::Initialize(AActor* InOwner, UVoxelStrateManager* InSt
Snapshot->Plans.Add(Plan.strateIndex, Plan);
}
NativeSurfaceSnapshot = Snapshot;
if (!Manifest->floatingIslands.empty())
{
TSharedPtr<FCoreFloatingIslandSnapshot, ESPMode::ThreadSafe> IslandSnapshot =
MakeShared<FCoreFloatingIslandSnapshot, ESPMode::ThreadSafe>();
for (const auto& IslandPlan : Manifest->floatingIslands)
{
TSharedPtr<FCoreFloatingIslandFieldSnapshot, ESPMode::ThreadSafe> Entry =
MakeShared<FCoreFloatingIslandFieldSnapshot, ESPMode::ThreadSafe>();
Entry->Recipe = IslandPlan.manifest.recipe;
Entry->Plan = IslandPlan.manifest.plan;
Entry->Field = MakeUnique<VoxelForgeCore::FloatingIslandFieldV1>(
Entry->Recipe, Entry->Plan);
if (!Entry->Field->isValid())
{
UE_LOG(LogTemp, Warning,
TEXT("[VoxelContentManager] Core floating-island field rejected strate %d."),
IslandPlan.strateIndex);
continue;
}
IslandSnapshot->Fields.Add(IslandPlan.strateIndex, Entry);
}
if (!IslandSnapshot->Fields.IsEmpty())
{
NativeFloatingIslandSnapshot = IslandSnapshot;
}
}
}
else
{
@@ -244,6 +376,66 @@ bool UVoxelContentManager::QueryNativeSurfaceAnchors(
return true;
}
bool UVoxelContentManager::QueryNativeFloatingIslandAnchor(
int32 StrateIndex, const FVector2D& LocalXYCm, float& OutGroundLocalZCm) const
{
OutGroundLocalZCm = 0.0f;
const AVoxelWorld* VoxelWorld = Cast<AVoxelWorld>(Owner.Get());
if (VoxelWorld == nullptr || !VoxelWorld->bUseVoxelForgeCore
|| !NativeFloatingIslandSnapshot.IsValid())
{
return false;
}
return NativeFloatingIslandSnapshot->GetTopAnchor(
StrateIndex, LocalXYCm, OutGroundLocalZCm);
}
bool UVoxelContentManager::QueryStrateWaterAnchor(
int32 StrateIndex, bool& bOutHasWater, float& OutWaterLocalZCm) const
{
bOutHasWater = false;
OutWaterLocalZCm = -FLT_MAX;
const AVoxelWorld* VoxelWorld = Cast<AVoxelWorld>(Owner.Get());
if (VoxelWorld == nullptr || StrateManager == nullptr)
{
return false;
}
if (VoxelWorld->bUseVoxelForgeCore && NativeSurfaceSnapshot.IsValid())
{
bool bHasPlan = false;
bool bEnabled = false;
float NativeWaterLocalZCm = -FLT_MAX;
if (NativeSurfaceSnapshot->GetWater(
StrateIndex, bHasPlan, bEnabled, NativeWaterLocalZCm) && bHasPlan)
{
bOutHasWater = bEnabled;
OutWaterLocalZCm = bEnabled ? NativeWaterLocalZCm : -FLT_MAX;
return true;
}
}
for (const FStrateSlot& Slot : StrateManager->GetLayout())
{
if (Slot.StrateIndex != StrateIndex)
{
continue;
}
const int32 MidChunkZ = Slot.BottomChunkZ
+ (Slot.TopChunkZ - Slot.BottomChunkZ) / 2;
const float ManagerWaterVoxelZ = StrateManager->GetWaterLevelWorldZForChunk(
FIntVector(0, 0, MidChunkZ));
if (ManagerWaterVoxelZ != -FLT_MAX)
{
bOutHasWater = true;
const float ManagerWaterLocalZCm = ManagerWaterVoxelZ * VOXEL_SIZE;
OutWaterLocalZCm = VoxelWorld->FromStrateManagerLocalZ(ManagerWaterLocalZCm);
}
return true;
}
return false;
}
void UVoxelContentManager::BeginDestroy()
{
// Backstop: stop any worker from touching us. EndPlay → NotifyShutdown should have already drained.
@@ -395,6 +587,11 @@ void UVoxelContentManager::UpdateDecorations(const FVector& PlayerWorldPos)
&& CurrentCtx.bSurfaceWorld
&& CurrentCtx.NativeSurface.IsValid()
&& CurrentCtx.NativeSurface->FindPlan(StrateIndex) != nullptr;
CurrentCtx.NativeIslands = NativeFloatingIslandSnapshot;
CurrentCtx.bNativeFloatingIslands = VoxelWorld != nullptr && VoxelWorld->bUseVoxelForgeCore
&& StrateManager->GetGeneratorTypeForChunk(RepChunk) == ECaveGeneratorType::FloatingIslands
&& CurrentCtx.NativeIslands.IsValid()
&& CurrentCtx.NativeIslands->FindField(StrateIndex) != nullptr;
{
bool bHasNativePlan = false;
bool bNativeWaterEnabled = false;
@@ -710,7 +907,17 @@ void UVoxelContentManager::BuildCellSpawns(const UVoxelGenerator* Gen, const FTr
FChunkBiomeCache BiomeCache;
const bool bHasBiomes = Ctx.BiomeCtx.IsValid();
auto D = [&](float VX, float VY, float VZ) { return Gen->GetDensityAt(VX, VY, VZ); };
auto D = [&](float VX, float VY, float VZ)
{
if (Ctx.bNativeFloatingIslands && Ctx.NativeIslands.IsValid())
{
float NativeDensity = 1.0f;
if (Ctx.NativeIslands->GetDensity(Ctx.StrateIndex, VX, VY, VZ, NativeDensity))
return NativeDensity;
return 1.0f;
}
return Gen->GetDensityAt(VX, VY, VZ);
};
auto GetSurface = [&](float VX, float VY, float& OutGround, float& OutCap)
{
if (Ctx.bNativeSurface && Ctx.NativeSurface.IsValid())
@@ -1338,6 +1545,21 @@ bool UVoxelContentManager::FindLandmarkColumn(const UVoxelGenerator* Gen, const
{
if (!Gen) return false;
const auto Density = [&](float SampleX, float SampleY, float SampleZ)
{
if (Ctx.bNativeFloatingIslands && Ctx.NativeIslands.IsValid())
{
float NativeDensity = 1.0f;
if (Ctx.NativeIslands->GetDensity(
Ctx.StrateIndex, SampleX, SampleY, SampleZ, NativeDensity))
{
return NativeDensity;
}
return 1.0f;
}
return Gen->GetDensityAt(SampleX, SampleY, SampleZ);
};
if (Ctx.bSurfaceWorld)
{
float hC, cC;
@@ -1368,7 +1590,7 @@ bool UVoxelContentManager::FindLandmarkColumn(const UVoxelGenerator* Gen, const
}
// Floor / Wall / Any → the terrain top.
if (!(hC >= Ctx.BottomVoxelZ && hC <= Ctx.TopVoxelZ)) return false;
if (!Ctx.bNativeSurface && Gen->GetDensityAt(VX, VY, hC) > 0.5f) return false;
if (!Ctx.bNativeSurface && Density(VX, VY, hC) > 0.5f) return false;
float d, hXp, hXm, hYp, hYm;
GetSurface(VX + 1.0f, VY, hXp, d);
GetSurface(VX - 1.0f, VY, hXm, d);
@@ -1384,19 +1606,19 @@ bool UVoxelContentManager::FindLandmarkColumn(const UVoxelGenerator* Gen, const
// Bounded by ColDepth like the decoration march (this runs SYNCHRONOUSLY on the game thread):
// once past open air, a solid run longer than ColDepth means bedrock down to the strate floor —
// stop instead of paying GetDensityAt across the whole remaining band.
float PrevD = Gen->GetDensityAt(VX, VY, Ctx.TopVoxelZ);
float PrevD = Density(VX, VY, Ctx.TopVoxelZ);
bool bSeenAir = (PrevD >= 0.0f);
float SolidRun = 0.0f;
for (float Z = Ctx.TopVoxelZ - Step; Z >= Ctx.BottomVoxelZ; Z -= Step)
{
const float Dz = Gen->GetDensityAt(VX, VY, Z);
const float Dz = Density(VX, VY, Z);
if ((PrevD >= 0.0f) != (Dz >= 0.0f)) // air ↔ solid crossing
{
float ZLo = Z, ZHi = Z + Step, DHi = PrevD, DLo = Dz;
for (int32 It = 0; It < 4; ++It)
{
const float ZM = 0.5f * (ZLo + ZHi);
const float DM = Gen->GetDensityAt(VX, VY, ZM);
const float DM = Density(VX, VY, ZM);
if ((DM >= 0.0f) == (DHi >= 0.0f)) { ZHi = ZM; DHi = DM; }
else { ZLo = ZM; DLo = DM; }
}
@@ -1405,9 +1627,9 @@ bool UVoxelContentManager::FindLandmarkColumn(const UVoxelGenerator* Gen, const
const float ZC = ZLo + (ZHi - ZLo) * T;
const FVector LocalGrad(
Gen->GetDensityAt(VX + 1.0f, VY, ZC) - Gen->GetDensityAt(VX - 1.0f, VY, ZC),
Gen->GetDensityAt(VX, VY + 1.0f, ZC) - Gen->GetDensityAt(VX, VY - 1.0f, ZC),
Gen->GetDensityAt(VX, VY, ZC + 1.0f) - Gen->GetDensityAt(VX, VY, ZC - 1.0f));
Density(VX + 1.0f, VY, ZC) - Density(VX - 1.0f, VY, ZC),
Density(VX, VY + 1.0f, ZC) - Density(VX, VY - 1.0f, ZC),
Density(VX, VY, ZC + 1.0f) - Density(VX, VY, ZC - 1.0f));
FVector N = OwnerXf.TransformVectorNoScale(LocalGrad).GetSafeNormal();
if (N.IsNearlyZero()) N = FVector::UpVector;