Let's talk

RSAsyncWatchAttribute.cpp

Source/RSGasHelpers/Private/RSAsyncWatchAttribute.cpp 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#include "RSAsyncWatchAttribute.h"
4
5#include "AbilitySystemComponent.h"
6#include "RSAbilitySystemLibrary.h"
7
8URSAsyncWatchAttribute* 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
22void 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
50void URSAsyncWatchAttribute::HandleChange(const FOnAttributeChangeData& Data)
51{
52 OnChanged.Broadcast(Data.Attribute, Data.NewValue, Data.OldValue);
53}
54
55void 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}

Still desyncing in packaged builds?

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