Bounded vertical route partition / streaming for handcrafted spiral climb maps (Only Up / Only Climb). Not World Partition, not Level Instances as core arch. - Z-cell segmentation + optional XY subcells, editor builder + commandlet - NonDestructive visibility backend + streaming-level backend - Offline HLOD proxies: MergedMesh / SimplifiedProxy (ProxyLOD) - Universal Level Instance + Packed Level Actor + HISM support (flatten+merge) - Vertical-aware runtime streamer (full/preload/HLOD/unload, hysteresis, velocity prediction, fall-risk), WP-style debug viz + vp.* console - Safe-by-default: only static decor streams; sky/lights/gameplay stay persistent Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
115 lines
3.8 KiB
C++
115 lines
3.8 KiB
C++
// Copyright IHY. Vertical Partition Streaming plugin.
|
|
#include "VerticalPartitionDebugComponent.h"
|
|
#include "VerticalPartitionRuntimeSubsystem.h"
|
|
#include "VerticalPartitionStatics.h"
|
|
#include "Engine/Engine.h"
|
|
#include "DrawDebugHelpers.h"
|
|
|
|
static TAutoConsoleVariable<int32> CVarVPDebug(
|
|
TEXT("vp.Debug"), 0,
|
|
TEXT("Master Vertical Partition debug toggle (gates DebugDraw + DebugOverlay)."), ECVF_Default);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVPDebugDraw(
|
|
TEXT("vp.DebugDraw"), 1,
|
|
TEXT("Draw 3D coloured cell boxes / ids / counts (requires vp.Debug 1)."), ECVF_Default);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVPDebugOverlay(
|
|
TEXT("vp.DebugOverlay"), 1,
|
|
TEXT("Draw the on-screen runtime stats overlay (requires vp.Debug 1)."), ECVF_Default);
|
|
|
|
UVerticalPartitionDebugComponent::UVerticalPartitionDebugComponent()
|
|
{
|
|
PrimaryComponentTick.bCanEverTick = true;
|
|
PrimaryComponentTick.bStartWithTickEnabled = true;
|
|
}
|
|
|
|
UVerticalPartitionRuntimeSubsystem* UVerticalPartitionDebugComponent::GetSub() const
|
|
{
|
|
return UVerticalPartitionRuntimeSubsystem::Get(this);
|
|
}
|
|
|
|
void UVerticalPartitionDebugComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
|
{
|
|
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
|
|
|
if (CVarVPDebug.GetValueOnGameThread() == 0)
|
|
{
|
|
return;
|
|
}
|
|
UVerticalPartitionRuntimeSubsystem* Sub = GetSub();
|
|
if (!Sub || !Sub->IsReady())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (CVarVPDebugDraw.GetValueOnGameThread() != 0)
|
|
{
|
|
DrawDebugCells(Sub);
|
|
}
|
|
if (CVarVPDebugOverlay.GetValueOnGameThread() != 0)
|
|
{
|
|
DrawOverlay(Sub);
|
|
}
|
|
}
|
|
|
|
void UVerticalPartitionDebugComponent::DrawDebugCells(UVerticalPartitionRuntimeSubsystem* Sub) const
|
|
{
|
|
#if ENABLE_DRAW_DEBUG
|
|
UWorld* World = GetWorld();
|
|
if (!World || !Sub)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (const TPair<FVerticalCellId, FVerticalCellRuntime>& Pair : Sub->GetCellRuntimes())
|
|
{
|
|
const FVerticalCellRuntime& C = Pair.Value;
|
|
if (!C.Bounds.IsValid)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Purple overrides the state colour when a cell is force-locked.
|
|
FColor Color = C.bForced
|
|
? FColor(180, 60, 220)
|
|
: UVerticalPartitionStatics::GetStateColor(C.State).ToFColor(true);
|
|
|
|
const FVector Center = C.Bounds.GetCenter();
|
|
const FVector Extent = C.Bounds.GetExtent();
|
|
DrawDebugBox(World, Center, Extent, Color, false, -1.f, 0, 4.f);
|
|
|
|
const FString Label = FString::Printf(TEXT("%s [%s] actors:%d"),
|
|
*C.Id.ToString(),
|
|
C.bForced ? TEXT("LOCK") : *UEnum::GetDisplayValueAsText(C.State).ToString(),
|
|
C.ResolvedActors.Num());
|
|
DrawDebugString(World, Center + FVector(0, 0, Extent.Z * 0.5f), Label, nullptr, Color, 0.f, true);
|
|
}
|
|
#endif // ENABLE_DRAW_DEBUG
|
|
}
|
|
|
|
void UVerticalPartitionDebugComponent::DrawOverlay(UVerticalPartitionRuntimeSubsystem* Sub) const
|
|
{
|
|
if (!GEngine || !Sub)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FVerticalRuntimeStats& S = Sub->GetStats();
|
|
const int32 Key = 0x5650; // 'VP'
|
|
auto Line = [&](int32 Slot, const FColor& Col, const FString& Text)
|
|
{
|
|
GEngine->AddOnScreenDebugMessage(Key + Slot, 0.f, Col, Text);
|
|
};
|
|
|
|
Line(0, FColor::Cyan, TEXT("==== Vertical Partition ===="));
|
|
Line(1, FColor::White, FString::Printf(TEXT("Player Z cell: %d"), S.PlayerCellZ));
|
|
Line(2, FColor::Green, FString::Printf(TEXT("Full cells: %d"), S.FullCellsLoaded));
|
|
Line(3, FColor::Blue, FString::Printf(TEXT("HLOD cells: %d"), S.HLODCellsVisible));
|
|
Line(4, FColor::Silver, FString::Printf(TEXT("Unloaded: %d"), S.CellsUnloaded));
|
|
Line(5, FColor::Yellow, FString::Printf(TEXT("Loading/async: %d / %d"), S.CellsLoading, S.ActiveAsyncLoads));
|
|
Line(6, FColor::White, FString::Printf(TEXT("Est. memory: %.1f MB"), S.EstimatedMemoryMB));
|
|
Line(7, FColor::White, FString::Printf(TEXT("Update time: %.2f ms"), S.LastUpdateTimeMS));
|
|
Line(8, S.HitchesOverThreshold > 0 ? FColor::Red : FColor::White,
|
|
FString::Printf(TEXT("Hitches: %d"), S.HitchesOverThreshold));
|
|
}
|