diff --git a/Config/DefaultGame.ini b/Config/DefaultGame.ini index a040057..d7d116c 100644 --- a/Config/DefaultGame.ini +++ b/Config/DefaultGame.ini @@ -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/") diff --git a/Content/Characters/(Shared)/Abilities/Death/GA_Character_Death.uasset b/Content/Characters/(Shared)/Abilities/Death/GA_Character_Death.uasset index f37ebce..71ed587 100644 Binary files a/Content/Characters/(Shared)/Abilities/Death/GA_Character_Death.uasset and b/Content/Characters/(Shared)/Abilities/Death/GA_Character_Death.uasset differ diff --git a/Content/Characters/(Shared)/Abilities/GA_Base.uasset b/Content/Characters/(Shared)/Abilities/GA_Base.uasset new file mode 100644 index 0000000..0579223 Binary files /dev/null and b/Content/Characters/(Shared)/Abilities/GA_Base.uasset differ diff --git a/Content/Characters/(Shared)/Abilities/GA_Cast.uasset b/Content/Characters/(Shared)/Abilities/GA_Cast.uasset index 3d593a2..0620789 100644 Binary files a/Content/Characters/(Shared)/Abilities/GA_Cast.uasset and b/Content/Characters/(Shared)/Abilities/GA_Cast.uasset differ diff --git a/Content/Characters/(Shared)/Abilities/Revive/GA_Character_Revive.uasset b/Content/Characters/(Shared)/Abilities/Revive/GA_Character_Revive.uasset index 51f9051..8b628eb 100644 Binary files a/Content/Characters/(Shared)/Abilities/Revive/GA_Character_Revive.uasset and b/Content/Characters/(Shared)/Abilities/Revive/GA_Character_Revive.uasset differ diff --git a/Content/Characters/(Shared)/Effects/BP_PoolRegen_Health.uasset b/Content/Characters/(Shared)/Effects/BP_PoolRegen_Health.uasset index 1e9e215..f8b58a6 100644 Binary files a/Content/Characters/(Shared)/Effects/BP_PoolRegen_Health.uasset and b/Content/Characters/(Shared)/Effects/BP_PoolRegen_Health.uasset differ diff --git a/Content/Characters/(Shared)/Effects/BP_PoolRegen_Stamina.uasset b/Content/Characters/(Shared)/Effects/BP_PoolRegen_Stamina.uasset index d84b79f..b34423d 100644 Binary files a/Content/Characters/(Shared)/Effects/BP_PoolRegen_Stamina.uasset and b/Content/Characters/(Shared)/Effects/BP_PoolRegen_Stamina.uasset differ diff --git a/Content/Characters/Creature1/Attributes/GE_Creature1.uasset b/Content/Characters/Creature1/Attributes/GE_Creature1.uasset deleted file mode 100644 index 73270c6..0000000 Binary files a/Content/Characters/Creature1/Attributes/GE_Creature1.uasset and /dev/null differ diff --git a/Content/Characters/Creature1/Attributes/GE_Creature1_Attributes.uasset b/Content/Characters/Creature1/Attributes/GE_Creature1_Attributes.uasset new file mode 100644 index 0000000..df91958 Binary files /dev/null and b/Content/Characters/Creature1/Attributes/GE_Creature1_Attributes.uasset differ diff --git a/Content/Characters/Creature1/BP_Creature1.uasset b/Content/Characters/Creature1/BP_Creature1.uasset index 6e5a98a..3723927 100644 Binary files a/Content/Characters/Creature1/BP_Creature1.uasset and b/Content/Characters/Creature1/BP_Creature1.uasset differ diff --git a/Content/Characters/Creature2/Attributes/GE_Creature2.uasset b/Content/Characters/Creature2/Attributes/GE_Creature2.uasset deleted file mode 100644 index 27ba3b0..0000000 Binary files a/Content/Characters/Creature2/Attributes/GE_Creature2.uasset and /dev/null differ diff --git a/Content/Characters/Creature2/Attributes/GE_Creature2_Attributes.uasset b/Content/Characters/Creature2/Attributes/GE_Creature2_Attributes.uasset new file mode 100644 index 0000000..1f74983 Binary files /dev/null and b/Content/Characters/Creature2/Attributes/GE_Creature2_Attributes.uasset differ diff --git a/Content/Characters/Creature2/BP_Creature2.uasset b/Content/Characters/Creature2/BP_Creature2.uasset index 766f172..ba777d5 100644 Binary files a/Content/Characters/Creature2/BP_Creature2.uasset and b/Content/Characters/Creature2/BP_Creature2.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Blast/GA_Hero1_Blast.uasset b/Content/Characters/Hero1/Abilities/Blast/GA_Hero1_Blast.uasset index ebb2103..161c30b 100644 Binary files a/Content/Characters/Hero1/Abilities/Blast/GA_Hero1_Blast.uasset and b/Content/Characters/Hero1/Abilities/Blast/GA_Hero1_Blast.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Blast/T_Hero1_Blast.uasset b/Content/Characters/Hero1/Abilities/Blast/T_Hero1_Blast.uasset new file mode 100644 index 0000000..eea2636 Binary files /dev/null and b/Content/Characters/Hero1/Abilities/Blast/T_Hero1_Blast.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Jump/GA_Hero1_Jump.uasset b/Content/Characters/Hero1/Abilities/Jump/GA_Hero1_Jump.uasset index 703b478..40fe665 100644 Binary files a/Content/Characters/Hero1/Abilities/Jump/GA_Hero1_Jump.uasset and b/Content/Characters/Hero1/Abilities/Jump/GA_Hero1_Jump.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Jump/T_Hero1_Jump.uasset b/Content/Characters/Hero1/Abilities/Jump/T_Hero1_Jump.uasset new file mode 100644 index 0000000..ce35a43 Binary files /dev/null and b/Content/Characters/Hero1/Abilities/Jump/T_Hero1_Jump.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset b/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset index 3251b27..af60af9 100644 Binary files a/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset and b/Content/Characters/Hero1/Abilities/Poison/AM_Hero1_Poison.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset b/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset index 6842526..2034f5e 100644 Binary files a/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset and b/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Poison/GE_Hero1_Poison_Target.uasset b/Content/Characters/Hero1/Abilities/Poison/GE_Hero1_Poison_Target.uasset index aca458d..e307caf 100644 Binary files a/Content/Characters/Hero1/Abilities/Poison/GE_Hero1_Poison_Target.uasset and b/Content/Characters/Hero1/Abilities/Poison/GE_Hero1_Poison_Target.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Poison/T_Hero1_Poison.uasset b/Content/Characters/Hero1/Abilities/Poison/T_Hero1_Poison.uasset new file mode 100644 index 0000000..5b632a3 Binary files /dev/null and b/Content/Characters/Hero1/Abilities/Poison/T_Hero1_Poison.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Shield/GA_Hero1_Shield.uasset b/Content/Characters/Hero1/Abilities/Shield/GA_Hero1_Shield.uasset index 0d9156f..e0a8ff0 100644 Binary files a/Content/Characters/Hero1/Abilities/Shield/GA_Hero1_Shield.uasset and b/Content/Characters/Hero1/Abilities/Shield/GA_Hero1_Shield.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Shield/T_Hero1_Shield.uasset b/Content/Characters/Hero1/Abilities/Shield/T_Hero1_Shield.uasset new file mode 100644 index 0000000..545bbb0 Binary files /dev/null and b/Content/Characters/Hero1/Abilities/Shield/T_Hero1_Shield.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset b/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset index 834b348..bc47ca9 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset and b/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset b/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset index 3f8658d..e9f2636 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset and b/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset b/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset index d0fd6b8..2fe4c50 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset and b/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset b/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset index b513039..90caadd 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset and b/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset differ diff --git a/Content/Characters/Hero2/Attributes/GE_Hero2_Attributes.uasset b/Content/Characters/Hero2/Attributes/GE_Hero2_Attributes.uasset index 8f6af04..ad8f734 100644 Binary files a/Content/Characters/Hero2/Attributes/GE_Hero2_Attributes.uasset and b/Content/Characters/Hero2/Attributes/GE_Hero2_Attributes.uasset differ diff --git a/Content/Core/Hud/WBP_Ability.uasset b/Content/Core/Hud/WBP_Ability.uasset new file mode 100644 index 0000000..9bde073 Binary files /dev/null and b/Content/Core/Hud/WBP_Ability.uasset differ diff --git a/Content/Core/Hud/WBP_AbilityPanel.uasset b/Content/Core/Hud/WBP_AbilityPanel.uasset new file mode 100644 index 0000000..96588e8 Binary files /dev/null and b/Content/Core/Hud/WBP_AbilityPanel.uasset differ diff --git a/Content/Core/Hud/WBP_Bar.uasset b/Content/Core/Hud/WBP_Bar.uasset new file mode 100644 index 0000000..a84261a Binary files /dev/null and b/Content/Core/Hud/WBP_Bar.uasset differ diff --git a/Content/Core/Hud/WBP_Hud.uasset b/Content/Core/Hud/WBP_Hud.uasset index c615adb..21451c2 100644 Binary files a/Content/Core/Hud/WBP_Hud.uasset and b/Content/Core/Hud/WBP_Hud.uasset differ diff --git a/Content/Core/Hud/WBP_Status.uasset b/Content/Core/Hud/WBP_Status.uasset index 441c16a..b853680 100644 Binary files a/Content/Core/Hud/WBP_Status.uasset and b/Content/Core/Hud/WBP_Status.uasset differ diff --git a/Content/Core/Hud/WBP_StatusBar.uasset b/Content/Core/Hud/WBP_StatusBar.uasset index 1e75789..1975a4c 100644 Binary files a/Content/Core/Hud/WBP_StatusBar.uasset and b/Content/Core/Hud/WBP_StatusBar.uasset differ diff --git a/Content/Core/Materials/M_Clock.uasset b/Content/Core/Materials/M_Clock.uasset new file mode 100644 index 0000000..8547db9 Binary files /dev/null and b/Content/Core/Materials/M_Clock.uasset differ diff --git a/Content/Core/Textures/T_AbilityBack.uasset b/Content/Core/Textures/T_AbilityBack.uasset new file mode 100644 index 0000000..6151f83 Binary files /dev/null and b/Content/Core/Textures/T_AbilityBack.uasset differ diff --git a/Content/Core/Textures/T_AbilityBorder.uasset b/Content/Core/Textures/T_AbilityBorder.uasset new file mode 100644 index 0000000..334ac46 Binary files /dev/null and b/Content/Core/Textures/T_AbilityBorder.uasset differ diff --git a/Plugins/CogEngine/Source/CogEngine/Private/CogEngineWindow_OutputLog.cpp b/Plugins/CogEngine/Source/CogEngine/Private/CogEngineWindow_OutputLog.cpp index 11a3ab9..7d8e83c 100644 --- a/Plugins/CogEngine/Source/CogEngine/Private/CogEngineWindow_OutputLog.cpp +++ b/Plugins/CogEngine/Source/CogEngine/Private/CogEngineWindow_OutputLog.cpp @@ -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(); diff --git a/RawAssets/T_AbilityBack.PNG b/RawAssets/T_AbilityBack.PNG new file mode 100644 index 0000000..1c793eb Binary files /dev/null and b/RawAssets/T_AbilityBack.PNG differ diff --git a/RawAssets/T_AbilityBack.afphoto b/RawAssets/T_AbilityBack.afphoto new file mode 100644 index 0000000..7c0085b Binary files /dev/null and b/RawAssets/T_AbilityBack.afphoto differ diff --git a/RawAssets/T_AbilityBorder.PNG b/RawAssets/T_AbilityBorder.PNG new file mode 100644 index 0000000..a5c631a Binary files /dev/null and b/RawAssets/T_AbilityBorder.PNG differ diff --git a/RawAssets/T_AbilityBorder.afphoto b/RawAssets/T_AbilityBorder.afphoto new file mode 100644 index 0000000..603d58b Binary files /dev/null and b/RawAssets/T_AbilityBorder.afphoto differ diff --git a/RawAssets/T_Hero1_Blast.PNG b/RawAssets/T_Hero1_Blast.PNG new file mode 100644 index 0000000..22fff8f Binary files /dev/null and b/RawAssets/T_Hero1_Blast.PNG differ diff --git a/RawAssets/T_Hero1_Blast.afphoto b/RawAssets/T_Hero1_Blast.afphoto new file mode 100644 index 0000000..7a5ffe1 Binary files /dev/null and b/RawAssets/T_Hero1_Blast.afphoto differ diff --git a/RawAssets/T_Hero1_Jump.PNG b/RawAssets/T_Hero1_Jump.PNG new file mode 100644 index 0000000..509e270 Binary files /dev/null and b/RawAssets/T_Hero1_Jump.PNG differ diff --git a/RawAssets/T_Hero1_Jump.afphoto b/RawAssets/T_Hero1_Jump.afphoto new file mode 100644 index 0000000..6de81e6 Binary files /dev/null and b/RawAssets/T_Hero1_Jump.afphoto differ diff --git a/RawAssets/T_Hero1_Poison.PNG b/RawAssets/T_Hero1_Poison.PNG new file mode 100644 index 0000000..331b055 Binary files /dev/null and b/RawAssets/T_Hero1_Poison.PNG differ diff --git a/RawAssets/T_Hero1_Poison.afphoto b/RawAssets/T_Hero1_Poison.afphoto new file mode 100644 index 0000000..568d395 Binary files /dev/null and b/RawAssets/T_Hero1_Poison.afphoto differ diff --git a/RawAssets/T_Hero1_Shield.PNG b/RawAssets/T_Hero1_Shield.PNG new file mode 100644 index 0000000..451fe3d Binary files /dev/null and b/RawAssets/T_Hero1_Shield.PNG differ diff --git a/RawAssets/T_Hero1_Shield.afphoto b/RawAssets/T_Hero1_Shield.afphoto new file mode 100644 index 0000000..7dbe82a Binary files /dev/null and b/RawAssets/T_Hero1_Shield.afphoto differ diff --git a/Source/CogSample/CogDefines.h b/Source/CogSample/CogDefines.h deleted file mode 100644 index 4cb5e46..0000000 --- a/Source/CogSample/CogDefines.h +++ /dev/null @@ -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 diff --git a/Source/CogSample/CogSampleAbilitySystemGlobals.cpp b/Source/CogSample/CogSampleAbilitySystemGlobals.cpp index a91f04c..047cf13 100644 --- a/Source/CogSample/CogSampleAbilitySystemGlobals.cpp +++ b/Source/CogSample/CogSampleAbilitySystemGlobals.cpp @@ -5,4 +5,4 @@ FGameplayEffectContext* UCogSampleAbilitySystemGlobals::AllocGameplayEffectContext() const { return new FCogSampleGameplayEffectContext(); -} +} \ No newline at end of file diff --git a/Source/CogSample/CogSampleAbilitySystemGlobals.h b/Source/CogSample/CogSampleAbilitySystemGlobals.h index 6282878..8ccecb8 100644 --- a/Source/CogSample/CogSampleAbilitySystemGlobals.h +++ b/Source/CogSample/CogSampleAbilitySystemGlobals.h @@ -9,5 +9,5 @@ class UCogSampleAbilitySystemGlobals : public UAbilitySystemGlobals { GENERATED_BODY() - virtual FGameplayEffectContext* AllocGameplayEffectContext() const override; + virtual FGameplayEffectContext* AllocGameplayEffectContext() const override; }; diff --git a/Source/CogSample/CogSampleAbilityTask_PlayMontageAndWaitForEvent.cpp b/Source/CogSample/CogSampleAbilityTask_PlayMontageAndWaitForEvent.cpp new file mode 100644 index 0000000..e52fe10 --- /dev/null +++ b/Source/CogSample/CogSampleAbilityTask_PlayMontageAndWaitForEvent.cpp @@ -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(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(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(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)); +} + + + diff --git a/Source/CogSample/CogSampleAbilityTask_PlayMontageAndWaitForEvent.h b/Source/CogSample/CogSampleAbilityTask_PlayMontageAndWaitForEvent.h new file mode 100644 index 0000000..7a2c4fd --- /dev/null +++ b/Source/CogSample/CogSampleAbilityTask_PlayMontageAndWaitForEvent.h @@ -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; +}; diff --git a/Source/CogSample/CogSampleCharacter.cpp b/Source/CogSample/CogSampleCharacter.cpp index bb605f5..9a5376a 100644 --- a/Source/CogSample/CogSampleCharacter.cpp +++ b/Source/CogSample/CogSampleCharacter.cpp @@ -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(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); } } diff --git a/Source/CogSample/CogSampleCharacter.h b/Source/CogSample/CogSampleCharacter.h index d896483..d479647 100644 --- a/Source/CogSample/CogSampleCharacter.h +++ b/Source/CogSample/CogSampleCharacter.h @@ -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); diff --git a/Source/CogSample/CogSampleCharacterMovementComponent.cpp b/Source/CogSample/CogSampleCharacterMovementComponent.cpp index ac33e8b..ee50915 100644 --- a/Source/CogSample/CogSampleCharacterMovementComponent.cpp +++ b/Source/CogSample/CogSampleCharacterMovementComponent.cpp @@ -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 //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Source/CogSample/CogSampleCharacterMovementComponent.h b/Source/CogSample/CogSampleCharacterMovementComponent.h index 689dd58..6af1c86 100644 --- a/Source/CogSample/CogSampleCharacterMovementComponent.h +++ b/Source/CogSample/CogSampleCharacterMovementComponent.h @@ -1,7 +1,7 @@ #pragma once #include "CoreMinimal.h" -#include "CogDefines.h" +#include "CogSampleDefines.h" #include "GameFramework/CharacterMovementComponent.h" #include "CogSampleCharacterMovementComponent.generated.h" diff --git a/Source/CogSample/CogSampleDefines.h b/Source/CogSample/CogSampleDefines.h new file mode 100644 index 0000000..8e5fe99 --- /dev/null +++ b/Source/CogSample/CogSampleDefines.h @@ -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 diff --git a/Source/CogSample/CogSampleExecCalculation_Damage.cpp b/Source/CogSample/CogSampleExecCalculation_Damage.cpp index 72650ed..696c5ac 100644 --- a/Source/CogSample/CogSampleExecCalculation_Damage.cpp +++ b/Source/CogSample/CogSampleExecCalculation_Damage.cpp @@ -2,7 +2,7 @@ #include "CogSampleAttributeSet_Health.h" #include "CogSampleCharacter.h" -#include "CogSampleTagLibrary.h" +#include "CogSampleFunctionLibrary_Tag.h" //-------------------------------------------------------------------------------------------------------------------------- struct FCogSampleDamageStatics diff --git a/Source/CogSample/CogSampleExecCalculation_Heal.cpp b/Source/CogSample/CogSampleExecCalculation_Heal.cpp index 74f6c0a..64fb873 100644 --- a/Source/CogSample/CogSampleExecCalculation_Heal.cpp +++ b/Source/CogSample/CogSampleExecCalculation_Heal.cpp @@ -2,7 +2,7 @@ #include "CogSampleAttributeSet_Health.h" #include "CogSampleCharacter.h" -#include "CogSampleTagLibrary.h" +#include "CogSampleFunctionLibrary_Tag.h" //-------------------------------------------------------------------------------------------------------------------------- struct FCogSampleHealStatics diff --git a/Source/CogSample/CogSampleExecCalculation_PoolRegen.cpp b/Source/CogSample/CogSampleExecCalculation_PoolRegen.cpp index ca43ca8..f2744ae 100644 --- a/Source/CogSample/CogSampleExecCalculation_PoolRegen.cpp +++ b/Source/CogSample/CogSampleExecCalculation_PoolRegen.cpp @@ -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; } diff --git a/Source/CogSample/CogSampleExecCalculation_PoolRegen.h b/Source/CogSample/CogSampleExecCalculation_PoolRegen.h index e4d35bb..4f01f1f 100644 --- a/Source/CogSample/CogSampleExecCalculation_PoolRegen.h +++ b/Source/CogSample/CogSampleExecCalculation_PoolRegen.h @@ -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; diff --git a/Source/CogSample/CogSampleFunctionLibrary_Gameplay.cpp b/Source/CogSample/CogSampleFunctionLibrary_Gameplay.cpp index 72821cc..573d08d 100644 --- a/Source/CogSample/CogSampleFunctionLibrary_Gameplay.cpp +++ b/Source/CogSample/CogSampleFunctionLibrary_Gameplay.cpp @@ -315,3 +315,4 @@ bool UCogSampleFunctionLibrary_Gameplay::IsActorMatchingTags(const AActor* Actor bool Result = IsActorAbilitySystemMatchingTags(AbilitySystem, RequiredTags, IgnoredTags); return Result; } + diff --git a/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h b/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h index bc8eed4..3499b95 100644 --- a/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h +++ b/Source/CogSample/CogSampleFunctionLibrary_Gameplay.h @@ -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); + + }; diff --git a/Source/CogSample/CogSampleTagLibrary.cpp b/Source/CogSample/CogSampleFunctionLibrary_Tag.cpp similarity index 87% rename from Source/CogSample/CogSampleTagLibrary.cpp rename to Source/CogSample/CogSampleFunctionLibrary_Tag.cpp index 6fb0aec..47d3bc2 100644 --- a/Source/CogSample/CogSampleTagLibrary.cpp +++ b/Source/CogSample/CogSampleFunctionLibrary_Tag.cpp @@ -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 FCogSampleTagLibrary::ActiveAbilityCooldownTags = +TArray UCogSampleFunctionLibrary_Tag::ActiveAbilityCooldownTags = { Tag_Ability_Cooldown_1, Tag_Ability_Cooldown_2, @@ -57,4 +62,4 @@ TArray FCogSampleTagLibrary::ActiveAbilityCooldownTags = Tag_Ability_Cooldown_6, Tag_Ability_Cooldown_7, Tag_Ability_Cooldown_8, -}; \ No newline at end of file +}; diff --git a/Source/CogSample/CogSampleTagLibrary.h b/Source/CogSample/CogSampleFunctionLibrary_Tag.h similarity index 89% rename from Source/CogSample/CogSampleTagLibrary.h rename to Source/CogSample/CogSampleFunctionLibrary_Tag.h index a0ad93b..c764e60 100644 --- a/Source/CogSample/CogSampleTagLibrary.h +++ b/Source/CogSample/CogSampleFunctionLibrary_Tag.h @@ -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: diff --git a/Source/CogSample/CogSampleGameState.cpp b/Source/CogSample/CogSampleGameState.cpp index cb1ca49..882fe9a 100644 --- a/Source/CogSample/CogSampleGameState.cpp +++ b/Source/CogSample/CogSampleGameState.cpp @@ -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 diff --git a/Source/CogSample/CogSampleGameState.h b/Source/CogSample/CogSampleGameState.h index c224cb3..79aad03 100644 --- a/Source/CogSample/CogSampleGameState.h +++ b/Source/CogSample/CogSampleGameState.h @@ -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; diff --git a/Source/CogSample/CogSampleGameplayAbility.cpp b/Source/CogSample/CogSampleGameplayAbility.cpp index 6fabb95..25d4174 100644 --- a/Source/CogSample/CogSampleGameplayAbility.cpp +++ b/Source/CogSample/CogSampleGameplayAbility.cpp @@ -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); +} \ No newline at end of file diff --git a/Source/CogSample/CogSampleGameplayAbility.h b/Source/CogSample/CogSampleGameplayAbility.h index d5302af..e02da56 100644 --- a/Source/CogSample/CogSampleGameplayAbility.h +++ b/Source/CogSample/CogSampleGameplayAbility.h @@ -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; diff --git a/Source/CogSample/CogSampleGameplayCueManager.cpp b/Source/CogSample/CogSampleGameplayCueManager.cpp new file mode 100644 index 0000000..3ed023a --- /dev/null +++ b/Source/CogSample/CogSampleGameplayCueManager.cpp @@ -0,0 +1,6 @@ +#include "CogSampleGameplayCueManager.h" + +bool UCogSampleGameplayCueManager::ShouldAsyncLoadRuntimeObjectLibraries() const +{ + return false; +} \ No newline at end of file diff --git a/Source/CogSample/CogSampleGameplayCueManager.h b/Source/CogSample/CogSampleGameplayCueManager.h new file mode 100644 index 0000000..5afa3c2 --- /dev/null +++ b/Source/CogSample/CogSampleGameplayCueManager.h @@ -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; +}; diff --git a/Source/CogSample/CogSampleLogCategories.cpp b/Source/CogSample/CogSampleLogCategories.cpp index e18ff0d..5a61dec 100644 --- a/Source/CogSample/CogSampleLogCategories.cpp +++ b/Source/CogSample/CogSampleLogCategories.cpp @@ -1,7 +1,7 @@ #include "CogSampleLogCategories.h" #include "AbilitySystemLog.h" -#include "CogDefines.h" +#include "CogSampleDefines.h" #if USE_COG #include "CogDebugLog.h" diff --git a/Source/CogSample/CogSampleModifierCalculation_Cost.cpp b/Source/CogSample/CogSampleModifierCalculation_Cost.cpp index b7eca7e..8a3d4ec 100644 --- a/Source/CogSample/CogSampleModifierCalculation_Cost.cpp +++ b/Source/CogSample/CogSampleModifierCalculation_Cost.cpp @@ -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() diff --git a/Source/CogSample/CogSamplePlayerController.cpp b/Source/CogSample/CogSamplePlayerController.cpp index 5d2db4f..f1bcdb5 100644 --- a/Source/CogSample/CogSamplePlayerController.cpp +++ b/Source/CogSample/CogSamplePlayerController.cpp @@ -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 TagretToIgnore; + FCogSampleTargetAcquisitionResult Result; + TargetAcquisition->FindBestTarget(this, TagretToIgnore, nullptr, true, FVector2D::ZeroVector, false, Result); + SetTarget(Result.Target); } - TArray 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 } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Source/CogSample/CogSampleTargetAcquisition.cpp b/Source/CogSample/CogSampleTargetAcquisition.cpp index e3b7e2c..4473837 100644 --- a/Source/CogSample/CogSampleTargetAcquisition.cpp +++ b/Source/CogSample/CogSampleTargetAcquisition.cpp @@ -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 diff --git a/Source/CogSample/CogSampleTask_WaitAttributeChanged.cpp b/Source/CogSample/CogSampleTask_ListenForAttributeChanged.cpp similarity index 62% rename from Source/CogSample/CogSampleTask_WaitAttributeChanged.cpp rename to Source/CogSample/CogSampleTask_ListenForAttributeChanged.cpp index 1ea3f1c..471b123 100644 --- a/Source/CogSample/CogSampleTask_WaitAttributeChanged.cpp +++ b/Source/CogSample/CogSampleTask_ListenForAttributeChanged.cpp @@ -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_ListenForAttributeChanged* WaitForAttributeChangedTask = NewObject(); 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); } \ No newline at end of file diff --git a/Source/CogSample/CogSampleTask_WaitAttributeChanged.h b/Source/CogSample/CogSampleTask_ListenForAttributeChanged.h similarity index 75% rename from Source/CogSample/CogSampleTask_WaitAttributeChanged.h rename to Source/CogSample/CogSampleTask_ListenForAttributeChanged.h index 2f1d0df..ac73582 100644 --- a/Source/CogSample/CogSampleTask_WaitAttributeChanged.h +++ b/Source/CogSample/CogSampleTask_ListenForAttributeChanged.h @@ -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; diff --git a/Source/CogSample/CogSampleTask_ListenForCooldownChanged.cpp b/Source/CogSample/CogSampleTask_ListenForCooldownChanged.cpp new file mode 100644 index 0000000..1d6af02 --- /dev/null +++ b/Source/CogSample/CogSampleTask_ListenForCooldownChanged.cpp @@ -0,0 +1,137 @@ +#include "CogSampleTask_ListenForCooldownChanged.h" + +//-------------------------------------------------------------------------------------------------------------------------- +UCogSampleTask_ListenForCooldownChanged* UCogSampleTask_ListenForCooldownChanged::ListenForCooldownChange(UAbilitySystemComponent* AbilitySystemComponent, FGameplayTagContainer InCooldownTags, bool InUseServerCooldown) +{ + UCogSampleTask_ListenForCooldownChanged* ListenForCooldownChange = NewObject(); + 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 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 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 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 > 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; +} diff --git a/Source/CogSample/CogSampleTask_ListenForCooldownChanged.h b/Source/CogSample/CogSampleTask_ListenForCooldownChanged.h new file mode 100644 index 0000000..501bb8a --- /dev/null +++ b/Source/CogSample/CogSampleTask_ListenForCooldownChanged.h @@ -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); +};