Files
UnrealEngineUWP/Engine/Source/Developer/GameplayDebugger/Private/GameplayDebuggingHUDComponent.cpp
Marc Audy 4c41590c3d Copying //UE4/Dev-Framework to Dev-Main (//UE4/Dev-Main) @ 2879625
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================
Change 2821607 on 2016/01/08 by Mieszko.Zielinski

	Added a way to limit amount of information logged by vlog by discarding logs from classes from outside of class whitelist #UE4

	This feature was followed by refactoring of functions taking FVisualLogEntry pointers to use references instead.

	#rb Lukasz.Furman

Change 2828384 on 2016/01/14 by Mieszko.Zielinski

	Back out of visual log refactor done as part of CL#2821607 #UE4

Change 2869215 on 2016/02/16 by Marc.Audy

	Store a WorldSettings pointer on ULevel instead of requiring it be index 0 in the Actors array. However, we will still generally attempt to keep it at index 0 for consistency with previous behavior
	#rb Bruce.Nesbit
	#jira UE-26417

Change 2869404 on 2016/02/16 by Ori.Cohen

	Improve UI for default collision. It now uses a single drop down and sets the appropriate flags under the hood.

	#rb Lina.Halper

Change 2870062 on 2016/02/17 by Jurre.deBaare

	Name parameter driven by bone controller
	#JIRA UE-25997
	#rb Thomas.Sarkanen

Change 2870280 on 2016/02/17 by Mieszko.Zielinski

	Vis log category handling fixes #UE4

	Also, a minor cleanup

	#rb Lukasz.Furman

Change 2871729 on 2016/02/18 by James.Golding

	UE-26663 Fix 'LOD For Collision' display name
	#rb thomas.sarkanen

Change 2871730 on 2016/02/18 by James.Golding

	UE-26580 Make ECollisionEnabled a BlueprintType
	UE-25373 Add a MakeHitResult node
	#rb thomas.sarkanen

Change 2871732 on 2016/02/18 by James.Golding

	UE-24397 Add 'test' option to async query API, and use it in places that made sense. Also removed deprecated (4.8) functions from API.
	#rb ori.cohen

Change 2872022 on 2016/02/18 by Lukasz.Furman

	gameplay debugger refactor
	#ue4

Change 2872082 on 2016/02/18 by Lukasz.Furman

	enabled old gameplay debugger as default one for now
	it will be deprecated with next version after testing in game projects
	#ue4

Change 2872390 on 2016/02/18 by Aaron.McLeran

	OR-15041 (CPU) Hitches due to audio decompression on Windows

	1) Moving ogg-vorbis file info parsing into a worker thread
	 - stat dumphitches now shows the vorbis stuff totally gone

	2) Moving async decoding tasks to be retrieved and started from OnBufferEnd callback

	#rb marc.audy

Change 2872418 on 2016/02/18 by Mieszko.Zielinski

	Fixed EQS debugger not storing data properly when subsequent Option is the one that produces result #UE4

	#rb Lukasz.Furman

Change 2872446 on 2016/02/18 by Aaron.McLeran

	Using cached value of ActualVolume in GetVolumeWeightedPriority

Change 2872770 on 2016/02/18 by Aaron.McLeran

	QAGame testing content for audio testing.

	Going to create a folder with specific sub-system testing maps for audio

Change 2873733 on 2016/02/19 by Jurre.deBaare

	- HLOD generated assets are now saved into a separate package instead of inside of the level asset
	#rb Ori.Cohen

Change 2873828 on 2016/02/19 by Ori.Cohen

	Distributions that bake out no longer load in cooked build.

	#JIRA UE-27126
	#rb Olaf.Piesche, Nick.Penwarden

Change 2874623 on 2016/02/19 by Aaron.McLeran

	UE-27131 Support for changing sound class volumes dynamically

	- new BP function to override a sound mix sound class adjuster
	- cleanup of AudioDevice.h and AudioDevice.cpp
	   - removing unnecessarily forward declares on various types
	   - removing unnecessary spaces and (void) params, etc

Change 2874922 on 2016/02/20 by Mieszko.Zielinski

	Fixed EQS tests being compiled out from Shipping and Test with WITH_DEV_AUTOMATION_TESTS macro #UE4

	#jira OR-15292
	#rb none

Change 2875838 on 2016/02/22 by Benn.Gallagher

[CL 2880055 by Marc Audy in Main branch]
2016-02-24 14:23:53 -05:00

1085 lines
37 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
//////////////////////////////////////////////////////////////////////////
// THIS CLASS IS NOW DEPRECATED AND WILL BE REMOVED IN NEXT VERSION
// Please check GameplayDebugger.h for details.
#include "GameplayDebuggerPrivatePCH.h"
#include "GameplayDebuggerSettings.h"
#include "Net/UnrealNetwork.h"
#include "GameplayDebuggingComponent.h"
#include "GameplayDebuggingHUDComponent.h"
#include "GameplayDebuggingControllerComponent.h"
#include "GameplayDebuggingReplicator.h"
#include "CanvasItem.h"
#include "Engine/Canvas.h"
#include "AI/Navigation/NavigationSystem.h"
#include "AITypes.h"
#include "AISystem.h"
#include "GenericTeamAgentInterface.h"
#include "AIController.h"
#include "EnvironmentQuery/EnvQueryTypes.h"
#include "Engine/Texture2D.h"
#include "Regex.h"
#include "DrawDebugHelpers.h"
#include "TimerManager.h" // Game play timers
#include "RenderUtils.h"
#include "EngineUtils.h"
DEFINE_LOG_CATEGORY_STATIC(LogHUD, Log, All);
AGameplayDebuggingHUDComponent::AGameplayDebuggingHUDComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, EngineShowFlags(EShowFlagInitMode::ESFIM_Game)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
World = NULL;
SetTickableWhenPaused(true);
# if WITH_EDITORONLY_DATA
SetIsTemporarilyHiddenInEditor(true);
SetActorHiddenInGame(false);
bHiddenEdLevel = true;
bHiddenEdLayer = true;
bHiddenEd = true;
bEditable = false;
# endif
#endif
ItemDescriptionWidth = 312.f; // 200.0f;
ItemScoreWidth = 50.0f;
TestScoreWidth = 100.0f;
}
void AGameplayDebuggingHUDComponent::Render()
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
EngineShowFlags = Canvas && Canvas->SceneView && Canvas->SceneView->Family ? Canvas->SceneView->Family->EngineShowFlags : FEngineShowFlags(GIsEditor ? EShowFlagInitMode::ESFIM_Editor : EShowFlagInitMode::ESFIM_Game);
PrintAllData();
#endif
}
AGameplayDebuggingReplicator* AGameplayDebuggingHUDComponent::GetDebuggingReplicator()
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (CachedDebuggingReplicator.IsValid() && CachedDebuggingReplicator->GetLocalPlayerOwner() == PlayerOwner)
{
return CachedDebuggingReplicator.Get();
}
for (TActorIterator<AGameplayDebuggingReplicator> It(GetWorld()); It; ++It)
{
AGameplayDebuggingReplicator* Replicator = *It;
if (!Replicator->IsPendingKill() && Replicator->GetLocalPlayerOwner() == PlayerOwner)
{
CachedDebuggingReplicator = Replicator;
return Replicator;
}
}
#endif
return NULL;
}
void AGameplayDebuggingHUDComponent::GetKeyboardDesc(TArray<FDebugCategoryView>& Categories)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
Categories.Add(FDebugCategoryView(EAIDebugDrawDataView::NavMesh, TEXT("NavMesh")));
Categories.Add(FDebugCategoryView(EAIDebugDrawDataView::Basic, TEXT("Basic")));
Categories.Add(FDebugCategoryView(EAIDebugDrawDataView::BehaviorTree, TEXT("BehaviorTree")));
Categories.Add(FDebugCategoryView(EAIDebugDrawDataView::EQS, TEXT("EQS")));
Categories.Add(FDebugCategoryView(EAIDebugDrawDataView::Perception, TEXT("Perception")));
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::PrintAllData()
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
// Allow child hud components to position the displayed info
DefaultContext = FPrintContext(GEngine->GetSmallFont(), Canvas, DebugInfoStartX, DebugInfoStartY);
DefaultContext.FontRenderInfo.bEnableShadow = true;
if (DefaultContext.Canvas != NULL)
{
float XL, YL;
const FString ToolName = FString::Printf(TEXT("Gameplay Debug Tool [Timestamp: %05.03f]"), GetWorld()->TimeSeconds);
CalulateStringSize(DefaultContext, DefaultContext.Font, ToolName, XL, YL);
PrintString(DefaultContext, FColorList::White, ToolName, DefaultContext.Canvas->ClipX / 2.0f - XL / 2.0f, 0);
}
const float MenuX = DefaultContext.CursorX;
const float MenuY = DefaultContext.CursorY;
UGameplayDebuggingComponent* DebugComponent = NULL;
if (GetDebuggingReplicator())
{
DebugComponent = GetDebuggingReplicator()->GetDebugComponent();
}
if (DebugComponent)
{
APlayerController* const MyPC = Cast<APlayerController>(PlayerOwner);
DrawDebugComponentData(MyPC, DebugComponent);
}
if (DefaultContext.Canvas && DefaultContext.Canvas->SceneView && DefaultContext.Canvas->SceneView->Family && DefaultContext.Canvas->SceneView->Family->EngineShowFlags.Game)
{
DrawMenu(MenuX, MenuY, DebugComponent);
}
#endif
}
void AGameplayDebuggingHUDComponent::DrawMenu(const float X, const float Y, class UGameplayDebuggingComponent* DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
const float OldX = DefaultContext.CursorX;
const float OldY = DefaultContext.CursorY;
UGameplayDebuggingControllerComponent* GDC = GetDebuggingReplicator()->FindComponentByClass<UGameplayDebuggingControllerComponent>();
if (DefaultContext.Canvas != NULL)
{
TArray<FDebugCategoryView> Categories;
GetKeyboardDesc(Categories);
UFont* OldFont = DefaultContext.Font;
DefaultContext.Font = GEngine->GetMediumFont();
TArray<float> CategoriesWidth;
CategoriesWidth.AddZeroed(Categories.Num());
float TotalWidth = 0.0f, MaxHeight = 0.0f;
FString ActivationKeyDisplayName = TEXT("'");
FString ActivationKeyName = TEXT("Apostrophe");
APlayerController* const MyPC = Cast<APlayerController>(PlayerOwner);
if (GDC)
{
ActivationKeyDisplayName = GDC->GetActivationKey().Key.GetDisplayName().ToString();
ActivationKeyName = GDC->GetActivationKey().Key.GetFName().ToString();
}
const FString KeyDesc = ActivationKeyName != ActivationKeyDisplayName ? FString::Printf(TEXT("(%s key)"), *ActivationKeyName) : TEXT("");
FString HeaderDesc = FString::Printf(TEXT("Tap %s %s to close, use Numpad numbers to toggle categories"), *ActivationKeyDisplayName, *KeyDesc);
float HeaderWidth = 0.0f;
CalulateStringSize(DefaultContext, DefaultContext.Font, HeaderDesc, HeaderWidth, MaxHeight);
for (int32 i = 0; i < Categories.Num(); i++)
{
Categories[i].Desc = FString::Printf(TEXT("%d:%s "), i, *Categories[i].Desc);
float StrHeight = 0.0f;
CalulateStringSize(DefaultContext, DefaultContext.Font, Categories[i].Desc, CategoriesWidth[i], StrHeight);
TotalWidth += CategoriesWidth[i];
MaxHeight = FMath::Max(MaxHeight, StrHeight);
}
{
static FString KeyShortcut = GDC->DebugCameraBind.GetInputText().ToString();
const int32 DebugCameraIndex = Categories.Add(FDebugCategoryView());
CategoriesWidth.AddZeroed(1);
Categories[DebugCameraIndex].Desc = FString::Printf(TEXT(" %s[%s]: %s "), GDC && GDC->GetDebugCameraController().IsValid() ? TEXT("{Green}") : TEXT("{White}"), *KeyShortcut, TEXT("Debug Camera"));
float StrHeight = 0.0f;
CalulateStringSize(DefaultContext, DefaultContext.Font, Categories[DebugCameraIndex].Desc, CategoriesWidth[DebugCameraIndex], StrHeight);
TotalWidth += CategoriesWidth[DebugCameraIndex];
MaxHeight = FMath::Max(MaxHeight, StrHeight);
}
{
static FString KeyShortcut = GDC->OnScreenDebugMessagesBind.GetInputText().ToString();
const int32 DebugCameraIndex = Categories.Add(FDebugCategoryView());
CategoriesWidth.AddZeroed(1);
Categories[DebugCameraIndex].Desc = FString::Printf(TEXT(" %s[%s]: %s "), GEngine && GEngine->bEnableOnScreenDebugMessages ? TEXT("{Green}") : TEXT("{White}"), *KeyShortcut, TEXT("DebugMessages"));
float StrHeight = 0.0f;
CalulateStringSize(DefaultContext, DefaultContext.Font, Categories[DebugCameraIndex].Desc, CategoriesWidth[DebugCameraIndex], StrHeight);
TotalWidth += CategoriesWidth[DebugCameraIndex];
MaxHeight = FMath::Max(MaxHeight, StrHeight);
}
{
static FString KeyShortcut = GDC->GameHUDBind.GetInputText().ToString();
const AHUD* GameHUD = MyPC ? MyPC->GetHUD() : NULL;
const int32 DebugCameraIndex = Categories.Add(FDebugCategoryView());
CategoriesWidth.AddZeroed(1);
Categories[DebugCameraIndex].Desc = FString::Printf(TEXT(" %s[%s]: %s "), GameHUD && GameHUD->bShowHUD ? TEXT("{Green}") : TEXT("{White}"), *KeyShortcut, TEXT("GameHUD"));
float StrHeight = 0.0f;
CalulateStringSize(DefaultContext, DefaultContext.Font, Categories[DebugCameraIndex].Desc, CategoriesWidth[DebugCameraIndex], StrHeight);
TotalWidth += CategoriesWidth[DebugCameraIndex];
MaxHeight = FMath::Max(MaxHeight, StrHeight);
}
TotalWidth = FMath::Max(TotalWidth, HeaderWidth);
FCanvasTileItem TileItem(FVector2D(10, 10), GWhiteTexture, FVector2D(TotalWidth + 20, MaxHeight + 20), FColor(0, 0, 0, 20));
TileItem.BlendMode = SE_BLEND_Translucent;
DrawItem(DefaultContext, TileItem, MenuStartX, MenuStartY);
PrintString(DefaultContext, FColorList::LightBlue, HeaderDesc, MenuStartX + 2.f, MenuStartY + 2.f);
float XPos = MenuStartX + 20.f;
for (int32 i = 0; i < Categories.Num(); i++)
{
const bool bIsActive = GameplayDebuggerSettings(GetDebuggingReplicator()).CheckFlag(Categories[i].View) ? true : false;
const bool bIsDisabled = Categories[i].View == EAIDebugDrawDataView::NavMesh ? false : (DebugComponent && DebugComponent->GetSelectedActor() ? false: true);
PrintString(DefaultContext, bIsDisabled ? (bIsActive ? FColorList::DarkGreen : FColorList::LightGrey) : (bIsActive ? FColorList::Green : FColorList::White), Categories[i].Desc, XPos, MenuStartY + MaxHeight + 2.f);
XPos += CategoriesWidth[i];
}
DefaultContext.Font = OldFont;
}
if ((!DebugComponent || !DebugComponent->GetSelectedActor()) && GetWorld()->GetNetMode() == NM_Client)
{
PrintString(DefaultContext, "\n{red}No Pawn selected - waiting for data to replicate from server. {green}Press and hold ' to select Pawn \n");
}
if (GDC && GDC->GetDebugCameraController().IsValid())
{
ADebugCameraController* DebugCamController = GDC->GetDebugCameraController().Get();
if (DebugCamController != NULL)
{
FVector const CamLoc = DebugCamController->PlayerCameraManager->GetCameraLocation();
FRotator const CamRot = DebugCamController->PlayerCameraManager->GetCameraRotation();
FString HitString;
FCollisionQueryParams TraceParams(NAME_None, true, this);
FHitResult Hit;
bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, CamLoc, CamRot.Vector() * 100000.f + CamLoc, ECC_Pawn, TraceParams);
if (bHit && Hit.GetActor() != nullptr)
{
HitString = FString::Printf(TEXT("{white}Under cursor: {yellow}'%s'"), *Hit.GetActor()->GetName());
DrawDebugLine(GetWorld(), Hit.Location, Hit.Location + Hit.Normal*30.f, FColor::White);
}
else
{
HitString = FString::Printf(TEXT("Not actor under cursor"));
}
PrintString(DefaultContext, FColor::White, HitString, MenuStartX, MenuStartY + 40);
}
}
DefaultContext.CursorX = OldX;
DefaultContext.CursorY = OldY;
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawDebugComponentData(APlayerController* MyPC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
AActor* SelectedActor = DebugComponent->GetSelectedActor();
const bool bDrawFullData = GetDebuggingReplicator()->GetSelectedActorToDebug() == SelectedActor;
const FVector ScreenLoc = SelectedActor ? ProjectLocation(DefaultContext, SelectedActor->GetActorLocation() + FVector(0.f, 0.f, SelectedActor->GetSimpleCollisionHalfHeight())) : FVector::ZeroVector;
OverHeadContext = FPrintContext(GEngine->GetSmallFont(), Canvas, ScreenLoc.X, ScreenLoc.Y);
//DefaultContext.CursorY += 20;
BlackboardFinishY = 0.0f;
FGameplayDebuggerSettings DebuggerSettings = GameplayDebuggerSettings(GetDebuggingReplicator());
bool bForceOverhead = false;
#if !WITH_EDITOR
bForceOverhead = bDrawFullData;
#endif
if (DebuggerSettings.CheckFlag(EAIDebugDrawDataView::OverHead) || bForceOverhead)
{
DrawOverHeadInformation(MyPC, DebugComponent);
}
if (DebuggerSettings.CheckFlag(EAIDebugDrawDataView::NavMesh))
{
DrawNavMeshSnapshot(MyPC, DebugComponent);
}
if (SelectedActor && bDrawFullData)
{
if (DebuggerSettings.CheckFlag(EAIDebugDrawDataView::Basic) /*|| EngineShowFlags.DebugAI*/)
{
DrawBasicData(MyPC, DebugComponent);
}
if (DebuggerSettings.CheckFlag(EAIDebugDrawDataView::BehaviorTree))
{
DrawBehaviorTreeData(MyPC, DebugComponent);
}
if (DebuggerSettings.CheckFlag(EAIDebugDrawDataView::EQS))
{
bool bEnabledEnvironmentQueryEd = true;
if (GConfig)
{
GConfig->GetBool(TEXT("EnvironmentQueryEd"), TEXT("EnableEnvironmentQueryEd"), bEnabledEnvironmentQueryEd, GEngineIni);
}
if (bEnabledEnvironmentQueryEd)
{
DrawEQSData(MyPC, DebugComponent);
}
}
if (DebuggerSettings.CheckFlag(EAIDebugDrawDataView::Perception) /*|| EngineShowFlags.DebugAI*/)
{
DrawPerception(MyPC, DebugComponent);
}
}
DrawGameSpecificView(MyPC, DebugComponent);
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawPath(APlayerController* MyPC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
static const FColor Grey(100,100,100);
static const FColor PathColor(192,192,192);
const int32 NumPathVerts = DebugComponent->PathPoints.Num();
UWorld* DrawWorld = GetWorld();
for (int32 VertIdx=0; VertIdx < NumPathVerts-1; ++VertIdx)
{
FVector const VertLoc = DebugComponent->PathPoints[VertIdx] + NavigationDebugDrawing::PathOffset;
DrawDebugSolidBox(DrawWorld, VertLoc, NavigationDebugDrawing::PathNodeBoxExtent, VertIdx < int32(DebugComponent->NextPathPointIndex) ? Grey : PathColor, false);
// draw line to next loc
FVector const NextVertLoc = DebugComponent->PathPoints[VertIdx+1] + NavigationDebugDrawing::PathOffset;
DrawDebugLine(DrawWorld, VertLoc, NextVertLoc, VertIdx < int32(DebugComponent->NextPathPointIndex) ? Grey : PathColor, false
, -1.f, 0
, NavigationDebugDrawing::PathLineThickness);
}
// draw last vert
if (NumPathVerts > 0)
{
DrawDebugBox(DrawWorld, DebugComponent->PathPoints[NumPathVerts-1] + NavigationDebugDrawing::PathOffset, FVector(15.f), Grey, false);
}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawOverHeadInformation(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
APawn* MyPawn = Cast<APawn>(DebugComponent->GetSelectedActor());
const FVector Loc3d = MyPawn ? MyPawn->GetActorLocation() + FVector(0.f, 0.f, MyPawn->GetSimpleCollisionHalfHeight()) : FVector::ZeroVector;
if (OverHeadContext.Canvas->SceneView == NULL || OverHeadContext.Canvas->SceneView->ViewFrustum.IntersectBox(Loc3d, FVector::ZeroVector) == false)
{
return;
}
const FVector ScreenLoc = OverHeadContext.Canvas->Project(Loc3d);
static const FVector2D FontScale(1.f, 1.f);
UFont* Font = GEngine->GetSmallFont();
float TextXL = 0.f;
float YL = 0.f;
FString ObjectName = FString::Printf( TEXT("{yellow}%s {white}(%s)"), *DebugComponent->ControllerName, *DebugComponent->PawnName);
CalulateStringSize(OverHeadContext, OverHeadContext.Font, ObjectName, TextXL, YL);
bool bDrawFullOverHead = MyPawn != nullptr && GetDebuggingReplicator()->GetSelectedActorToDebug() == MyPawn;
float IconXLocation = OverHeadContext.DefaultX;
float IconYLocation = OverHeadContext.DefaultY;
if (bDrawFullOverHead)
{
OverHeadContext.DefaultX -= (0.5f*TextXL*FontScale.X);
OverHeadContext.DefaultY -= (1.2f*YL*FontScale.Y);
IconYLocation = OverHeadContext.DefaultY;
OverHeadContext.CursorX = OverHeadContext.DefaultX;
OverHeadContext.CursorY = OverHeadContext.DefaultY;
}
if (DebugComponent->DebugIcon.Len() > 0)
{
UTexture2D* RegularIcon = (UTexture2D*)StaticLoadObject(UTexture2D::StaticClass(), NULL, *DebugComponent->DebugIcon, NULL, LOAD_NoWarn | LOAD_Quiet, NULL);
if (RegularIcon)
{
FCanvasIcon Icon = UCanvas::MakeIcon(RegularIcon);
if (Icon.Texture)
{
const float DesiredIconSize = bDrawFullOverHead ? 32.f : 16.f;
DrawIcon(OverHeadContext, FColor::White, Icon, IconXLocation, IconYLocation - DesiredIconSize, DesiredIconSize / Icon.Texture->GetSurfaceWidth());
}
}
}
if (bDrawFullOverHead)
{
OverHeadContext.FontRenderInfo.bEnableShadow = bDrawFullOverHead;
PrintString(OverHeadContext, bDrawFullOverHead ? FColor::White : FColor(255, 255, 255, 128), FString::Printf(TEXT("%s\n"), *ObjectName));
OverHeadContext.FontRenderInfo.bEnableShadow = false;
}
if (EngineShowFlags.DebugAI)
{
DrawPath(PC, DebugComponent);
}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawBasicData(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
PrintString(DefaultContext, TEXT("\n{R=0,G=255,B=0,A=255}BASIC DATA\n"));
UFont* OldFont = DefaultContext.Font;
DefaultContext.Font = GEngine->GetMediumFont();
PrintString(DefaultContext, FString::Printf(TEXT("Controller Name: {yellow}%s\n"), *DebugComponent->ControllerName));
DefaultContext.Font = OldFont;
PrintString(DefaultContext, FString::Printf(TEXT("Pawn Name: {yellow}%s{white}, Pawn Class: {yellow}%s\n"), *DebugComponent->PawnName, *DebugComponent->PawnClass));
// movement
if (DebugComponent->bIsUsingCharacter)
{
PrintString(DefaultContext, FString::Printf(TEXT("Movement Mode: {yellow}%s{white}, Base: {yellow}%s\n"), *DebugComponent->MovementModeInfo, *DebugComponent->MovementBaseInfo));
PrintString(DefaultContext, FString::Printf(TEXT("NavData: {yellow}%s{white}, Path following: {yellow}%s\n"), *DebugComponent->NavDataInfo, *DebugComponent->PathFollowingInfo));
}
// logic
if (DebugComponent->bIsUsingBehaviorTree)
{
PrintString(DefaultContext, FString::Printf(TEXT("Behavior: {yellow}%s{white}, Tree: {yellow}%s\n"), *DebugComponent->CurrentAIState, *DebugComponent->CurrentAIAssets));
PrintString(DefaultContext, FString::Printf(TEXT("Active task: {yellow}%s\n"), *DebugComponent->CurrentAITask));
}
// ability + animation
if (DebugComponent->bIsUsingAbilities && DebugComponent->bIsUsingCharacter)
{
PrintString(DefaultContext, FString::Printf(TEXT("Ability: {yellow}%s{white}, Montage: {yellow}%s\n"), *DebugComponent->AbilityInfo, *DebugComponent->MontageInfo));
}
else if (DebugComponent->bIsUsingCharacter)
{
PrintString(DefaultContext, FString::Printf(TEXT("Montage: {yellow}%s\n"), *DebugComponent->MontageInfo));
}
else if (DebugComponent->bIsUsingAbilities)
{
PrintString(DefaultContext, FString::Printf(TEXT("Ability: {yellow}%s\n"), *DebugComponent->AbilityInfo));
}
// putting gameplay tasks' stuff last since it can expand heavily
PrintString(DefaultContext, FString::Printf(TEXT("GameplayTasks:\n{yellow}%s\n"), *DebugComponent->GameplayTasksState));
DrawPath(PC, DebugComponent);
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawBehaviorTreeData(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
PrintString(DefaultContext, TEXT("\n{green}BEHAVIOR TREE\n"));
PrintString(DefaultContext, FString::Printf(TEXT("Brain Component: {yellow}%s\n"), *DebugComponent->BrainComponentName));
PrintString(DefaultContext, DebugComponent->BrainComponentString);
PrintString(DefaultContext, FColor::White, DebugComponent->BlackboardString, 600.0f, DebugInfoStartY);
BlackboardFinishY = DefaultContext.CursorY;
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawEQSData(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) && WITH_EQS
PrintString(DefaultContext, TEXT("\n{green}EQS {white}[Use + key to switch query]\n"));
if (DebugComponent->EQSLocalData.Num() == 0)
{
return;
}
const int32 EQSIndex = DebugComponent->EQSLocalData.Num() > 0 ? FMath::Clamp(DebugComponent->CurrentEQSIndex, 0, DebugComponent->EQSLocalData.Num() - 1) : INDEX_NONE;
if (!DebugComponent->EQSLocalData.IsValidIndex(EQSIndex))
{
return;
}
{
int32 Index = 0;
PrintString(DefaultContext, TEXT("{white}Queries: "));
for (auto CurrentQuery : DebugComponent->EQSLocalData)
{
if (EQSIndex == Index)
{
PrintString(DefaultContext, FString::Printf(TEXT("{green}%s, "), *CurrentQuery.Name));
}
else
{
PrintString(DefaultContext, FString::Printf(TEXT("{yellow}%s, "), *CurrentQuery.Name));
}
Index++;
}
PrintString(DefaultContext, TEXT("\n"));
}
auto& CurrentLocalData = DebugComponent->EQSLocalData[EQSIndex];
/** find and draw item selection */
int32 BestItemIndex = INDEX_NONE;
{
APlayerController* const MyPC = Cast<APlayerController>(PlayerOwner);
FVector CamLocation;
FVector FireDir;
if (!MyPC->GetSpectatorPawn())
{
FRotator CamRotation;
MyPC->GetPlayerViewPoint(CamLocation, CamRotation);
FireDir = CamRotation.Vector();
}
else
{
FireDir = DefaultContext.Canvas->SceneView->GetViewDirection();
CamLocation = DefaultContext.Canvas->SceneView->ViewMatrices.ViewOrigin;
}
float bestAim = 0;
for (int32 Index = 0; Index < CurrentLocalData.RenderDebugHelpers.Num(); ++Index)
{
auto& CurrentItem = CurrentLocalData.RenderDebugHelpers[Index];
const FVector AimDir = CurrentItem.Location - CamLocation;
float FireDist = AimDir.SizeSquared();
FireDist = FMath::Sqrt(FireDist);
float newAim = FireDir | AimDir;
newAim = newAim / FireDist;
if (newAim > bestAim)
{
BestItemIndex = Index;
bestAim = newAim;
}
}
if (BestItemIndex != INDEX_NONE)
{
DrawDebugSphere(World, CurrentLocalData.RenderDebugHelpers[BestItemIndex].Location, CurrentLocalData.RenderDebugHelpers[BestItemIndex].Radius, 8, FColor::Red, false);
int32 FailedTestIndex = CurrentLocalData.RenderDebugHelpers[BestItemIndex].FailedTestIndex;
if (FailedTestIndex != INDEX_NONE)
{
PrintString(DefaultContext, FString::Printf(TEXT("{red}Selected item failed with test %d: {yellow}%s {LightBlue}(%s)\n")
, FailedTestIndex
, *CurrentLocalData.Tests[FailedTestIndex].ShortName
, *CurrentLocalData.Tests[FailedTestIndex].Detailed
));
PrintString(DefaultContext, FString::Printf(TEXT("{white}'%s' with score %3.3f\n\n"), *CurrentLocalData.RenderDebugHelpers[BestItemIndex].AdditionalInformation, CurrentLocalData.RenderDebugHelpers[BestItemIndex].FailedScore));
}
}
}
PrintString(DefaultContext, FString::Printf(TEXT("{white}Timestamp: {yellow}%.3f (%.2fs ago)\n")
, CurrentLocalData.Timestamp, PC->GetWorld()->GetTimeSeconds() - CurrentLocalData.Timestamp
));
PrintString(DefaultContext, FString::Printf(TEXT("{white}Query ID: {yellow}%d\n")
, CurrentLocalData.Id
));
PrintString(DefaultContext, FString::Printf(TEXT("{white}Query contains %d options: "), CurrentLocalData.Options.Num()));
for (int32 OptionIndex = 0; OptionIndex < CurrentLocalData.Options.Num(); ++OptionIndex)
{
if (OptionIndex == CurrentLocalData.UsedOption)
{
PrintString(DefaultContext, FString::Printf(TEXT("{green}%s, "), *CurrentLocalData.Options[OptionIndex]));
}
else
{
PrintString(DefaultContext, FString::Printf(TEXT("{yellow}%s, "), *CurrentLocalData.Options[OptionIndex]));
}
}
PrintString(DefaultContext, TEXT("\n"));
const float RowHeight = 20.0f;
const int32 NumTests = CurrentLocalData.Tests.Num();
if (CurrentLocalData.NumValidItems > 0 && GetDebuggingReplicator()->EnableEQSOnHUD )
{
// draw test weights for best X items
const int32 NumItems = CurrentLocalData.Items.Num();
FCanvasTileItem TileItem(FVector2D(0, 0), GWhiteTexture, FVector2D(Canvas->SizeX, RowHeight), FLinearColor::Black);
FLinearColor ColorOdd(0, 0, 0, 0.6f);
FLinearColor ColorEven(0, 0, 0.4f, 0.4f);
TileItem.BlendMode = SE_BLEND_Translucent;
// table header
{
DefaultContext.CursorY += RowHeight;
const float HeaderY = DefaultContext.CursorY + 3.0f;
TileItem.SetColor(ColorOdd);
DrawItem(DefaultContext, TileItem, 0, DefaultContext.CursorY);
float HeaderX = DefaultContext.CursorX;
PrintString(DefaultContext, FColor::Yellow, FString::Printf(TEXT("Num items: %d"), CurrentLocalData.NumValidItems), HeaderX, HeaderY);
HeaderX += ItemDescriptionWidth;
PrintString(DefaultContext, FColor::White, TEXT("Score"), HeaderX, HeaderY);
HeaderX += ItemScoreWidth;
for (int32 TestIdx = 0; TestIdx < NumTests; TestIdx++)
{
PrintString(DefaultContext, FColor::White, FString::Printf(TEXT("Test %d"), TestIdx), HeaderX, HeaderY);
HeaderX += TestScoreWidth;
}
DefaultContext.CursorY += RowHeight;
}
// valid items
for (int32 Idx = 0; Idx < NumItems; Idx++)
{
TileItem.SetColor((Idx % 2) ? ColorOdd : ColorEven);
DrawItem(DefaultContext, TileItem, 0, DefaultContext.CursorY);
DrawEQSItemDetails(Idx, DebugComponent);
DefaultContext.CursorY += RowHeight;
}
DefaultContext.CursorY += RowHeight;
}
// test description
PrintString(DefaultContext, TEXT("All tests from used option:\n"));
for (int32 TestIdx = 0; TestIdx < NumTests; TestIdx++)
{
FString TestDesc = FString::Printf(TEXT("{white}Test %d = {yellow}%s {LightBlue}(%s)\n"), TestIdx,
*CurrentLocalData.Tests[TestIdx].ShortName,
*CurrentLocalData.Tests[TestIdx].Detailed);
PrintString(DefaultContext, TestDesc);
}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawEQSItemDetails(int32 ItemIdx, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) && WITH_EQS
const float PosY = DefaultContext.CursorY + 1.0f;
float PosX = DefaultContext.CursorX;
const int32 EQSIndex = DebugComponent->EQSLocalData.Num() > 0 ? FMath::Clamp(DebugComponent->CurrentEQSIndex, 0, DebugComponent->EQSLocalData.Num() - 1) : INDEX_NONE;
auto& CurrentLocalData = DebugComponent->EQSLocalData[EQSIndex];
const EQSDebug::FItemData& ItemData = CurrentLocalData.Items[ItemIdx];
PrintString(DefaultContext, FColor::White, ItemData.Desc, PosX, PosY);
PosX += ItemDescriptionWidth;
FString ScoreDesc = FString::Printf(TEXT("%.2f"), ItemData.TotalScore);
PrintString(DefaultContext, FColor::Yellow, ScoreDesc, PosX, PosY);
PosX += ItemScoreWidth;
FCanvasTileItem ActiveTileItem(FVector2D(0, PosY + 15.0f), GWhiteTexture, FVector2D(0, 2.0f), FLinearColor::Yellow);
FCanvasTileItem BackTileItem(FVector2D(0, PosY + 15.0f), GWhiteTexture, FVector2D(0, 2.0f), FLinearColor(0.1f, 0.1f, 0.1f));
const float BarWidth = 80.0f;
const int32 NumTests = ItemData.TestScores.Num();
float TotalWeightedScore = 0.0f;
for (int32 Idx = 0; Idx < NumTests; Idx++)
{
TotalWeightedScore += ItemData.TestScores[Idx];
}
for (int32 Idx = 0; Idx < NumTests; Idx++)
{
const float ScoreW = ItemData.TestScores[Idx];
const float ScoreN = ItemData.TestValues[Idx];
FString DescScoreW = FString::Printf(TEXT("%.2f"), ScoreW);
FString DescScoreN = (ScoreN == UEnvQueryTypes::SkippedItemValue) ? TEXT("SKIP") : FString::Printf(TEXT("%.2f"), ScoreN);
FString TestDesc = DescScoreW + FString(" {LightBlue}") + DescScoreN;
float Pct = (TotalWeightedScore > KINDA_SMALL_NUMBER) ? (ScoreW / TotalWeightedScore) : 0.0f;
ActiveTileItem.Position.X = PosX;
ActiveTileItem.Size.X = BarWidth * Pct;
BackTileItem.Position.X = PosX + ActiveTileItem.Size.X;
BackTileItem.Size.X = FMath::Max(BarWidth * (1.0f - Pct), 0.0f);
DrawItem(DefaultContext, ActiveTileItem, ActiveTileItem.Position.X, ActiveTileItem.Position.Y);
DrawItem(DefaultContext, BackTileItem, BackTileItem.Position.X, BackTileItem.Position.Y);
PrintString(DefaultContext, FColor::Green, TestDesc, PosX, PosY);
PosX += TestScoreWidth;
}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) && WITH_EQS
}
void AGameplayDebuggingHUDComponent::DrawPerception(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (!DebugComponent)
{
return;
}
PrintString(DefaultContext, FColor::Green, TEXT("\nPERCEPTION COMPONENT\n"));
PrintString(DefaultContext, FString::Printf(TEXT("Draw Colors:")));
PrintString(DefaultContext, *DebugComponent->PerceptionLegend);
PrintString(DefaultContext, FString::Printf(TEXT("\nDistance Sensor-PlayerPawn: %.1f\n"), DebugComponent->DistanceFromSensor));
PrintString(DefaultContext, FString::Printf(TEXT("Distance Pawn-PlayerPawn: %.1f\n"), DebugComponent->DistanceFromPlayer));
float VerticalLabelOffset = 0.f;
for (const FGameplayDebuggerShapeElement& Shape : DebugComponent->PerceptionShapeElements)
{
switch (Shape.GetType())
{
case EGameplayDebuggerShapeElement::String:
{
const FVector& Loc = Shape.Points[0];
const FVector ScreenLoc = DefaultContext.Canvas->Project(Loc);
PrintString(DefaultContext, Shape.GetFColor(), Shape.Description, ScreenLoc.X, ScreenLoc.Y + VerticalLabelOffset);
VerticalLabelOffset += 17;
}
break;
case EGameplayDebuggerShapeElement::Segment:
{
DrawDebugLine(World, Shape.Points[0], Shape.Points[1], Shape.GetFColor());
}
break;
case EGameplayDebuggerShapeElement::SinglePoint:
{
DrawDebugSphere(World, Shape.Points[0], Shape.ThicknesOrRadius, 16, Shape.GetFColor());
}
break;
case EGameplayDebuggerShapeElement::Cylinder:
{
static const float DefaultCylinderHeight = 50.f;
const FVector EndLocation = ensure(Shape.Points.Num() > 1) ? Shape.Points[1] : (Shape.Points[0] + FVector::UpVector * DefaultCylinderHeight);
DrawDebugCylinder(World, Shape.Points[0], Shape.Points[1], Shape.ThicknesOrRadius, 16, Shape.GetFColor());
}
break;
}
}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::DrawNavMeshSnapshot(APlayerController* PC, class UGameplayDebuggingComponent *DebugComponent)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (DebugComponent && DebugComponent->NavmeshRepData.Num())
{
UGameplayDebuggingControllerComponent* GDC = PC ? PC->FindComponentByClass<UGameplayDebuggingControllerComponent>() : NULL;
FString NextUpdateDesc;
if (GDC)
{
const float TimeLeft = GDC->GetUpdateNavMeshTimeRemaining();
NextUpdateDesc = FString::Printf(TEXT(", next update: {yellow}%.1fs"), TimeLeft);
}
PrintString(DefaultContext, FString::Printf(TEXT("\n\n{green}Showing NavMesh (%.1fkB)%s\n"),
DebugComponent->NavmeshRepData.Num() / 1024.0f, *NextUpdateDesc));
}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
//////////////////////////////////////////////////////////////////////////
void AGameplayDebuggingHUDComponent::PrintString(FPrintContext& Context, const FString& InString )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
class FParserHelper
{
enum TokenType
{
OpenTag,
CloseTag,
NewLine,
EndOfString,
RegularChar,
Tab
};
enum Tag
{
DefinedColor,
OtherColor,
ErrorTag,
};
uint8 ReadToken()
{
uint8 OutToken = RegularChar;
TCHAR ch = Index < DataString.Len() ? DataString[Index] : '\0';
switch(ch)
{
case '\0':
OutToken = EndOfString;
break;
case '{':
OutToken = OpenTag;
Index++;
break;
case '}':
OutToken = CloseTag;
Index++;
break;
case '\n':
OutToken = NewLine;
Index++;
break;
case '\t':
OutToken = Tab;
Index++;
break;
default:
OutToken = RegularChar;
break;
}
return OutToken;
}
uint32 ParseTag( FString& OutData )
{
FString TagString;
int32 OryginalIndex = Index;
uint8 token = ReadToken();
while (token != EndOfString && token != CloseTag)
{
if (token == RegularChar)
{
TagString.AppendChar(DataString[Index++]);
}
token = ReadToken();
}
int OutTag = ErrorTag;
if (token != CloseTag)
{
Index = OryginalIndex;
OutData = FString::Printf( TEXT("{%s"), *TagString);
OutData.AppendChar(DataString[Index-1]);
return OutTag;
}
if (GColorList.IsValidColorName(*TagString.ToLower()))
{
OutTag = DefinedColor;
OutData = TagString;
}
else
{
FColor Color;
if (Color.InitFromString(TagString))
{
OutTag = OtherColor;
OutData = TagString;
}
else
{
OutTag = ErrorTag;
OutData = FString::Printf( TEXT("{%s"), *TagString);
OutData.AppendChar(DataString[Index-1]);
}
}
//Index++;
return OutTag;
}
struct StringNode
{
FString String;
FColor Color;
bool bNewLine;
StringNode() : Color(FColor::White), bNewLine(false) {}
};
int32 Index;
FString DataString;
public:
TArray<StringNode> Strings;
void ParseString(const FString& StringToParse)
{
Index = 0;
DataString = StringToParse;
Strings.Add(StringNode());
if (Index >= DataString.Len())
return;
uint8 Token = ReadToken();
while (Token != EndOfString)
{
switch (Token)
{
case RegularChar:
Strings[Strings.Num()-1].String.AppendChar( DataString[Index++] );
break;
case NewLine:
Strings.Add(StringNode());
Strings[Strings.Num()-1].bNewLine = true;
Strings[Strings.Num()-1].Color = Strings[Strings.Num()-2].Color;
break;
case EndOfString:
break;
case Tab:
{
const FString TabString(TEXT(" "));
Strings[Strings.Num()-1].String.Append(TabString);
static bool sbTest = false;
if (sbTest)
{
Index++;
}
break;
}
case OpenTag:
{
FString OutData;
switch (ParseTag(OutData))
{
case DefinedColor:
{
int32 i = Strings.Add(StringNode());
Strings[i].Color = GColorList.GetFColorByName(*OutData.ToLower());
}
break;
case OtherColor:
{
FColor NewColor;
if (NewColor.InitFromString( OutData ))
{
int32 i = Strings.Add(StringNode());
Strings[i].Color = NewColor;
break;
}
}
default:
Strings[Strings.Num()-1].String += OutData;
break;
}
}
break;
}
Token = ReadToken();
}
}
};
FParserHelper Helper;
Helper.ParseString( InString );
float YMovement = 0;
float XL = 0.f, YL = 0.f;
CalulateStringSize(Context, Context.Font, TEXT("X"), XL, YL);
for (int32 Index=0; Index < Helper.Strings.Num(); ++Index)
{
if (Index > 0 && Helper.Strings[Index].bNewLine)
{
if (Context.Canvas != NULL && YMovement + Context.CursorY > Context.Canvas->ClipY)
{
Context.DefaultX += Context.Canvas->ClipX / 2;
Context.CursorX = Context.DefaultX;
Context.CursorY = Context.DefaultY;
YMovement = 0;
}
YMovement += YL;
Context.CursorX = Context.DefaultX;
}
const FString Str = Helper.Strings[Index].String;
if (Str.Len() > 0 && Context.Canvas != NULL)
{
float SizeX, SizeY;
CalulateStringSize(Context, Context.Font, Str, SizeX, SizeY);
FCanvasTextItem TextItem( FVector2D::ZeroVector, FText::FromString(Str), Context.Font, FLinearColor::White );
if (Context.FontRenderInfo.bEnableShadow)
{
TextItem.EnableShadow( FColor::Black, FVector2D( 1, 1 ) );
}
TextItem.SetColor(Helper.Strings[Index].Color);
DrawItem( Context, TextItem, Context.CursorX, YMovement + Context.CursorY );
Context.CursorX += SizeX;
}
}
Context.CursorY += YMovement;
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::PrintString(FPrintContext& Context, const FColor& InColor, const FString& InString )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
PrintString(Context, FString::Printf(TEXT("{%s}%s"), *InColor.ToString(), *InString));
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
}
void AGameplayDebuggingHUDComponent::PrintString(FPrintContext& Context, const FColor& InColor, const FString& InString, float X, float Y )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
const float OldX = Context.CursorX, OldY = Context.CursorY;
const float OldDX = Context.DefaultX, OldDY = Context.DefaultY;
Context.DefaultX = Context.CursorX = X;
Context.DefaultY = Context.CursorY = Y;
PrintString(Context, InColor, InString);
Context.CursorX = OldX;
Context.CursorY = OldY;
Context.DefaultX = OldDX;
Context.DefaultY = OldDY;
#endif
}
void AGameplayDebuggingHUDComponent::CalulateStringSize(const AGameplayDebuggingHUDComponent::FPrintContext& DefaultContext, UFont* Font, const FString& InString, float& OutX, float& OutY )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
FString String = InString;
const FRegexPattern ElementRegexPattern(TEXT("\\{.*?\\}"));
FRegexMatcher ElementRegexMatcher(ElementRegexPattern, String);
while (ElementRegexMatcher.FindNext())
{
int32 AttributeListBegin = ElementRegexMatcher.GetCaptureGroupBeginning(0);
int32 AttributeListEnd = ElementRegexMatcher.GetCaptureGroupEnding(0);
String.RemoveAt(AttributeListBegin, AttributeListEnd - AttributeListBegin);
ElementRegexMatcher = FRegexMatcher(ElementRegexPattern, String);
}
OutX = OutY = 0;
if (DefaultContext.Canvas != NULL)
{
DefaultContext.Canvas->StrLen(Font != NULL ? Font : DefaultContext.Font, String, OutX, OutY);
}
#endif
}
void AGameplayDebuggingHUDComponent::CalulateTextSize(const AGameplayDebuggingHUDComponent::FPrintContext& DefaultContext, UFont* Font, const FText& InText, float& OutX, float& OutY)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
CalulateStringSize(DefaultContext, Font, InText.ToString(), OutX, OutY);
#endif
}
FVector AGameplayDebuggingHUDComponent::ProjectLocation(const AGameplayDebuggingHUDComponent::FPrintContext& Context, const FVector& Location)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (Context.Canvas != NULL)
{
return Context.Canvas->Project(Location);
}
#endif
return FVector();
}
void AGameplayDebuggingHUDComponent::DrawItem(const AGameplayDebuggingHUDComponent::FPrintContext& DefaultContext, class FCanvasItem& Item, float X, float Y )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (DefaultContext.Canvas)
{
DefaultContext.Canvas->DrawItem( Item, FVector2D( X, Y ) );
}
#endif
}
void AGameplayDebuggingHUDComponent::DrawIcon(const AGameplayDebuggingHUDComponent::FPrintContext& DefaultContext, const FColor& InColor, const FCanvasIcon& Icon, float X, float Y, float Scale)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (DefaultContext.Canvas)
{
DefaultContext.Canvas->SetDrawColor(InColor);
DefaultContext.Canvas->DrawIcon(Icon, X, Y, Scale);
}
#endif
}