Let's talk

RSAsyncWaitTagCount.h

Source/RSGasHelpers/Public/RSAsyncWaitTagCount.h Raw Download ZIP

Click a line number to link it. Shift-click to select a range.

1// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "Engine/CancellableAsyncAction.h"
7#include "GameplayTagContainer.h"
8#include "RSAsyncWaitTagCount.generated.h"
9
10class UAbilitySystemComponent;
11
12DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FRSTagCountChanged, FGameplayTag, Tag, int32, NewCount);
13
14/**
15 * Fires OnCountChanged whenever the number of a gameplay tag on an ASC changes
16 * (stacks of State.Burning, charges of Ability.Charge, State.Stunned on or off).
17 * Fires once right away with the current count, so a widget never polls in Tick.
18 * Works on clients: tag counts that replicate (effect tags in Mixed or Full mode,
19 * replicated loose tags) trigger it when they arrive.
20 *
21 * Call Cancel (or let the widget's Destruct call it) to unbind.
22 */
23UCLASS(meta = (ExposedAsyncProxy = "AsyncTask"))
24class RSGASHELPERS_API URSAsyncWaitTagCount : public UCancellableAsyncAction
25{
26 GENERATED_BODY()
27
28public:
29 UPROPERTY(BlueprintAssignable)
30 FRSTagCountChanged OnCountChanged;
31
32 /** Watch a tag on the actor's ASC (PlayerState setups included). Child tags count towards their parent. */
33 UFUNCTION(BlueprintCallable, Category = "RS|GAS", meta = (BlueprintInternalUseOnly = "true", DefaultToSelf = "Actor"))
34 static URSAsyncWaitTagCount* WaitGameplayTagCount(AActor* Actor, FGameplayTag Tag, bool bFireInitialCount = true);
35
36 virtual void Activate() override;
37 virtual void Cancel() override;
38
39private:
40 void HandleTagChanged(const FGameplayTag Tag, int32 NewCount);
41
42 TWeakObjectPtr<UAbilitySystemComponent> WeakASC;
43 FGameplayTag WatchedTag;
44 FDelegateHandle Binding;
45 bool bFireInitial = true;
46};

Still desyncing in packaged builds?

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