Custom gameplay debugger category in Unreal Engine

Posted on Feb 18, 2020

Motivation

Debugging your game data and visualizing it is a very powerful tool. Epic is using it widely for AI debugging purposes (AI, Behavior Tree, EQS) as well as GAS (Gameplay Ability System). However, it is not tight up to any module and can be used with arbitrary module and data. Unfortunately, documentation for Gameplay Debugger is obsolete and a lot of components no longer exist in Unreal’s codebase.

Creating a new category

  1. Gameplay debugger is implemented in its dedicated module, make sure it is included in your dependencies (.Build.cs file).
  2. Create a class inheriting FGameplayDebuggerCategory. Make sure it’s surrounded by #if WITH_GAMEPLAY_DEBUGGER, otherwise it may fail to compile in the Shipping configuration.
  3. Override void CollectData(APlayerController* OwnerPC, AActor* DebugActor) function. Use this function to collect data you want to use or display.
  4. Override DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext) function. Use this function to draw data on screen.
  5. Create a static function for creating an instance, static TSharedRef<FGameplayDebuggerCategory> MakeInstance(). It will be used to register a new category to the gameplay debugger.
  6. Create a nested structure that will be used to store and serialize all the data.

Here is an example code for GameplayDebuggerCategory_Generic class:

#pragma once

#if WITH_GAMEPLAY_DEBUGGER

#include "CoreMinimal.h"
#include "GameplayDebuggerCategory.h"

class APlayerController;
class AActor;

class FGameplayDebuggerCategory_Generic : public FGameplayDebuggerCategory
{
public:
	FGameplayDebuggerCategory_Generic();
	virtual void CollectData(APlayerController* OwnerPC, AActor* DebugActor) override;
	virtual void DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext) override;
	
	static TSharedRef<FGameplayDebuggerCategory> MakeInstance();
	
protected:
	struct FRepData
	{
		// Put all data you want to display here
		FString ActorName;
		
		void Serialize(FArchive& Ar);
	};
	
	FRepData DataPack;
};

#endif // WITH_GAMEPLAY_DEBUGGER

Here is corresponding implementation file:

#include "GameplayDebuggerCategory_Generic.h"

#if WITH_GAMEPLAY_DEBUGGER

#include "GameFramework/Actor.h"
#include "GameFramework/PlayerController.h"

FGameplayDebuggerCategory_Generic::FGameplayDebuggerCategory_Generic()
{
    SetDataPackReplication<FRepData>(&DataPack);
}

void FGameplayDebuggerCategory_Generic::CollectData(APlayerController* OwnerPC, AActor* DebugActor)
{
    if (OwnerPC)
    {
        DataPack.ActorName = OwnerPC->GetPawn()->GetName();
    }
}

void FGameplayDebuggerCategory_Generic::DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext)
{
    if (!DataPack.ActorName.IsEmpty())
    {
        CanvasContext.Printf(TEXT("{yellow}Actor name: {white}%s"), *DataPack.ActorName);
    }
}

TSharedRef<FGameplayDebuggerCategory> FGameplayDebuggerCategory_Generic::MakeInstance()
{
    return MakeShareable(new FGameplayDebuggerCategory_Generic());
}

void FGameplayDebuggerCategory_Generic::FRepData::Serialize(FArchive& Ar)
{
    Ar << ActorName;
}

#endif // WITH_GAMEPLAY_DEBUGGER

Adding a category to gameplay debugger

The following steps are executed in the module’s startup function (I have not tested if it’s possible to add or remove a category at any other time).

To add a category to the gameplay debugger simply get the gameplay debugger module and call the RegisterCategory function and then NotifyCategoriesChanged.

Here is an example code registering a new category:

#if WITH_GAMEPLAY_DEBUGGER
    IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get();
	GameplayDebuggerModule.RegisterCategory(
        "Generic",
        IGameplayDebugger::FOnGetCategory::CreateStatic(
            &FGameplayDebuggerCategory_Generic::MakeInstance),
        EGameplayDebuggerCategoryState::EnabledInGameAndSimulate, 
        1);
	GameplayDebuggerModule.NotifyCategoriesChanged();
#endif

Settings

Some settings regarding default display and hotkeys are available under the Gameplay Debugger tab in Project Settings.