forked from tranek/GASDocumentation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAsyncTaskCooldownChanged.cpp
135 lines (112 loc) · 4.52 KB
/
AsyncTaskCooldownChanged.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2020 Dan Kestranek.
#include "Characters/Abilities/AsyncTaskCooldownChanged.h"
UAsyncTaskCooldownChanged * UAsyncTaskCooldownChanged::ListenForCooldownChange(UAbilitySystemComponent * AbilitySystemComponent, FGameplayTagContainer InCooldownTags, bool InUseServerCooldown)
{
UAsyncTaskCooldownChanged* ListenForCooldownChange = NewObject<UAsyncTaskCooldownChanged>();
ListenForCooldownChange->ASC = AbilitySystemComponent;
ListenForCooldownChange->CooldownTags = InCooldownTags;
ListenForCooldownChange->UseServerCooldown = InUseServerCooldown;
if (!IsValid(AbilitySystemComponent) || InCooldownTags.Num() < 1)
{
ListenForCooldownChange->EndTask();
return nullptr;
}
AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(ListenForCooldownChange, &UAsyncTaskCooldownChanged::OnActiveGameplayEffectAddedCallback);
TArray<FGameplayTag> CooldownTagArray;
InCooldownTags.GetGameplayTagArray(CooldownTagArray);
for (FGameplayTag CooldownTag : CooldownTagArray)
{
AbilitySystemComponent->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).AddUObject(ListenForCooldownChange, &UAsyncTaskCooldownChanged::CooldownTagChanged);
}
return ListenForCooldownChange;
}
void UAsyncTaskCooldownChanged::EndTask()
{
if (IsValid(ASC))
{
ASC->OnActiveGameplayEffectAddedDelegateToSelf.RemoveAll(this);
TArray<FGameplayTag> CooldownTagArray;
CooldownTags.GetGameplayTagArray(CooldownTagArray);
for (FGameplayTag CooldownTag : CooldownTagArray)
{
ASC->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).RemoveAll(this);
}
}
SetReadyToDestroy();
MarkAsGarbage();
}
void UAsyncTaskCooldownChanged::OnActiveGameplayEffectAddedCallback(UAbilitySystemComponent * Target, const FGameplayEffectSpec & SpecApplied, FActiveGameplayEffectHandle ActiveHandle)
{
FGameplayTagContainer AssetTags;
SpecApplied.GetAllAssetTags(AssetTags);
FGameplayTagContainer GrantedTags;
SpecApplied.GetAllGrantedTags(GrantedTags);
TArray<FGameplayTag> CooldownTagArray;
CooldownTags.GetGameplayTagArray(CooldownTagArray);
for (FGameplayTag CooldownTag : CooldownTagArray)
{
if (AssetTags.HasTagExact(CooldownTag) || GrantedTags.HasTagExact(CooldownTag))
{
float TimeRemaining = 0.0f;
float Duration = 0.0f;
// Expecting cooldown tag to always be first tag
FGameplayTagContainer CooldownTagContainer(GrantedTags.GetByIndex(0));
GetCooldownRemainingForTag(CooldownTagContainer, TimeRemaining, Duration);
if (ASC->GetOwnerRole() == ROLE_Authority)
{
// Player is Server
OnCooldownBegin.Broadcast(CooldownTag, TimeRemaining, Duration);
}
else if (!UseServerCooldown && SpecApplied.GetContext().GetAbilityInstance_NotReplicated())
{
// Client using predicted cooldown
OnCooldownBegin.Broadcast(CooldownTag, TimeRemaining, Duration);
}
else if (UseServerCooldown && SpecApplied.GetContext().GetAbilityInstance_NotReplicated() == nullptr)
{
// Client using Server's cooldown. This is Server's corrective cooldown GE.
OnCooldownBegin.Broadcast(CooldownTag, TimeRemaining, Duration);
}
else if (UseServerCooldown && SpecApplied.GetContext().GetAbilityInstance_NotReplicated())
{
// Client using Server's cooldown but this is predicted cooldown GE.
// This can be useful to gray out abilities until Server's cooldown comes in.
OnCooldownBegin.Broadcast(CooldownTag, -1.0f, -1.0f);
}
}
}
}
void UAsyncTaskCooldownChanged::CooldownTagChanged(const FGameplayTag CooldownTag, int32 NewCount)
{
if (NewCount == 0)
{
OnCooldownEnd.Broadcast(CooldownTag, -1.0f, -1.0f);
}
}
bool UAsyncTaskCooldownChanged::GetCooldownRemainingForTag(FGameplayTagContainer InCooldownTags, float & TimeRemaining, float & CooldownDuration)
{
if (IsValid(ASC) && InCooldownTags.Num() > 0)
{
TimeRemaining = 0.f;
CooldownDuration = 0.f;
FGameplayEffectQuery const Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(InCooldownTags);
TArray< TPair<float, float> > DurationAndTimeRemaining = ASC->GetActiveEffectsTimeRemainingAndDuration(Query);
if (DurationAndTimeRemaining.Num() > 0)
{
int32 BestIdx = 0;
float LongestTime = DurationAndTimeRemaining[0].Key;
for (int32 Idx = 1; Idx < DurationAndTimeRemaining.Num(); ++Idx)
{
if (DurationAndTimeRemaining[Idx].Key > LongestTime)
{
LongestTime = DurationAndTimeRemaining[Idx].Key;
BestIdx = Idx;
}
}
TimeRemaining = DurationAndTimeRemaining[BestIdx].Key;
CooldownDuration = DurationAndTimeRemaining[BestIdx].Value;
return true;
}
}
return false;
}