// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE. #pragma once #include "CoreMinimal.h" #include "Engine/CancellableAsyncAction.h" #include "AttributeSet.h" #include "GameplayEffectTypes.h" #include "RSAsyncWatchAttribute.generated.h" class UAbilitySystemComponent; DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FRSAttributeChanged, FGameplayAttribute, Attribute, float, NewValue, float, OldValue); /** * Watches one or more attributes and fires OnChanged when any of them changes. * Fires once right away with the current value, so a widget can bind in * Construct and never poll in Tick. Works on clients: attribute replication * runs the same change delegate. * * Call Cancel (or let the widget's Destruct call it) to unbind. */ UCLASS(meta = (ExposedAsyncProxy = "AsyncTask")) class RSGASHELPERS_API URSAsyncWatchAttribute : public UCancellableAsyncAction { GENERATED_BODY() public: UPROPERTY(BlueprintAssignable) FRSAttributeChanged OnChanged; /** Watch attributes on the actor's ASC (PlayerState setups included). */ UFUNCTION(BlueprintCallable, Category = "RS|GAS", meta = (BlueprintInternalUseOnly = "true", DefaultToSelf = "Actor")) static URSAsyncWatchAttribute* WatchAttributes(AActor* Actor, const TArray& Attributes, bool bFireInitialValue = true); virtual void Activate() override; virtual void Cancel() override; private: void HandleChange(const FOnAttributeChangeData& Data); TWeakObjectPtr WeakASC; TArray Watched; TArray> Bindings; bool bFireInitial = true; };