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
+2
View File
@@ -4,6 +4,8 @@ ProjectName=Third Person Game Template
[/Script/GameplayAbilities.AbilitySystemGlobals]
AbilitySystemGlobalsClassName=/Script/CogSample.CogSampleAbilitySystemGlobals
GlobalGameplayCueManagerClass=/Script/CogSample.CogSampleGameplayCueManager
+GameplayCueNotifyPaths="/Game/"
[/Script/DataRegistry.DataRegistrySettings]
+DirectoriesToScan=(Path="/Game/Core/Debug/")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -243,7 +243,7 @@ void UCogEngineWindow_OutputLog::RenderContent()
if (IsTableShown == false)
{
ImGui::BeginChild("Scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
ImGui::BeginChild("Scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
}
const char* BufferStart = TextBuffer.begin();
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.
-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);
};