The Games DevProgramming and Game Development. Tips, Tricks and Tutorials.

Native Gameplay Tags (New in 4.27 and UE5)

· Updated Gameplay Ability System

Updated for UE 5.8: the macros below all still exist in 5.8, and the sample code has been fixed.

This is a quick rundown of the NativeGameplayTags system, added in UE 4.27 and available in UE5. These tags populate the editor’s GameplayTags drop-down (same as my older struct version), and you can also add the same tags to your DefaultGameplayTags.ini just fine, as the engine will not allow dupes.

Everything lives in NativeGameplayTags.h, which adds the following macros:

/** Declares a native gameplay tag that is defined in a cpp with UE_DEFINE_GAMEPLAY_TAG so other modules or code can use the tag variable. */
#define UE_DECLARE_GAMEPLAY_TAG_EXTERN(TagName)

/** Defines a native gameplay tag that is externally declared in a header. */
#define UE_DEFINE_GAMEPLAY_TAG(TagName, Tag)

/** Same as above, with a developer comment. (5.1+) */
#define UE_DEFINE_GAMEPLAY_TAG_COMMENT(TagName, Tag, Comment)

/** Defines a native gameplay tag that is only available to the cpp file you define it in. */
#define UE_DEFINE_GAMEPLAY_TAG_STATIC(TagName, Tag)

Every define macro has a static_assert that it is only used in a .cpp file, so never put them in a header. The variable each macro creates is an FNativeGameplayTag, which converts implicitly to FGameplayTag (or call GetTag()).

File-local tags

We will start with the simplest one, UE_DEFINE_GAMEPLAY_TAG_STATIC. It is only used in .cpp files, and the tag is only usable in that file. Useful for a quick one-off tag. I recommend wrapping them in a namespace to avoid global pollution:

namespace KaosGameplayAbilityTags
{
	UE_DEFINE_GAMEPLAY_TAG_STATIC(TAG_Gameplay_Action_Player_AimDownsights, "Gameplay.Ability.AimDownSights");
	UE_DEFINE_GAMEPLAY_TAG_STATIC(TAG_Gameplay_Status_AimingDownSights, "Gameplay.Status.AimingDownSights");
}

UKaosGameplayAbility_ADS::UKaosGameplayAbility_ADS()
{
	NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted;
	NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy::ClientOrServer;
	ActivationOwnedTags.AddTagFast(KaosGameplayAbilityTags::TAG_Gameplay_Status_AimingDownSights);
	SetAssetTags(FGameplayTagContainer(KaosGameplayAbilityTags::TAG_Gameplay_Action_Player_AimDownsights));
}

As you can see, we define the tags and use the variable name to use them. The benefit is we can use these in constructors.

Note: in 5.5+ the AbilityTags property on UGameplayAbility is deprecated for game code. Use SetAssetTags in the constructor to set defaults, and GetAssetTags() to read them. (The original version of this post used AbilityTags.AddTagFast.)

Tags shared across files and modules

The other two macros work in tandem. Declare in a header, for example “KaosNativeTags.h”:

// Copyright InterKaos Games. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "NativeGameplayTags.h"

namespace MyGamesTags
{
	UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_Status_Dead)
	UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_AbilityActivation_Fail_Dead)
}

Then define them in the matching cpp. Use UE_DEFINE_GAMEPLAY_TAG_COMMENT so the tag gets a developer comment:

// Copyright InterKaos Games. All Rights Reserved.

#include "KaosNativeTags.h"

namespace MyGamesTags
{
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Gameplay_Status_Dead, "Gameplay.Status.Dead", "Tag applied to actor when they are dead")
	UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_AbilityActivation_Fail_Dead, "AbilityActivation.Fail.Dead", "Ability failed to activate because the AvatarActor was dead.")
}

If you don’t need a comment, UE_DEFINE_GAMEPLAY_TAG(TagName, Tag) does the same without one. Before 5.1 there was no way to comment native tags.

Then include the header in any .cpp and use the tag:

if (OptionalRelevantTags && AbilitySystemComponentTags.HasTag(MyGamesTags::TAG_Gameplay_Status_Dead))
{
	// If player is dead and was rejected due to blocking tags, give that feedback
	OptionalRelevantTags->AddTag(MyGamesTags::TAG_AbilityActivation_Fail_Dead);
}

Gotchas

  • UE_DECLARE_GAMEPLAY_TAG_EXTERN expands to a plain extern FNativeGameplayTag TagName; with no module API macro. If you need to use a tag from another module and hit link errors, write the extern by hand with your API macro (for example extern KAOSGAME_API FNativeGameplayTag TagName;).
  • A native tag stays registered while any module that defines it is loaded, and is unregistered when its module unloads.
  • If you hit packaging issues, you can shadow the tag inside DefaultGameplayTags.ini.

With that, hopefully you can make good use of these in your game code!