Files
UnrealEngineUWP/Engine/Source/Runtime/AIModule/Private/EnvironmentQuery/EnvQueryDebugHelpers.cpp
ryan durand 0f0464a30e Updating copyright for Engine Runtime.
#rnx
#rb none


#ROBOMERGE-OWNER: ryan.durand
#ROBOMERGE-AUTHOR: ryan.durand
#ROBOMERGE-SOURCE: CL 10869210 via CL 10869511 via CL 10869900
#ROBOMERGE-BOT: (v613-10869866)

[CL 10870549 by ryan durand in Main branch]
2019-12-26 14:45:42 -05:00

239 lines
8.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "EnvironmentQuery/EnvQueryDebugHelpers.h"
#include "Serialization/MemoryWriter.h"
#include "Serialization/MemoryReader.h"
#include "EnvironmentQuery/EnvQueryGenerator.h"
#include "EnvironmentQuery/EnvQueryTest.h"
#include "VisualLoggerExtension.h"
#include "EnvironmentQuery/EQSRenderingComponent.h"
#if USE_EQS_DEBUGGER
void UEnvQueryDebugHelpers::QueryToBlobArray(FEnvQueryInstance& Query, TArray<uint8>& BlobArray, bool bUseCompression)
{
EQSDebug::FQueryData EQSLocalData;
UEnvQueryDebugHelpers::QueryToDebugData(Query, EQSLocalData);
DebugDataToBlobArray(EQSLocalData, BlobArray, bUseCompression);
}
void UEnvQueryDebugHelpers::DebugDataToBlobArray(EQSDebug::FQueryData& EQSLocalData, TArray<uint8>& BlobArray, bool bUseCompression)
{
if (!bUseCompression)
{
FMemoryWriter ArWriter(BlobArray);
ArWriter << EQSLocalData;
}
else
{
TArray<uint8> UncompressedBuffer;
FMemoryWriter ArWriter(UncompressedBuffer);
ArWriter << EQSLocalData;
const int32 UncompressedSize = UncompressedBuffer.Num();
const int32 HeaderSize = sizeof(int32);
BlobArray.Init(0, HeaderSize + FMath::TruncToInt(1.1f * UncompressedSize));
int32 CompressedSize = BlobArray.Num() - HeaderSize;
uint8* DestBuffer = BlobArray.GetData();
FMemory::Memcpy(DestBuffer, &UncompressedSize, HeaderSize);
DestBuffer += HeaderSize;
FCompression::CompressMemory(NAME_Zlib, (void*)DestBuffer, CompressedSize, (void*)UncompressedBuffer.GetData(), UncompressedSize, COMPRESS_BiasMemory);
BlobArray.SetNum(CompressedSize + HeaderSize, false);
}
}
void UEnvQueryDebugHelpers::QueryToDebugData(FEnvQueryInstance& Query, EQSDebug::FQueryData& EQSLocalData, int32 MaxItemsToStore)
{
// step 1: data for rendering component
EQSLocalData.Reset();
FEQSSceneProxy::CollectEQSData(&Query, &Query, 1.0f, true, EQSLocalData.SolidSpheres, EQSLocalData.Texts, EQSLocalData.RenderDebugHelpers);
// step 2: detailed scoring data for HUD
const int32 FirstItemIndex = 0;
const int32 NumTests = Query.ItemDetails.IsValidIndex(0) ? Query.ItemDetails[0].TestResults.Num() : 0;
const int32 NumItems = FMath::Min(MaxItemsToStore, Query.NumValidItems);
EQSLocalData.Name = Query.QueryName;
EQSLocalData.Id = Query.QueryID;
EQSLocalData.Items.Reset(NumItems);
EQSLocalData.Tests.Reset(NumTests);
EQSLocalData.NumValidItems = Query.NumValidItems;
UEnvQueryItemType* ItemCDO = Query.ItemType.GetDefaultObject();
for (int32 ItemIdx = 0; ItemIdx < NumItems; ItemIdx++)
{
EQSDebug::FItemData ItemInfo;
ItemInfo.ItemIdx = ItemIdx + FirstItemIndex;
ItemInfo.TotalScore = Query.Items[ItemInfo.ItemIdx].Score;
const uint8* ItemData = Query.RawData.GetData() + Query.Items[ItemInfo.ItemIdx].DataOffset;
ItemInfo.Desc = FString::Printf(TEXT("[%d] %s"), ItemInfo.ItemIdx, *ItemCDO->GetDescription(ItemData));
ItemInfo.TestValues.Reserve(NumTests);
ItemInfo.TestScores.Reserve(NumTests);
for (int32 TestIdx = 0; TestIdx < NumTests; TestIdx++)
{
const float ScoreN = Query.ItemDetails[ItemInfo.ItemIdx].TestResults[TestIdx];
const float ScoreW = Query.ItemDetails[ItemInfo.ItemIdx].TestWeightedScores[TestIdx];
ItemInfo.TestValues.Add(ScoreN);
ItemInfo.TestScores.Add(ScoreW);
}
EQSLocalData.Items.Add(ItemInfo);
}
const int32 NumAllTests = Query.Options[Query.OptionIndex].Tests.Num();
for (int32 TestIdx = 0; TestIdx < NumAllTests; TestIdx++)
{
EQSDebug::FTestData TestInfo;
UEnvQueryTest* TestOb = Query.Options[Query.OptionIndex].Tests[TestIdx];
TestInfo.ShortName = TestOb->GetDescriptionTitle().ToString();
TestInfo.Detailed = TestOb->GetDescriptionDetails().ToString().Replace(TEXT("\n"), TEXT(", "));
EQSLocalData.Tests.Add(TestInfo);
}
EQSLocalData.UsedOption = Query.OptionIndex;
const int32 NumOptions = Query.Options.Num();
for (int32 OptionIndex = 0; OptionIndex < NumOptions; ++OptionIndex)
{
const FString UserName = Query.Options[OptionIndex].Generator->OptionName;
EQSLocalData.Options.Add(UserName.Len() > 0 ? UserName : Query.Options[OptionIndex].Generator->GetName());
}
}
void UEnvQueryDebugHelpers::BlobArrayToDebugData(const TArray<uint8>& BlobArray, EQSDebug::FQueryData& EQSLocalData, bool bUseCompression)
{
if (!bUseCompression)
{
FMemoryReader ArReader(BlobArray);
ArReader << EQSLocalData;
}
else
{
TArray<uint8> UncompressedBuffer;
int32 UncompressedSize = 0;
const int32 HeaderSize = sizeof(int32);
uint8* SrcBuffer = (uint8*)BlobArray.GetData();
FMemory::Memcpy(&UncompressedSize, SrcBuffer, HeaderSize);
SrcBuffer += HeaderSize;
const int32 CompressedSize = BlobArray.Num() - HeaderSize;
UncompressedBuffer.AddZeroed(UncompressedSize);
FCompression::UncompressMemory(NAME_Zlib, (void*)UncompressedBuffer.GetData(), UncompressedSize, SrcBuffer, CompressedSize);
FMemoryReader ArReader(UncompressedBuffer);
ArReader << EQSLocalData;
}
}
#endif //ENABLE_VISUAL_LOG
#if ENABLE_VISUAL_LOG && USE_EQS_DEBUGGER
#define PRINT_TABLE_ROW(__src__, __dst__, __len__) \
{ \
const FString DataToPrint = __src__; \
__dst__ += DataToPrint; \
for (int32 i = DataToPrint.Len(); i < __len__; i++) __dst__ += FString::Printf(TEXT(" ")); \
}
namespace
{
static void DrawEQSItemDetails(const EQSDebug::FQueryData& EQSLocalData, int32 ItemIdx, FVisualLogLine& LogLine)
{
const EQSDebug::FItemData& ItemData = EQSLocalData.Items[ItemIdx];
PRINT_TABLE_ROW(ItemData.Desc, LogLine.Line, 27);
PRINT_TABLE_ROW(FString::Printf(TEXT(" | %.2f"), ItemData.TotalScore), LogLine.Line, 8);
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);
PRINT_TABLE_ROW(FString(TEXT(" | ")) + DescScoreW + FString(" ") + DescScoreN, LogLine.Line, 15);
}
}
}
void UEnvQueryDebugHelpers::LogQueryInternal(FEnvQueryInstance& Query, const FName& CategoryName, ELogVerbosity::Type Verbosity, float TimeSeconds, FVisualLogEntry *CurrentEntry)
{
const int32 UniqueId = FVisualLogger::Get().GetUniqueId(TimeSeconds);
EQSDebug::FQueryData EQSLocalData;
UEnvQueryDebugHelpers::QueryToDebugData(Query, EQSLocalData);
TArray<uint8> BlobArray;
DebugDataToBlobArray(EQSLocalData, BlobArray);
const FString AdditionalLogInfo = FString::Printf(TEXT("Executed EQS: \n - Name: '%s' (id=%d, option=%d),\n - All Items: %d,\n - ValidItems: %d"), *Query.QueryName, Query.QueryID, Query.OptionIndex, Query.ItemDetails.Num(), Query.NumValidItems);
FVisualLogLine Line(CategoryName, Verbosity, AdditionalLogInfo, Query.QueryID);
Line.TagName = *EVisLogTags::TAG_EQS;
Line.UniqueId = UniqueId;
CurrentEntry->AddDataBlock(EVisLogTags::TAG_EQS, BlobArray, CategoryName, Verbosity).UniqueId = UniqueId;
if (EQSLocalData.NumValidItems > 0)
{
const int32 NumTests = EQSLocalData.Tests.Num();
Line.Line += FString(TEXT("\n"));
// draw test weights for best X items
const int32 NumItems = EQSLocalData.Items.Num();
// print sorted tests' descriptions, to be able to tie TestIdx with an actual test
const FEnvQueryOptionInstance& Option = Query.Options[Query.OptionIndex];
for (int32 TestIdx = 0; TestIdx < NumTests; TestIdx++)
{
Line.Line += FString::Printf(TEXT("%d: %s\n"), TestIdx, *Option.Tests[TestIdx]->GetDescriptionTitle().ToString());
}
// table header
{
FString HeaderString;
PRINT_TABLE_ROW(FString::Printf(TEXT("Item "), EQSLocalData.NumValidItems), HeaderString, 27);
PRINT_TABLE_ROW(FString::Printf(TEXT(" | Score"), EQSLocalData.NumValidItems), HeaderString, 8);
for (int32 TestIdx = 0; TestIdx < NumTests; TestIdx++)
{
PRINT_TABLE_ROW(FString::Printf(TEXT(" | Test %d "), TestIdx), HeaderString, 15);
}
Line.Line += HeaderString;
}
Line.Line += FString(TEXT("\n"));
// valid items
for (int32 Idx = 0; Idx < NumItems; Idx++)
{
DrawEQSItemDetails(EQSLocalData, Idx, Line);
Line.Line += FString(TEXT("\n"));
}
}
CurrentEntry->LogLines.Add(Line);
}
#undef PRINT_TABLE_ROW
#endif //ENABLE_VISUAL_LOG && USE_EQS_DEBUGGER