CelticCraft/Plugins/VoxelFree/Source/Voxel/Private/VoxelDebug/VoxelDebugManager.cpp

697 lines
No EOL
24 KiB
C++

// Copyright 2020 Phyronnaz
#include "VoxelDebug/VoxelDebugManager.h"
#include "VoxelDebug/VoxelDebugUtilities.h"
#include "VoxelData/VoxelData.h"
#include "VoxelRender/IVoxelLODManager.h"
#include "VoxelRender/IVoxelRenderer.h"
#include "VoxelData/VoxelDataIncludes.h"
#include "VoxelComponents/VoxelInvokerComponent.h"
#include "VoxelTools/VoxelDataTools.h"
#include "VoxelTools/VoxelSurfaceTools.h"
#include "VoxelTools/VoxelBlueprintLibrary.h"
#include "VoxelMessages.h"
#include "VoxelWorld.h"
#include "IVoxelPool.h"
#include "VoxelThreadPool.h"
#include "Engine/Engine.h"
#include "EngineUtils.h"
#include "DrawDebugHelpers.h"
#include "Kismet/GameplayStatics.h"
static TAutoConsoleVariable<int32> CVarShowUpdatedChunks(
TEXT("voxel.renderer.ShowUpdatedChunks"),
0,
TEXT("If true, will show the chunks recently updated"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowRenderChunks(
TEXT("voxel.renderer.ShowRenderChunks"),
0,
TEXT("If true, will show the render chunks"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowMultiplayerSyncedChunks(
TEXT("voxel.multiplayer.ShowSyncedChunks"),
0,
TEXT("If true, will show the synced chunks"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowValuesState(
TEXT("voxel.data.ShowValuesState"),
0,
TEXT("If true, will show the values data chunks and their status (cached/created...)"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowMaterialsState(
TEXT("voxel.data.ShowMaterialsState"),
0,
TEXT("If true, will show the materials data chunks and their status (cached/created...)"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowDirtyValues(
TEXT("voxel.data.ShowDirtyValues"),
0,
TEXT("If true, will show the data chunks with dirty values"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowDirtyMaterials(
TEXT("voxel.data.ShowDirtyMaterials"),
0,
TEXT("If true, will show the data chunks with dirty materials"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarFreezeDebug(
TEXT("voxel.FreezeDebug"),
0,
TEXT("If true, won't clear previous frames boxes"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarDebugDrawTime(
TEXT("voxel.debug.DrawTime"),
1,
TEXT("Draw time will be multiplied by this"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowChunksEmptyStates(
TEXT("voxel.renderer.ShowChunksEmptyStates"),
0,
TEXT("If true, will show updated chunks empty state, only if non-empty. Use ShowAllChunksEmptyStates to show empty too."),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowAllChunksEmptyStates(
TEXT("voxel.renderer.ShowAllChunksEmptyStates"),
0,
TEXT("If true, will show updated chunks empty state, both empty and non-empty. Use ShowChunksEmptyStates to only show non-empty ones"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowWorldBounds(
TEXT("voxel.ShowWorldBounds"),
0,
TEXT("If true, will show the world bounds"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowInvokers(
TEXT("voxel.ShowInvokers"),
0,
TEXT("If true, will show the voxel invokers"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowDirtyVoxels(
TEXT("voxel.data.ShowDirtyVoxels"),
0,
TEXT("If true, will show every dirty voxel in the scene"),
ECVF_Default);
static TAutoConsoleVariable<int32> CVarShowPlaceableItemsChunks(
TEXT("voxel.data.ShowPlaceableItemsChunks"),
0,
TEXT("If true, will show every chunk that has a placeable item"),
ECVF_Default);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<typename T>
inline FConsoleCommandWithWorldAndArgsDelegate CreateCommandWithVoxelWorldDelegate(T Lambda)
{
return FConsoleCommandWithWorldAndArgsDelegate::CreateLambda([=](const TArray<FString>& Args, UWorld* World)
{
for (TActorIterator<AVoxelWorld> It(World); It; ++It)
{
if (It->IsCreated())
{
Lambda(**It, Args);
}
}
});
}
template<typename T>
inline FConsoleCommandWithWorldAndArgsDelegate CreateCommandWithVoxelWorldDelegateNoArgs(T Lambda)
{
return CreateCommandWithVoxelWorldDelegate([&](AVoxelWorld& World, const TArray<FString>& Args) { Lambda(World); });
}
static FAutoConsoleCommandWithWorldAndArgs ClearChunksEmptyStatesCmd(
TEXT("voxel.renderer.ClearChunksEmptyStates"),
TEXT("Clear the empty states debug"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World) { World.GetDebugManager().ClearChunksEmptyStates(); }));
static FAutoConsoleCommandWithWorldAndArgs UpdateAllCmd(
TEXT("voxel.renderer.UpdateAll"),
TEXT("Update all the chunks in all the voxel world in the scene"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World) { UVoxelBlueprintLibrary::UpdateBounds(&World, FVoxelIntBox::Infinite); }));
static FAutoConsoleCommandWithWorldAndArgs RecomputeMeshPositionsCmd(
TEXT("voxel.renderer.RecomputeMeshPositions"),
TEXT("Recompute the positions of all the meshes in all the voxel world in the scene"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World) { World.GetRenderer().RecomputeMeshPositions(); }));
static FAutoConsoleCommandWithWorldAndArgs ForceLODsUpdateCmd(
TEXT("voxel.renderer.ForceLODUpdate"),
TEXT("Update the LODs"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World) { World.GetLODManager().ForceLODsUpdate(); }));
static FAutoConsoleCommandWithWorldAndArgs CacheAllValuesCmd(
TEXT("voxel.data.CacheAllValues"),
TEXT("Cache all values"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::CacheValues(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs CacheAllMaterialsCmd(
TEXT("voxel.data.CacheAllMaterials"),
TEXT("Cache all materials"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::CacheMaterials(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs ClearAllCachedValuesCmd(
TEXT("voxel.data.ClearAllCachedValues"),
TEXT("Clear all cached values"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::ClearCachedValues(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs ClearAllCachedMaterialsCmd(
TEXT("voxel.data.ClearAllCachedMaterials"),
TEXT("Clear all cached materials"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::ClearCachedMaterials(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs CheckForSingleValuesCmd(
TEXT("voxel.data.CheckForSingleValues"),
TEXT("Check if values in a chunk are all the same, and if so only store one"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::CheckForSingleValues(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs CheckForSingleMaterialsCmd(
TEXT("voxel.data.CheckForSingleMaterials"),
TEXT("Check if materials in a chunk are all the same, and if so only store one"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::CheckForSingleMaterials(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs RoundVoxelsCmd(
TEXT("voxel.data.RoundVoxels"),
TEXT("Round all voxels that do not impact the surface nor the normals"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::RoundVoxels(&World, FVoxelIntBox::Infinite);
if (World.GetData().bEnableUndoRedo) UVoxelBlueprintLibrary::SaveFrame(&World);
}));
static FAutoConsoleCommandWithWorldAndArgs ClearUnusedMaterialsCmd(
TEXT("voxel.data.ClearUnusedMaterials"),
TEXT("Will clear all materials that do not affect the surface to improve compression"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::ClearUnusedMaterials(&World, FVoxelIntBox::Infinite);
if (World.GetData().bEnableUndoRedo) UVoxelBlueprintLibrary::SaveFrame(&World);
}));
static FAutoConsoleCommandWithWorldAndArgs RegenerateAllSpawnersCmd(
TEXT("voxel.spawners.RegenerateAll"),
TEXT("Regenerate all spawners that can be regenerated"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelBlueprintLibrary::RegenerateSpawners(&World, FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorldAndArgs CompressIntoHeightmapCmd(
TEXT("voxel.data.CompressIntoHeightmap"),
TEXT("Update the heightmap to match the voxel world data"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::CompressIntoHeightmap(&World);
UVoxelBlueprintLibrary::UpdateBounds(&World, FVoxelIntBox::Infinite);
if (World.GetData().bEnableUndoRedo) UVoxelBlueprintLibrary::SaveFrame(&World);
}));
static FAutoConsoleCommandWithWorldAndArgs RoundToGeneratorCmd(
TEXT("voxel.data.RoundToGenerator"),
TEXT("Set the voxels back to the generator value if all the voxels in a radius of 2 have the same sign as the generator"),
CreateCommandWithVoxelWorldDelegateNoArgs([](AVoxelWorld& World)
{
UVoxelDataTools::RoundToGenerator(&World, FVoxelIntBox::Infinite);
UVoxelBlueprintLibrary::UpdateBounds(&World, FVoxelIntBox::Infinite);
if (World.GetData().bEnableUndoRedo) UVoxelBlueprintLibrary::SaveFrame(&World);
}));
static bool GShowCollisionAndNavmeshDebug = false;
static FAutoConsoleCommandWithWorldAndArgs ShowCollisionAndNavmeshDebugCmd(
TEXT("voxel.renderer.ShowCollisionAndNavmeshDebug"),
TEXT("If true, will show chunks used for collisions/navmesh and will color all chunks according to their usage"),
CreateCommandWithVoxelWorldDelegate([](AVoxelWorld& World, const TArray<FString>& Args)
{
if (Args.Num() == 0)
{
GShowCollisionAndNavmeshDebug = !GShowCollisionAndNavmeshDebug;
}
else if (Args[0] == "0")
{
GShowCollisionAndNavmeshDebug = false;
}
else
{
GShowCollisionAndNavmeshDebug = true;
}
World.GetLODManager().UpdateBounds(FVoxelIntBox::Infinite);
}));
static FAutoConsoleCommandWithWorld RebaseOntoCameraCmd(
TEXT("voxel.RebaseOntoCamera"),
TEXT("Call SetWorldOriginLocation so that the camera is at 0 0 0"),
FConsoleCommandWithWorldDelegate::CreateLambda([](UWorld* World)
{
auto* CameraManager = UGameplayStatics::GetPlayerCameraManager(World, 0);
if (ensure(CameraManager))
{
const FVector Position = CameraManager->GetCameraLocation();
UGameplayStatics::SetWorldOriginLocation(World, UGameplayStatics::GetWorldOriginLocation(World) + FIntVector(Position));
}
}));
static FAutoConsoleCommand CmdDestroyGlobalThreadPool(
TEXT("voxel.threading.DestroyGlobalPool"),
TEXT("Destroy the global thread pool"),
FConsoleCommandDelegate::CreateStatic(&IVoxelPool::DestroyGlobalPool));
static FAutoConsoleCommandWithWorld CmdDestroyWorldThreadPool(
TEXT("voxel.threading.DestroyWorldPool"),
TEXT("Destroy the current world thread pool"),
FConsoleCommandWithWorldDelegate::CreateStatic(&IVoxelPool::DestroyWorldPool));
static FAutoConsoleCommand CmdLogThreadPoolStats(
TEXT("voxel.threading.LogStats"),
TEXT(""),
FConsoleCommandDelegate::CreateLambda([](){ FVoxelQueuedThreadPoolStats::Get().LogTimes(); }));
static FAutoConsoleCommand CmdLogMemoryStats(
TEXT("voxel.LogMemoryStats"),
TEXT(""),
FConsoleCommandDelegate::CreateStatic(&UVoxelBlueprintLibrary::LogMemoryStats));
static void LogSecondsPerCycles()
{
LOG_VOXEL(Log, TEXT("SECONDS PER CYCLES: %e"), FPlatformTime::GetSecondsPerCycle());
}
static FAutoConsoleCommand CmdLogSecondsPerCycles(
TEXT("voxel.debug.LogSecondsPerCycles"),
TEXT(""),
FConsoleCommandDelegate::CreateStatic(&LogSecondsPerCycles));
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
inline float GetBoundsThickness(const FVoxelIntBox& Bounds)
{
return Bounds.Size().GetMax();
}
#define DRAW_BOUNDS(Bounds, Color, bThick) UVoxelDebugUtilities::DrawDebugIntBox(World, Bounds, DebugDT, bThick ? GetBoundsThickness(Bounds) : 0, FLinearColor(Color));
#define DRAW_BOUNDS_ARRAY(BoundsArray, Color, bThick) for (auto& Bounds : BoundsArray) { DRAW_BOUNDS(Bounds, FColorList::Color, bThick) }
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
FVoxelDebugManagerSettings::FVoxelDebugManagerSettings(
const AVoxelWorld* World,
EVoxelPlayType PlayType,
const TVoxelSharedRef<IVoxelPool>& Pool,
const TVoxelSharedRef<FVoxelData>& Data,
bool bDisabled)
: VoxelWorld(const_cast<AVoxelWorld*>(World))
, Pool(Pool)
, Data(Data)
, bDisabled(bDisabled)
{
}
TVoxelSharedRef<FVoxelDebugManager> FVoxelDebugManager::Create(const FVoxelDebugManagerSettings& Settings)
{
return MakeShareable(new FVoxelDebugManager(Settings));
}
void FVoxelDebugManager::Destroy()
{
StopTicking();
}
FVoxelDebugManager::FVoxelDebugManager(const FVoxelDebugManagerSettings& Settings)
: Settings(Settings)
{
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FVoxelDebugManager::ReportUpdatedChunks(TFunction<TArray<FVoxelIntBox>()> InUpdatedChunks)
{
if (CVarShowUpdatedChunks.GetValueOnGameThread())
{
VOXEL_ASYNC_FUNCTION_COUNTER();
UpdatedChunks = InUpdatedChunks();
FString Log = "Updated chunks: ";
for (auto& Bounds : UpdatedChunks)
{
Log += Bounds.ToString() + "; ";
}
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), 1, FColor::Blue, Log);
LOG_VOXEL(Log, TEXT("%s"), *Log);
}
}
void FVoxelDebugManager::ReportRenderChunks(TFunction<TArray<FVoxelIntBox>()> InRenderChunks)
{
if (CVarShowRenderChunks.GetValueOnGameThread())
{
VOXEL_ASYNC_FUNCTION_COUNTER();
RenderChunks = InRenderChunks();
}
}
void FVoxelDebugManager::ReportMultiplayerSyncedChunks(TFunction<TArray<FVoxelIntBox>()> InMultiplayerSyncedChunks)
{
if (CVarShowMultiplayerSyncedChunks.GetValueOnGameThread())
{
VOXEL_ASYNC_FUNCTION_COUNTER();
MultiplayerSyncedChunks = InMultiplayerSyncedChunks();
}
}
void FVoxelDebugManager::ReportMeshTaskCount(int32 InTaskCount)
{
MeshTaskCount = InTaskCount;
}
void FVoxelDebugManager::ReportMeshTasksCallbacksQueueNum(int32 Num)
{
MeshTasksCallbacksQueueNum = Num;
}
void FVoxelDebugManager::ReportMeshActionQueueNum(int32 Num)
{
MeshActionQueueNum = Num;
}
void FVoxelDebugManager::ReportFoliageTaskCount(int32 TaskCount)
{
FoliageTaskCount.Set(TaskCount);
}
void FVoxelDebugManager::ReportChunkEmptyState(const FVoxelIntBox& Bounds, bool bIsEmpty)
{
ChunksEmptyStates.Emplace(FChunkEmptyState{ Bounds, bIsEmpty });
}
void FVoxelDebugManager::ClearChunksEmptyStates()
{
ChunksEmptyStates.Reset();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool FVoxelDebugManager::ShowCollisionAndNavmeshDebug()
{
return GShowCollisionAndNavmeshDebug;
}
FColor FVoxelDebugManager::GetCollisionAndNavmeshDebugColor(bool bEnableCollisions, bool bEnableNavmesh)
{
if (bEnableCollisions && bEnableNavmesh)
{
return FColor::Yellow;
}
if (bEnableCollisions)
{
return FColor::Blue;
}
if (bEnableNavmesh)
{
return FColor::Green;
}
return FColor::White;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FVoxelDebugManager::Tick(float DeltaTime)
{
VOXEL_FUNCTION_COUNTER();
if (Settings.bDisabled) return;
auto* World = Settings.VoxelWorld.Get();
if (!World) return;
if (World->bDisableDebugManager) return;
const float DebugDT = DeltaTime * 1.5f * CVarDebugDrawTime.GetValueOnGameThread();
if (CVarShowRenderChunks.GetValueOnGameThread())
{
DRAW_BOUNDS_ARRAY(RenderChunks, Grey, false);
}
if (CVarShowUpdatedChunks.GetValueOnGameThread())
{
DRAW_BOUNDS_ARRAY(UpdatedChunks, Blue, true);
}
if (CVarShowMultiplayerSyncedChunks.GetValueOnGameThread())
{
DRAW_BOUNDS_ARRAY(MultiplayerSyncedChunks, Blue, true);
}
if (CVarShowWorldBounds.GetValueOnGameThread())
{
DRAW_BOUNDS(Settings.Data->WorldBounds, FColorList::Red, true);
}
if (!World->bDisableOnScreenMessages)
{
const int32 PoolTaskCount = Settings.Pool->GetNumTasks();
if (PoolTaskCount > 0)
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, FString::Printf(TEXT("Total tasks remaining: %d"), PoolTaskCount));
}
if (MeshTaskCount > 0)
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, FString::Printf(TEXT("Mesh tasks remaining: %d"), MeshTaskCount));
}
if (MeshTasksCallbacksQueueNum > 0)
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, FString::Printf(TEXT("Mesh tasks callbacks queued: %d"), MeshTasksCallbacksQueueNum));
}
if (MeshActionQueueNum > 0)
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, FString::Printf(TEXT("Mesh actions queued: %d"), MeshActionQueueNum));
}
if (FoliageTaskCount.GetValue() > 0)
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, FString::Printf(TEXT("Foliage tasks remaining: %d"), FoliageTaskCount.GetValue()));
}
}
if (!CVarFreezeDebug.GetValueOnGameThread())
{
UpdatedChunks.Reset();
MultiplayerSyncedChunks.Reset();
}
if (CVarShowInvokers.GetValueOnGameThread())
{
const FColor LocalInvokerColor = FColor::Green;
const FColor RemoteInvokerColor = FColor::Silver;
const FColor LODColor = FColor::Red;
const FColor CollisionsColor = FColor::Blue;
const FColor NavmeshColor = FColor::Green;
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, LocalInvokerColor, TEXT("Local Invokers"));
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, RemoteInvokerColor, TEXT("Remote Invokers"));
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, LODColor, TEXT("Invokers LOD Bounds"));
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, CollisionsColor, TEXT("Invokers Collisions Bounds"));
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, NavmeshColor, TEXT("Invokers Navmesh Bounds"));
for (auto& Invoker : UVoxelInvokerComponentBase::GetInvokers(World->GetWorld()))
{
if (Invoker.IsValid())
{
DrawDebugPoint(
World->GetWorld(),
World->LocalToGlobal(Invoker->GetInvokerVoxelPosition(World)),
100,
Invoker->IsLocalInvoker() ? LocalInvokerColor : RemoteInvokerColor,
false,
DebugDT);
const auto InvokerSettings = Invoker->GetInvokerSettings(World);
if (InvokerSettings.bUseForLOD)
{
DRAW_BOUNDS(InvokerSettings.LODBounds, LODColor, true);
}
if (InvokerSettings.bUseForCollisions)
{
DRAW_BOUNDS(InvokerSettings.CollisionsBounds, CollisionsColor, true);
}
if (InvokerSettings.bUseForNavmesh)
{
DRAW_BOUNDS(InvokerSettings.NavmeshBounds, NavmeshColor, true);
}
}
}
}
if (CVarShowChunksEmptyStates.GetValueOnGameThread())
{
const static FColor NotEmpty = FColorList::Brown;
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, NotEmpty, TEXT("Not empty chunks (range analysis failed)"));
for (auto& EmptyState : ChunksEmptyStates)
{
if (!EmptyState.bIsEmpty)
{
DRAW_BOUNDS(EmptyState.Bounds, NotEmpty, false);
}
}
}
if (CVarShowAllChunksEmptyStates.GetValueOnGameThread())
{
const static FColor Empty = FColorList::Green;
const static FColor NotEmpty = FColorList::Brown;
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, Empty, TEXT("Empty chunks (range analysis successful)"));
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, NotEmpty, TEXT("Not empty chunks (range analysis failed)"));
for (auto& EmptyState : ChunksEmptyStates)
{
if (EmptyState.bIsEmpty)
{
DRAW_BOUNDS(EmptyState.Bounds, Empty, false);
}
else
{
DRAW_BOUNDS(EmptyState.Bounds, NotEmpty, false);
}
}
}
const FColor SingleColor = FColorList::Green;
const FColor SingleDirtyColor = FColorList::Blue;
const FColor CachedColor = FColorList::Yellow;
const FColor DirtyColor = FColorList::Red;
const UVoxelDebugUtilities::FDrawDataOctreeSettings DrawDataOctreeSettings
{
World,
DebugDT,
false,
false,
SingleColor,
SingleDirtyColor,
CachedColor,
DirtyColor
};
if (CVarShowValuesState.GetValueOnGameThread())
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, "Values state:");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, DirtyColor, "Dirty");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, CachedColor, "Cached");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, SingleColor, "Single Item Stored");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, SingleDirtyColor, "Single Item Stored - Dirty");
auto LocalDrawDataOctreeSettings = DrawDataOctreeSettings;
LocalDrawDataOctreeSettings.bShowSingle = true;
LocalDrawDataOctreeSettings.bShowCached = true;
FVoxelReadScopeLock Lock(*Settings.Data, FVoxelIntBox::Infinite, FUNCTION_FNAME);
UVoxelDebugUtilities::DrawDataOctreeImpl<FVoxelValue>(*Settings.Data, LocalDrawDataOctreeSettings);
}
if (CVarShowMaterialsState.GetValueOnGameThread())
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, FColor::White, "Materials state:");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, DirtyColor, "Dirty");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, CachedColor, "Cached");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, SingleColor, "Single Item Stored");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, SingleDirtyColor, "Single Item Stored - Dirty");
auto LocalDrawDataOctreeSettings = DrawDataOctreeSettings;
LocalDrawDataOctreeSettings.bShowSingle = true;
LocalDrawDataOctreeSettings.bShowCached = true;
FVoxelReadScopeLock Lock(*Settings.Data, FVoxelIntBox::Infinite, FUNCTION_FNAME);
UVoxelDebugUtilities::DrawDataOctreeImpl<FVoxelMaterial>(*Settings.Data, LocalDrawDataOctreeSettings);
}
if (CVarShowDirtyValues.GetValueOnGameThread())
{
auto LocalDrawDataOctreeSettings = DrawDataOctreeSettings;
LocalDrawDataOctreeSettings.bShowSingle = false;
LocalDrawDataOctreeSettings.bShowCached = false;
FVoxelReadScopeLock Lock(*Settings.Data, FVoxelIntBox::Infinite, FUNCTION_FNAME);
UVoxelDebugUtilities::DrawDataOctreeImpl<FVoxelValue>(*Settings.Data, LocalDrawDataOctreeSettings);
}
if (CVarShowDirtyMaterials.GetValueOnGameThread())
{
auto LocalDrawDataOctreeSettings = DrawDataOctreeSettings;
LocalDrawDataOctreeSettings.bShowSingle = false;
LocalDrawDataOctreeSettings.bShowCached = false;
FVoxelReadScopeLock Lock(*Settings.Data, FVoxelIntBox::Infinite, FUNCTION_FNAME);
UVoxelDebugUtilities::DrawDataOctreeImpl<FVoxelMaterial>(*Settings.Data, LocalDrawDataOctreeSettings);
}
if (CVarShowPlaceableItemsChunks.GetValueOnGameThread())
{
FVoxelReadScopeLock Lock(*Settings.Data, FVoxelIntBox::Infinite, FUNCTION_FNAME);
FVoxelOctreeUtilities::IterateEntireTree(Settings.Data->GetOctree(), [&](const FVoxelDataOctreeBase& Octree)
{
if (Octree.IsLeafOrHasNoChildren() && Octree.GetItemHolder().NumItems() > 0)
{
ensureThreadSafe(Octree.IsLockedForRead());
UVoxelDebugUtilities::DrawDebugIntBox(World, Octree.GetBounds(), DebugDT, 0, FColorList::Red);
}
});
}
if (GShowCollisionAndNavmeshDebug)
{
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, GetCollisionAndNavmeshDebugColor(true, false), "Chunks with collisions");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, GetCollisionAndNavmeshDebugColor(false, true), "Chunks with navmesh");
GEngine->AddOnScreenDebugMessage(OBJECT_LINE_ID(), DebugDT, GetCollisionAndNavmeshDebugColor(true, true), "Chunks with navmesh and collision");
}
if (CVarShowDirtyVoxels.GetValueOnGameThread())
{
FVoxelDataUtilities::IterateDirtyDataInBounds<FVoxelValue>(
*Settings.Data,
FVoxelIntBox::Infinite,
[&](int32 X, int32 Y, int32 Z, const FVoxelValue& Value)
{
DrawDebugPoint(
World->GetWorld(),
World->LocalToGlobal(FIntVector(X, Y, Z)),
2,
Value.IsEmpty() ? FColor::Blue : FColor::Red,
false,
DebugDT);
});
}
}