sample UI ability cooldown

This commit is contained in:
Arnaud Jamin
2023-10-09 02:20:52 -04:00
parent 02b402023a
commit ad7cbb1667
82 changed files with 810 additions and 78 deletions
-19
View File
@@ -1,19 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#ifndef USE_COG
#define USE_COG (ENABLE_DRAW_DEBUG && !NO_LOGGING)
#endif
#if USE_COG
#define IF_COG(expr) { expr; }
#define COG_LOG_CATEGORY FLogCategoryBase
#else //USE_COG
#define IF_COG(expr) (0)
#define COG_LOG_CATEGORY FNoLoggingCategory
#endif //USE_COG
@@ -5,4 +5,4 @@
FGameplayEffectContext* UCogSampleAbilitySystemGlobals::AllocGameplayEffectContext() const
{
return new FCogSampleGameplayEffectContext();
}
}
@@ -9,5 +9,5 @@ class UCogSampleAbilitySystemGlobals : public UAbilitySystemGlobals
{
GENERATED_BODY()
virtual FGameplayEffectContext* AllocGameplayEffectContext() const override;
virtual FGameplayEffectContext* AllocGameplayEffectContext() const override;
};
@@ -0,0 +1,288 @@
#include "CogSampleAbilityTask_PlayMontageAndWaitForEvent.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "Animation/AnimInstance.h"
#include "CogSampleDefines.h"
#include "CogSampleLogCategories.h"
#include "GameFramework/Character.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleAbilityTask_PlayMontageAndWaitForEvent::UCogSampleAbilityTask_PlayMontageAndWaitForEvent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
Rate = 1.f;
bStopWhenAbilityEnds = true;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted)
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s - Interrupted:%d"), *Montage->GetFName().ToString(), bInterrupted);
if (Ability && Ability->GetCurrentMontage() == MontageToPlay)
{
if (Montage == MontageToPlay)
{
AbilitySystemComponent->ClearAnimatingAbility(Ability);
// Reset AnimRootMotionTranslationScale
ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
if (Character && (Character->GetLocalRole() == ROLE_Authority ||
(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
{
Character->SetAnimRootMotionTranslationScale(1.f);
}
}
}
if (bInterrupted)
{
if (ShouldBroadcastAbilityTaskDelegates())
{
OnInterrupted.Broadcast(FGameplayTag(), FGameplayEventData());
}
}
else
{
if (ShouldBroadcastAbilityTaskDelegates())
{
OnBlendOut.Broadcast(FGameplayTag(), FGameplayEventData());
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnAbilityCancelled()
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s"), *GetNameSafe(MontageToPlay));
// TODO: Merge this fix back to engine, it was calling the wrong callback
if (StopPlayingMontage())
{
// Let the BP handle the interrupt as well
if (ShouldBroadcastAbilityTaskDelegates())
{
OnCancelled.Broadcast(FGameplayTag(), FGameplayEventData());
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnMontageEnded(UAnimMontage* Montage, bool bInterrupted)
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s - Interrupted:%d"), *Montage->GetFName().ToString(), bInterrupted);
if (!bInterrupted)
{
if (ShouldBroadcastAbilityTaskDelegates())
{
OnCompleted.Broadcast(FGameplayTag(), FGameplayEventData());
}
}
EndTask();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnGameplayEvent(FGameplayTag EventTag, const FGameplayEventData* Payload)
{
if (ShouldBroadcastAbilityTaskDelegates() == false)
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s - Event:%s - ShouldBroadcastAbilityTaskDelegates:false"), *GetNameSafe(MontageToPlay), *EventTag.ToString());
return;
}
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s - Event:%s"), *GetNameSafe(MontageToPlay), *EventTag.ToString());
FGameplayEventData TempData = *Payload;
TempData.EventTag = EventTag;
EventReceived.Broadcast(EventTag, TempData);
}
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleAbilityTask_PlayMontageAndWaitForEvent* UCogSampleAbilityTask_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent(UGameplayAbility* OwningAbility,
FName TaskInstanceName, UAnimMontage* MontageToPlay, FGameplayTagContainer EventTags, float Rate, FName StartSection, bool bStopWhenAbilityEnds, float AnimRootMotionTranslationScale)
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, OwningAbility, TEXT("Montage:%s"), *GetNameSafe(MontageToPlay));
UAbilitySystemGlobals::NonShipping_ApplyGlobalAbilityScaler_Rate(Rate);
UCogSampleAbilityTask_PlayMontageAndWaitForEvent* MyObj = NewAbilityTask<UCogSampleAbilityTask_PlayMontageAndWaitForEvent>(OwningAbility, TaskInstanceName);
MyObj->MontageToPlay = MontageToPlay;
MyObj->EventTags = EventTags;
MyObj->Rate = Rate;
MyObj->StartSection = StartSection;
MyObj->AnimRootMotionTranslationScale = AnimRootMotionTranslationScale;
MyObj->bStopWhenAbilityEnds = bStopWhenAbilityEnds;
return MyObj;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::Activate()
{
if (Ability == nullptr)
{
return;
}
bool bPlayedMontage = false;
if (AbilitySystemComponent.IsValid())
{
const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();
if (AnimInstance != nullptr)
{
// Bind to event callback
EventHandle = AbilitySystemComponent->AddGameplayEventTagContainerDelegate(EventTags, FGameplayEventTagMulticastDelegate::FDelegate::CreateUObject(this, &UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnGameplayEvent));
if (AbilitySystemComponent->PlayMontage(Ability, Ability->GetCurrentActivationInfo(), MontageToPlay, Rate, StartSection) > 0.f)
{
// Playing a montage could potentially fire off a callback into game code which could kill this ability! Early out if we are pending kill.
if (ShouldBroadcastAbilityTaskDelegates() == false)
{
return;
}
CancelledHandle = Ability->OnGameplayAbilityCancelled.AddUObject(this, &UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnAbilityCancelled);
BlendingOutDelegate.BindUObject(this, &UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnMontageBlendingOut);
AnimInstance->Montage_SetBlendingOutDelegate(BlendingOutDelegate, MontageToPlay);
MontageEndedDelegate.BindUObject(this, &UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnMontageEnded);
AnimInstance->Montage_SetEndDelegate(MontageEndedDelegate, MontageToPlay);
ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
if (Character && (Character->GetLocalRole() == ROLE_Authority ||
(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
{
Character->SetAnimRootMotionTranslationScale(AnimRootMotionTranslationScale);
}
bPlayedMontage = true;
}
}
else
{
COG_LOG_ABILITY(ELogVerbosity::Warning, Ability, TEXT("Montage:%s - PlayMontage failed."), *GetNameSafe(MontageToPlay));
}
}
else
{
COG_LOG_ABILITY(ELogVerbosity::Warning, Ability, TEXT("Montage:%s - Invalid AbilitySystemComponent"), *GetNameSafe(MontageToPlay));
}
if (!bPlayedMontage)
{
COG_LOG_ABILITY(ELogVerbosity::Warning, Ability, TEXT("Montage:%s - Failed to play montage."), *GetNameSafe(MontageToPlay));
if (ShouldBroadcastAbilityTaskDelegates())
{
//ABILITY_LOG(Display, TEXT("%s: OnCancelled"), *GetName());
OnCancelled.Broadcast(FGameplayTag(), FGameplayEventData());
}
}
SetWaitingOnAvatar();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::ExternalCancel()
{
check(AbilitySystemComponent.IsValid());
OnAbilityCancelled();
Super::ExternalCancel();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleAbilityTask_PlayMontageAndWaitForEvent::OnDestroy(bool AbilityEnded)
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s - AbilityEnded:%d"), *GetNameSafe(MontageToPlay), AbilityEnded);
// Note: Clearing montage end delegate isn't necessary since its not a multicast and will be cleared when the next montage plays.
// (If we are destroyed, it will detect this and not do anything)
// This delegate, however, should be cleared as it is a multicast
if (Ability)
{
Ability->OnGameplayAbilityCancelled.Remove(CancelledHandle);
if (AbilityEnded && bStopWhenAbilityEnds)
{
StopPlayingMontage();
}
}
if (AbilitySystemComponent.IsValid())
{
AbilitySystemComponent->RemoveGameplayEventTagContainerDelegate(EventTags, EventHandle);
}
Super::OnDestroy(AbilityEnded);
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSampleAbilityTask_PlayMontageAndWaitForEvent::StopPlayingMontage()
{
COG_LOG_ABILITY(ELogVerbosity::VeryVerbose, Ability, TEXT("Montage:%s"), *GetNameSafe(MontageToPlay));
const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
if (!ActorInfo)
{
return false;
}
UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();
if (AnimInstance == nullptr)
{
return false;
}
// Check if the montage is still playing
// The ability would have been interrupted, in which case we should automatically stop the montage
if (AbilitySystemComponent.IsValid() && Ability)
{
if (AbilitySystemComponent->GetAnimatingAbility() == Ability
&& AbilitySystemComponent->GetCurrentMontage() == MontageToPlay)
{
// Unbind delegates so they don't get called as well
FAnimMontageInstance* MontageInstance = AnimInstance->GetActiveInstanceForMontage(MontageToPlay);
if (MontageInstance)
{
MontageInstance->OnMontageBlendingOutStarted.Unbind();
MontageInstance->OnMontageEnded.Unbind();
}
AbilitySystemComponent->CurrentMontageStop();
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
FString UCogSampleAbilityTask_PlayMontageAndWaitForEvent::GetDebugString() const
{
UAnimMontage* PlayingMontage = nullptr;
if (Ability)
{
const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();
if (AnimInstance != nullptr)
{
PlayingMontage = AnimInstance->Montage_IsActive(MontageToPlay) ? MontageToPlay : AnimInstance->GetCurrentActiveMontage();
}
}
return FString::Printf(TEXT("PlayMontageAndWaitForEvent. MontageToPlay: %s (Currently Playing): %s"), *GetNameSafe(MontageToPlay), *GetNameSafe(PlayingMontage));
}
@@ -0,0 +1,117 @@
#pragma once
#include "CoreMinimal.h"
#include "Abilities/Tasks/AbilityTask.h"
#include "CogSampleAbilityTask_PlayMontageAndWaitForEvent.generated.h"
class UGDAbilitySystemComponent;
/** Delegate type used, EventTag and Payload may be empty if it came from the montage callbacks */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FCogSamplePlayMontageAndWaitForEventDelegate, FGameplayTag, EventTag, FGameplayEventData, EventData);
/**
* This task combines PlayMontageAndWait and WaitForEvent into one task, so you can wait for multiple types of activations such as from a melee combo
* Much of this code is copied from one of those two ability tasks
* This is a good task to look at as an example when creating game-specific tasks
* It is expected that each game will have a set of game-specific tasks to do what they want
*/
UCLASS()
class UCogSampleAbilityTask_PlayMontageAndWaitForEvent : public UAbilityTask
{
GENERATED_BODY()
public:
// Constructor and overrides
UCogSampleAbilityTask_PlayMontageAndWaitForEvent(const FObjectInitializer& ObjectInitializer);
/**
* The Blueprint node for this task, PlayMontageAndWaitForEvent, has some black magic from the plugin that automagically calls Activate()
* inside of K2Node_LatentAbilityCall as stated in the AbilityTask.h. Ability logic written in C++ probably needs to call Activate() itself manually.
*/
virtual void Activate() override;
virtual void ExternalCancel() override;
virtual FString GetDebugString() const override;
virtual void OnDestroy(bool AbilityEnded) override;
/** The montage completely finished playing */
UPROPERTY(BlueprintAssignable)
FCogSamplePlayMontageAndWaitForEventDelegate OnCompleted;
/** The montage started blending out */
UPROPERTY(BlueprintAssignable)
FCogSamplePlayMontageAndWaitForEventDelegate OnBlendOut;
/** The montage was interrupted */
UPROPERTY(BlueprintAssignable)
FCogSamplePlayMontageAndWaitForEventDelegate OnInterrupted;
/** The ability task was explicitly cancelled by another ability */
UPROPERTY(BlueprintAssignable)
FCogSamplePlayMontageAndWaitForEventDelegate OnCancelled;
/** One of the triggering gameplay events happened */
UPROPERTY(BlueprintAssignable)
FCogSamplePlayMontageAndWaitForEventDelegate EventReceived;
/**
* Play a montage and wait for it end. If a gameplay event happens that matches EventTags (or EventTags is empty), the EventReceived delegate will fire with a tag and event data.
* If StopWhenAbilityEnds is true, this montage will be aborted if the ability ends normally. It is always stopped when the ability is explicitly cancelled.
* On normal execution, OnBlendOut is called when the montage is blending out, and OnCompleted when it is completely done playing
* OnInterrupted is called if another montage overwrites this, and OnCancelled is called if the ability or task is cancelled
*
* @param TaskInstanceName Set to override the name of this task, for later querying
* @param MontageToPlay The montage to play on the character
* @param EventTags Any gameplay events matching this tag will activate the EventReceived callback. If empty, all events will trigger callback
* @param Rate Change to play the montage faster or slower
* @param bStopWhenAbilityEnds If true, this montage will be aborted if the ability ends normally. It is always stopped when the ability is explicitly cancelled
* @param AnimRootMotionTranslationScale Change to modify size of root motion or set to 0 to block it entirely
*/
UFUNCTION(BlueprintCallable, Category = "Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE"))
static UCogSampleAbilityTask_PlayMontageAndWaitForEvent* PlayMontageAndWaitForEvent(
UGameplayAbility* OwningAbility,
FName TaskInstanceName,
UAnimMontage* MontageToPlay,
FGameplayTagContainer EventTags,
float Rate = 1.f,
FName StartSection = NAME_None,
bool bStopWhenAbilityEnds = true,
float AnimRootMotionTranslationScale = 1.f);
private:
/** Montage that is playing */
UPROPERTY()
UAnimMontage* MontageToPlay;
/** List of tags to match against gameplay events */
UPROPERTY()
FGameplayTagContainer EventTags;
/** Playback rate */
UPROPERTY()
float Rate;
/** Section to start montage from */
UPROPERTY()
FName StartSection;
/** Modifies how root motion movement to apply */
UPROPERTY()
float AnimRootMotionTranslationScale;
/** Rather montage should be aborted if ability ends */
UPROPERTY()
bool bStopWhenAbilityEnds;
/** Checks if the ability is playing a montage and stops that montage, returns true if a montage was stopped, false if not. */
bool StopPlayingMontage();
void OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted);
void OnAbilityCancelled();
void OnMontageEnded(UAnimMontage* Montage, bool bInterrupted);
void OnGameplayEvent(FGameplayTag EventTag, const FGameplayEventData* Payload);
FOnMontageBlendingOutStarted BlendingOutDelegate;
FOnMontageEnded MontageEndedDelegate;
FDelegateHandle CancelledHandle;
FDelegateHandle EventHandle;
};
+5 -5
View File
@@ -6,12 +6,12 @@
#include "CogSampleAttributeSet_Health.h"
#include "CogSampleAttributeSet_Misc.h"
#include "CogSampleCharacterMovementComponent.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "CogSampleFunctionLibrary_Team.h"
#include "CogSampleGameplayAbility.h"
#include "CogSampleLogCategories.h"
#include "CogSamplePlayerController.h"
#include "CogSampleRootMotionParams.h"
#include "CogSampleTagLibrary.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "EnhancedInputComponent.h"
@@ -250,7 +250,7 @@ void ACogSampleCharacter::InitializeAbilitySystem()
{
if (UCogSampleGameplayAbility* Ab = Cast<UCogSampleGameplayAbility>(AddedSpec->GetPrimaryInstance()))
{
Ab->SetSlotTag(FCogSampleTagLibrary::ActiveAbilityCooldownTags[Index]);
Ab->SetCooldownTag(UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags[Index]);
}
}
@@ -702,7 +702,7 @@ void ACogSampleCharacter::UpdateActiveAbilitySlots()
{
FGameplayAbilitySpecHandle& Handle = ActiveAbilityHandles[i];
if (FCogSampleTagLibrary::ActiveAbilityCooldownTags.IsValidIndex(i) == false)
if (UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags.IsValidIndex(i) == false)
{
return;
}
@@ -719,8 +719,8 @@ void ACogSampleCharacter::UpdateActiveAbilitySlots()
continue;
}
FGameplayTag SlotTag = FCogSampleTagLibrary::ActiveAbilityCooldownTags[i];
AbilityInstance->SetSlotTag(SlotTag);
FGameplayTag SlotTag = UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags[i];
AbilityInstance->SetCooldownTag(SlotTag);
}
}
+8 -1
View File
@@ -4,7 +4,7 @@
#include "AbilitySystemInterface.h"
#include "ActiveGameplayEffectHandle.h"
#include "AttributeSet.h"
#include "CogDefines.h"
#include "CogSampleDefines.h"
#include "CogInterfaceAllegianceActor.h"
#include "CogInterfaceDebugFilteredActor.h"
#include "CogSampleDamageEvent.h"
@@ -29,6 +29,8 @@ struct FCogSampleRootMotionParams;
struct FGameplayEffectSpec;
struct FOnAttributeChangeData;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCogSampleCooldownUpdateEventDelegate, const UGameplayAbility*, Ability, float, Duration, float, TimeRemaining);
//--------------------------------------------------------------------------------------------------------------------------
USTRUCT(BlueprintType)
struct FActiveAbilityInfo
@@ -214,6 +216,9 @@ public:
UPROPERTY(BlueprintAssignable)
FCogSampleDamageEventDelegate OnDamageReceived;
UPROPERTY(BlueprintAssignable)
FCogSampleCooldownUpdateEventDelegate OnCooldownUpdated;
//----------------------------------------------------------------------------------------------------------------------
// Root Motion
//----------------------------------------------------------------------------------------------------------------------
@@ -261,6 +266,8 @@ private:
void OnGameplayEffectRemoved(const FActiveGameplayEffect& RemovedGameplayEffect);
void OnCooldownEffectUpdated(const FActiveGameplayEffect& GameplayEffect, bool bIsEffectRemoved);
void OnGhostTagNewOrRemoved(const FGameplayTag InTag, int32 NewCount);
void OnScaleAttributeChanged(const FOnAttributeChangeData& Data);
@@ -2,14 +2,18 @@
#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "CogDebugDraw.h"
#include "CogDebugPlot.h"
#include "CogSampleAttributeSet_Speed.h"
#include "CogSampleDefines.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "CogSampleLogCategories.h"
#include "CogSampleTagLibrary.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/Character.h"
#if USE_COG
#include "CogDebugDraw.h"
#include "CogDebugPlot.h"
#endif //USE_COG
//--------------------------------------------------------------------------------------------------------------------------
// UCogSampleCharacterMovementComponent::FCogSampleSavedMove
//--------------------------------------------------------------------------------------------------------------------------
@@ -1,7 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "CogDefines.h"
#include "CogSampleDefines.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "CogSampleCharacterMovementComponent.generated.h"
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "CoreMinimal.h"
#ifndef USE_COG
#define USE_COG (ENABLE_DRAW_DEBUG && !NO_LOGGING)
#endif
#if USE_COG
#include "CogDebugLogMacros.h"
#include "CogDebugSettings.h"
#define IF_COG(expr) { expr; }
#define COG_LOG_CATEGORY FLogCategoryBase
#define COG_LOG_ABILITY(Verbosity, Ability, Format, ...) \
if (Ability != nullptr) \
{ \
AActor* Actor = Ability->GetAvatarActorFromActorInfo(); \
if (FCogDebugSettings::IsDebugActiveForObject(Actor) || (int32)Verbosity <= (int32)ELogVerbosity::Warning) \
{ \
COG_LOG(LogCogAbility, Verbosity, TEXT("%s - %s - %s - %s"), \
*GetNameSafe(Actor), \
*GetNameSafe(Ability), \
ANSI_TO_TCHAR(__FUNCTION__), \
*FString::Printf(Format, ##__VA_ARGS__)); \
} \
} \
#else //USE_COG
#define IF_COG(expr) (0)
#define COG_LOG_CATEGORY FNoLoggingCategory
#define COG_LOG_ABILITY(...) (0)
#endif //USE_COG
@@ -2,7 +2,7 @@
#include "CogSampleAttributeSet_Health.h"
#include "CogSampleCharacter.h"
#include "CogSampleTagLibrary.h"
#include "CogSampleFunctionLibrary_Tag.h"
//--------------------------------------------------------------------------------------------------------------------------
struct FCogSampleDamageStatics
@@ -2,7 +2,7 @@
#include "CogSampleAttributeSet_Health.h"
#include "CogSampleCharacter.h"
#include "CogSampleTagLibrary.h"
#include "CogSampleFunctionLibrary_Tag.h"
//--------------------------------------------------------------------------------------------------------------------------
struct FCogSampleHealStatics
@@ -17,6 +17,18 @@ void UCogSampleExecCalculation_PoolRegen::Execute_Implementation(const FGameplay
EvaluationParameters.SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
EvaluationParameters.TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();
float MaxAmount = 0.0f;
if (MaxAmountAttribute.IsValid())
{
const float Amount = TargetAbilitySystem->GetNumericAttribute(AmountAttribute);
MaxAmount = TargetAbilitySystem->GetNumericAttribute(MaxAmountAttribute);
if (Amount >= MaxAmount)
{
return;
}
}
const float Period = ExecutionParams.GetOwningSpec().GetPeriod();
float RegenRateValue = 0.0f;
@@ -38,7 +50,6 @@ void UCogSampleExecCalculation_PoolRegen::Execute_Implementation(const FGameplay
case ECogSamplePoolRegenMode::MaxPoolDuration:
{
const float MaxAmount = TargetAbilitySystem->GetNumericAttribute(MaxAmountAttribute);
const float TotalDurationValue = TotalDuration.GetValueAtLevel(Spec.GetLevel());
RegenRateValue = TotalDurationValue > 0 ? (MaxAmount / TotalDurationValue) * Period : 0.0f;
}
@@ -24,6 +24,9 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FGameplayAttribute AmountAttribute;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FGameplayAttribute MaxAmountAttribute;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FGameplayTag DisableRegenTag;
@@ -36,9 +39,6 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (EditConditionHides, EditCondition = "Mode == ECogSamplePoolRegenMode::ScalableFloatRate"))
FScalableFloat RegenRate;
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (EditConditionHides, EditCondition = "Mode == ECogSamplePoolRegenMode::MaxPoolDuration"))
FGameplayAttribute MaxAmountAttribute;
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta = (EditConditionHides, EditCondition = "Mode == ECogSamplePoolRegenMode::MaxPoolDuration"))
FScalableFloat TotalDuration;
@@ -315,3 +315,4 @@ bool UCogSampleFunctionLibrary_Gameplay::IsActorMatchingTags(const AActor* Actor
bool Result = IsActorAbilitySystemMatchingTags(AbilitySystem, RequiredTags, IgnoredTags);
return Result;
}
@@ -1,7 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "CogDefines.h"
#include "CogSampleDefines.h"
#include "CogSampleFunctionLibrary_Gameplay.generated.h"
class UAbilitySystemComponent;
@@ -82,4 +82,7 @@ public:
static bool IsActorMatchingTags(const AActor* Actor, const FGameplayTagContainer& RequiredTags, const FGameplayTagContainer& IgnoredTags);
static bool MatchCooldownTag(const FGameplayTagContainer& TagContainer);
};
@@ -1,8 +1,9 @@
#include "CogSampleTagLibrary.h"
#include "CogSampleFunctionLibrary_Tag.h"
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Activation_Fail_Cooldown, "Ability.Activation.Fail.Cooldown");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Activation_Fail_Cost, "Ability.Activation.Fail.Cost");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown, "Ability.Cooldown");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown_1, "Ability.Cooldown.1");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown_2, "Ability.Cooldown.2");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown_3, "Ability.Cooldown.3");
@@ -12,6 +13,10 @@ UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown_6, "Ability.Cooldown.6");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown_7, "Ability.Cooldown.7");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Cooldown_8, "Ability.Cooldown.8");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Type_Active, "Ability.Type.Active");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Type_Passive, "Ability.Type.Passive");
UE_DEFINE_GAMEPLAY_TAG(Tag_Ability_Type_Hidden, "Ability.Type.Hidden");
UE_DEFINE_GAMEPLAY_TAG(Tag_Effect_Alignment_Negative, "Effect.Alignment.Negative");
UE_DEFINE_GAMEPLAY_TAG(Tag_Effect_Alignment_Positive, "Effect.Alignment.Positive");
@@ -47,7 +52,7 @@ UE_DEFINE_GAMEPLAY_TAG(Tag_MontageEvent_Cast_End, "MontageEvent.Cast.End");
UE_DEFINE_GAMEPLAY_TAG(Tag_Unit_Hero, "Unit.Hero");
UE_DEFINE_GAMEPLAY_TAG(Tag_Unit_Creature, "Unit.Creature");
TArray<FGameplayTag> FCogSampleTagLibrary::ActiveAbilityCooldownTags =
TArray<FGameplayTag> UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags =
{
Tag_Ability_Cooldown_1,
Tag_Ability_Cooldown_2,
@@ -57,4 +62,4 @@ TArray<FGameplayTag> FCogSampleTagLibrary::ActiveAbilityCooldownTags =
Tag_Ability_Cooldown_6,
Tag_Ability_Cooldown_7,
Tag_Ability_Cooldown_8,
};
};
@@ -6,6 +6,7 @@
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Activation_Fail_Cooldown);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Activation_Fail_Cost);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown_1);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown_2);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown_3);
@@ -15,6 +16,10 @@ UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown_6);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown_7);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Cooldown_8);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Type_Active);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Type_Passive);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Ability_Type_Hidden);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Effect_Alignment_Negative);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Effect_Alignment_Positive);
@@ -49,7 +54,7 @@ UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_MontageEvent_Cast_End);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Unit_Hero);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Tag_Unit_Creature);
struct FCogSampleTagLibrary
struct UCogSampleFunctionLibrary_Tag
{
public:
+2 -2
View File
@@ -2,7 +2,8 @@
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "CogDefines.h"
#include "CogSampleDefines.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "GameFramework/Character.h"
#include "GameFramework/GameMode.h"
#include "GameFramework/GameState.h"
@@ -45,7 +46,6 @@
#include "CogInputDataAsset_Actions.h"
#include "CogInputWindow_Actions.h"
#include "CogInputWindow_Gamepad.h"
#include "CogSampleTagLibrary.h"
#include "CogWindowManager.h"
#endif //USE_COG
+1 -1
View File
@@ -1,8 +1,8 @@
#pragma once
#include "CoreMinimal.h"
#include "CogSampleDefines.h"
#include "GameFramework/GameStateBase.h"
#include "CogDefines.h"
#include "CogSampleGameState.generated.h"
class UCogWindowManager;
+50 -5
View File
@@ -1,9 +1,13 @@
#include "CogSampleGameplayAbility.h"
#include "CogSampleTagLibrary.h"
#include "CogSampleGameplayEffectContext.h"
#include "CogSampleFunctionLibrary_Gameplay.h"
#include "CogSampleAttributeSet_Caster.h"
#include "CogSampleFunctionLibrary_Gameplay.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "CogSampleGameplayEffectContext.h"
#include "CogSampleLogCategories.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleGameplayAbility::UCogSampleGameplayAbility()
@@ -12,6 +16,27 @@ UCogSampleGameplayAbility::UCogSampleGameplayAbility()
ActivationBlockedTags.AddTag(Tag_Status_Dead);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::PreActivate(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, FOnGameplayAbilityEnded::FDelegate* OnGameplayAbilityEndedDelegate, const FGameplayEventData* TriggerEventData)
{
COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("PreActivate"));
Super::PreActivate(Handle, ActorInfo, ActivationInfo, OnGameplayAbilityEndedDelegate, TriggerEventData);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT("PredictionKey:%s"), *GetAbilitySystemComponentFromActorInfo_Checked()->ScopedPredictionKey.ToString());
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{
Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
COG_LOG_ABILITY(ELogVerbosity::Verbose, this, TEXT(""));
}
//--------------------------------------------------------------------------------------------------------------------------
float UCogSampleGameplayAbility::GetUnmitigatedCooldownDuration_Implementation() const
{
@@ -113,7 +138,7 @@ const FGameplayTagContainer* UCogSampleGameplayAbility::GetCooldownTags() const
{
MutableTags->AppendTags(*ParentTags);
}
MutableTags->AddTag(SlotTag);
MutableTags->AddTag(CooldownTag);
return MutableTags;
}
@@ -121,6 +146,11 @@ const FGameplayTagContainer* UCogSampleGameplayAbility::GetCooldownTags() const
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::ApplyCooldown(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const
{
if (ActorInfo->AbilitySystemComponent->HasMatchingGameplayTag(Tag_Status_NoCooldown))
{
return;
}
if (GetUnmitigatedCooldownDuration() <= 0.0f)
{
return;
@@ -129,7 +159,7 @@ void UCogSampleGameplayAbility::ApplyCooldown(const FGameplayAbilitySpecHandle H
if (UGameplayEffect* CooldownEffect = GetCooldownGameplayEffect())
{
FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(CooldownEffect->GetClass(), GetAbilityLevel());
SpecHandle.Data.Get()->DynamicGrantedTags.AddTag(SlotTag);
SpecHandle.Data.Get()->DynamicGrantedTags.AddTag(CooldownTag);
ApplyGameplayEffectSpecToOwner(Handle, ActorInfo, ActivationInfo, SpecHandle);
}
}
@@ -137,6 +167,11 @@ void UCogSampleGameplayAbility::ApplyCooldown(const FGameplayAbilitySpecHandle H
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const
{
if (ActorInfo->AbilitySystemComponent->HasMatchingGameplayTag(Tag_Status_NoCost))
{
return;
}
if (GetUnmitigatedCost() <= 0.0f)
{
return;
@@ -191,3 +226,13 @@ int32 UCogSampleGameplayAbility::GetIntValueAtAbilityLevel(const FScalableFloat&
{
return UCogSampleFunctionLibrary_Gameplay::GetIntValue(ScalableFloat, GetAbilityLevel());
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleGameplayAbility::GetCooldownInfos(float& TimeRemaining, float& CooldownDuration) const
{
//-------------------------------------------------------------------------------------
// Provide a default Handle as it is not used in GetCooldownTimeRemainingAndDuration
//-------------------------------------------------------------------------------------
FGameplayAbilitySpecHandle Handle;
GetCooldownTimeRemainingAndDuration(Handle, CurrentActorInfo, TimeRemaining, CooldownDuration);
}
+13 -5
View File
@@ -13,20 +13,26 @@ public:
UCogSampleGameplayAbility();
const FGameplayTag& GetSlotTag() const { return SlotTag; }
void SetSlotTag(FGameplayTag Value) { SlotTag = Value; }
//----------------------------------------------------------------------------------------------------------------------
// UGameplayAbility overrides
//----------------------------------------------------------------------------------------------------------------------
virtual void PreActivate(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, FOnGameplayAbilityEnded::FDelegate* OnGameplayAbilityEndedDelegate, const FGameplayEventData* TriggerEventData) override;
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
//----------------------------------------------------------------------------------------------------------------------
// Cooldown & Cost
//----------------------------------------------------------------------------------------------------------------------
UFUNCTION(BlueprintNativeEvent, BlueprintPure, Category = Ability)
float GetUnmitigatedCooldownDuration() const;
UFUNCTION(BlueprintNativeEvent, BlueprintPure, Category = Ability)
float GetUnmitigatedCost() const;
const FGameplayTag& GetCooldownTag() const { return CooldownTag; }
void SetCooldownTag(FGameplayTag Value) { CooldownTag = Value; }
virtual const FGameplayTagContainer* GetCooldownTags() const override;
virtual void ApplyCooldown(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const override;
@@ -37,6 +43,8 @@ public:
virtual void ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const override;
UFUNCTION(BlueprintCallable, Category = Ability, BlueprintPure=false)
virtual void GetCooldownInfos(float& TimeRemaining, float& CooldownDuration) const;
//----------------------------------------------------------------------------------------------------------------------
// Scalable Float
@@ -56,7 +64,7 @@ private:
bool IsCostGameplayEffectIsZero(const UGameplayEffect* GameplayEffect, float Level, const FGameplayEffectContextHandle& EffectContext) const;
UPROPERTY(BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
FGameplayTag SlotTag;
FGameplayTag CooldownTag;
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Cooldowns", meta = (AllowPrivateAccess = "true"))
FScalableFloat Cooldown;
@@ -0,0 +1,6 @@
#include "CogSampleGameplayCueManager.h"
bool UCogSampleGameplayCueManager::ShouldAsyncLoadRuntimeObjectLibraries() const
{
return false;
}
@@ -0,0 +1,13 @@
#pragma once
#include "CoreMinimal.h"
#include "GameplayCueManager.h"
#include "CogSampleGameplayCueManager.generated.h"
UCLASS()
class UCogSampleGameplayCueManager : public UGameplayCueManager
{
GENERATED_BODY()
virtual bool ShouldAsyncLoadRuntimeObjectLibraries() const override;
};
+1 -1
View File
@@ -1,7 +1,7 @@
#include "CogSampleLogCategories.h"
#include "AbilitySystemLog.h"
#include "CogDefines.h"
#include "CogSampleDefines.h"
#if USE_COG
#include "CogDebugLog.h"
@@ -1,8 +1,8 @@
#include "CogSampleModifierCalculation_Cost.h"
#include "CogSampleGameplayAbility.h"
#include "CogSampleFunctionLibrary_Tag.h"
#include "CogSampleAttributeSet_Caster.h"
#include "CogSampleTagLibrary.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleModifierCalculation_Cost::UCogSampleModifierCalculation_Cost()
+19 -8
View File
@@ -1,7 +1,7 @@
#include "CogSamplePlayerController.h"
#include "CogDebugLogMacros.h"
#include "CogDefines.h"
#include "CogSampleDefines.h"
#include "CogSampleCharacter.h"
#include "CogSampleLogCategories.h"
#include "CogSampleTargetAcquisition.h"
@@ -10,6 +10,7 @@
#if USE_COG
#include "CogAbilityReplicator.h"
#include "CogDebugDefines.h"
#include "CogDebugDraw.h"
#include "CogDebugReplicator.h"
#include "CogEngineReplicator.h"
#endif //USE_COG
@@ -154,16 +155,26 @@ void ACogSamplePlayerController::Tick(float DeltaSeconds)
//--------------------------------------------------------------------------------------------------------------------------
void ACogSamplePlayerController::TickTargeting(float DeltaSeconds)
{
if (TargetAcquisition == nullptr)
if (IsLocalController())
{
SetTarget(nullptr);
return;
if (TargetAcquisition == nullptr)
{
SetTarget(nullptr);
return;
}
TArray<AActor*> TagretToIgnore;
FCogSampleTargetAcquisitionResult Result;
TargetAcquisition->FindBestTarget(this, TagretToIgnore, nullptr, true, FVector2D::ZeroVector, false, Result);
SetTarget(Result.Target);
}
TArray<AActor*> TagretToIgnore;
FCogSampleTargetAcquisitionResult Result;
TargetAcquisition->FindBestTarget(this, TagretToIgnore, nullptr, true, FVector2D::ZeroVector, false, Result);
SetTarget(Result.Target);
#if USE_COG
if (Target != nullptr && ControlledCharacter != nullptr)
{
FCogDebugDraw::Segment(LogCogTargetAcquisition, ControlledCharacter.Get(), ControlledCharacter->GetActorLocation(), Target->GetActorLocation(), FColor::White, false);
}
#endif //USE_COG
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -1,8 +1,8 @@
#include "CogSampleTargetAcquisition.h"
#include "Camera/CameraComponent.h"
#include "CogDefines.h"
#include "CogSampleCharacter.h"
#include "CogSampleDefines.h"
#include "CogSampleFunctionLibrary_Gameplay.h"
#include "CogSampleLogCategories.h"
#include "CogSampleTargetableInterface.h"
@@ -129,7 +129,7 @@ void UCogSampleTargetAcquisition::FindBestTarget(
const FVector2D SearchDirectionNormalized = (TargetSwitchSearchDirection.IsNearlyZero() == false) ? TargetSwitchSearchDirection.GetSafeNormal() : FVector2D::ZeroVector;
if (SearchDirectionNormalized.IsNearlyZero() == false)
{
IF_COG(FCogDebugDraw::Segment2D(LogCogTargetAcquisition, Controller, FVector2D::ZeroVector, FVector2D(SearchDirectionNormalized.X, -SearchDirectionNormalized.Y), FColor(255, 255, 0, 255), bIsDebugPersistent));
FCogDebugDraw::Segment2D(LogCogTargetAcquisition, Controller, FVector2D::ZeroVector, FVector2D(SearchDirectionNormalized.X, -SearchDirectionNormalized.Y), FColor(255, 255, 0, 255), bIsDebugPersistent);
}
#endif //USE_COG
@@ -1,14 +1,14 @@
#include "CogSampleTask_WaitAttributeChanged.h"
#include "CogSampleTask_ListenForAttributeChanged.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleTask_WaitAttributeChanged* UCogSampleTask_WaitAttributeChanged::ListenForAttributeChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayAttribute Attribute)
UCogSampleTask_ListenForAttributeChanged* UCogSampleTask_ListenForAttributeChanged::ListenForAttributeChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayAttribute Attribute)
{
if (!IsValid(AbilitySystemComponent) || !Attribute.IsValid())
{
return nullptr;
}
UCogSampleTask_WaitAttributeChanged* WaitForAttributeChangedTask = NewObject<UCogSampleTask_WaitAttributeChanged>();
UCogSampleTask_ListenForAttributeChanged* WaitForAttributeChangedTask = NewObject<UCogSampleTask_ListenForAttributeChanged>();
WaitForAttributeChangedTask->AbilitySystemComponent = AbilitySystemComponent;
WaitForAttributeChangedTask->AttributeToListenFor = Attribute;
@@ -16,13 +16,13 @@ UCogSampleTask_WaitAttributeChanged* UCogSampleTask_WaitAttributeChanged::Listen
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleTask_WaitAttributeChanged::Activate()
void UCogSampleTask_ListenForAttributeChanged::Activate()
{
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeToListenFor).AddUObject(this, &UCogSampleTask_WaitAttributeChanged::AttributeChanged);
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeToListenFor).AddUObject(this, &UCogSampleTask_ListenForAttributeChanged::AttributeChanged);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleTask_WaitAttributeChanged::EndTask()
void UCogSampleTask_ListenForAttributeChanged::EndTask()
{
if (IsValid(AbilitySystemComponent))
{
@@ -34,7 +34,7 @@ void UCogSampleTask_WaitAttributeChanged::EndTask()
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleTask_WaitAttributeChanged::AttributeChanged(const FOnAttributeChangeData& Data)
void UCogSampleTask_ListenForAttributeChanged::AttributeChanged(const FOnAttributeChangeData& Data)
{
OnAttributeChanged.Broadcast(Data.Attribute, Data.NewValue, Data.OldValue);
}
@@ -4,7 +4,7 @@
#include "AbilitySystemComponent.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "CogSampleTask_WaitAttributeChanged.generated.h"
#include "CogSampleTask_ListenForAttributeChanged.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnAttributeChangedDelegate, FGameplayAttribute, Attribute, float, NewValue, float, OldValue)
;
@@ -12,7 +12,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnAttributeChangedDelegate, FGam
* Blueprint node to automatically register a listener for all attribute changes in an AbilitySystemComponent.
*/
UCLASS(BlueprintType, meta = (ExposedAsyncProxy = AsyncTask))
class UCogSampleTask_WaitAttributeChanged : public UBlueprintAsyncActionBase
class UCogSampleTask_ListenForAttributeChanged : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
@@ -21,7 +21,7 @@ public:
FOnAttributeChangedDelegate OnAttributeChanged;
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UCogSampleTask_WaitAttributeChanged* ListenForAttributeChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayAttribute Attribute);
static UCogSampleTask_ListenForAttributeChanged* ListenForAttributeChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayAttribute Attribute);
virtual void Activate() override;
@@ -0,0 +1,137 @@
#include "CogSampleTask_ListenForCooldownChanged.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogSampleTask_ListenForCooldownChanged* UCogSampleTask_ListenForCooldownChanged::ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayTagContainer InCooldownTags, bool InUseServerCooldown)
{
UCogSampleTask_ListenForCooldownChanged* ListenForCooldownChange = NewObject<UCogSampleTask_ListenForCooldownChanged>();
ListenForCooldownChange->AbilitySystem = AbilitySystemComponent;
ListenForCooldownChange->CooldownTags = InCooldownTags;
ListenForCooldownChange->UseServerCooldown = InUseServerCooldown;
if (!IsValid(AbilitySystemComponent) || InCooldownTags.Num() < 1)
{
ListenForCooldownChange->EndTask();
return nullptr;
}
AbilitySystemComponent->OnActiveGameplayEffectAddedDelegateToSelf.AddUObject(ListenForCooldownChange, &UCogSampleTask_ListenForCooldownChanged::OnActiveGameplayEffectAddedCallback);
TArray<FGameplayTag> CooldownTagArray;
InCooldownTags.GetGameplayTagArray(CooldownTagArray);
for (FGameplayTag CooldownTag : CooldownTagArray)
{
AbilitySystemComponent->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).AddUObject(ListenForCooldownChange, &UCogSampleTask_ListenForCooldownChanged::CooldownTagChanged);
}
return ListenForCooldownChange;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleTask_ListenForCooldownChanged::EndTask()
{
if (IsValid(AbilitySystem))
{
AbilitySystem->OnActiveGameplayEffectAddedDelegateToSelf.RemoveAll(this);
TArray<FGameplayTag> CooldownTagArray;
CooldownTags.GetGameplayTagArray(CooldownTagArray);
for (FGameplayTag CooldownTag : CooldownTagArray)
{
AbilitySystem->RegisterGameplayTagEvent(CooldownTag, EGameplayTagEventType::NewOrRemoved).RemoveAll(this);
}
}
SetReadyToDestroy();
MarkAsGarbage();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSampleTask_ListenForCooldownChanged::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 (AbilitySystem->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 UCogSampleTask_ListenForCooldownChanged::CooldownTagChanged(const FGameplayTag CooldownTag, int32 NewCount)
{
if (NewCount == 0)
{
OnCooldownEnd.Broadcast(CooldownTag, -1.0f, -1.0f);
}
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogSampleTask_ListenForCooldownChanged::GetCooldownRemainingForTag(FGameplayTagContainer InCooldownTags, float& TimeRemaining, float& CooldownDuration)
{
if (IsValid(AbilitySystem) && InCooldownTags.Num() > 0)
{
TimeRemaining = 0.f;
CooldownDuration = 0.f;
FGameplayEffectQuery const Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(InCooldownTags);
TArray< TPair<float, float> > DurationAndTimeRemaining = AbilitySystem->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;
}
@@ -0,0 +1,51 @@
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "AbilitySystemComponent.h"
#include "GameplayTagContainer.h"
#include "CogSampleTask_ListenForCooldownChanged.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCogSampleOnCooldownChangedEventDelegate, FGameplayTag, CooldownTag, float, TimeRemaining, float, Duration);
/**
* Blueprint node to automatically register a listener for changes (Begin and End) to an array of Cooldown tags.
* Useful to use in UI.
*/
UCLASS(BlueprintType, meta = (ExposedAsyncProxy = AsyncTask))
class UCogSampleTask_ListenForCooldownChanged : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable)
FCogSampleOnCooldownChangedEventDelegate OnCooldownBegin;
UPROPERTY(BlueprintAssignable)
FCogSampleOnCooldownChangedEventDelegate OnCooldownEnd;
// Listens for changes (Begin and End) to cooldown GameplayEffects based on the cooldown tag.
// UseServerCooldown determines if the Sever's cooldown is returned in addition to the local predicted cooldown.
// If using ServerCooldown, TimeRemaining and Duration will return -1 to signal local predicted cooldown has begun.
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UCogSampleTask_ListenForCooldownChanged* ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayTagContainer CooldownTags, bool UseServerCooldown);
// You must call this function manually when you want the AsyncTask to end.
// For UMG Widgets, you would call it in the Widget's Destruct event.
UFUNCTION(BlueprintCallable)
void EndTask();
protected:
UPROPERTY()
UAbilitySystemComponent* AbilitySystem;
FGameplayTagContainer CooldownTags;
bool UseServerCooldown;
virtual void OnActiveGameplayEffectAddedCallback(UAbilitySystemComponent* Target, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveHandle);
virtual void CooldownTagChanged(const FGameplayTag CooldownTag, int32 NewCount);
bool GetCooldownRemainingForTag(FGameplayTagContainer CooldownTags, float& TimeRemaining, float& CooldownDuration);
};