This class can be used to create custom Gameplay Debugger categories. It’s recommended to have these in a separate editor-only module.
Registering a custom category
You can register the category for example in a custom editor module’s StartupModule
:
#if WITH_GAMEPLAY_DEBUGGER
IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
GameplayDebuggerModule.RegisterCategory(
"Tapegame",
IGameplayDebugger::FOnGetCategory::CreateStatic(&FGameplayDebuggerCategory_Tapegame::MakeInstance),
EGameplayDebuggerCategoryState::EnabledInGameAndSimulate
);
GameplayDebuggerModule.NotifyCategoriesChanged();
#endif
You can also unregister the category in ShutdownModule. The name should match the one you registered.
#if WITH_GAMEPLAY_DEBUGGER
if (IGameplayDebugger::IsAvailable())
{
IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
GameplayDebuggerModule.UnregisterCategory("CategoryName");
GameplayDebuggerModule.NotifyCategoriesChanged();
}
#endif
Implementing a custom category
The category needs two functions: CollectData
and DrawData
. Override them from the base class. They are called automatically, with the call interval determined by CollectDataInterval
(by default, called every tick).
The category is expected to have a “replication data pack” - a struct which stores all the debug data this category uses. The implementation example below shows how this is used.
The DrawData
function receives a FGameplayDebuggerCanvasContext
parameter. This contains a number of functions that can be used to display the data. For example, using Printf
will display it in the debugger’s section of the UI. You can also do more complex things, such as overlaying the information on an actor:
//assuming D is a struct which contains a Position FVector
//which is some actor's location in the world
const FVector2D Loc = CanvasContext.ProjectLocation(D.Position);
CanvasContext.PrintfAt(
Loc.X,
Loc.Y,
TEXT("Satisfaction: %d\nTags: %s"),
D.SatisfactionLevel,
*FString::Join(D.Tags, TEXT(", "))
);
Category implementation example
#pragma once
#if WITH_GAMEPLAY_DEBUGGER
#include "CoreMinimal.h"
#include "GameplayDebuggerCategory.h"
class GAMEJAMREWINDEDITOR_API FGameplayDebuggerCategory_Tapegame : public FGameplayDebuggerCategory
{
public:
FGameplayDebuggerCategory_Tapegame();
virtual void CollectData(APlayerController* OwnerPC, AActor* DebugActor) override;
virtual void DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext) override;
static TSharedRef<FGameplayDebuggerCategory> MakeInstance();
protected:
struct FRepData
{
float AverageRating = 0;
void Serialize(FArchive& Ar);
};
FRepData DataPack;
};
#endif
#include "GameplayDebuggerCategory_Tapegame.h"
#include "Core/TapeGameModeBase.h"
#include "GameFramework/PlayerController.h"
#include "Kismet/GameplayStatics.h"
#include "World/WorldManager.h"
#if WITH_GAMEPLAY_DEBUGGER
FGameplayDebuggerCategory_Tapegame::FGameplayDebuggerCategory_Tapegame()
{
CollectDataInterval = 5;
SetDataPackReplication<FRepData>(&DataPack);
}
void FGameplayDebuggerCategory_Tapegame::CollectData(APlayerController* OwnerPC, AActor* DebugActor)
{
if(!OwnerPC)
{
return;
}
const auto& GameMode = Cast<ATapeGameModeBase>(UGameplayStatics::GetGameMode(OwnerPC));
if(GameMode)
{
DataPack.AverageRating = GameMode->WorldManager->GetAverageCustomerStoreRatingPercentage();
}
}
void FGameplayDebuggerCategory_Tapegame::DrawData(APlayerController* OwnerPC,
FGameplayDebuggerCanvasContext& CanvasContext)
{
CanvasContext.Printf(TEXT("{yellow}Average rating: {white}%.2f%%"), DataPack.AverageRating * 100);
}
TSharedRef<FGameplayDebuggerCategory> FGameplayDebuggerCategory_Tapegame::MakeInstance()
{
return MakeShareable(new FGameplayDebuggerCategory_Tapegame());
}
void FGameplayDebuggerCategory_Tapegame::FRepData::Serialize(FArchive& Ar)
{
Ar << AverageRating;
}
#endif
Notes
CollectData
has a parameter DebugActor
. This is the actor which is currently selected in the editor - the user can detach and select another actor, which will become the debug actor.