wip(unreal): round 3 -- owner's in-game defects classified; opening room fixed; Core biome query

Luna, integration round 3, from the owner's four in-game screenshots:
- Capsule rings at the opening and the shaft continuing through the cave room were Core
  world defects: the synthetic bore is removed and the opening gets a finite origin room
  and floor (solid below). New world version, W1/W8/W16 identical: density
  a8bcb72d41092503, mesh 90f29ba15e24579f, payload 82c6b489e7bb7fd7, topology
  7b99448a1f844f2c.
- B-side landing and surface: headless coverage found no missing tiles or LOD-transition
  gaps (960 / 640 fine tiles compiled after travel); best explained by Core's missing
  SurfaceWorld representation. Null-RHI cannot rule out a presentation-only issue.
- Core mode GetBiomeAtWorldLocation now answers (e.g. Biome_Surface_Plain); biome
  terrain itself is not generated yet (proposal: native Core SurfaceWorld evaluator).
Owner checked the Step29 viewer himself: the surface strate type is absent there too.

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 21:45:49 +02:00
1 parent 075e58187e
commit 75210e56f3
8 files changed
+957 -24

No files matched your search

+2 -6
View File
@@ -12463,16 +12463,12 @@ int32 AVoxelWorld::GetStrateAtPosition(FVector WorldPosition) const
FVoxelBiomeQuery AVoxelWorld::GetBiomeAtWorldLocation(FVector WorldLocation) const
{
FVoxelBiomeQuery Out;
if (bUseVoxelForgeCore)
{
// Core ne publie pas encore le query biome historique.
// Core does not expose the legacy biome query API yet.
return Out;
}
if (!Generator) return Out;
// Bring the world point into actor-LOCAL voxel space — the SAME transform the decoration scatter
// applies (UpdateDecorations), so the probe agrees with where props actually land.
// Convert using the legacy generator's authored voxel size; Core still queries this biome field.
// Convertir avec l'échelle historique du générateur; Core interroge toujours ce champ de biomes.
const FVector Local = GetActorTransform().InverseTransformPosition(WorldLocation);
const float VX = Local.X / VOXEL_SIZE;
const float VY = Local.Y / VOXEL_SIZE;
@@ -12,6 +12,8 @@
#include "Engine/World.h"
#include "GameFramework/Actor.h"
#include "GameFramework/GameModeBase.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/WorldSettings.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformProcess.h"
@@ -12615,6 +12617,135 @@ std::array<std::uint64_t, 4> StandaloneCoreAggregateHashes(
return Aggregates;
}
bool AuditCoreClipmapCoverage(
const std::vector<VoxelForgeCore::TileKey>& Tiles,
VoxelForgeCore::Vec3d Focus,
std::int32_t FocusRadiusVoxels,
std::int32_t& OutLocalTileCount,
std::int32_t& OutCheckedFaces,
std::int32_t& OutTransitionFaces,
FString& OutError)
{
struct FBounds
{
std::int64_t Min[3]{};
std::int64_t Max[3]{};
std::int32_t Lod = 0;
};
OutLocalTileCount = 0;
OutCheckedFaces = 0;
OutTransitionFaces = 0;
OutError.Reset();
std::vector<FBounds> Bounds;
Bounds.reserve(Tiles.size());
for (const VoxelForgeCore::TileKey& Key : Tiles)
{
if (Key.lod < 0 || Key.lod > 8)
{
OutError = TEXT("Core clipmap contains an invalid LOD key.");
return false;
}
const std::int64_t Extent = 32ll << Key.lod;
FBounds Box;
Box.Lod = Key.lod;
Box.Min[0] = static_cast<std::int64_t>(Key.coordinate.x) * Extent;
Box.Min[1] = static_cast<std::int64_t>(Key.coordinate.y) * Extent;
Box.Min[2] = static_cast<std::int64_t>(Key.coordinate.z) * Extent;
for (int32 Axis = 0; Axis < 3; ++Axis) Box.Max[Axis] = Box.Min[Axis] + Extent;
Bounds.push_back(Box);
}
// Une clipmap Core ne doit jamais renvoyer deux boites qui se chevauchent en volume.
// A Core clipmap must never return two tile boxes that overlap in volume.
for (std::size_t A = 0; A < Bounds.size(); ++A)
{
for (std::size_t B = A + 1; B < Bounds.size(); ++B)
{
bool bOverlaps = true;
for (int32 Axis = 0; Axis < 3; ++Axis)
{
bOverlaps = bOverlaps
&& FMath::Min(Bounds[A].Max[Axis], Bounds[B].Max[Axis])
> FMath::Max(Bounds[A].Min[Axis], Bounds[B].Min[Axis]);
}
if (bOverlaps)
{
OutError = FString::Printf(
TEXT("Core clipmap tiles overlap: index %llu and %llu."),
static_cast<unsigned long long>(A), static_cast<unsigned long long>(B));
return false;
}
}
}
const double FocusPoint[3] = {Focus.x, Focus.y, Focus.z};
for (std::size_t TileIndex = 0; TileIndex < Bounds.size(); ++TileIndex)
{
const FBounds& Tile = Bounds[TileIndex];
if (Tile.Lod > 2) continue;
bool bNearFocus = true;
for (int32 Axis = 0; Axis < 3; ++Axis)
{
bNearFocus = bNearFocus
&& static_cast<double>(Tile.Max[Axis]) >= FocusPoint[Axis] - FocusRadiusVoxels
&& static_cast<double>(Tile.Min[Axis]) <= FocusPoint[Axis] + FocusRadiusVoxels;
}
if (!bNearFocus) continue;
++OutLocalTileCount;
for (int32 Axis = 0; Axis < 3; ++Axis)
{
const int32 UAxis = (Axis + 1) % 3;
const int32 VAxis = (Axis + 2) % 3;
const std::int64_t FaceArea = (Tile.Max[UAxis] - Tile.Min[UAxis])
* (Tile.Max[VAxis] - Tile.Min[VAxis]);
for (const bool bPositiveFace : {false, true})
{
const std::int64_t FaceCoordinate = bPositiveFace ? Tile.Max[Axis] : Tile.Min[Axis];
std::int64_t CoveredArea = 0;
bool bTouchesLodTransition = false;
for (std::size_t NeighbourIndex = 0; NeighbourIndex < Bounds.size(); ++NeighbourIndex)
{
if (NeighbourIndex == TileIndex) continue;
const FBounds& Neighbour = Bounds[NeighbourIndex];
if (Neighbour.Min[Axis] != FaceCoordinate
&& Neighbour.Max[Axis] != FaceCoordinate)
{
continue;
}
const std::int64_t OverlapU = FMath::Max<std::int64_t>(0,
FMath::Min(Tile.Max[UAxis], Neighbour.Max[UAxis])
- FMath::Max(Tile.Min[UAxis], Neighbour.Min[UAxis]));
const std::int64_t OverlapV = FMath::Max<std::int64_t>(0,
FMath::Min(Tile.Max[VAxis], Neighbour.Max[VAxis])
- FMath::Max(Tile.Min[VAxis], Neighbour.Min[VAxis]));
if (OverlapU == 0 || OverlapV == 0) continue;
CoveredArea += OverlapU * OverlapV;
bTouchesLodTransition = bTouchesLodTransition || Neighbour.Lod != Tile.Lod;
}
++OutCheckedFaces;
if (CoveredArea != FaceArea)
{
OutError = FString::Printf(
TEXT("Core clipmap has a missing or overlapping neighbour at LOD %d, axis %d, face %d (coverage %lld/%lld)."),
Tile.Lod, Axis, bPositiveFace ? 1 : 0,
static_cast<long long>(CoveredArea), static_cast<long long>(FaceArea));
return false;
}
if (bTouchesLodTransition) ++OutTransitionFaces;
}
}
}
if (OutLocalTileCount == 0 || OutTransitionFaces == 0)
{
OutError = TEXT("Core clipmap coverage audit found no local tiles or no local LOD transition faces.");
return false;
}
return true;
}
bool VerifyStandaloneCoreAdapter(const FString& Json, FString& OutError)
{
FTCHARToUTF8 Utf8Json(*Json);
@@ -13091,7 +13222,11 @@ bool RunCoreWorldActorIntegrationTest(const FExploreArguments& Arguments, FStrin
// Core complets en mémoire simultanément ; elle calcule aussi les hachages après édition.
TMap<FVoxelTileKey, FVoxelForgeCoreTileHashRecord> ExpectedHashes;
TMap<FVoxelTileKey, FVoxelForgeCoreTileHashRecord> ExpectedPostEditHashes;
TMap<FVoxelTileKey, FVoxelForgeCoreTileHashRecord> ExpectedTravelHashes;
TMap<FVoxelTileKey, FVoxelForgeCoreTileHashRecord> ExpectedSurfaceTravelHashes;
TSet<FVoxelTileKey> ExpectedInitialDesiredSet;
TSet<FVoxelTileKey> ExpectedTravelDesiredSet;
TSet<FVoxelTileKey> ExpectedSurfaceTravelDesiredSet;
TArray<FVoxelTileKey> ExpectedAffectedTiles;
FVector CarveLocalPositionCm = FVector::ZeroVector;
FVoxelTileKey CarveTargetTile;
@@ -13101,7 +13236,28 @@ bool RunCoreWorldActorIntegrationTest(const FExploreArguments& Arguments, FStrin
CarveBrushRadiusLegacyVoxels * static_cast<double>(VOXEL_SIZE) / CoreVoxelSizeCm;
uint64 ExpectedEditDigest = 0;
std::array<std::uint64_t, 4> InitialAggregates{};
std::array<std::uint64_t, 4> TravelAggregates{};
std::array<std::uint64_t, 4> SurfaceTravelAggregates{};
std::size_t ExpectedInitialTileCount = 0;
std::size_t ExpectedTravelTileCount = 0;
std::size_t TravelFineTilesCompiled = 0;
std::size_t TravelRegionsBuilt = 0;
std::int32_t TravelCoverageLocalTiles = 0;
std::int32_t TravelCoverageFaces = 0;
std::int32_t TravelLodTransitionFaces = 0;
std::int32_t TravelTilesWithSkirts = 0;
std::size_t SurfaceTravelFineTilesCompiled = 0;
std::size_t SurfaceTravelRegionsBuilt = 0;
std::int32_t SurfaceTravelCoverageLocalTiles = 0;
std::int32_t SurfaceTravelCoverageFaces = 0;
std::int32_t SurfaceTravelLodTransitionFaces = 0;
std::int32_t SurfaceTravelTilesWithSkirts = 0;
VoxelForgeCore::TileRegionCompileStats TravelCompileStats;
VoxelForgeCore::TileRegionCompileStats SurfaceTravelCompileStats;
const VoxelForgeCore::Vec3d TravelCameraVoxels{-156.75164794921875, 25.093801498413086,
-823.67364501953125};
const VoxelForgeCore::Vec3d SurfaceCameraVoxels{-156.75164794921875, 25.093801498413086,
-1024.0};
{
FTCHARToUTF8 Utf8Json(*Json);
std::string CoreError;
@@ -13206,6 +13362,120 @@ bool RunCoreWorldActorIntegrationTest(const FExploreArguments& Arguments, FStrin
}
}
InitialAggregates = StandaloneCoreAggregateHashes(AggregateRows);
// Rebuild and hash the same full clipmap at W1 and W16; the main reference is W8.
// Recompiler et hacher le même clipmap à W1 et W16 ; la référence principale est W8.
auto BuildWorkerHash = [&](uint32 WorkerLimit,
std::array<std::uint64_t, 4>& OutHashes) -> bool
{
std::optional<VoxelForgeCore::ResolvedWorldSnapshot> WorkerSnapshot =
VoxelForgeCore::ResolvedWorldSnapshot::FromJson(
std::string_view(Utf8Json.Get(), static_cast<std::size_t>(Utf8Json.Length())),
CoreError);
if (!WorkerSnapshot)
{
OutError = FString::Printf(TEXT("Core worker-hash snapshot failed: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
VoxelForgeCore::World WorkerWorld(std::move(*WorkerSnapshot));
VoxelForgeCore::ShapeBuildRequest WorkerRequest = Request;
WorkerRequest.workerLimit = WorkerLimit;
FStandaloneCoreAdapterScheduler WorkerScheduler;
if (!WorkerWorld.compile(WorkerRequest, WorkerScheduler, CoreError))
{
OutError = FString::Printf(TEXT("Core W%u compile failed: %s"), WorkerLimit,
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
WorkerWorld.retainTileRegions(Desired);
std::vector<FStandaloneCoreAdapterTileHashes> WorkerRows;
WorkerRows.reserve(Desired.size());
for (const VoxelForgeCore::TileKey& Key : Desired)
{
const std::optional<VoxelForgeCore::TileMesh> Mesh =
WorkerWorld.generateTile(Key, Options, CoreError);
if (!Mesh || !Mesh->hasDensityHash || !Mesh->hasMeshHash
|| !Mesh->hasPayloadHash || !Mesh->hasTopologyHash)
{
OutError = FString::Printf(TEXT("Core W%u tile hash failed: %s"), WorkerLimit,
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
WorkerRows.push_back({Key,
{Mesh->densityHash, Mesh->meshHash, Mesh->payloadHash, Mesh->topologyHash}});
}
OutHashes = StandaloneCoreAggregateHashes(WorkerRows);
return true;
};
std::array<std::uint64_t, 4> Worker1Aggregates{};
std::array<std::uint64_t, 4> Worker16Aggregates{};
if (!BuildWorkerHash(1, Worker1Aggregates)
|| !BuildWorkerHash(16, Worker16Aggregates))
{
return false;
}
if (Worker1Aggregates != InitialAggregates || Worker16Aggregates != InitialAggregates)
{
OutError = TEXT("Core full-clipmap hashes differ across worker limits 1, 8, and 16.");
return false;
}
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] worker_hash_matrix=1/8/16 stable=1 density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx"),
static_cast<unsigned long long>(InitialAggregates[0]),
static_cast<unsigned long long>(InitialAggregates[1]),
static_cast<unsigned long long>(InitialAggregates[2]),
static_cast<unsigned long long>(InitialAggregates[3]));
if (!Manager->GetLayout().IsEmpty() && Manager->GetLayout()[0].Definition != nullptr)
{
const FStrateSlot& TopSlot = Manager->GetLayout()[0];
const FIntVector MidChunk(0, 0, (TopSlot.TopChunkZ + TopSlot.BottomChunkZ) / 2);
const FStrateGenerationParams TopParams = Manager->GetGenerationParams(MidChunk);
const float TopZ = (static_cast<float>(TopSlot.TopChunkZ) + 1.0f) * CHUNK_SIZE;
const float BottomZ = static_cast<float>(TopSlot.BottomChunkZ) * CHUNK_SIZE;
const UVoxelSeasonAsset* EffectiveSeason = AuthoredSettings->Season.LoadSynchronous();
const float OriginRadius = EffectiveSeason != nullptr
? EffectiveSeason->GetOriginSpineRadius() : AuthoredSettings->OriginSpineRadius;
const VoxelPassageGeometry::FOriginLandingGeometry Geometry =
VoxelPassageGeometry::BuildOriginLandingGeometry(
TopZ, BottomZ, TopParams.BoundarySealThickness,
OriginRadius);
if (Geometry.bValid)
{
const double RoomZ = 0.5 * (Geometry.FloorZ + Geometry.CeilingZ);
const float RoomDensity = ReferenceWorld.densityAt({0.0, 0.0, RoomZ});
const float FloorCenterBelow = ReferenceWorld.densityAt(
{0.0, 0.0, Geometry.FloorZ - 8.0});
const float FloorSideBelow = ReferenceWorld.densityAt(
{Geometry.HalfWidth * 0.5, 0.0, Geometry.FloorZ - 8.0});
const float FloorCenterAbove = ReferenceWorld.densityAt(
{0.0, 0.0, Geometry.FloorZ + 8.0});
const float FloorSideAbove = ReferenceWorld.densityAt(
{Geometry.HalfWidth * 0.5, 0.0, Geometry.FloorZ + 8.0});
const float ShaftContinuationDensity = ReferenceWorld.densityAt(
{0.0, 0.0, Geometry.FloorZ - 32.0});
if (!(RoomDensity > 0.0f) || !(FloorCenterBelow < 0.0f)
|| !(FloorSideBelow < 0.0f) || !(FloorCenterAbove > 0.0f)
|| !(FloorSideAbove > 0.0f) || !(ShaftContinuationDensity < 0.0f))
{
OutError = FString::Printf(
TEXT("Core origin landing geometry failed: room=%.3f floor_below=(%.3f,%.3f) floor_above=(%.3f,%.3f) shaft_below=%.3f."),
RoomDensity, FloorCenterBelow, FloorSideBelow,
FloorCenterAbove, FloorSideAbove, ShaftContinuationDensity);
return false;
}
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] origin_landing=PASS floor=%.3f room=%.3f floor_below=(%.3f,%.3f) floor_above=(%.3f,%.3f) shaft_below=%.3f"),
Geometry.FloorZ, RoomDensity, FloorCenterBelow, FloorSideBelow,
FloorCenterAbove, FloorSideAbove, ShaftContinuationDensity);
}
else
{
OutError = TEXT("Core origin landing test geometry is invalid for the top strate.");
return false;
}
}
if (!bFoundCarveVertex)
{
OutError = TEXT("Standalone Core reference has no level-0 surface vertex for the carve fixture.");
@@ -13274,6 +13544,174 @@ bool RunCoreWorldActorIntegrationTest(const FExploreArguments& Arguments, FStrin
OutError = TEXT("Standalone Core edit fixture did not affect its carved level-0 tile.");
return false;
}
// The authored lower landing is in the second strate (the biome/surface strate). Compile
// its fine clipmap pages from the same Core reference before moving AVoxelWorld there.
// Le palier inférieur appartient à la strate surface/biomes; préparer la référence avant le déplacement.
const std::vector<VoxelForgeCore::TileKey> TravelDesired =
ReferenceWorld.desiredTiles(TravelCameraVoxels);
if (TravelDesired.empty())
{
OutError = TEXT("Standalone Core returned no desired tiles at the authored lower landing.");
return false;
}
FString CoverageError;
if (!AuditCoreClipmapCoverage(TravelDesired, TravelCameraVoxels, 128,
TravelCoverageLocalTiles, TravelCoverageFaces, TravelLodTransitionFaces,
CoverageError))
{
OutError = FString::Printf(TEXT("Standalone Core lower-landing coverage failed: %s"),
*CoverageError);
return false;
}
std::vector<VoxelForgeCore::TileKey> MissingFineTiles;
MissingFineTiles.reserve(TravelDesired.size());
for (const VoxelForgeCore::TileKey& Key : TravelDesired)
{
const FVoxelTileKey RuntimeKey(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
ExpectedTravelDesiredSet.Add(RuntimeKey);
if (Key.lod < ReferenceWorld.configuration().fullResolutionLodCount)
{
MissingFineTiles.push_back(Key);
}
}
if (!ReferenceWorld.compileTileRegion(MissingFineTiles, 16, Scheduler, CoreError,
&TravelFineTilesCompiled, &TravelCompileStats))
{
OutError = FString::Printf(TEXT("Standalone Core lower-landing region compile failed: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
ReferenceWorld.retainTileRegions(TravelDesired);
TravelRegionsBuilt = TravelCompileStats.regionsBuilt;
VoxelForgeCore::TileGenerationOptions TravelOptions;
TravelOptions.hashDensity = true;
std::vector<FStandaloneCoreAdapterTileHashes> TravelRows;
TravelRows.reserve(TravelDesired.size());
for (const VoxelForgeCore::TileKey& Key : TravelDesired)
{
const std::optional<VoxelForgeCore::TileMesh> Mesh =
ReferenceWorld.generateTile(Key, TravelOptions, CoreError);
if (!Mesh || !Mesh->hasDensityHash || !Mesh->hasMeshHash
|| !Mesh->hasPayloadHash || !Mesh->hasTopologyHash)
{
OutError = FString::Printf(TEXT("Standalone Core lower-landing tile generation failed: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
const FVoxelTileKey RuntimeKey(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
FVoxelForgeCoreTileHashRecord Record;
Record.Density = Mesh->densityHash;
Record.Mesh = Mesh->meshHash;
Record.Payload = Mesh->payloadHash;
Record.Topology = Mesh->topologyHash;
Record.Triangles = static_cast<int32>(Mesh->indices.size() / 3);
Record.bEmpty = Mesh->indices.empty();
Record.bHasHashes = true;
ExpectedTravelHashes.Add(RuntimeKey, Record);
TravelRows.push_back({Key, {Record.Density, Record.Mesh, Record.Payload, Record.Topology}});
if (Mesh->groups.skirtTriangleCount > 0) ++TravelTilesWithSkirts;
}
TravelAggregates = StandaloneCoreAggregateHashes(TravelRows);
ExpectedTravelTileCount = TravelDesired.size();
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] standalone_travel_reference=1 location=(%.3f,%.3f,%.3f) tiles=%llu fine_compiled=%llu regions=%llu local_tiles=%d checked_faces=%d lod_transition_faces=%d skirt_tiles=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx"),
TravelCameraVoxels.x, TravelCameraVoxels.y, TravelCameraVoxels.z,
static_cast<unsigned long long>(ExpectedTravelTileCount),
static_cast<unsigned long long>(TravelFineTilesCompiled),
static_cast<unsigned long long>(TravelRegionsBuilt),
TravelCoverageLocalTiles, TravelCoverageFaces, TravelLodTransitionFaces,
TravelTilesWithSkirts,
static_cast<unsigned long long>(TravelAggregates[0]),
static_cast<unsigned long long>(TravelAggregates[1]),
static_cast<unsigned long long>(TravelAggregates[2]),
static_cast<unsigned long long>(TravelAggregates[3]));
// Compile a second destination deeper in the biome strate, matching the owner's surface screenshot.
// Compiler une seconde destination dans la strate biome, à l'emplacement de la capture surface.
const std::vector<VoxelForgeCore::TileKey> SurfaceTravelDesired =
ReferenceWorld.desiredTiles(SurfaceCameraVoxels);
if (SurfaceTravelDesired.empty())
{
OutError = TEXT("Standalone Core returned no desired tiles at the surface-strate fixture.");
return false;
}
if (!AuditCoreClipmapCoverage(SurfaceTravelDesired, SurfaceCameraVoxels, 128,
SurfaceTravelCoverageLocalTiles, SurfaceTravelCoverageFaces,
SurfaceTravelLodTransitionFaces, CoverageError))
{
OutError = FString::Printf(TEXT("Standalone Core surface-strate coverage failed: %s"),
*CoverageError);
return false;
}
std::vector<VoxelForgeCore::TileKey> MissingSurfaceFineTiles;
MissingSurfaceFineTiles.reserve(SurfaceTravelDesired.size());
for (const VoxelForgeCore::TileKey& Key : SurfaceTravelDesired)
{
const FVoxelTileKey RuntimeKey(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
ExpectedSurfaceTravelDesiredSet.Add(RuntimeKey);
if (Key.lod < ReferenceWorld.configuration().fullResolutionLodCount)
MissingSurfaceFineTiles.push_back(Key);
}
// Keep the retained reference clipmap bounded while compiling the second remote region.
// Garder la référence bornée avant de compiler la seconde région distante.
ReferenceWorld.retainTileRegions(SurfaceTravelDesired);
if (!ReferenceWorld.compileTileRegion(MissingSurfaceFineTiles, 16, Scheduler, CoreError,
&SurfaceTravelFineTilesCompiled, &SurfaceTravelCompileStats))
{
OutError = FString::Printf(TEXT("Standalone Core surface-strate region compile failed: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
SurfaceTravelRegionsBuilt = SurfaceTravelCompileStats.regionsBuilt;
std::vector<FStandaloneCoreAdapterTileHashes> SurfaceTravelRows;
SurfaceTravelRows.reserve(SurfaceTravelDesired.size());
for (const VoxelForgeCore::TileKey& Key : SurfaceTravelDesired)
{
const std::optional<VoxelForgeCore::TileMesh> Mesh =
ReferenceWorld.generateTile(Key, TravelOptions, CoreError);
if (!Mesh || !Mesh->hasDensityHash || !Mesh->hasMeshHash
|| !Mesh->hasPayloadHash || !Mesh->hasTopologyHash)
{
OutError = FString::Printf(TEXT("Standalone Core surface-strate tile generation failed: %s"),
UTF8_TO_TCHAR(CoreError.c_str()));
return false;
}
const FVoxelTileKey RuntimeKey(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
FVoxelForgeCoreTileHashRecord Record;
Record.Density = Mesh->densityHash;
Record.Mesh = Mesh->meshHash;
Record.Payload = Mesh->payloadHash;
Record.Topology = Mesh->topologyHash;
Record.Triangles = static_cast<int32>(Mesh->indices.size() / 3);
Record.bEmpty = Mesh->indices.empty();
Record.bHasHashes = true;
ExpectedSurfaceTravelHashes.Add(RuntimeKey, Record);
SurfaceTravelRows.push_back({Key,
{Record.Density, Record.Mesh, Record.Payload, Record.Topology}});
if (Mesh->groups.skirtTriangleCount > 0) ++SurfaceTravelTilesWithSkirts;
}
SurfaceTravelAggregates = StandaloneCoreAggregateHashes(SurfaceTravelRows);
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] standalone_surface_reference=1 location=(%.3f,%.3f,%.3f) tiles=%d fine_compiled=%llu regions=%llu local_tiles=%d checked_faces=%d lod_transition_faces=%d skirt_tiles=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx"),
SurfaceCameraVoxels.x, SurfaceCameraVoxels.y, SurfaceCameraVoxels.z,
ExpectedSurfaceTravelDesiredSet.Num(),
static_cast<unsigned long long>(SurfaceTravelFineTilesCompiled),
static_cast<unsigned long long>(SurfaceTravelRegionsBuilt),
SurfaceTravelCoverageLocalTiles, SurfaceTravelCoverageFaces,
SurfaceTravelLodTransitionFaces, SurfaceTravelTilesWithSkirts,
static_cast<unsigned long long>(SurfaceTravelAggregates[0]),
static_cast<unsigned long long>(SurfaceTravelAggregates[1]),
static_cast<unsigned long long>(SurfaceTravelAggregates[2]),
static_cast<unsigned long long>(SurfaceTravelAggregates[3]));
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] standalone_reference=1 tiles=%llu affected=%d target=(%d,%d,%d) lod=%d"),
static_cast<unsigned long long>(ExpectedInitialTileCount),
@@ -13607,6 +14045,234 @@ bool RunCoreWorldActorIntegrationTest(const FExploreArguments& Arguments, FStrin
ExpectedAffectedTiles.Num(), CarveTargetTile.Coord.X, CarveTargetTile.Coord.Y,
CarveTargetTile.Coord.Z, CarveTargetTile.Level,
static_cast<unsigned long long>(ExpectedPostEditHashes.FindChecked(CarveTargetTile).Mesh));
Actor->UnregisterStreamingAnchor(Anchor);
Anchor->Destroy();
if (!WaitForStable(180.0))
{
OutError = TEXT("Core did not settle after removing the CollisionOnly anchor fixture.");
return false;
}
APlayerController* TravelController = TestWorld->SpawnActor<APlayerController>(
APlayerController::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator);
APawn* TravelPawn = TestWorld->SpawnActor<APawn>(
APawn::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator);
if (TravelController == nullptr || TravelPawn == nullptr)
{
OutError = TEXT("Could not create the BuildHost player/controller for the Core travel proof.");
return false;
}
USceneComponent* TravelPawnRoot = NewObject<USceneComponent>(TravelPawn, NAME_None, RF_Transient);
if (TravelPawnRoot == nullptr)
{
OutError = TEXT("Could not create a root component for the BuildHost travel pawn.");
return false;
}
TravelPawn->SetRootComponent(TravelPawnRoot);
TravelPawnRoot->RegisterComponent();
const FVector TravelWorldPosition(
TravelCameraVoxels.x * CoreVoxelSizeCm,
TravelCameraVoxels.y * CoreVoxelSizeCm,
TravelCameraVoxels.z * CoreVoxelSizeCm);
TravelPawn->SetActorLocation(TravelWorldPosition);
TravelController->Possess(TravelPawn);
if (TravelController->GetPawn() != TravelPawn)
{
OutError = TEXT("BuildHost player controller did not possess the travel pawn.");
return false;
}
if (!WaitForStable(300.0))
{
OutError = FString::Printf(
TEXT("Core did not page and settle around the traveled pawn: desired=%d loaded=%d pending=%d cooks=%d active=%d."),
Actor->DesiredSorted.Num(), Actor->LoadedTiles.Num(), Actor->PendingTiles.Num(),
Actor->PendingCollisionCooks.Num(),
Actor->ActiveTaskCount.load(std::memory_order_acquire));
return false;
}
TSet<FVoxelTileKey> ActualTravelDesiredSet;
std::vector<VoxelForgeCore::TileKey> ActorTravelDesired;
ActorTravelDesired.reserve(static_cast<std::size_t>(Actor->DesiredSorted.Num()));
for (const FVoxelTileKey& Key : Actor->DesiredSorted)
{
ActualTravelDesiredSet.Add(Key);
ActorTravelDesired.push_back({{Key.Coord.X, Key.Coord.Y, Key.Coord.Z}, Key.Level});
}
if (ActualTravelDesiredSet.Num() != ExpectedTravelDesiredSet.Num())
{
OutError = FString::Printf(
TEXT("Core actor desired %d tiles at the lower landing; standalone Core expects %d."),
ActualTravelDesiredSet.Num(), ExpectedTravelDesiredSet.Num());
return false;
}
for (const FVoxelTileKey& Key : ExpectedTravelDesiredSet)
{
if (!ActualTravelDesiredSet.Contains(Key) || !Actor->LoadedTiles.Contains(Key))
{
OutError = FString::Printf(
TEXT("Core actor omitted or failed to load lower-landing tile (%d,%d,%d) lod=%d."),
Key.Coord.X, Key.Coord.Y, Key.Coord.Z, Key.Level);
return false;
}
const FVoxelForgeCoreTileHashRecord* Actual = Actor->VoxelForgeCoreTileHashes.Find(Key);
const FVoxelForgeCoreTileHashRecord* Expected = ExpectedTravelHashes.Find(Key);
if (Actual == nullptr || Expected == nullptr || !Actual->bHasHashes
|| Actual->Density != Expected->Density || Actual->Mesh != Expected->Mesh
|| Actual->Payload != Expected->Payload || Actual->Topology != Expected->Topology
|| Actual->Triangles != Expected->Triangles || Actual->bEmpty != Expected->bEmpty)
{
OutError = FString::Printf(
TEXT("Core actor lower-landing tile differs from standalone Core at (%d,%d,%d) lod=%d."),
Key.Coord.X, Key.Coord.Y, Key.Coord.Z, Key.Level);
return false;
}
}
FString ActorCoverageError;
std::int32_t ActorCoverageLocalTiles = 0;
std::int32_t ActorCoverageFaces = 0;
std::int32_t ActorTransitionFaces = 0;
if (!AuditCoreClipmapCoverage(ActorTravelDesired,
{TravelCameraVoxels.x, TravelCameraVoxels.y, TravelCameraVoxels.z}, 128,
ActorCoverageLocalTiles, ActorCoverageFaces, ActorTransitionFaces,
ActorCoverageError))
{
OutError = FString::Printf(TEXT("AVoxelWorld lower-landing coverage failed: %s"),
*ActorCoverageError);
return false;
}
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] pass phase=surface_travel center=(%.3f,%.3f,%.3f) desired=%d loaded=%d local_tiles=%d checked_faces=%d lod_transition_faces=%d density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx"),
TravelCameraVoxels.x, TravelCameraVoxels.y, TravelCameraVoxels.z,
ActualTravelDesiredSet.Num(), Actor->LoadedTiles.Num(), ActorCoverageLocalTiles,
ActorCoverageFaces, ActorTransitionFaces,
static_cast<unsigned long long>(TravelAggregates[0]),
static_cast<unsigned long long>(TravelAggregates[1]),
static_cast<unsigned long long>(TravelAggregates[2]),
static_cast<unsigned long long>(TravelAggregates[3]));
const FVector SurfaceWorldPosition(
SurfaceCameraVoxels.x * CoreVoxelSizeCm,
SurfaceCameraVoxels.y * CoreVoxelSizeCm,
SurfaceCameraVoxels.z * CoreVoxelSizeCm);
TravelPawn->SetActorLocation(SurfaceWorldPosition);
auto WaitForSurfaceVisualTiles = [&]()
{
const double Deadline = FPlatformTime::Seconds() + 120.0;
while (FPlatformTime::Seconds() < Deadline)
{
TestWorld->Tick(LEVELTICK_All, 0.016f);
++GFrameCounter;
FPlatformProcess::Sleep(0.001f);
bool bVisualTilesReady = true;
for (const FVoxelTileKey& Key : ExpectedSurfaceTravelDesiredSet)
{
const FVoxelForgeCoreTileHashRecord* Expected = ExpectedSurfaceTravelHashes.Find(Key);
const FVoxelForgeCoreTileHashRecord* Actual = Actor->VoxelForgeCoreTileHashes.Find(Key);
if (Expected == nullptr || Actual == nullptr || !Actual->bHasHashes
|| (!Expected->bEmpty && !Actor->LoadedTiles.Contains(Key)))
{
bVisualTilesReady = false;
break;
}
}
if (bVisualTilesReady) return true;
}
return false;
};
if (!WaitForSurfaceVisualTiles())
{
int32 HashedSurfaceTiles = 0;
int32 MissingVisibleSurfaceTiles = 0;
for (const FVoxelTileKey& Key : ExpectedSurfaceTravelDesiredSet)
{
if (Actor->VoxelForgeCoreTileHashes.Contains(Key)) ++HashedSurfaceTiles;
const FVoxelForgeCoreTileHashRecord* Expected = ExpectedSurfaceTravelHashes.Find(Key);
if (Expected != nullptr && !Expected->bEmpty && !Actor->LoadedTiles.Contains(Key))
++MissingVisibleSurfaceTiles;
}
OutError = FString::Printf(
TEXT("Core did not load the surface-strate visual set: expected=%d hashed=%d missing_visible=%d desired=%d loaded=%d pending=%d active=%d."),
ExpectedSurfaceTravelDesiredSet.Num(), HashedSurfaceTiles,
MissingVisibleSurfaceTiles, Actor->DesiredSorted.Num(), Actor->LoadedTiles.Num(),
Actor->PendingTiles.Num(), Actor->ActiveTaskCount.load(std::memory_order_acquire));
return false;
}
TSet<FVoxelTileKey> ActualSurfaceVisualDesiredSet;
std::vector<VoxelForgeCore::TileKey> ActorSurfaceTravelDesired;
ActorSurfaceTravelDesired.reserve(static_cast<std::size_t>(Actor->DesiredSorted.Num()));
for (const FVoxelTileKey& Key : Actor->DesiredSorted)
{
if (!Actor->CollisionOnlyTiles.Contains(Key))
{
ActualSurfaceVisualDesiredSet.Add(Key);
ActorSurfaceTravelDesired.push_back({{Key.Coord.X, Key.Coord.Y, Key.Coord.Z}, Key.Level});
}
}
if (ActualSurfaceVisualDesiredSet.Num() != ExpectedSurfaceTravelDesiredSet.Num())
{
OutError = FString::Printf(
TEXT("Core actor desired %d visual tiles at the surface-strate fixture; standalone Core expects %d."),
ActualSurfaceVisualDesiredSet.Num(), ExpectedSurfaceTravelDesiredSet.Num());
return false;
}
for (const FVoxelTileKey& Key : ExpectedSurfaceTravelDesiredSet)
{
if (!ActualSurfaceVisualDesiredSet.Contains(Key))
{
OutError = FString::Printf(
TEXT("Core actor omitted surface-strate visual tile (%d,%d,%d) lod=%d."),
Key.Coord.X, Key.Coord.Y, Key.Coord.Z, Key.Level);
return false;
}
const FVoxelForgeCoreTileHashRecord* Actual = Actor->VoxelForgeCoreTileHashes.Find(Key);
const FVoxelForgeCoreTileHashRecord* Expected = ExpectedSurfaceTravelHashes.Find(Key);
if (Actual == nullptr || Expected == nullptr || !Actual->bHasHashes
|| (!Expected->bEmpty && !Actor->LoadedTiles.Contains(Key))
|| Actual->Density != Expected->Density || Actual->Mesh != Expected->Mesh
|| Actual->Payload != Expected->Payload || Actual->Topology != Expected->Topology
|| Actual->Triangles != Expected->Triangles || Actual->bEmpty != Expected->bEmpty)
{
OutError = FString::Printf(
TEXT("Core actor surface-strate tile differs from standalone Core at (%d,%d,%d) lod=%d."),
Key.Coord.X, Key.Coord.Y, Key.Coord.Z, Key.Level);
return false;
}
}
FString SurfaceCoverageError;
std::int32_t ActorSurfaceLocalTiles = 0;
std::int32_t ActorSurfaceCheckedFaces = 0;
std::int32_t ActorSurfaceTransitionFaces = 0;
if (!AuditCoreClipmapCoverage(ActorSurfaceTravelDesired,
{SurfaceCameraVoxels.x, SurfaceCameraVoxels.y, SurfaceCameraVoxels.z}, 128,
ActorSurfaceLocalTiles, ActorSurfaceCheckedFaces, ActorSurfaceTransitionFaces,
SurfaceCoverageError))
{
OutError = FString::Printf(TEXT("AVoxelWorld surface-strate coverage failed: %s"),
*SurfaceCoverageError);
return false;
}
const FVoxelBiomeQuery SurfaceBiome = Actor->GetBiomeAtWorldLocation(SurfaceWorldPosition);
if (!SurfaceBiome.bHasBiomes || SurfaceBiome.DominantContextIndex < 0)
{
OutError = TEXT("Core-mode biome query returned no dominant biome at the authored surface-strate fixture.");
return false;
}
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldTest] pass phase=surface_strate_travel center=(%.3f,%.3f,%.3f) desired=%d loaded=%d fine_compiled=%llu regions=%llu local_tiles=%d checked_faces=%d lod_transition_faces=%d biome_index=%d biome=%s density=0x%016llx mesh=0x%016llx payload=0x%016llx topology=0x%016llx"),
SurfaceCameraVoxels.x, SurfaceCameraVoxels.y, SurfaceCameraVoxels.z,
ActualSurfaceVisualDesiredSet.Num(), Actor->LoadedTiles.Num(),
static_cast<unsigned long long>(SurfaceTravelFineTilesCompiled),
static_cast<unsigned long long>(SurfaceTravelRegionsBuilt), ActorSurfaceLocalTiles,
ActorSurfaceCheckedFaces, ActorSurfaceTransitionFaces,
SurfaceBiome.DominantContextIndex, *SurfaceBiome.DominantName.ToString(),
static_cast<unsigned long long>(SurfaceTravelAggregates[0]),
static_cast<unsigned long long>(SurfaceTravelAggregates[1]),
static_cast<unsigned long long>(SurfaceTravelAggregates[2]),
static_cast<unsigned long long>(SurfaceTravelAggregates[3]));
return true;
}