并未考虑网络复制等等网络问题
// Copyright 2022 - 2024 Dream Moon Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "GameplayTags.h"
#include "AbilitySystemComponent.h"
#include "AsyncTaskCooldownChange.generated.h"
/**
*
*/
UCLASS(BlueprintType, meta=(ExposedAsyncProxy = AsyncTask))
class DREAMGAMEPLAY_API UAsyncTaskCooldownChange : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnCooldownBegin, const FGameplayTagContainer&, CooldownTag, TSubclassOf<UGameplayEffect>, EffectClass, float, TimeRemaining, float, Duration);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnCooldownEnd, const FGameplayTagContainer&, CooldownTag, TSubclassOf<UGameplayEffect>, EffectClass);
public:
UPROPERTY(BlueprintAssignable)
FOnCooldownBegin OnCooldownBegin;
UPROPERTY(BlueprintAssignable)
FOnCooldownEnd OnCooldownEnd;
UFUNCTION(BlueprintCallable, meta=(BlueprintInternalUseOnly = "true"))
static UAsyncTaskCooldownChange* ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayTagContainer CooldownTag, bool bUseServerCooldown);
protected:
UPROPERTY()
UAbilitySystemComponent* AbilitySystemComp;
FGameplayTagContainer CooldownsToListenFor;
void OnCooldownBeginDelegate(UAbilitySystemComponent* ASC, const FGameplayEffectSpec& Spec, FActiveGameplayEffectHandle Handle);
void OnCooldownEndDelegate(const FActiveGameplayEffect& Effect);
};
// Copyright 2022 - 2024 Dream Moon Team. All Rights Reserved.
#include "Ability/AsyncTaskCooldownChange.h"
UAsyncTaskCooldownChange* UAsyncTaskCooldownChange::ListenForCooldownChange(
UAbilitySystemComponent* AbilitySystemComponent, FGameplayTagContainer CooldownTag, bool bUseServerCooldown)
{
UAsyncTaskCooldownChange* Node = NewObject<UAsyncTaskCooldownChange>();
Node->AbilitySystemComp = AbilitySystemComponent;
Node->CooldownsToListenFor = CooldownTag;
if (!IsValid(AbilitySystemComponent) || !CooldownTag.IsValid())
{
Node->RemoveFromRoot();
return nullptr;
}
AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(Node, &UAsyncTaskCooldownChange::OnCooldownBeginDelegate);
AbilitySystemComponent->OnAnyGameplayEffectRemovedDelegate().AddUObject(Node, &UAsyncTaskCooldownChange::OnCooldownEndDelegate);
return Node;
}
void UAsyncTaskCooldownChange::OnCooldownBeginDelegate(UAbilitySystemComponent* ASC, const FGameplayEffectSpec& Spec,
FActiveGameplayEffectHandle Handle)
{
FGameplayEffectQuery Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(CooldownsToListenFor);
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;
}
}
/* Result */
OnCooldownBegin.Broadcast(CooldownsToListenFor,
Spec.Def.GetClass(),
DurationAndTimeRemaining[BestIdx].Key,
DurationAndTimeRemaining[BestIdx].Value);
}
}
void UAsyncTaskCooldownChange::OnCooldownEndDelegate(const FActiveGameplayEffect& Effect)
{
FGameplayEffectQuery Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(CooldownsToListenFor);
OnCooldownEnd.Broadcast(CooldownsToListenFor, Effect.Spec.Def.GetClass());
}