wip(assembler): round S6 -- in-game cold view counted; workers mostly idle, apply cap not the floor

Direct per-tile trace on the BuildHost actor (owner plan, 2,578 keys): full set
17.4 s legacy; gated coarse-first (after the 9-tile walkable ring) 11.7 s with
the ring still at 0.63 s, but full LOD0 slips 2.3 -> 10.2 s. Startup apply
boost changed nothing (0.4%). 37.6 worker-s over 17.4 s on 10 slots = ~3.3
busy: the floor is admission/work supply. S5's 251 ms staircase was the trace
sampler. Fixed CVar parsing in headless BeginPlay and the 60 m/s crossing
instrument. All three knobs stay opt-in.

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-19 06:46:54 +02:00
1 parent c0596c5f24
commit b9c13c37c0
11 files changed
+903 -31

No files matched your search

@@ -72,6 +72,7 @@
#include "VoxelTerrainOpDefinition.h"
#include "VoxelTypes.h"
#include "VoxelWorld.h"
#include "VoxelStartupTrace.h"
#include "VoxelForgeCoreAssetAdapter.h"
#include "VoxelForgeCore/VoxelForgeCore.h"
@@ -878,6 +879,7 @@ struct FExploreArguments
int32 PassageFloorWrites = 1;
bool bStandaloneWorldExport = false;
bool bCoreWorldTest = false;
bool bCoreWorldStreamTraceOnly = false;
bool bRenderCameraOverride = false;
FVector RenderCamera = FVector::ZeroVector;
bool bRenderTargetOverride = false;
@@ -923,6 +925,9 @@ bool ParseArguments(const FString& Params, FExploreArguments& OutArguments, FStr
int32 CoreWorldTest = 0;
FParse::Value(*Params, TEXT("coreworldtest="), CoreWorldTest);
OutArguments.bCoreWorldTest = CoreWorldTest != 0;
int32 CoreWorldStreamTraceOnly = 0;
FParse::Value(*Params, TEXT("coreworldstreamtrace="), CoreWorldStreamTraceOnly);
OutArguments.bCoreWorldStreamTraceOnly = CoreWorldStreamTraceOnly != 0;
FParse::Value(*Params, TEXT("corevoxelsizecm="), OutArguments.CoreVoxelSizeCm);
if (!FMath::IsFinite(OutArguments.CoreVoxelSizeCm)
|| OutArguments.CoreVoxelSizeCm < VOXEL_SIZE
@@ -1499,6 +1504,11 @@ bool ParseArguments(const FString& Params, FExploreArguments& OutArguments, FStr
OutError = TEXT("coreworldtest requires settingsref and must omit strateref.");
return false;
}
if (OutArguments.bCoreWorldStreamTraceOnly && !OutArguments.bCoreWorldTest)
{
OutError = TEXT("coreworldstreamtrace requires coreworldtest.");
return false;
}
if ((OutArguments.bCoreHybridMesher || OutArguments.bCoreHybridFixturePlacement
|| OutArguments.bCoreHybridCliffOnly || OutArguments.bCoreHybridFixturesOnly
|| OutArguments.bCoreFloatingIslandTest || OutArguments.bCoreFallbackTest
@@ -17329,6 +17339,241 @@ bool RunCoreWorldActorIntegrationTest(const FExploreArguments& Arguments, FStrin
return false;
}
if (Arguments.bCoreWorldStreamTraceOnly)
{
const UWorld::InitializationValues WorldInitialization = UWorld::InitializationValues()
.AllowAudioPlayback(false)
.RequiresHitProxies(false)
.CreatePhysicsScene(true)
.CreateNavigation(false)
.CreateAISystem(false)
.ShouldSimulatePhysics(true)
.SetDefaultGameMode(AGameModeBase::StaticClass())
.SetTransactional(false);
UWorld* TestWorld = UWorld::CreateWorld(
EWorldType::Game, false, FName(TEXT("VoxelForgeCoreStreamTraceWorld")),
GetTransientPackage(), false, ERHIFeatureLevel::Num, &WorldInitialization);
if (TestWorld == nullptr)
{
OutError = TEXT("Could not create the transient BuildHost stream-trace world.");
return false;
}
UGameInstance* TestGameInstance = NewObject<UGameInstance>(GEngine);
FWorldContext& TestWorldContext = GEngine->CreateNewWorldContext(EWorldType::Game);
TestWorldContext.OwningGameInstance = TestGameInstance;
TestWorldContext.SetCurrentWorld(TestWorld);
TestWorld->SetGameInstance(TestGameInstance);
TestWorld->SetShouldTick(false);
TestGameInstance->Init();
TestWorld->AddToRoot();
struct FStreamTraceWorldCleanup
{
UWorld* World = nullptr;
uint64 PreviousFrameCounter = GFrameCounter;
~FStreamTraceWorldCleanup()
{
if (World != nullptr)
{
if (World->HasBegunPlay())
{
World->BeginTearingDown();
World->EndPlay(EEndPlayReason::Quit);
}
if (UGameInstance* GameInstance = World->GetGameInstance())
{
GameInstance->Shutdown();
}
if (GEngine != nullptr) GEngine->DestroyWorldContext(World);
World->DestroyWorld(false);
if (World->IsRooted()) World->RemoveFromRoot();
}
GFrameCounter = PreviousFrameCounter;
}
} Cleanup{TestWorld, GFrameCounter};
if (!TestWorld->SetGameMode(FURL()))
{
OutError = TEXT("Could not create the transient BuildHost GameMode for stream tracing.");
return false;
}
if (AGameModeBase* GameMode = TestWorld->GetAuthGameMode())
{
GameMode->DefaultPawnClass = nullptr;
}
UPlayer* TestPlayer = NewObject<UPlayer>(GEngine, NAME_None, RF_Transient);
APlayerController* PlayerController = TestWorld->SpawnActor<APlayerController>(
APlayerController::StaticClass(), FTransform::Identity, FActorSpawnParameters());
if (TestPlayer == nullptr || PlayerController == nullptr)
{
OutError = TEXT("Could not create the BuildHost stream-trace player controller.");
return false;
}
PlayerController->SetPlayer(TestPlayer);
TestWorld->AddController(PlayerController);
APawn* PlayerPawn = TestWorld->SpawnActor<APawn>(
APawn::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator);
if (PlayerPawn == nullptr)
{
OutError = TEXT("Could not create the BuildHost stream-trace pawn.");
return false;
}
USceneComponent* PawnRoot = NewObject<USceneComponent>(PlayerPawn, NAME_None, RF_Transient);
if (PawnRoot == nullptr)
{
OutError = TEXT("Could not create the BuildHost stream-trace pawn root.");
return false;
}
PlayerPawn->SetRootComponent(PawnRoot);
PawnRoot->RegisterComponent();
PlayerPawn->SetActorLocation(FVector::ZeroVector, false, nullptr, ETeleportType::TeleportPhysics);
PlayerController->Possess(PlayerPawn);
if (TestWorld->GetFirstPlayerController() != PlayerController
|| PlayerController->GetPawn() != PlayerPawn)
{
OutError = TEXT("BuildHost stream-trace controller did not retain its pawn.");
return false;
}
const FTransform ActorTransform = FTransform::Identity;
AVoxelWorld* Actor = TestWorld->SpawnActorDeferred<AVoxelWorld>(
AVoxelWorld::StaticClass(), ActorTransform, nullptr, nullptr,
ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
if (Actor == nullptr)
{
OutError = TEXT("Could not spawn the transient AVoxelWorld for stream tracing.");
return false;
}
Actor->Settings = AuthoredSettings;
Actor->bManageAtmosphere = false;
Actor->bUseVoxelForgeCore = true;
Actor->CoreVoxelSizeCm = Arguments.CoreVoxelSizeCm;
Actor->CoreMesherRecipe = Arguments.CoreHybridMesherVersion == 2
? EVoxelForgeCoreMesherRecipe::WorldAssemblerHybridV2
: (Arguments.CoreHybridMesherVersion == 1
? EVoxelForgeCoreMesherRecipe::WorldAssemblerHybridV1
: EVoxelForgeCoreMesherRecipe::MarchingCubesV1);
Actor->CoreClipRadius = 3;
Actor->CoreMaxClipLevel = 8;
Actor->bCaptureVoxelForgeCoreHashesForValidation = true;
Actor->FinishSpawning(ActorTransform);
TestWorld->InitializeActorsForPlay(FURL());
TestWorld->BeginPlay();
if (!VoxelForgeStartupTrace::IsActive())
{
OutError = TEXT("Core stream trace mode requires -voxel.StartupTraceFile.");
return false;
}
Actor->SetActorTickEnabled(true);
auto DesiredTilesLoaded = [](const AVoxelWorld* World)
{
if (World == nullptr || World->DesiredSorted.IsEmpty()) return false;
for (const FVoxelTileKey& Key : World->DesiredSorted)
{
if (!World->LoadedTiles.Contains(Key)) return false;
}
return true;
};
auto CollisionSetSettled = [](const AVoxelWorld* World)
{
if (World == nullptr) return false;
for (const FVoxelTileKey& Key : World->CollisionDesiredTiles)
{
if (!World->CollisionReadyTiles.Contains(Key)
&& !World->CollisionNotRequiredTiles.Contains(Key)) return false;
}
return true;
};
const double ActorBeginSeconds = FPlatformTime::Seconds();
constexpr double WalkStartSeconds = 30.0;
constexpr double RunDurationSeconds = 45.0;
TArray<double> SpawnTickMilliseconds;
TArray<double> WalkTickMilliseconds;
TArray<TPair<double, double>> TickSamples;
bool bInitialSetReady = false;
double InitialSetReadySeconds = -1.0;
while (FPlatformTime::Seconds() - ActorBeginSeconds < RunDurationSeconds)
{
const double TickStartSeconds = FPlatformTime::Seconds();
TestWorld->Tick(LEVELTICK_All, 0.016f);
const double TickMilliseconds =
(FPlatformTime::Seconds() - TickStartSeconds) * 1000.0;
++GFrameCounter;
const double ElapsedSeconds = FPlatformTime::Seconds() - ActorBeginSeconds;
TickSamples.Emplace(ElapsedSeconds, TickMilliseconds);
if (!bInitialSetReady && Actor->IsVoxelForgeCoreReady()
&& Actor->bAllChunksLoaded && Actor->PendingTiles.IsEmpty()
&& Actor->PendingCollisionCooks.IsEmpty() && Actor->PendingUnload.IsEmpty()
&& Actor->ActiveTaskCount.load(std::memory_order_acquire) == 0
&& DesiredTilesLoaded(Actor) && CollisionSetSettled(Actor))
{
bInitialSetReady = true;
InitialSetReadySeconds = ElapsedSeconds;
VoxelForgeStartupTrace::RecordEvent(TEXT("stream_trace_milestone"), FString::Printf(
TEXT("\"name\":\"initial_set_ready\",\"elapsed_s\":%s,\"desired\":%d,\"loaded\":%d,\"collision_desired\":%d,\"collision_ready\":%d"),
*FString::SanitizeFloat(ElapsedSeconds), Actor->DesiredSorted.Num(),
Actor->LoadedTiles.Num(), Actor->CollisionDesiredTiles.Num(),
Actor->CollisionReadyTiles.Num()));
}
FPlatformProcess::Sleep(0.016f);
}
for (const TPair<double, double>& Sample : TickSamples)
{
if (bInitialSetReady && Sample.Key <= InitialSetReadySeconds)
{
SpawnTickMilliseconds.Add(Sample.Value);
}
else if (Sample.Key >= WalkStartSeconds)
{
WalkTickMilliseconds.Add(Sample.Value);
}
}
auto PercentileMilliseconds = [](TArray<double> Values, double Fraction)
{
if (Values.IsEmpty()) return 0.0;
Values.Sort();
const int32 Index = FMath::Clamp(
FMath::CeilToInt(Fraction * static_cast<double>(Values.Num() - 1)),
0, Values.Num() - 1);
return Values[Index];
};
const auto MaxMilliseconds = [](const TArray<double>& Values)
{
double Maximum = 0.0;
for (const double Value : Values) Maximum = FMath::Max(Maximum, Value);
return Maximum;
};
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldStreamTrace] initial_ready=%d initial_ready_s=%.6f walk_start_s=%.3f run_s=%.3f desired=%d loaded=%d "
"spawn_tick_ms_p95=%.3f spawn_tick_ms_max=%.3f walk_tick_ms_p95=%.3f walk_tick_ms_max=%.3f"),
bInitialSetReady ? 1 : 0, InitialSetReadySeconds, WalkStartSeconds,
RunDurationSeconds, Actor->DesiredSorted.Num(), Actor->LoadedTiles.Num(),
PercentileMilliseconds(SpawnTickMilliseconds, 0.95),
MaxMilliseconds(SpawnTickMilliseconds),
PercentileMilliseconds(WalkTickMilliseconds, 0.95),
MaxMilliseconds(WalkTickMilliseconds));
if (!bInitialSetReady)
{
OutError = FString::Printf(
TEXT("Actor-only Core stream trace did not reach initial readiness: ready=%d desired=%d loaded=%d pending=%d cooks=%d active=%d."),
Actor->IsVoxelForgeCoreReady() ? 1 : 0, Actor->DesiredSorted.Num(),
Actor->LoadedTiles.Num(), Actor->PendingTiles.Num(),
Actor->PendingCollisionCooks.Num(),
Actor->ActiveTaskCount.load(std::memory_order_acquire));
return false;
}
UE_LOG(LogTemp, Display,
TEXT("[VoxelForgeCoreWorldStreamTrace] pass complete=1 recipe=%s voxel_cm=%.3f walk_speed_cm_s=600 walk_direction=+Y"),
Arguments.CoreHybridMesherVersion == 2 ? TEXT("WorldAssemblerHybridV2")
: (Arguments.CoreHybridMesherVersion == 1 ? TEXT("WorldAssemblerHybridV1")
: TEXT("MarchingCubesV1")),
Arguments.CoreVoxelSizeCm);
return true;
}
// Build one Standalone reference before creating the actor world so the two full Core worlds
// never overlap in memory. The reference also precomputes the exact edit result and hashes.
// Construire la référence Standalone avant le monde acteur pour ne jamais garder deux mondes