Agent skill

Ue Gameplay Tags Messaging

by quodsoler in quodsoler/unreal-engine-skills

A skill your agent uses when defining, querying or replicating Gameplay Tags, or wiring decoupled event messaging between gameplay systems in C++.

MITAuto-check passedDatabases

Install Ue Gameplay Tags Messaging

skills CLI
$ npx skills add quodsoler/unreal-engine-skills --skill ue-gameplay-tags-messaging -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install quodsoler/unreal-engine-skills ue-gameplay-tags-messaging --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ue-gameplay-tags-messaging .claude/skills/ue-gameplay-tags-messaging && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
ue-gameplay-tags-messaging
GitHub stars
362
Token cost
~6.9k tokens
SKILL.md length
2,289 words
Files
3 (incl. references)
Skills in repo
31
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when defining, querying or replicating Gameplay Tags, or wiring decoupled event messaging between gameplay systems in C++.

  • Replicating Gameplay Tags
  • SKILL.md covers Context, Tag Sources, Native Tag Definitions and Ini and Data Table Tag Sources, plus 9 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • Wiring decoupled event messaging between gameplay systems in C++

What it does

Ue Gameplay Tags Messaging is an agent skill from quodsoler/unreal-engine-skills. Use when defining, querying or replicating Gameplay Tags, or wiring decoupled event messaging between gameplay systems in C++. Also use when the user mentions 'FGameplayTag', 'FGameplayTagContainer', 'FGameplayTagQuery', 'UEDEFINEGAMEPLAYTAG', 'native gameplay tag', 'DefaultGameplayTags.ini', 'GameplayTagList', 'tag redirect', 'MatchesTag', 'HasTagExact', 'RequestGameplayTag', 'UGameplayTagsManager', 'Categories meta', 'tag picker', 'gameplay message', 'message bus', 'event bus' or 'AsyncMessageSystem'. For…

Its SKILL.md is about 6.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 3 other files, including reference files (for example `references/gameplay-messaging.md` and `references/gameplay-tag-reference.md`).

It sits in Databases, covering Event-driven systems, On-page SEO and Database administration. It works with C++. The repository describes itself as: Unreal Engine C++ skills for AI coding agents. 27 skills covering gameplay, rendering, networking, animation, and more. Works with Claude Code, Cursor, Windsurf, and any agent… The licence is MIT.

When your agent uses it

  • Replicating Gameplay Tags
  • Wiring decoupled event messaging between gameplay systems in C++
  • The user mentions FGameplayTag
  • FGameplayTagContainer

Example prompts

  • “FGameplayTag”
  • “FGameplayTagContainer”
  • “FGameplayTagQuery”
  • “/ue-gameplay-tags-messaging”

What it can do on your machine

Read from SKILL.md and the folder at commit f3742d7. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are cpp and ini).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Ue Gameplay Tags Messaging loads about 6.9k tokens when it runs, and up to ~17k if it reads all its reference files. Until then it costs about 168 tokens; SKILL.md has 2,289 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~168
When it runs · the whole SKILL.md, loaded when a task matches
~6.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~17k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from quodsoler/unreal-engine-skills at commit f3742d7, republished under its MIT licence (© quodsoler). 2,289 words, ~6,940 tokens.

Download SKILL.mdSave it as .claude/skills/ue-gameplay-tags-messaging/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
ue-gameplay-tags-messaging
description
Use when defining, querying or replicating Gameplay Tags, or wiring decoupled event messaging between gameplay systems in C++. Also use when the user mentions 'FGameplayTag', 'FGameplayTagContainer', 'FGameplayTagQuery', 'UE_DEFINE_GAMEPLAY_TAG', 'native gameplay tag', 'DefaultGameplayTags.ini', 'GameplayTagList', 'tag redirect', 'MatchesTag', 'HasTagExact', 'RequestGameplayTag', 'UGameplayTagsManager', 'Categories meta', 'tag picker', 'gameplay message', 'message bus', 'event bus' or 'AsyncMessageSystem'. For abilities, effects and cues that consume tags, see ue-gameplay-abilities; for wire cost and RPCs, see ue-networking-replication.
metadata.version
2.0.0
metadata.engine
5.8

UE Gameplay Tags and Messaging

Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".

Gameplay Tags are a built-in runtime module, not a plugin: add "GameplayTags" to PublicDependencyModuleNames in your Build.cs and include GameplayTagContainer.h / NativeGameplayTags.h / GameplayTagsManager.h. This skill owns tag definition (native and ini), FGameplayTag, FGameplayTagContainer, FGameplayTagQuery, UGameplayTagsManager, editor filtering, and decoupled gameplay messaging — including the AsyncMessageSystem plugin (Experimental in 5.8).

Context

Read .agents/ue-project-context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.

Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.

Request is about…Go to
Declaring tags in C++, native tag macros, module setupNative Tag Definitions
Declaring tags in .ini, data tables, renaming a tagIni and Data Table Tag Sources
Testing a tag, container membership, parent vs exactMatching Semantics
Multi-tag conditions, AND/OR/NOT, designer-authored rulesTag Queries
Actors exposing tags, gates and states built from tagsTag-Driven Design
Sending tags over the network, tag cost, hot pathsReplication and Performance
Broadcasting events between systems without hard referencesDecoupled Messaging
Tag pickers, Categories filtering, per-team tag filesEditor UX and Filtering

Tag Sources

A tag must be registered before it can be requested. Four sources feed the one global dictionary held by UGameplayTagsManager:

SourceWhereUse for
NativeUE_DEFINE_GAMEPLAY_TAG* in a module .cppTags C++ compares against by name
Default iniConfig/DefaultGameplayTags.ini, +GameplayTagList=Tags authored by designers
Extra iniConfig/Tags/*.ini and plugin config dirsPer-team or per-plugin tag lists
Data tableUDataTable of FGameplayTagTableRow listed in GameplayTagTableListBulk import from a spreadsheet

EGameplayTagSourceType (Native, DefaultTagList, TagList, RestrictedTagList, DataTable, Invalid) names these in the editor. Tags are hierarchical: registering MyGame.State.Stunned implicitly registers MyGame.State and MyGame.

Native Tag Definitions

Declare in a public header, define in exactly one .cpp of the same module. The macros static_assert that they are used from a .cpp.

cpp
// MyGameplayTags.h
#pragma once

#include "NativeGameplayTags.h"

MYGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_MyGame_State_Stunned);
MYGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_MyGame_Damage_Fire);
MYGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_MyGame_Message_ScoreChanged);
cpp
// MyGameplayTags.cpp
#include "MyGameplayTags.h"

UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_MyGame_State_Stunned, "MyGame.State.Stunned", "Character cannot act");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_MyGame_Damage_Fire, "MyGame.Damage.Fire", "Fire damage channel");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_MyGame_Message_ScoreChanged, "MyGame.Message.ScoreChanged", "Score changed broadcast");
MacroParametersEffect
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TagName)extern FNativeGameplayTag TagName; — goes in the header, prefixed with your _API macro
UE_DEFINE_GAMEPLAY_TAG(TagName, Tag)Defines the variable with an empty dev comment
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TagName, Tag, Comment)Same plus a developer comment shown in the editor
UE_DEFINE_GAMEPLAY_TAG_STATIC(TagName, Tag)static — visible only inside that one .cpp, with no matching declaration in a header

Tag and Comment are bare string literals: the macro wraps Comment in TEXT() itself. Writing TEXT("…") there does not compile.

FNativeGameplayTag registers on static construction and unregisters when the module unloads, so tags from a plugin disappear cleanly with the plugin. It converts implicitly to FGameplayTag and also exposes GetTag():

cpp
const FGameplayTag Stunned = TAG_MyGame_State_Stunned.GetTag();
if (OwnedTags.HasTag(TAG_MyGame_State_Stunned))
{
    return;
}

One definition rule: exactly one UE_DEFINE_GAMEPLAY_TAG (or _COMMENT / _STATIC) per tag variable per binary. Two modules defining the same tag string is fine (the manager reference-counts registrations), but two definitions of the same variable is a link error, and a definition in a header breaks every translation unit that includes it.

To register a tag whose name is only known at runtime, call the manager directly:

cpp
const FGameplayTag Runtime = UGameplayTagsManager::Get().AddNativeGameplayTag(
    FName(TEXT("MyGame.Generated.Slot01")), TEXT("Generated at startup"));

AddNativeGameplayTag after startup invalidates fast replication (see Replication and Performance). Register from CallOrRegister_OnAddNativeTagsDelegate, and run code that consumes tags from CallOrRegister_OnDoneAddingNativeTagsDelegate:

cpp
// MyGameModule.cpp — FDelegateHandle NativeTagsHandle; is a member of FMyGameModule.
#include "MyGameModule.h"
#include "GameplayTagsManager.h"

void FMyGameModule::StartupModule()
{
    NativeTagsHandle = UGameplayTagsManager::CallOrRegister_OnDoneAddingNativeTagsDelegate(
        FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FMyGameModule::OnTagsReady));
}

void FMyGameModule::ShutdownModule()
{
    UGameplayTagsManager::UnregisterNativeTagDelegate(NativeTagsHandle);
}

If registration already finished, CallOrRegister_OnDoneAddingNativeTagsDelegate runs the delegate immediately and CallOrRegister_OnAddNativeTagsDelegate runs it at the end of the current module load (GameplayTagsManager.h:419-427), so there is no ordering hazard in calling them late.

Ini and Data Table Tag Sources

UGameplayTagsSettings is UCLASS(config=GameplayTags, defaultconfig) deriving from UGameplayTagsList, so Project Settings → Gameplay Tags writes Config/DefaultGameplayTags.ini:

ini
[/Script/GameplayTags.GameplayTagsSettings]
ImportTagsFromConfig=True
FastReplication=False
NumBitsForContainerSize=6
NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="MyGame.State.Stunned",DevComment="Character cannot act")
+GameplayTagList=(Tag="MyGame.Damage.Fire",DevComment="Fire damage channel")
+GameplayTagTableList=/Game/Data/DT_MyGameTags.DT_MyGameTags
+GameplayTagRedirects=(OldTagName="MyGame.State.Stun",NewTagName="MyGame.State.Stunned")
KeyTypeMeaning
ImportTagsFromConfigboolMaster switch for ini-defined tags; read back through UGameplayTagsManager::ShouldImportTagsFromINI()
GameplayTagListTArray<FGameplayTagTableRow>Tag (FName) plus DevComment (FString)
GameplayTagTableListTArray<FSoftObjectPath>Data tables of FGameplayTagTableRow, loaded by LoadGameplayTagTables
GameplayTagRedirectsTArray<FGameplayTagRedirect>OldTagName → NewTagName; inherited from UGameplayTagsList
CategoryRemappingTArray<FGameplayTagCategoryRemap>Remaps an engine Categories filter onto project categories
RestrictedConfigFilesTArray<FRestrictedConfigInfo>Top-level tags only a named owner may edit
InvalidTagCharactersFStringCharacters rejected in tag names, beyond newline and friends

Extra ini sources live in Config/Tags/ (added automatically) and in any directory passed to UGameplayTagsManager::Get().AddTagIniSearchPath(RootDir); RemoveTagIniSearchPath takes them away again. A Game Feature plugin's config directory is registered this way, which is why its tags appear only while the plugin is active.

Renaming a tag requires a redirect. FGameplayTagRedirect is { OldTagName, NewTagName }; FGameplayTagRedirectors::Get().RedirectTag(OldName, OutTag) is what serialization uses (engine-internal: the class is not exported). Without a redirect, every asset that referenced the old name silently loads an invalid tag.

Full ini and data-table details are in gameplay-tag-reference.md.

Matching Semantics

FGameplayTag is one FName. A container keeps the explicitly added tags plus a transient expanded parent list, so parent-aware checks are array lookups, not string parsing.

CallReceiverSemantics{"A.1"} vs A
MatchesTag(TagToCheck)FGameplayTagThis tag or any parent equals TagToCheckA.1.MatchesTag(A) → true; A.MatchesTag(A.1) → false
MatchesTagExact(TagToCheck)FGameplayTagNames equalA.1.MatchesTagExact(A) → false
MatchesAny(ContainerToCheck)FGameplayTagParent-expanded match against any tag in the containerA.1.MatchesAny({A,B}) → true
MatchesAnyExact(ContainerToCheck)FGameplayTagContainer explicitly holds this tagA.1.MatchesAnyExact({A,B}) → false
HasTag(TagToCheck)FGameplayTagContainerExplicit or parent list contains it{A.1}.HasTag(A) → true
HasTagExact(TagToCheck)FGameplayTagContainerExplicit list only{A.1}.HasTagExact(A) → false
HasAny / HasAnyExactFGameplayTagContainerAt least one; false for an empty argument{A.1}.HasAny({A,B}) → true
HasAll / HasAllExactFGameplayTagContainerAll; true for an empty argument{A.1,B.1}.HasAll({A,B}) → true
Filter(OtherContainer)FGameplayTagContainerNew container of tags matching any tag in OtherContainer, parents expanded{A.1,C}.Filter({A}) → {A.1}
FilterExact(OtherContainer)FGameplayTagContainerTrue intersection, exact names{A.1,C}.FilterExact({A}) → {}

The empty-argument asymmetry is deliberate: "any of nothing" is false, "all of nothing" is true. Gates written as RequiredTags.IsEmpty() || Owned.HasAll(RequiredTags) are redundant.

cpp
FGameplayTagContainer MakeStateTags(const FGameplayTagContainer& ExtraTags)
{
    FGameplayTagContainer Owned;
    Owned.AddTag(TAG_MyGame_State_Stunned);    // checks uniqueness and refills parents
    Owned.AddTagFast(TAG_MyGame_Damage_Fire);  // no uniqueness check — only when the tag is known to be new
    Owned.AppendTags(ExtraTags);
    Owned.RemoveTag(TAG_MyGame_State_Stunned);

    if (!Owned.IsEmpty())
    {
        UE_LOG(LogMyGame, Log, TEXT("%d tags, first %s, last %s: %s"),
            Owned.Num(), *Owned.First().ToString(), *Owned.Last().ToString(), *Owned.ToStringSimple());
    }

    return Owned;
}

Parent navigation: FGameplayTag::RequestDirectParent() returns x for x.y, FGameplayTag::GetGameplayTagParents() returns a container holding the tag plus every parent, and FGameplayTagContainer::GetGameplayTagParents() does the same for a whole container. ParseParentTags(TArray<FGameplayTag>&) does it without touching the manager.

AddTagFast skips the Contains check but still fills parents; use it when building a container from data you already know is unique, never in place of AddTag on user input.

Tag Queries

FGameplayTagQuery is a compiled token stream — cheap to evaluate, expensive to build. Build it once, store it, evaluate it many times.

cpp
// MyBurnRule.cpp
#include "GameplayTagContainer.h"
#include "MyGameplayTags.h"

bool ShouldBurn(const FGameplayTagContainer& OwnedTags)
{
    FGameplayTagContainer Elements;
    Elements.AddTag(TAG_MyGame_Damage_Fire);

    // (any element tag) AND NOT Stunned
    FGameplayTagQuery ComplexQuery = FGameplayTagQuery::BuildQuery(
        FGameplayTagQueryExpression()
            .AllExprMatch()
            .AddExpr(FGameplayTagQueryExpression().AnyTagsMatch().AddTags(Elements))
            .AddExpr(FGameplayTagQueryExpression().NoTagsMatch().AddTag(TAG_MyGame_State_Stunned)));

    return ComplexQuery.Matches(OwnedTags);
}

The shortcut form covers the common cases without an expression tree:

cpp
FGameplayTagContainer Blocking;
Blocking.AddTag(TAG_MyGame_State_Stunned);
const FGameplayTagQuery BlockedQuery = FGameplayTagQuery::MakeQuery_MatchAnyTags(Blocking);

Shortcuts on FGameplayTagQuery: MakeQuery_MatchAnyTags, MakeQuery_MatchAllTags, MakeQuery_MatchNoTags, MakeQuery_ExactMatchAnyTags, MakeQuery_ExactMatchAllTags, MakeQuery_MatchTag. Expression verbs on FGameplayTagQueryExpression: AnyTagsMatch, AllTagsMatch, NoTagsMatch, AnyTagsExactMatch, AllTagsExactMatch, AnyExprMatch, AllExprMatch, NoExprMatch, fed by AddTag, AddTags and AddExpr.

Evaluate from either side — Query.Matches(Container) or Container.MatchesQuery(Query). Both call the same evaluator.

Expose a query as a UPROPERTY and designers get the query editor with no extra work:

cpp
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Gating")
FGameplayTagQuery ActivationQuery;

ReplaceTagsFast(Tags) and ReplaceTagFast(Tag) swap the tag dictionary of a cached query without rebuilding the token stream; the new container must be the same size.

Tag-Driven Design

Anything that owns tags should expose them through IGameplayTagAssetInterface so unrelated systems can ask without casting:

cpp
// MyTaggedActor.h
#pragma once

#include "GameFramework/Actor.h"
#include "GameplayTagAssetInterface.h"
#include "GameplayTagContainer.h"
#include "MyTaggedActor.generated.h"

UCLASS()
class MYGAME_API AMyTaggedActor : public AActor, public IGameplayTagAssetInterface
{
    GENERATED_BODY()

public:
    virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override;

protected:
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tags", meta = (Categories = "MyGame.State"))
    FGameplayTagContainer OwnedTags;
};
cpp
// MyTaggedActor.cpp
#include "MyTaggedActor.h"

void AMyTaggedActor::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
{
    TagContainer.AppendTags(OwnedTags);
}

HasMatchingGameplayTag, HasAllMatchingGameplayTags and HasAnyMatchingGameplayTags come from the interface for free — they call your GetOwnedGameplayTags. From Blueprint the equivalents are UBlueprintGameplayTagLibrary::DoesTagAssetInterfaceHaveTag, HasAnyMatchingGameplayTags and GetOwnedGameplayTags.

Counted tags: an FGameplayTagContainer is a set, so two sources granting Stunned and one removing it leaves nothing. When several sources can grant the same tag, use FGameplayTagCountContainer (GameplayEffectTypes.h:1102, in the GameplayAbilities plugin; it is what an ASC uses for owned tags). UpdateTagCount(Tag, +1/-1, EGameplayTagReplicationState::None) adjusts the count (the single-tag overload has no default for the third argument; UpdateTagCount(Container, Delta) takes two), GetTagCount(Tag) includes child tags (A.B and A.C added make GetTagCount(A) == 2), GetExplicitTagCount does not, GetExplicitGameplayTags() returns the current set for GetOwnedGameplayTags, and RegisterGameplayTagEvent(Tag, EGameplayTagEventType::NewOrRemoved | AnyCountChange) returns an FOnGameplayEffectTagCountChanged (void(const FGameplayTag, int32 NewCount)) to bind. With GAS in the project, use the ASC's loose tags instead of owning one.

Design rules that hold up:

  • Tags name states and categories, not objects. MyGame.State.Stunned and MyGame.Damage.Fire are good; MyGame.Actor.Goblin03 is a class reference wearing a tag.
  • Depth is the query. Keep the hierarchy shallow enough that HasTag(MyGame.Damage) is a meaningful question.
  • Author the gate, not the branch. Expose FGameplayTagContainer or FGameplayTagQuery properties and let data decide, instead of if (Tag == SpecificTag) chains.
  • Never store a tag as FName or FString on a gameplay type. Store FGameplayTag; it validates, redirects and replicates.
Show full SKILL.md (997 more words)Show less

Replication and Performance

An FGameplayTag is a single FName — copy it freely, pass it by value. Cost lives in registration and in serialization.

ConcernRule
LookupRequestGameplayTag walks a map every call. Resolve once into a native tag or a member, never per tick or per hit
Container build-upAddTag refills the parent array each call; AddTagFast skips the uniqueness check; FGameplayTagContainer::CreateFromArray builds parents once for a whole array
Wire formatFGameplayTag::NetSerialize and FGameplayTagContainer::NetSerialize are registered via TStructOpsTypeTraits — a replicated tag property already uses them
FastReplication=TrueReplicates tags by net index instead of name. Client and server dictionaries must be identical, so it breaks if a plugin adds tags on only one side
bDynamicReplication=TruePer-connection index assignment; slightly more expensive than FastReplication but tolerates differing dictionaries. Ignored when FastReplication is on
NetIndexFirstBitSegmentBits in the first index segment; tags listed in CommonlyReplicatedTags get the low indices and fit in one segment
NumBitsForContainerSizeBits used for a replicated container's element count — size it to your real containers

UGameplayTagsManager::Get().DoneAddingNativeTags() flushes native registration; after it, adding more tags is unsafe with fast replication because the net index table has already been built and hashed (GetNetworkGameplayTagNodeIndexHash).

For the wire cost of the properties that carry these containers, and for push-model replication, see ue-networking-replication.

Decoupled Messaging

Pick the lightest mechanism that fits:

NeedUse
A few known listeners inside one gameA dynamic multicast delegate on a UGameInstanceSubsystem or UWorldSubsystem
Tag-addressed, hierarchical, cross-thread, typed payloadsAsyncMessageSystem plugin (Experimental in 5.8)
Ability activation and GAS-side eventsSendGameplayEventToActor / RegisterGameplayTagEvent, owned by ue-gameplay-abilities

A dynamic multicast delegate on a subsystem is often enough, and it costs nothing extra:

cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMyScoreChanged, AActor*, Scorer, int32, NewScore);

UPROPERTY(BlueprintAssignable, Category = "Score")
FMyScoreChanged OnScoreChanged;

Reach for AsyncMessageSystem when listeners must be addressed by tag hierarchy or must run off the game thread. Enable the plugin in the .uproject and add "AsyncMessageSystem" to PublicDependencyModuleNames; it already depends on GameplayTags. The recipe, verbatim signatures, binding options and endpoints are in gameplay-messaging.md.

cpp
// MyScorePayload.h
#pragma once

#include "StructUtils/InstancedStruct.h"
#include "MyScorePayload.generated.h"

USTRUCT()
struct FMyScorePayload
{
    GENERATED_BODY()

    UPROPERTY()
    int32 NewScore = 0;
};
cpp
// MyScoreComponent.cpp — queue side
#include "AsyncMessageWorldSubsystem.h"
#include "AsyncMessageSystemBase.h"
#include "MyGameplayTags.h"
#include "MyScorePayload.h"

void UMyScoreComponent::BroadcastScore(int32 NewScore)
{
    TSharedPtr<FAsyncMessageSystemBase> Sys = UAsyncMessageWorldSubsystem::GetSharedMessageSystem(GetWorld());
    if (!Sys.IsValid())
    {
        return;
    }

    FMyScorePayload Payload;
    Payload.NewScore = NewScore;
    Sys->QueueMessageForBroadcast(FAsyncMessageId(TAG_MyGame_Message_ScoreChanged.GetTag()),
        FInstancedStruct::Make<FMyScorePayload>(Payload));
}

Not in the engine: UGameplayMessageSubsystem and its GameplayMessageRouter are Lyra sample code, copied into the Lyra project, not shipped in Engine/. Do not #include "GameFramework/GameplayMessageSubsystem.h" — it does not resolve. Port the Lyra files into your own module, or use AsyncMessageSystem.

Editor UX and Filtering

meta = (Categories = "…") restricts a tag picker to one subtree. The metadata keys are Categories and GameplayTagFilter, declared in namespace GameplayTagsManager in ObjectMacros.h:

cpp
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Damage", meta = (Categories = "MyGame.Damage"))
FGameplayTag DamageType;

UFUNCTION(BlueprintCallable, Category = "Damage")
void ApplyElement(UPARAM(meta = (GameplayTagFilter = "MyGame.Damage")) FGameplayTag Element);

UGameplayTagsManager::GetCategoriesMetaFromField reads Categories first and falls back to GameplayTagFilter; GetCategoriesMetaFromFunction(Func, ParamName) is what resolves the filter for a Blueprint pin. Both accept a comma-separated list of roots.

FGameplayTagCategoryRemap (BaseCategory → RemapCategories) in UGameplayTagsSettings redirects an engine-side filter such as a Mover or GAS Categories value onto your own subtree, so engine properties show your tags. UGameplayTagsDeveloperSettings (config=EditorPerProjectUserSettings) holds the per-user FavoriteTagSource and DeveloperConfigName used when adding a new tag from the picker. IGameplayTagsModule::OnGameplayTagTreeChanged and OnTagSettingsChanged let editor tooling refresh when the dictionary changes.

Deprecated — do not use

Do not emitUse in 5.8Source
UGameplayTagsManager::OnLastChanceToAddNativeTags()CallOrRegister_OnAddNativeTagsDelegate, or AddNativeGameplayTag directlyUE_DEPRECATED(5.8) in GameplayTagsManager.h:415
CallOrRegister_OnDoneAddingNativeTagsCallOrRegister_OnDoneAddingNativeTagsDelegateName never existed; GameplayTagsManager.h:429
UGameplayTagsManager::GetSingleTagContainer(Tag)FindTagNode(Tag) or FGameplayTag::GetSingleTagContainer()UE_DEPRECATED(5.4) in GameplayTagsManager.h:472
FGameplayTagContainer::AddParentsForTagParseParentTags or UGameplayTagsManager::ExtractParentTagsUE_DEPRECATED(5.4) in GameplayTagContainer.h:615
UGameplayTagsManager::ShouldClearInvalidTags()Nothing — invalid tags are never clearedUE_DEPRECATED(5.5) in GameplayTagsManager.h:594
ClearInvalidTags ini keyRemove itUE_DEPRECATED(5.5) in GameplayTagsSettings.h:115
+GameplayTagRedirects under [/Script/Engine.Engine]Same key under [/Script/GameplayTags.GameplayTagsSettings]"deprecated location" error, GameplayTagRedirectors.cpp:26-56
EGameplayTagMatchType::Explicit / IncludeParentTagsThe Exact suffix on each call (HasTagExact, MatchesTagExact)Enum does not exist in 5.8
Container.HasTag(Tag, MatchTypeA, MatchTypeB)HasTag(Tag) or HasTagExact(Tag)One-argument forms only, GameplayTagContainer.h:299,316
Container.MatchesAll(Other)HasAll(Other) / HasAllExact(Other)No such member; GameplayTagContainer.h:379,402
Container.Matches(Query)Container.MatchesQuery(Query) or Query.Matches(Container)GameplayTagContainer.h:464,803
MakeQuery_MatchAnyTagsExactMakeQuery_ExactMatchAnyTagsGameplayTagContainer.h:857
DEFINE_GAMEPLAY_TAG / DECLARE_GAMEPLAY_TAG_EXTERN (no UE_)UE_DEFINE_GAMEPLAY_TAG / UE_DECLARE_GAMEPLAY_TAG_EXTERNNativeGameplayTags.h:31,41
IGameplayTagsModule::Get().GetGameplayTagsManager()UGameplayTagsManager::Get()Module exposes only the two change delegates, GameplayTagsModule.h:47-50
UGameplayMessageSubsystem (Lyra sample, not engine)A subsystem delegate, or AsyncMessageSystemNot present anywhere under Engine/Source or Engine/Plugins

Common Mistakes

Requesting a tag before the manager has it: RequestGameplayTag(FName("MyGame.X")) during static init or early module startup ensures and returns an empty tag. Use a native tag variable, or defer the lookup into CallOrRegister_OnDoneAddingNativeTagsDelegate.

Two definitions of the same native tag: UE_DEFINE_GAMEPLAY_TAG in a header, or the same variable defined in two .cpp files, is a duplicate-symbol link error. Declare once with UE_DECLARE_GAMEPLAY_TAG_EXTERN in the header, define once in a .cpp. Use UE_DEFINE_GAMEPLAY_TAG_STATIC when the tag is file-local.

MatchesTag where exactness was meant: Owned.HasTag(TAG_MyGame_Damage_Fire) is true for a container holding MyGame.Damage.Fire.Napalm, and DamageType.MatchesTag(FireTag) is true for any fire subtype. When you need the leaf and only the leaf, use HasTagExact / MatchesTagExact.

Hard-coded tag strings in gameplay code: RequestGameplayTag(FName("MyGame.State.Stunned")) sprinkled through a class survives a rename with no compile error and no redirect. One native tag, referenced everywhere.

Module dependency: Engine.Build.cs lists "GameplayTags" as a public dependency, so any module that depends on Engine already compiles and links tag code without it. Add "GameplayTags" explicitly anyway (public if tag types appear in your public headers, private otherwise) so the dependency survives if Engine is ever dropped and IWYU tools see it. Modules that do not depend on Engine (rare) do need it.

Renaming an ini tag without a redirect: every asset referencing the old name loads an invalid tag and WarnOnInvalidTags at most logs it. Add +GameplayTagRedirects=(OldTagName="Old",NewTagName="New") in the same commit as the rename.

Calling AddNativeGameplayTag late with FastReplication=True: the net index table is already built, so client and server disagree. Register during module startup, or use bDynamicReplication instead.

Building an FGameplayTagQuery per frame: BuildQuery emits a token stream. Build it in the constructor or BeginPlay, store it, and call Matches in the hot path.

Expecting a Lyra message router: #include "GameFramework/GameplayMessageSubsystem.h" does not resolve in a clean project — that subsystem ships with the Lyra sample, not the engine. Use a subsystem delegate or the AsyncMessageSystem plugin.

  • ue-gameplay-abilities — GAS-side tag usage: ability activation gates, granted tags, RegisterGameplayTagEvent and gameplay events
  • ue-state-trees — State Tree conditions and tasks that evaluate tag containers and queries
  • ue-game-features — plugin-scoped tag ini sources and the activation lifecycle that registers them
  • ue-ai-navigation — Smart Object and behaviour tag filtering
  • ue-cpp-foundations — UPROPERTY/UFUNCTION specifiers, delegates, subsystems that host messaging
  • ue-networking-replication — replicating tag properties, push model, RPC cost
  • ue-data-assets-tables — UDataTable assets used as a tag source and for tag-keyed data

© quodsoler, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files (references) in skills/ue-gameplay-tags-messaging of quodsoler/unreal-engine-skills.

  • SKILL.md
  • references/gameplay-messaging.md
  • references/gameplay-tag-reference.md

Open the folder on GitHubat commit f3742d7

Compare with similar skills

Ue Gameplay Tags Messaging next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Ue Gameplay Tags Messaging compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Ue Gameplay Tags Messaging this skillquodsoler/unreal-engine-skills362—~6.9kAutomated safety check: PassMIT
Ddia Principlesluoling8192/ai-coding-principles172—~4.7kAutomated safety check: PassMIT
Triage Tt Metal Assertstenstorrent/tt-mlir314—~7.8kAutomated safety check: PassApache-2.0
Databricks Zerobus Ingestdatabricks/databricks-agent-skills345—~6.3kAutomated safety check: PassCustom licence
Ue Specifiersfjz13/UnrealSpecifiers1.1k—~1.4kAutomated safety check: PassCustom licence
Azure Resource Manager Redis Dotnetmicrosoft/skills3.1k5 repos~3kAutomated safety check: PassMIT

Similar skills

  • Ddia Principles

    luoling8192/ai-coding-principles

    Designing Data-Intensive Applications (DDIA) distilled reference guide by Martin Kleppmann.

    172 GitHub stars~4.7k tokensUpdated 6 mo ago
    DatabasesAuto-check passed
  • Triage Tt Metal Asserts

    tenstorrent/tt-mlir

    Triage a tt-metal uplift diff or digest of TTFATAL validation changes against what tt-mlir guarantees at each optimization level (0: workarounds only, 1: optimizer with DRAM-only fallback, 2: L1…

    314 GitHub stars~7.8k tokensUpdated yesterday
    DatabasesAuto-check passed
  • Databricks Zerobus Ingest

    databricks/databricks-agent-skills

    Official

    Push records from apps, services, devices, or scripts directly into Unity Catalog Delta tables with Zerobus Ingest: SDKs (Python, TypeScript, Go, Java, Rust, C++, .NET), REST, OTLP, MQTT, Arrow…

    345 GitHub stars~6.3k tokensUpdated yesterday
    DevOps & CloudAuto-check passed
  • Ue Specifiers

    fjz13/UnrealSpecifiers

    A skill your agent uses when writing, editing, reviewing, validating, or explaining Unreal Engine C++ reflected declarations: UCLASS, USTRUCT, UENUM, UINTERFACE, UPROPERTY, UFUNCTION, UPARAM, UMETA…

    1.1k GitHub stars~1.4k tokensUpdated 4 mo ago
    Game DevelopmentAuto-check passed
  • Official

    Azure Resource Manager SDK for Redis in .NET. An agent skill from microsoft/skills.

    3.1k GitHub starsUsed in 5 repos~3k tokens
    DatabasesAuto-check passed
  • Tlaplus Spec Generator

    ArabelaTso/Skills-4-SE

    Automatically generate TLA+ specifications from source code (C/C++, Python) for formal verification of distributed systems.

    253 GitHub stars~2.3k tokensUpdated 1 mo ago
    DatabasesAuto-check passed

More from quodsoler/unreal-engine-skills

All 31 skills in this repo
  • Unreal Actor-Component Architecture

    quodsoler/unreal-engine-skills

    Unreal Engine C++ guidance for AActor and UActorComponent: lifecycle hooks, spawning, component creation and attachment, ticking, interfaces and composition.

    362 GitHub stars~7.5k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Engine AI and Navigation

    quodsoler/unreal-engine-skills

    Guides Unreal Engine C++ AI work across AI controllers, behavior trees, blackboards, perception, navmesh pathfinding, EQS and Smart Objects.

    362 GitHub stars~8.9k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Engine Animation System

    quodsoler/unreal-engine-skills

    Reference for writing and debugging Unreal Engine 5.8 animation C++: AnimInstance and proxy, montages, notifies, curves, blend spaces, state machines, linked layers and root motion.

    362 GitHub stars~7k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Engine Async and Threading

    quodsoler/unreal-engine-skills

    Picks and applies the right Unreal Engine C++ concurrency API, from UE::Tasks and FPipe to ParallelFor, FRunnable, locks and timers, with game-thread safety rules.

    362 GitHub stars~8k tokensUpdated 12 days ago
    Auto-check passed
  • Ue Audio System

    quodsoler/unreal-engine-skills

    A skill your agent uses when playing, mixing or debugging sound in Unreal Engine — one-shot SFX, looping ambience, music, dialogue or procedural audio.

    362 GitHub stars~7.9k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Blueprint and C++ Interop

    quodsoler/unreal-engine-skills

    Reference for exposing Unreal Engine C++ to Blueprint and calling Blueprint from C++, covering UFUNCTION and UPROPERTY specifiers, latent and async nodes, and interfaces.

    362 GitHub stars~7.8k tokensUpdated 12 days ago
    Auto-check passed

Works with

Questions about Ue Gameplay Tags Messaging

What does Ue Gameplay Tags Messaging do?

A skill your agent uses when defining, querying or replicating Gameplay Tags, or wiring decoupled event messaging between gameplay systems in C++. Ue Gameplay Tags Messaging is an agent skill from quodsoler/unreal-engine-skills. Use when defining, querying or replicating Gameplay Tags, or wiring decoupled event messaging between gameplay systems in C++.

When should I use Ue Gameplay Tags Messaging?

Ue Gameplay Tags Messaging fits situations like: replicating Gameplay Tags; wiring decoupled event messaging between gameplay systems in C++; the user mentions FGameplayTag; FGameplayTagContainer.

How do I install Ue Gameplay Tags Messaging in Claude Code?

Run `npx skills add quodsoler/unreal-engine-skills --skill ue-gameplay-tags-messaging -a claude-code`. Or copy the skill folder (skills/ue-gameplay-tags-messaging in quodsoler/unreal-engine-skills) into .claude/skills/ue-gameplay-tags-messaging in your project. Claude Code loads it when a task matches its description.

How do I install Ue Gameplay Tags Messaging in Codex?

Run `npx skills add quodsoler/unreal-engine-skills --skill ue-gameplay-tags-messaging -a codex`. Or copy the skill folder (skills/ue-gameplay-tags-messaging in quodsoler/unreal-engine-skills) into .agents/skills/ue-gameplay-tags-messaging in your project. Codex loads it when a task matches its description.

Can I use Ue Gameplay Tags Messaging in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add quodsoler/unreal-engine-skills --skill ue-gameplay-tags-messaging -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ue-gameplay-tags-messaging, .gemini/skills/ue-gameplay-tags-messaging, .github/skills/ue-gameplay-tags-messaging and .opencode/skills/ue-gameplay-tags-messaging in your project.

What does Ue Gameplay Tags Messaging need to run?

SKILL.md names no scripts, command-line tools or credentials: Ue Gameplay Tags Messaging is instructions for the agent only.

Does Ue Gameplay Tags Messaging access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Ue Gameplay Tags Messaging safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Ue Gameplay Tags Messaging use?

Ue Gameplay Tags Messaging is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Ue Gameplay Tags Messaging use?

About 6.9k tokens (SKILL.md is roughly 28k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 9.8k tokens, read only when the agent opens those files.

What are the alternatives to Ue Gameplay Tags Messaging?

Skills that share tags, products or a category with Ue Gameplay Tags Messaging: Ddia Principles (luoling8192/ai-coding-principles, 172 stars), Triage Tt Metal Asserts (tenstorrent/tt-mlir, 314 stars), Databricks Zerobus Ingest (databricks/databricks-agent-skills, 345 stars) and Ue Specifiers (fjz13/UnrealSpecifiers, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Ue Gameplay Tags Messaging?

quodsoler (a GitHub user) maintains it in quodsoler/unreal-engine-skills, which has 362 GitHub stars. The repository holds 31 skills in this directory. The repository was last updated on September 28, 2026.

Source: quodsoler/unreal-engine-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.