GameplayMessageSystem

Overview of the GameplayMessageSystem

Updated 9 months ago Edit Page Revisions

The GameplayMessageSystem (also known as the GameplayMessageSubsystem, or GameplayMessageRouter) is a subsystem that allows otherwise unconnected gameplay objects to communicate with each other.

Table of Contents

  • About the GameplayMessageSystem
  • Enabling the GameplayMessageSystem
    • Dependencies of the GameplayMessageSubsystem
    • Up
  • Using the GameplayMessageSystem
    • Using the GameplayMessageSystem in C++
    • Using the GameplayMessageSystem in Blueprint
    • GameplayMessageSubsystem in Lyra

About the GameplayMessageSystem

Introduced with Unreal Engine 5.0, the GameplayMessageSystem provides a standalone and easily-extensible messaging system. Using this system gameplay objects can communicate with each other without needed to find direct references, assign delegates, or otherwise know about each other. Properly used, the GameplayMessageSystem can dramatically reduce interdependency between objects in your project.

Core Concepts

Broadcast

  • A gameplay object (typically an Actor) can Broadcast using the GameplayMessageSystem
  • The Broadcast will specify a Channel and a Message (filled out by the sender prior to broadcasting)
  • Broadcasters do not know which objects will receive their messages (if any)
  • Broadcasts are not network replicated unless explicitly replicated via RPC

Listener

  • A gameplay object (typically an Actor) can Listen using the GameplayMessageSystem
  • The Listener will specify a Channel to listen to, and a Callback function
    • The Callback function must have parameters for the Channel and Message
  • Listeners do not know which objects are Broadcasting messages (if any)

Channel

  • A Channel is a GameplayTag.
  • Both the Broadcaster and Listener must agree on a Channel if a message is to be received
  • You can arbitrarily define any GameplayTag as a Channel
    • To prevent future confusion, you might want to devise an organizational hierarchy for message channels

Message

  • A Message is a Structure[1]
  • Any USTRUCT is valid to use as a message, but both Broadcaster and Listener must agree on the type of structure used
  • Typically the Listener will utilize the data contained in the Message to perform an action

The Lyra example project uses a single FLyraVerbMessage structure for almost all Messages sent. This Message structure is shown below, and has enough information data fields to encompass most common gameplay events.

USTRUCT(BlueprintType)
struct FLyraVerbMessage
{
	GENERATED_BODY()

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	FGameplayTag Verb;

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	TObjectPtr<UObject> Instigator = nullptr;

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	TObjectPtr<UObject> Target = nullptr;

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	FGameplayTagContainer InstigatorTags;

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	FGameplayTagContainer TargetTags;

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	FGameplayTagContainer ContextTags;

	UPROPERTY(BlueprintReadWrite, Category=Gameplay)
	double Magnitude = 1.0;

	// Returns a debug string representation of this message
	LYRAGAME_API FString ToString() const;
};

Publish-Subscribe Model

If you are familiar with other Software Engineering patterns, you may recognize that the GameplayMessageSystem is an implementation of a Publish-Subscribe pattern (or pub-sub). For more information about this Software Design Pattern read here.

Why Use the GameplayMessageSystem

Benefits

  • Dramatically reduce interdependency between objects in your project
  • Eliminate linkage between User Interface and gameplay actors

Drawbacks

  • Decoupling objects can make it more challenging to know what might be triggering specific behaviors
  • Challenging to cleanly organize all of the GameplayTags required for the GameplayMessagingSystem

Additional Reading