Let's talk

GAS Helpers v0.2.0

Small C++ helpers for the Unreal Engine 5 Gameplay Ability System in multiplayer games: safe ASC lookup, activate-by-tag with a result, replicated loose tags, SetByCaller spec builder, cooldown time by tag, ability input by tag with Enhanced Input, ASC state dump, and async attribute and tag-count watchers for UI without Tick.

The problem
Six common GAS questions with no clear answer from the engine: why the ASC is null, why an ability did nothing, why a tag never reached clients, why an effect applied at 0.
What it replaces
Breakpoints, print strings and comparing server and client state by hand.
What it saves
Our estimate: an hour or two each time one of these bugs comes up, which on a GAS project is often. One call per helper.
Who it is for
C++ programmers already using GAS in a multiplayer game.

Small C++ helpers for the Unreal Engine 5 Gameplay Ability System in multiplayer games. Free, MIT licensed, no sign-up.

Unreal Engine 5.5 to 5.8. Compiled clean (0 errors, 0 warnings) on 5.5, 5.6, 5.7 and 5.8, and covered by automation tests that run each helper against a real Ability System Component on every one of those versions (standalone world, so the tests exercise server-side behaviour; replication itself is not simulated). Still a preview: test it in your project, and send problems to contact@reignancestudios.com.

What is inside

HelperWhat it fixesTutorial
FindAbilitySystemComponentNull ASC when it lives on the PlayerStateASC on PlayerState
TryActivateAbilityByTag"Nothing happens" with no reason: tells you NotGranted vs BlockedAbility fires twice or not at all
AddReplicatedLooseTag / RemoveReplicatedLooseTagLoose tags that exist on the server but never reach clientsReplicated loose tags
MakeSpecWithSetByCallerEffects applied with magnitude 0 because a SetByCaller was missedPredicted cost and cooldown
DumpAbilitySystemStateComparing server and client ASC state by handAbility fires twice or not at all
URSAsyncWatchAttributeHealth bars polling in TickAttribute UI without Tick
URSAsyncWaitTagCount (new in 0.2.0)Stack, charge and status UI polling tag counts in TickReplicated loose tags
GetCooldownRemainingByTag (new in 0.2.0)Cooldown widgets that search active effects by hand, or miss the predicted cooldownPredicted cost and cooldown
PressAbilityInputByTag / ReleaseAbilityInputByTag + URSAbilityInputConfig (new in 0.2.0)Abilities bound to numeric input IDs; WaitInputRelease that never firesAbility fires twice or not at all

Not included on purpose: a local-only gameplay cue helper. The engine already has one, UGameplayCueFunctionLibrary::ExecuteGameplayCueOnActor (and Add/Remove), which runs the cue on this machine only.

The Examples folder holds a PlayerState, Character, AttributeSet and a predicted Dash ability. They are not compiled with the plugin: copy them into your game module.

Install

  1. Download the ZIP and unzip it into YourProject/Plugins/RSGasHelpers.
  2. Make sure the Gameplay Abilities and Enhanced Input plugins are enabled (both are on by default in new projects).
  3. Add "RSGasHelpers" to PublicDependencyModuleNames in your game's .Build.cs if you call it from C++.
  4. Regenerate project files and build.

Usage

C++
#include "RSAbilitySystemLibrary.h"

const ERSActivateResult Result =
    URSAbilitySystemLibrary::TryActivateAbilityByTag(this, TAG_Ability_Dash);

if (Result == ERSActivateResult::Blocked)
{
    UE_LOG(LogTemp, Warning, TEXT("%s"),
        *URSAbilitySystemLibrary::DumpAbilitySystemState(this));
}

Bind abilities to input by tag

Make a URSAbilityInputConfig data asset, add one row per Input Action with the ability tag it starts, then bind it in your character:

C++
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);
    InputConfig->BindAbilityActions(CastChecked<UEnhancedInputComponent>(PlayerInputComponent),
        this, &AMyCharacter::AbilityInputPressed, &AMyCharacter::AbilityInputReleased);
}

void AMyCharacter::AbilityInputPressed(FGameplayTag Tag)  { URSAbilitySystemLibrary::PressAbilityInputByTag(this, Tag); }
void AMyCharacter::AbilityInputReleased(FGameplayTag Tag) { URSAbilitySystemLibrary::ReleaseAbilityInputByTag(this, Tag); }

A press starts every granted ability whose tags include the row's tag. If the ability is already active, the press goes to it instead, with its activation prediction key, so WaitInputPress and WaitInputRelease work for charge-and-release abilities. In Blueprint, call the two functions from the Started and Completed pins of an Enhanced Input event.

Help

These helpers fix single symptoms. If your abilities still desync in packaged builds or at real latency, the cause is usually ownership or prediction setup across the project. A Diagnostic finds it in two days.

Changelog

v0.2.0 (2026-10-31)

  • New URSAsyncWaitTagCount (Wait Gameplay Tag Count): fires on every count change of a tag, with the current count first.
  • New GetCooldownRemainingByTag: time left and duration of the cooldown that grants a tag, including the predicted cooldown on the owning client.
  • New PressAbilityInputByTag, ReleaseAbilityInputByTag and the URSAbilityInputConfig data asset: Enhanced Input actions bound to abilities by tag, with presses forwarded to active abilities for WaitInputPress / WaitInputRelease.
  • Needs the Enhanced Input plugin.
  • Automation tests for every helper, run on UE 5.5 to 5.8.

v0.1.0 (2026-10-30)

  • First preview release.
  • URSAbilitySystemLibrary: FindAbilitySystemComponent, TryActivateAbilityByTag, AddReplicatedLooseTag, RemoveReplicatedLooseTag, MakeSpecWithSetByCaller, DumpAbilitySystemState.
  • URSAsyncWatchAttribute: attribute watcher for UI without Tick.
  • Examples: PlayerState with ASC, Character init, AttributeSet with prediction-safe OnReps, predicted Dash ability.
  • On UE 5.7 and later, RemoveReplicatedLooseTag removes through the container overload: the engine's single-tag path does not fire AnyCountChange when a count drops without reaching 0.

Tutorials that use it

Still desyncing in packaged builds?

Free code fixes one symptom. A Diagnostic finds the cause across your project in two days.