代码拉取完成,页面将自动刷新
#pragma once
#include "Abilities/LyraGameplayAbility.h"
#include "AbilitySystemComponent.h"
#include "NativeGameplayTags.h"
#include "LyraAbilitySystemComponent.generated.h"
class AActor;
class UGameplayAbility;
class ULyraAbilityTagRelationshipMapping;
class UObject;
struct FFrame;
struct FGameplayAbilityTargetDataHandle;
/**
* 声明一个在cpp中用 UE_DEFINE_GAMEPLAY_TAG 定义的本地游戏标签,以允许其他模块或代码使用创建的标签变量。
*/
LYRAGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_AbilityInputBlocked);
/**
* ULyraAbilitySystemComponent
*
* Base ability system component class used by this project.
*/
UCLASS()
class LYRAGAME_API ULyraAbilitySystemComponent : public UAbilitySystemComponent
{
GENERATED_BODY()
public:
// 这是一个内部类,用于在真实的 C++ 构造函数被调用后完成 UObject 的创建(初始化属性)。
// FObjectInitializer::Get() 获取当前构造对象的 ObjectInitializer。只能在 UObject 派生类的构造函数内部使用。
// 默认构造函数,在使用 C++ 的 "new" 语法时使用。UObject::UObject 将设置对象指针。
// 构造函数
ULyraAbilitySystemComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
//~UActorComponent interface
/**
* 结束此组件的游戏性。
* 仅在 bHasBegunPlay 为 true 时从 AActor::EndPlay 调用。
*/
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
//~End of UActorComponent interface
// 初始化能力角色信息
/**
* 初始化 Abilities 的 ActorInfo - 这个结构保存关于我们是在哪个角色上行动以及谁控制我们的信息。
* OwnerActor 是在逻辑上拥有此组件的角色。
* AvatarActor 是我们在世界中实际扮演的角色。通常是一个 Pawn,但也可能是一个 Tower、Building、Turret 等,可能与 Owner 相同。
*/
virtual void InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor) override;
// 应取消能力函数
typedef TFunctionRef<bool(const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)> TShouldCancelAbilityFunc;
void CancelAbilitiesByFunc(TShouldCancelAbilityFunc ShouldCancelFunc, bool bReplicateCancelAbility);
void CancelInputActivatedAbilities(bool bReplicateCancelAbility);
void AbilityInputTagPressed(const FGameplayTag& InputTag);
void AbilityInputTagReleased(const FGameplayTag& InputTag);
void ProcessAbilityInput(float DeltaTime, bool bGamePaused);
void ClearAbilityInput();
bool IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const;
void AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility);
void RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility);
void CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility);
// Uses a gameplay effect to add the specified dynamic granted tag.
void AddDynamicTagGameplayEffect(const FGameplayTag& Tag);
// Removes all active instances of the gameplay effect that was used to add the specified dynamic granted tag.
void RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag);
/** Gets the ability target data associated with the given ability handle and activation info */
void GetAbilityTargetData(const FGameplayAbilitySpecHandle AbilityHandle, FGameplayAbilityActivationInfo ActivationInfo, FGameplayAbilityTargetDataHandle& OutTargetDataHandle);
/** Sets the current tag relationship mapping, if null it will clear it out */
void SetTagRelationshipMapping(ULyraAbilityTagRelationshipMapping* NewMapping);
/** Looks at ability tags and gathers additional required and blocking tags */
void GetAdditionalActivationTagRequirements(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer& OutActivationRequired, FGameplayTagContainer& OutActivationBlocked) const;
protected:
void TryActivateAbilitiesOnSpawn();
virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& Spec) override;
virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& Spec) override;
virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability) override;
virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason) override;
virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled) override;
virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags) override;
virtual void HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled) override;
/** Notify client that an ability failed to activate */
UFUNCTION(Client, Unreliable)
void ClientNotifyAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason);
void HandleAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason);
protected:
// 如果设置了此表,则用于查找激活和取消的标签关系。
UPROPERTY()
TObjectPtr<ULyraAbilityTagRelationshipMapping> TagRelationshipMapping;
// 本帧按下其输入的能力的句柄。
TArray<FGameplayAbilitySpecHandle> InputPressedSpecHandles;
// 本帧释放其输入的能力的句柄。
TArray<FGameplayAbilitySpecHandle> InputReleasedSpecHandles;
// 持续按下其输入的能力的句柄。
TArray<FGameplayAbilitySpecHandle> InputHeldSpecHandles;
// 每个激活组中运行的能力数量。
int32 ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::MAX];
};
// Copyright Epic Games, Inc. All Rights Reserved.
#include "LyraAbilitySystemComponent.h"
#include "AbilitySystem/Abilities/LyraGameplayAbility.h"
#include "AbilitySystem/LyraAbilityTagRelationshipMapping.h"
#include "Animation/LyraAnimInstance.h"
#include "Engine/World.h"
#include "GameFramework/Pawn.h"
#include "LyraGlobalAbilitySystem.h"
#include "LyraLogChannels.h"
#include "System/LyraAssetManager.h"
#include "System/LyraGameData.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraAbilitySystemComponent)
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked");
ULyraAbilitySystemComponent::ULyraAbilitySystemComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
/**
* 与 empty 相同,但不会改变内存分配,除非新的大小大于当前数组。根据需要对持有的项目调用析构函数,然后将 ArrayNum 置零。
*
* @param NewSize 在调用此函数后预期的使用大小。
*/
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 = Cast<ULyraGameplayAbility>(AbilitySpec.Ability);
if (!LyraAbilityCDO)
{
continue;
}
if (LyraAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced)
{
TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances();
for (UGameplayAbility* AbilityInstance : Instances)
{
ULyraGameplayAbility* LyraAbilityInstance = Cast<ULyraGameplayAbility>(AbilityInstance);
if (LyraAbilityInstance)
{
// Ability instances may be missing for replays
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)
{
if (const ULyraGameplayAbility* LyraAbilityCDO = Cast<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 = Cast<ULyraGameplayAbility>(AbilitySpec.Ability);
if (!LyraAbilityCDO)
{
UE_LOG(LogLyraAbilitySystem, Error, TEXT("CancelAbilitiesByFunc: Non-LyraGameplayAbility %s was Granted to ASC. Skipping."), *AbilitySpec.Ability.GetName());
continue;
}
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 = Cast<ULyraGameplayAbility>(AbilitySpec->Ability);
if (LyraAbilityCDO && 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 = Cast<ULyraGameplayAbility>(AbilitySpec->Ability);
if (LyraAbilityCDO && 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);
if (ULyraGameplayAbility* LyraAbility = Cast<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);
if (ULyraGameplayAbility* LyraAbility = Cast<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;
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。