541 lines
19 KiB
C++
541 lines
19 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LyraAbilitySystemComponent.h"
|
|
|
|
#include "Abilities/GameplayAbility.h"
|
|
#include "Abilities/GameplayAbilityTargetTypes.h"
|
|
#include "Abilities/GameplayAbilityTypes.h"
|
|
#include "Abilities/LyraGameplayAbility.h"
|
|
#include "AbilitySystem/LyraAbilityTagRelationshipMapping.h"
|
|
#include "Animation/LyraAnimInstance.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "Engine/World.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "GameFramework/Pawn.h"
|
|
#include "GameplayAbilitySpec.h"
|
|
#include "GameplayEffect.h"
|
|
#include "GameplayEffectTypes.h"
|
|
#include "GameplayTagContainer.h"
|
|
#include "HAL/PlatformMath.h"
|
|
#include "HAL/UnrealMemory.h"
|
|
#include "Logging/LogCategory.h"
|
|
#include "Logging/LogMacros.h"
|
|
#include "LyraGlobalAbilitySystem.h"
|
|
#include "LyraLogChannels.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "System/LyraAssetManager.h"
|
|
#include "System/LyraGameData.h"
|
|
#include "Templates/Casts.h"
|
|
#include "Templates/SharedPointer.h"
|
|
#include "Templates/SubclassOf.h"
|
|
#include "Trace/Detail/Channel.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "UObject/SoftObjectPtr.h"
|
|
#include "UObject/UObjectBaseUtility.h"
|
|
#include "UObject/WeakObjectPtr.h"
|
|
#include "UObject/WeakObjectPtrTemplates.h"
|
|
|
|
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked");
|
|
|
|
ULyraAbilitySystemComponent::ULyraAbilitySystemComponent(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
InputPressedSpecHandles.Reset();
|
|
InputReleasedSpecHandles.Reset();
|
|
InputHeldSpecHandles.Reset();
|
|
|
|
FMemory::Memset(ActivationGroupCounts, 0, sizeof(ActivationGroupCounts));
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|
{
|
|
if (ULyraGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem<ULyraGlobalAbilitySystem>(GetWorld()))
|
|
{
|
|
GlobalAbilitySystem->UnregisterASC(this);
|
|
}
|
|
|
|
Super::EndPlay(EndPlayReason);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor)
|
|
{
|
|
FGameplayAbilityActorInfo* ActorInfo = AbilityActorInfo.Get();
|
|
check(ActorInfo);
|
|
check(InOwnerActor);
|
|
|
|
const bool bHasNewPawnAvatar = Cast<APawn>(InAvatarActor) && (InAvatarActor != ActorInfo->AvatarActor);
|
|
|
|
Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor);
|
|
|
|
if (bHasNewPawnAvatar)
|
|
{
|
|
// Notify all abilities that a new pawn avatar has been set
|
|
for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
|
|
{
|
|
ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec.Ability);
|
|
|
|
if (LyraAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced)
|
|
{
|
|
TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances();
|
|
for (UGameplayAbility* AbilityInstance : Instances)
|
|
{
|
|
ULyraGameplayAbility* LyraAbilityInstance = CastChecked<ULyraGameplayAbility>(AbilityInstance);
|
|
LyraAbilityInstance->OnPawnAvatarSet();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LyraAbilityCDO->OnPawnAvatarSet();
|
|
}
|
|
}
|
|
|
|
// Register with the global system once we actually have a pawn avatar. We wait until this time since some globally-applied effects may require an avatar.
|
|
if (ULyraGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem<ULyraGlobalAbilitySystem>(GetWorld()))
|
|
{
|
|
GlobalAbilitySystem->RegisterASC(this);
|
|
}
|
|
|
|
if (ULyraAnimInstance* LyraAnimInst = Cast<ULyraAnimInstance>(ActorInfo->GetAnimInstance()))
|
|
{
|
|
LyraAnimInst->InitializeWithAbilitySystem(this);
|
|
}
|
|
|
|
TryActivateAbilitiesOnSpawn();
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::TryActivateAbilitiesOnSpawn()
|
|
{
|
|
ABILITYLIST_SCOPE_LOCK();
|
|
for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
|
|
{
|
|
const ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec.Ability);
|
|
LyraAbilityCDO->TryActivateAbilityOnSpawn(AbilityActorInfo.Get(), AbilitySpec);
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::CancelAbilitiesByFunc(TShouldCancelAbilityFunc ShouldCancelFunc, bool bReplicateCancelAbility)
|
|
{
|
|
ABILITYLIST_SCOPE_LOCK();
|
|
for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
|
|
{
|
|
if (!AbilitySpec.IsActive())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec.Ability);
|
|
|
|
if (LyraAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced)
|
|
{
|
|
// Cancel all the spawned instances, not the CDO.
|
|
TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances();
|
|
for (UGameplayAbility* AbilityInstance : Instances)
|
|
{
|
|
ULyraGameplayAbility* LyraAbilityInstance = CastChecked<ULyraGameplayAbility>(AbilityInstance);
|
|
|
|
if (ShouldCancelFunc(LyraAbilityInstance, AbilitySpec.Handle))
|
|
{
|
|
if (LyraAbilityInstance->CanBeCanceled())
|
|
{
|
|
LyraAbilityInstance->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), LyraAbilityInstance->GetCurrentActivationInfo(), bReplicateCancelAbility);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogLyraAbilitySystem, Error, TEXT("CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false."), *LyraAbilityInstance->GetName());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Cancel the non-instanced ability CDO.
|
|
if (ShouldCancelFunc(LyraAbilityCDO, AbilitySpec.Handle))
|
|
{
|
|
// Non-instanced abilities can always be canceled.
|
|
check(LyraAbilityCDO->CanBeCanceled());
|
|
LyraAbilityCDO->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), FGameplayAbilityActivationInfo(), bReplicateCancelAbility);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::CancelInputActivatedAbilities(bool bReplicateCancelAbility)
|
|
{
|
|
auto ShouldCancelFunc = [this](const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)
|
|
{
|
|
const ELyraAbilityActivationPolicy ActivationPolicy = LyraAbility->GetActivationPolicy();
|
|
return ((ActivationPolicy == ELyraAbilityActivationPolicy::OnInputTriggered) || (ActivationPolicy == ELyraAbilityActivationPolicy::WhileInputActive));
|
|
};
|
|
|
|
CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::AbilitySpecInputPressed(FGameplayAbilitySpec& Spec)
|
|
{
|
|
Super::AbilitySpecInputPressed(Spec);
|
|
|
|
// We don't support UGameplayAbility::bReplicateInputDirectly.
|
|
// Use replicated events instead so that the WaitInputPress ability task works.
|
|
if (Spec.IsActive())
|
|
{
|
|
// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.
|
|
InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey());
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::AbilitySpecInputReleased(FGameplayAbilitySpec& Spec)
|
|
{
|
|
Super::AbilitySpecInputReleased(Spec);
|
|
|
|
// We don't support UGameplayAbility::bReplicateInputDirectly.
|
|
// Use replicated events instead so that the WaitInputRelease ability task works.
|
|
if (Spec.IsActive())
|
|
{
|
|
// Invoke the InputReleased event. This is not replicated here. If someone is listening, they may replicate the InputReleased event to the server.
|
|
InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey());
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::AbilityInputTagPressed(const FGameplayTag& InputTag)
|
|
{
|
|
if (InputTag.IsValid())
|
|
{
|
|
for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
|
|
{
|
|
if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag)))
|
|
{
|
|
InputPressedSpecHandles.AddUnique(AbilitySpec.Handle);
|
|
InputHeldSpecHandles.AddUnique(AbilitySpec.Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::AbilityInputTagReleased(const FGameplayTag& InputTag)
|
|
{
|
|
if (InputTag.IsValid())
|
|
{
|
|
for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items)
|
|
{
|
|
if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag)))
|
|
{
|
|
InputReleasedSpecHandles.AddUnique(AbilitySpec.Handle);
|
|
InputHeldSpecHandles.Remove(AbilitySpec.Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused)
|
|
{
|
|
if (HasMatchingGameplayTag(TAG_Gameplay_AbilityInputBlocked))
|
|
{
|
|
ClearAbilityInput();
|
|
return;
|
|
}
|
|
|
|
static TArray<FGameplayAbilitySpecHandle> AbilitiesToActivate;
|
|
AbilitiesToActivate.Reset();
|
|
|
|
//@TODO: See if we can use FScopedServerAbilityRPCBatcher ScopedRPCBatcher in some of these loops
|
|
|
|
//
|
|
// Process all abilities that activate when the input is held.
|
|
//
|
|
for (const FGameplayAbilitySpecHandle& SpecHandle : InputHeldSpecHandles)
|
|
{
|
|
if (const FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle))
|
|
{
|
|
if (AbilitySpec->Ability && !AbilitySpec->IsActive())
|
|
{
|
|
const ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec->Ability);
|
|
|
|
if (LyraAbilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::WhileInputActive)
|
|
{
|
|
AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Process all abilities that had their input pressed this frame.
|
|
//
|
|
for (const FGameplayAbilitySpecHandle& SpecHandle : InputPressedSpecHandles)
|
|
{
|
|
if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle))
|
|
{
|
|
if (AbilitySpec->Ability)
|
|
{
|
|
AbilitySpec->InputPressed = true;
|
|
|
|
if (AbilitySpec->IsActive())
|
|
{
|
|
// Ability is active so pass along the input event.
|
|
AbilitySpecInputPressed(*AbilitySpec);
|
|
}
|
|
else
|
|
{
|
|
const ULyraGameplayAbility* LyraAbilityCDO = CastChecked<ULyraGameplayAbility>(AbilitySpec->Ability);
|
|
|
|
if (LyraAbilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::OnInputTriggered)
|
|
{
|
|
AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try to activate all the abilities that are from presses and holds.
|
|
// We do it all at once so that held inputs don't activate the ability
|
|
// and then also send a input event to the ability because of the press.
|
|
//
|
|
for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : AbilitiesToActivate)
|
|
{
|
|
TryActivateAbility(AbilitySpecHandle);
|
|
}
|
|
|
|
//
|
|
// Process all abilities that had their input released this frame.
|
|
//
|
|
for (const FGameplayAbilitySpecHandle& SpecHandle : InputReleasedSpecHandles)
|
|
{
|
|
if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle))
|
|
{
|
|
if (AbilitySpec->Ability)
|
|
{
|
|
AbilitySpec->InputPressed = false;
|
|
|
|
if (AbilitySpec->IsActive())
|
|
{
|
|
// Ability is active so pass along the input event.
|
|
AbilitySpecInputReleased(*AbilitySpec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear the cached ability handles.
|
|
//
|
|
InputPressedSpecHandles.Reset();
|
|
InputReleasedSpecHandles.Reset();
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::ClearAbilityInput()
|
|
{
|
|
InputPressedSpecHandles.Reset();
|
|
InputReleasedSpecHandles.Reset();
|
|
InputHeldSpecHandles.Reset();
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability)
|
|
{
|
|
Super::NotifyAbilityActivated(Handle, Ability);
|
|
|
|
ULyraGameplayAbility* LyraAbility = CastChecked<ULyraGameplayAbility>(Ability);
|
|
|
|
AddAbilityToActivationGroup(LyraAbility->GetActivationGroup(), LyraAbility);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
|
|
{
|
|
Super::NotifyAbilityFailed(Handle, Ability, FailureReason);
|
|
|
|
if (APawn* Avatar = Cast<APawn>(GetAvatarActor()))
|
|
{
|
|
if (!Avatar->IsLocallyControlled() && Ability->IsSupportedForNetworking())
|
|
{
|
|
ClientNotifyAbilityFailed(Ability, FailureReason);
|
|
return;
|
|
}
|
|
}
|
|
|
|
HandleAbilityFailed(Ability, FailureReason);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled)
|
|
{
|
|
Super::NotifyAbilityEnded(Handle, Ability, bWasCancelled);
|
|
|
|
ULyraGameplayAbility* LyraAbility = CastChecked<ULyraGameplayAbility>(Ability);
|
|
|
|
RemoveAbilityFromActivationGroup(LyraAbility->GetActivationGroup(), LyraAbility);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags)
|
|
{
|
|
FGameplayTagContainer ModifiedBlockTags = BlockTags;
|
|
FGameplayTagContainer ModifiedCancelTags = CancelTags;
|
|
|
|
if (TagRelationshipMapping)
|
|
{
|
|
// Use the mapping to expand the ability tags into block and cancel tag
|
|
TagRelationshipMapping->GetAbilityTagsToBlockAndCancel(AbilityTags, &ModifiedBlockTags, &ModifiedCancelTags);
|
|
}
|
|
|
|
Super::ApplyAbilityBlockAndCancelTags(AbilityTags, RequestingAbility, bEnableBlockTags, ModifiedBlockTags, bExecuteCancelTags, ModifiedCancelTags);
|
|
|
|
//@TODO: Apply any special logic like blocking input or movement
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled)
|
|
{
|
|
Super::HandleChangeAbilityCanBeCanceled(AbilityTags, RequestingAbility, bCanBeCanceled);
|
|
|
|
//@TODO: Apply any special logic like blocking input or movement
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer& OutActivationRequired, FGameplayTagContainer& OutActivationBlocked) const
|
|
{
|
|
if (TagRelationshipMapping)
|
|
{
|
|
TagRelationshipMapping->GetRequiredAndBlockedActivationTags(AbilityTags, &OutActivationRequired, &OutActivationBlocked);
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::SetTagRelationshipMapping(ULyraAbilityTagRelationshipMapping* NewMapping)
|
|
{
|
|
TagRelationshipMapping = NewMapping;
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::ClientNotifyAbilityFailed_Implementation(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
|
|
{
|
|
HandleAbilityFailed(Ability, FailureReason);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::HandleAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
|
|
{
|
|
//UE_LOG(LogLyraAbilitySystem, Warning, TEXT("Ability %s failed to activate (tags: %s)"), *GetPathNameSafe(Ability), *FailureReason.ToString());
|
|
|
|
if (const ULyraGameplayAbility* LyraAbility = Cast<const ULyraGameplayAbility>(Ability))
|
|
{
|
|
LyraAbility->OnAbilityFailedToActivate(FailureReason);
|
|
}
|
|
}
|
|
|
|
bool ULyraAbilitySystemComponent::IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const
|
|
{
|
|
bool bBlocked = false;
|
|
|
|
switch (Group)
|
|
{
|
|
case ELyraAbilityActivationGroup::Independent:
|
|
// Independent abilities are never blocked.
|
|
bBlocked = false;
|
|
break;
|
|
|
|
case ELyraAbilityActivationGroup::Exclusive_Replaceable:
|
|
case ELyraAbilityActivationGroup::Exclusive_Blocking:
|
|
// Exclusive abilities can activate if nothing is blocking.
|
|
bBlocked = (ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Blocking] > 0);
|
|
break;
|
|
|
|
default:
|
|
checkf(false, TEXT("IsActivationGroupBlocked: Invalid ActivationGroup [%d]\n"), (uint8)Group);
|
|
break;
|
|
}
|
|
|
|
return bBlocked;
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility)
|
|
{
|
|
check(LyraAbility);
|
|
check(ActivationGroupCounts[(uint8)Group] < INT32_MAX);
|
|
|
|
ActivationGroupCounts[(uint8)Group]++;
|
|
|
|
const bool bReplicateCancelAbility = false;
|
|
|
|
switch (Group)
|
|
{
|
|
case ELyraAbilityActivationGroup::Independent:
|
|
// Independent abilities do not cancel any other abilities.
|
|
break;
|
|
|
|
case ELyraAbilityActivationGroup::Exclusive_Replaceable:
|
|
case ELyraAbilityActivationGroup::Exclusive_Blocking:
|
|
CancelActivationGroupAbilities(ELyraAbilityActivationGroup::Exclusive_Replaceable, LyraAbility, bReplicateCancelAbility);
|
|
break;
|
|
|
|
default:
|
|
checkf(false, TEXT("AddAbilityToActivationGroup: Invalid ActivationGroup [%d]\n"), (uint8)Group);
|
|
break;
|
|
}
|
|
|
|
const int32 ExclusiveCount = ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Replaceable] + ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Blocking];
|
|
if (!ensure(ExclusiveCount <= 1))
|
|
{
|
|
UE_LOG(LogLyraAbilitySystem, Error, TEXT("AddAbilityToActivationGroup: Multiple exclusive abilities are running."));
|
|
}
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility)
|
|
{
|
|
check(LyraAbility);
|
|
check(ActivationGroupCounts[(uint8)Group] > 0);
|
|
|
|
ActivationGroupCounts[(uint8)Group]--;
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility)
|
|
{
|
|
auto ShouldCancelFunc = [this, Group, IgnoreLyraAbility](const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)
|
|
{
|
|
return ((LyraAbility->GetActivationGroup() == Group) && (LyraAbility != IgnoreLyraAbility));
|
|
};
|
|
|
|
CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& Tag)
|
|
{
|
|
const TSubclassOf<UGameplayEffect> DynamicTagGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DynamicTagGameplayEffect);
|
|
if (!DynamicTagGE)
|
|
{
|
|
UE_LOG(LogLyraAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]."), *ULyraGameData::Get().DynamicTagGameplayEffect.GetAssetName());
|
|
return;
|
|
}
|
|
|
|
const FGameplayEffectSpecHandle SpecHandle = MakeOutgoingSpec(DynamicTagGE, 1.0f, MakeEffectContext());
|
|
FGameplayEffectSpec* Spec = SpecHandle.Data.Get();
|
|
|
|
if (!Spec)
|
|
{
|
|
UE_LOG(LogLyraAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]."), *GetNameSafe(DynamicTagGE));
|
|
return;
|
|
}
|
|
|
|
Spec->DynamicGrantedTags.AddTag(Tag);
|
|
|
|
ApplyGameplayEffectSpecToSelf(*Spec);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag)
|
|
{
|
|
const TSubclassOf<UGameplayEffect> DynamicTagGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DynamicTagGameplayEffect);
|
|
if (!DynamicTagGE)
|
|
{
|
|
UE_LOG(LogLyraAbilitySystem, Warning, TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."), *ULyraGameData::Get().DynamicTagGameplayEffect.GetAssetName());
|
|
return;
|
|
}
|
|
|
|
FGameplayEffectQuery Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(FGameplayTagContainer(Tag));
|
|
Query.EffectDefinition = DynamicTagGE;
|
|
|
|
RemoveActiveEffects(Query);
|
|
}
|
|
|
|
void ULyraAbilitySystemComponent::GetAbilityTargetData(const FGameplayAbilitySpecHandle AbilityHandle, FGameplayAbilityActivationInfo ActivationInfo, FGameplayAbilityTargetDataHandle& OutTargetDataHandle)
|
|
{
|
|
TSharedPtr<FAbilityReplicatedDataCache> ReplicatedData = AbilityTargetDataMap.Find(FGameplayAbilitySpecHandleAndPredictionKey(AbilityHandle, ActivationInfo.GetActivationPredictionKey()));
|
|
if (ReplicatedData.IsValid())
|
|
{
|
|
OutTargetDataHandle = ReplicatedData->TargetData;
|
|
}
|
|
}
|