RSAsyncWatchAttribute.cpp
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 | #include "RSAsyncWatchAttribute.h" |
| 4 | |
| 5 | #include "AbilitySystemComponent.h" |
| 6 | #include "RSAbilitySystemLibrary.h" |
| 7 | |
| 8 | URSAsyncWatchAttribute* URSAsyncWatchAttribute::WatchAttributes(AActor* Actor, const TArray<FGameplayAttribute>& Attributes, bool bFireInitialValue) |
| 9 | { |
| 10 | URSAsyncWatchAttribute* Action = NewObject<URSAsyncWatchAttribute>(); |
| 11 | Action->WeakASC = URSAbilitySystemLibrary::FindAbilitySystemComponent(Actor); |
| 12 | for (const FGameplayAttribute& Attribute : Attributes) |
| 13 | { |
| 14 | // A duplicate would bind twice and fire OnChanged twice per change. |
| 15 | Action->Watched.AddUnique(Attribute); |
| 16 | } |
| 17 | Action->bFireInitial = bFireInitialValue; |
| 18 | Action->RegisterWithGameInstance(Actor); |
| 19 | return Action; |
| 20 | } |
| 21 | |
| 22 | void URSAsyncWatchAttribute::Activate() |
| 23 | { |
| 24 | UAbilitySystemComponent* ASC = WeakASC.Get(); |
| 25 | if (!ASC) |
| 26 | { |
| 27 | // Common on clients: the PlayerState (and its ASC) has not replicated yet. |
| 28 | // Retry from OnRep_PlayerState instead of polling. |
| 29 | Cancel(); |
| 30 | return; |
| 31 | } |
| 32 | |
| 33 | for (const FGameplayAttribute& Attribute : Watched) |
| 34 | { |
| 35 | if (!Attribute.IsValid()) |
| 36 | { |
| 37 | continue; |
| 38 | } |
| 39 | |
| 40 | Bindings.Emplace(Attribute, ASC->GetGameplayAttributeValueChangeDelegate(Attribute).AddUObject(this, &URSAsyncWatchAttribute::HandleChange)); |
| 41 | |
| 42 | if (bFireInitial) |
| 43 | { |
| 44 | const float Value = ASC->GetNumericAttribute(Attribute); |
| 45 | OnChanged.Broadcast(Attribute, Value, Value); |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | void URSAsyncWatchAttribute::HandleChange(const FOnAttributeChangeData& Data) |
| 51 | { |
| 52 | OnChanged.Broadcast(Data.Attribute, Data.NewValue, Data.OldValue); |
| 53 | } |
| 54 | |
| 55 | void URSAsyncWatchAttribute::Cancel() |
| 56 | { |
| 57 | if (UAbilitySystemComponent* ASC = WeakASC.Get()) |
| 58 | { |
| 59 | for (const TPair<FGameplayAttribute, FDelegateHandle>& Binding : Bindings) |
| 60 | { |
| 61 | ASC->GetGameplayAttributeValueChangeDelegate(Binding.Key).Remove(Binding.Value); |
| 62 | } |
| 63 | } |
| 64 | Bindings.Reset(); |
| 65 | Super::Cancel(); |
| 66 | } |