第一次提交

This commit is contained in:
不明不惑
2026-03-03 01:23:02 +08:00
commit 3e434877e8
1053 changed files with 102411 additions and 0 deletions

View File

@@ -0,0 +1,947 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_AbilitySystemFunctionLibrary.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Logging/LogMacros.h"
#include "AbilitySystemLog.h"
#include "GameplayCueManager.h"
#include "Animation/AnimSequenceBase.h"
#include "Animation/AnimMontage.h"
bool UGGA_AbilitySystemFunctionLibrary::FindAbilitySystemComponent(AActor* Actor, TSubclassOf<UAbilitySystemComponent> DesiredClass, UAbilitySystemComponent*& ASC)
{
if (UAbilitySystemComponent* Instance = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Actor))
{
if (Instance->GetClass()->IsChildOf(DesiredClass))
{
ASC = Instance;
return true;
}
}
return false;
}
UAbilitySystemComponent* UGGA_AbilitySystemFunctionLibrary::GetAbilitySystemComponent(AActor* Actor, TSubclassOf<UAbilitySystemComponent> DesiredClass)
{
if (UAbilitySystemComponent* Instance = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Actor))
{
if (Instance->GetClass()->IsChildOf(DesiredClass))
{
return Instance;
}
}
return nullptr;
}
void UGGA_AbilitySystemFunctionLibrary::InitAbilityActorInfo(UAbilitySystemComponent* AbilitySystem, AActor* InOwnerActor, AActor* InAvatarActor)
{
if (!IsValid(AbilitySystem) || !IsValid(InOwnerActor) || !IsValid(InAvatarActor))
{
return;
}
AbilitySystem->InitAbilityActorInfo(InOwnerActor, InAvatarActor);
}
AActor* UGGA_AbilitySystemFunctionLibrary::GetOwnerActor(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return nullptr;
}
return AbilitySystem->GetOwnerActor();
}
AActor* UGGA_AbilitySystemFunctionLibrary::GetAvatarActor(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return nullptr;
}
return AbilitySystem->GetAvatarActor_Direct();
}
int32 UGGA_AbilitySystemFunctionLibrary::HandleGameplayEvent(UAbilitySystemComponent* AbilitySystem, FGameplayTag EventTag, const FGameplayEventData& Payload)
{
if (!IsValid(AbilitySystem) || !EventTag.IsValid())
{
return false;
}
return AbilitySystem->HandleGameplayEvent(EventTag, &Payload);
}
bool UGGA_AbilitySystemFunctionLibrary::TryActivateAbilities(UAbilitySystemComponent* AbilitySystem, TArray<FGameplayAbilitySpecHandle> AbilitiesToActivate, bool bAllowRemoteActivation,
bool bFirstOnly)
{
if (!IsValid(AbilitySystem) || AbilitiesToActivate.IsEmpty())
{
return false;
}
int32 Num = 0;
for (int32 i = 0; i < AbilitiesToActivate.Num(); i++)
{
if (AbilitySystem->TryActivateAbility(AbilitiesToActivate[i], bAllowRemoteActivation))
{
Num++;
if (bFirstOnly)
{
return true;
}
}
}
return Num == AbilitiesToActivate.Num();
}
bool UGGA_AbilitySystemFunctionLibrary::HasActivatableTriggeredAbility(UAbilitySystemComponent* AbilitySystem, FGameplayTag Tag)
{
if (!IsValid(AbilitySystem) || !Tag.IsValid())
{
return false;
}
return AbilitySystem->HasActivatableTriggeredAbility(Tag);
}
void UGGA_AbilitySystemFunctionLibrary::GetActivatableGameplayAbilitySpecsByAllMatchingTags(const UAbilitySystemComponent* AbilitySystem, const FGameplayTagContainer& Tags,
TArray<FGameplayAbilitySpecHandle>& MatchingGameplayAbilities,
bool bOnlyAbilitiesThatSatisfyTagRequirements)
{
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return;
}
MatchingGameplayAbilities.Empty();
TArray<FGameplayAbilitySpec*> AbilitiesToActivate;
AbilitySystem->GetActivatableGameplayAbilitySpecsByAllMatchingTags(Tags, AbilitiesToActivate, bOnlyAbilitiesThatSatisfyTagRequirements);
for (FGameplayAbilitySpec* GameplayAbilitySpec : AbilitiesToActivate)
{
MatchingGameplayAbilities.Add(GameplayAbilitySpec->Handle);
}
}
void UGGA_AbilitySystemFunctionLibrary::GetActivatableGameplayAbilitySpecs(const UAbilitySystemComponent* AbilitySystem, const FGameplayTagContainer& Tags, const UObject* SourceObject,
TArray<FGameplayAbilitySpecHandle>& MatchingGameplayAbilities, bool bOnlyAbilitiesThatSatisfyTagRequirements)
{
if (SourceObject == nullptr)
{
GetActivatableGameplayAbilitySpecsByAllMatchingTags(AbilitySystem, Tags, MatchingGameplayAbilities, bOnlyAbilitiesThatSatisfyTagRequirements);
return;
}
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return;
}
TArray<FGameplayAbilitySpec*> AbilitiesToActivate;
for (const FGameplayAbilitySpec& Spec : AbilitySystem->GetActivatableAbilities())
{
if (Spec.Ability && Spec.Ability->GetAssetTags().HasAll(Tags) && Spec.SourceObject == SourceObject)
{
// Consider abilities that are blocked by tags currently if we're supposed to (default behavior).
// That way, we can use the blocking to find an appropriate ability based on tags when we have more than
// one ability that match the GameplayTagContainer.
if (!bOnlyAbilitiesThatSatisfyTagRequirements || Spec.Ability->DoesAbilitySatisfyTagRequirements(*AbilitySystem))
{
MatchingGameplayAbilities.Add(Spec.Handle);
}
}
}
}
bool UGGA_AbilitySystemFunctionLibrary::GetFirstActivatableAbility(const UAbilitySystemComponent* AbilitySystem, FGameplayTagContainer Tags, FGameplayAbilitySpecHandle& MatchingGameplayAbility,
const UObject* SourceObject, bool bOnlyAbilitiesThatSatisfyTagRequirements)
{
if (SourceObject == nullptr)
{
return GetFirstActivatableAbilityByAllMatchingTags(AbilitySystem, Tags, MatchingGameplayAbility, bOnlyAbilitiesThatSatisfyTagRequirements);
}
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return false;
}
for (const FGameplayAbilitySpec& Spec : AbilitySystem->GetActivatableAbilities())
{
if (Spec.Ability && Spec.Ability->GetAssetTags().HasAll(Tags) && SourceObject == Spec.SourceObject)
{
// Consider abilities that are blocked by tags currently if we're supposed to (default behavior).
// That way, we can use the blocking to find an appropriate ability based on tags when we have more than
// one ability that match the GameplayTagContainer.
if (!bOnlyAbilitiesThatSatisfyTagRequirements || Spec.Ability->DoesAbilitySatisfyTagRequirements(*AbilitySystem))
{
MatchingGameplayAbility = Spec.Handle;
return true;
}
}
}
return false;
}
bool UGGA_AbilitySystemFunctionLibrary::GetFirstActivatableAbilityByAllMatchingTags(const UAbilitySystemComponent* AbilitySystem, FGameplayTagContainer Tags,
FGameplayAbilitySpecHandle& MatchingGameplayAbility, bool bOnlyAbilitiesThatSatisfyTagRequirements)
{
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return false;
}
for (const FGameplayAbilitySpec& Spec : AbilitySystem->GetActivatableAbilities())
{
if (Spec.Ability && Spec.Ability->GetAssetTags().HasAll(Tags))
{
// Consider abilities that are blocked by tags currently if we're supposed to (default behavior).
// That way, we can use the blocking to find an appropriate ability based on tags when we have more than
// one ability that match the GameplayTagContainer.
if (!bOnlyAbilitiesThatSatisfyTagRequirements || Spec.Ability->DoesAbilitySatisfyTagRequirements(*AbilitySystem))
{
MatchingGameplayAbility = Spec.Handle;
return true;
}
}
}
return false;
}
void UGGA_AbilitySystemFunctionLibrary::GetActiveAbilityInstancesWithTags(const UAbilitySystemComponent* AbilitySystem, const FGameplayTagContainer& Tags,
TArray<UGameplayAbility*>& MatchingAbilityInstances)
{
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return;
}
TArray<FGameplayAbilitySpec*> AbilitiesToActivate;
AbilitySystem->GetActivatableGameplayAbilitySpecsByAllMatchingTags(Tags, AbilitiesToActivate, false);
// Iterate the list of all ability specs
for (FGameplayAbilitySpec* Spec : AbilitiesToActivate)
{
// Iterate all instances on this ability spec
TArray<UGameplayAbility*> AbilityInstances = Spec->GetAbilityInstances();
for (UGameplayAbility* ActiveAbility : AbilityInstances)
{
if (ActiveAbility->IsActive())
{
MatchingAbilityInstances.Add(ActiveAbility);
}
}
}
}
bool UGGA_AbilitySystemFunctionLibrary::SendGameplayEventToActor(AActor* Actor, FGameplayTag EventTag, FGameplayEventData Payload)
{
if (IsValid(Actor))
{
UAbilitySystemComponent* AbilitySystemComponent = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Actor);
if (IsValid(AbilitySystemComponent))
{
FScopedPredictionWindow NewScopedWindow(AbilitySystemComponent, true);
if (AbilitySystemComponent->HandleGameplayEvent(EventTag, &Payload) > 0)
{
return true;
}
}
else
{
ABILITY_LOG(Error, TEXT("UAbilitySystemBPLibrary::SendGameplayEventToActor: Invalid ability system component retrieved from Actor %s. EventTag was %s"), *Actor->GetName(),
*EventTag.ToString());
}
}
return false;
}
void UGGA_AbilitySystemFunctionLibrary::BreakAbilityEndedData(const FAbilityEndedData& AbilityEndedData, UGameplayAbility*& AbilityThatEnded, FGameplayAbilitySpecHandle& AbilitySpecHandle,
bool& bReplicateEndAbility, bool& bWasCancelled)
{
AbilityThatEnded = AbilityEndedData.AbilityThatEnded;
AbilitySpecHandle = AbilityEndedData.AbilitySpecHandle;
bReplicateEndAbility = AbilityEndedData.bReplicateEndAbility;
bWasCancelled = AbilityEndedData.bWasCancelled;
}
bool UGGA_AbilitySystemFunctionLibrary::FindAllAbilitiesWithTagsInOrder(const UAbilitySystemComponent* AbilitySystem, TArray<FGameplayTag> Tags, TArray<FGameplayAbilitySpecHandle>& OutAbilityHandles,
bool bExactMatch)
{
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return false;
}
// ensure the output array is empty
OutAbilityHandles.Empty();
for (const FGameplayTag& Tag : Tags)
{
TArray<FGameplayAbilitySpecHandle> Handles;
AbilitySystem->FindAllAbilitiesWithTags(Handles, Tag.GetSingleTagContainer(), bExactMatch);
OutAbilityHandles.Append(Handles);
}
return !OutAbilityHandles.IsEmpty();
}
bool UGGA_AbilitySystemFunctionLibrary::FindAbilityMatchingQuery(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle& OutAbilityHandle, FGameplayTagQuery Query,
const UObject* SourceObject)
{
if (!IsValid(AbilitySystem) || Query.IsEmpty())
{
return false;
}
// iterate through all Ability Specs
for (const FGameplayAbilitySpec& CurrentSpec : AbilitySystem->GetActivatableAbilities())
{
// try to get the ability instance
UGameplayAbility* AbilityInstance = CurrentSpec.GetPrimaryInstance();
// default to the CDO if we can't
if (!AbilityInstance)
{
AbilityInstance = CurrentSpec.Ability;
}
if (SourceObject && CurrentSpec.SourceObject != SourceObject)
{
continue;
}
// ensure the ability instance is valid
if (IsValid(AbilityInstance) && AbilityInstance->GetAssetTags().MatchesQuery(Query))
{
OutAbilityHandle = CurrentSpec.Handle;
return true;
}
}
return false;
}
FGameplayAbilitySpec* UGGA_AbilitySystemFunctionLibrary::FindAbilitySpecFromClass(const UAbilitySystemComponent* AbilitySystem, TSubclassOf<UGameplayAbility> AbilityClass, const UObject* SourceObject)
{
if (!IsValid(AbilitySystem) || AbilityClass == nullptr)
{
return nullptr;
}
for (const FGameplayAbilitySpec& Spec : AbilitySystem->GetActivatableAbilities())
{
if (Spec.Ability == nullptr)
{
continue;
}
if (SourceObject && Spec.SourceObject != SourceObject)
{
continue;
}
if (Spec.Ability->GetClass() == AbilityClass)
{
return const_cast<FGameplayAbilitySpec*>(&Spec);
}
}
return nullptr;
}
bool UGGA_AbilitySystemFunctionLibrary::FindAbilityFromClass(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle& OutAbilityHandle, TSubclassOf<UGameplayAbility> AbilityClass,
const UObject* SourceObject)
{
if (!IsValid(AbilitySystem) || AbilityClass == nullptr)
{
return false;
}
for (const FGameplayAbilitySpec& Spec : AbilitySystem->GetActivatableAbilities())
{
if (Spec.Ability == nullptr)
{
continue;
}
if (SourceObject && Spec.SourceObject != SourceObject)
{
continue;
}
if (Spec.Ability->GetClass() == AbilityClass)
{
OutAbilityHandle = Spec.Handle;
return true;
}
}
return false;
}
bool UGGA_AbilitySystemFunctionLibrary::FindAbilityWithTags(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle& OutAbilityHandle, FGameplayTagContainer Tags, bool bExactMatch,
const UObject* SourceObject)
{
if (!IsValid(AbilitySystem) || Tags.IsEmpty())
{
return false;
}
// iterate through all Ability Specs
for (const FGameplayAbilitySpec& CurrentSpec : AbilitySystem->GetActivatableAbilities())
{
// try to get the ability instance
UGameplayAbility* AbilityInstance = CurrentSpec.GetPrimaryInstance();
// default to the CDO if we can't
if (!AbilityInstance)
{
AbilityInstance = CurrentSpec.Ability;
}
if (SourceObject && CurrentSpec.SourceObject != SourceObject)
{
continue;
}
// ensure the ability instance is valid
if (IsValid(AbilityInstance))
{
// do we want an exact match?
if (bExactMatch)
{
// check if we match all tags
if (AbilityInstance->GetAssetTags().HasAll(Tags))
{
OutAbilityHandle = CurrentSpec.Handle;
return true;
}
}
else
{
// check if we match any tags
if (AbilityInstance->GetAssetTags().HasAny(Tags))
{
OutAbilityHandle = CurrentSpec.Handle;
return true;
}
}
}
}
return false;
}
void UGGA_AbilitySystemFunctionLibrary::AddLooseGameplayTag(UAbilitySystemComponent* AbilitySystem, const FGameplayTag& GameplayTag, int32 Count)
{
if (!IsValid(AbilitySystem) || !GameplayTag.IsValid())
{
return;
}
AbilitySystem->AddLooseGameplayTag(GameplayTag, Count);
}
void UGGA_AbilitySystemFunctionLibrary::AddLooseGameplayTags(UAbilitySystemComponent* AbilitySystem, const FGameplayTagContainer& GameplayTags, int32 Count)
{
if (!IsValid(AbilitySystem) || GameplayTags.IsEmpty())
{
return;
}
AbilitySystem->AddLooseGameplayTags(GameplayTags, Count);
}
void UGGA_AbilitySystemFunctionLibrary::RemoveLooseGameplayTag(UAbilitySystemComponent* AbilitySystem, const FGameplayTag& GameplayTag, int32 Count)
{
if (!IsValid(AbilitySystem) || !GameplayTag.IsValid())
{
return;
}
AbilitySystem->RemoveLooseGameplayTag(GameplayTag, Count);
}
void UGGA_AbilitySystemFunctionLibrary::RemoveLooseGameplayTags(UAbilitySystemComponent* AbilitySystem, const FGameplayTagContainer& GameplayTags, int32 Count)
{
if (!IsValid(AbilitySystem) || GameplayTags.IsEmpty())
{
return;
}
AbilitySystem->RemoveLooseGameplayTags(GameplayTags, Count);
}
void UGGA_AbilitySystemFunctionLibrary::RemoveAllGameplayCues(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return;
}
AbilitySystem->RemoveAllGameplayCues();
}
float UGGA_AbilitySystemFunctionLibrary::PlayMontage(UAbilitySystemComponent* AbilitySystem, UGameplayAbility* AnimatingAbility, FGameplayAbilityActivationInfo ActivationInfo, UAnimMontage* Montage,
float InPlayRate, FName StartSectionName,
float StartTimeSeconds)
{
if (!IsValid(AbilitySystem) || !Montage || !AnimatingAbility)
{
return -1.f;;
}
return AbilitySystem->PlayMontage(AnimatingAbility, ActivationInfo, Montage, InPlayRate, StartSectionName, StartTimeSeconds);
}
void UGGA_AbilitySystemFunctionLibrary::CurrentMontageStop(UAbilitySystemComponent* AbilitySystem, float OverrideBlendOutTime)
{
if (!IsValid(AbilitySystem))
{
return;
}
AbilitySystem->CurrentMontageStop(OverrideBlendOutTime);
}
void UGGA_AbilitySystemFunctionLibrary::StopMontageIfCurrent(UAbilitySystemComponent* AbilitySystem, const UAnimMontage* Montage, float OverrideBlendOutTime)
{
if (!IsValid(AbilitySystem) || !Montage)
{
return;
}
AbilitySystem->StopMontageIfCurrent(*Montage, OverrideBlendOutTime);
}
void UGGA_AbilitySystemFunctionLibrary::ClearAnimatingAbility(UAbilitySystemComponent* AbilitySystem, UGameplayAbility* Ability)
{
if (!IsValid(AbilitySystem) || !Ability)
{
return;
}
AbilitySystem->ClearAnimatingAbility(Ability);
}
void UGGA_AbilitySystemFunctionLibrary::CurrentMontageJumpToSection(UAbilitySystemComponent* AbilitySystem, FName SectionName)
{
if (!IsValid(AbilitySystem) || SectionName == NAME_None)
{
return;
}
AbilitySystem->CurrentMontageJumpToSection(SectionName);
}
void UGGA_AbilitySystemFunctionLibrary::CurrentMontageSetNextSectionName(UAbilitySystemComponent* AbilitySystem, FName FromSectionName, FName ToSectionName)
{
if (!IsValid(AbilitySystem) || FromSectionName == NAME_None || ToSectionName == NAME_None)
return;
AbilitySystem->CurrentMontageSetNextSectionName(FromSectionName, ToSectionName);
}
void UGGA_AbilitySystemFunctionLibrary::CurrentMontageSetPlayRate(UAbilitySystemComponent* AbilitySystem, float InPlayRate)
{
if (!IsValid(AbilitySystem) || InPlayRate <= 0.f)
{
return;
}
AbilitySystem->CurrentMontageSetPlayRate(InPlayRate);
}
UGameplayAbility* UGGA_AbilitySystemFunctionLibrary::GetAnimatingAbility(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return nullptr;
}
return AbilitySystem->GetAnimatingAbility();
}
bool UGGA_AbilitySystemFunctionLibrary::IsAnimatingAbility(UAbilitySystemComponent* AbilitySystem, UGameplayAbility* Ability)
{
if (!IsValid(AbilitySystem))
{
return false;
}
return AbilitySystem->IsAnimatingAbility(Ability);
}
UGameplayAbility* UGGA_AbilitySystemFunctionLibrary::GetAnimatingAbilityFromActor(AActor* Actor, UAnimSequenceBase* Animation)
{
if (UAbilitySystemComponent* ASC = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Actor))
{
if (ASC->GetCurrentMontage() == Animation)
{
if (UGameplayAbility* Ability = ASC->GetAnimatingAbility())
{
return Ability;
}
}
}
return nullptr;
}
bool UGGA_AbilitySystemFunctionLibrary::FindAnimatingAbilityFromActor(AActor* Actor, UAnimSequenceBase* Animation, TSubclassOf<UGameplayAbility> DesiredClass, UGameplayAbility*& AbilityInstance)
{
UGameplayAbility* Ability = GetAnimatingAbilityFromActor(Actor, Animation);
if (UClass* ActualClass = DesiredClass)
{
if (Ability && Ability->GetClass()->IsChildOf(ActualClass))
{
AbilityInstance = Ability;
return true;
}
}
return false;
}
UAnimMontage* UGGA_AbilitySystemFunctionLibrary::GetCurrentMontage(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return nullptr;
}
return AbilitySystem->GetCurrentMontage();
}
int32 UGGA_AbilitySystemFunctionLibrary::GetCurrentMontageSectionID(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return INDEX_NONE;
}
return AbilitySystem->GetCurrentMontageSectionID();
}
FName UGGA_AbilitySystemFunctionLibrary::GetCurrentMontageSectionName(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return NAME_None;
}
return AbilitySystem->GetCurrentMontageSectionName();
}
float UGGA_AbilitySystemFunctionLibrary::GetCurrentMontageSectionLength(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return 0.0f;
}
return AbilitySystem->GetCurrentMontageSectionLength();
}
float UGGA_AbilitySystemFunctionLibrary::GetCurrentMontageSectionTimeLeft(UAbilitySystemComponent* AbilitySystem)
{
if (!IsValid(AbilitySystem))
{
return 0.0f;
}
return AbilitySystem->GetCurrentMontageSectionTimeLeft();
}
void UGGA_AbilitySystemFunctionLibrary::SetAbilityInputPressed(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return;
}
FScopedAbilityListLock ActiveScopeLock(*AbilitySystem);
if (FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
if (Spec->Ability)
{
Spec->InputPressed = true;
if (Spec->IsActive())
{
if (Spec->Ability->bReplicateInputDirectly && AbilitySystem->IsOwnerActorAuthoritative() == false)
{
AbilitySystem->ServerSetInputPressed(Spec->Handle);
}
AbilitySystem->AbilitySpecInputPressed(*Spec);
PRAGMA_DISABLE_DEPRECATION_WARNINGS
#if ENGINE_MINOR_VERSION > 4
// Fixing this up to use the instance activation, but this function should be deprecated as it cannot work with InstancedPerExecution
UE_CLOG(Spec->Ability->GetInstancingPolicy() == EGameplayAbilityInstancingPolicy::InstancedPerExecution, LogAbilitySystem, Warning,
TEXT("%hs: %s is InstancedPerExecution. This is unreliable for Input as you may only interact with the latest spawned Instance"), __func__, *GetNameSafe(Spec->Ability));
TArray<UGameplayAbility*> Instances = Spec->GetAbilityInstances();
const FGameplayAbilityActivationInfo& ActivationInfo = Instances.IsEmpty() ? Spec->ActivationInfo : Instances.Last()->GetCurrentActivationInfoRef();
// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.
AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec->Handle, ActivationInfo.GetActivationPredictionKey());
#else
// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.
AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec->Handle, Spec->ActivationInfo.GetActivationPredictionKey());
#endif
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
else
{
// Ability is not active, so try to activate it
AbilitySystem->TryActivateAbility(Spec->Handle);
}
}
}
}
void UGGA_AbilitySystemFunctionLibrary::SetAbilityInputReleased(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return;
}
FScopedAbilityListLock ActiveScopeLock(*AbilitySystem);
if (FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
Spec->InputPressed = false;
if (Spec->Ability && Spec->IsActive())
{
if (Spec->Ability->bReplicateInputDirectly && AbilitySystem->IsOwnerActorAuthoritative() == false)
{
AbilitySystem->ServerSetInputReleased(Spec->Handle);
}
AbilitySystem->AbilitySpecInputReleased(*Spec);
PRAGMA_DISABLE_DEPRECATION_WARNINGS
#if ENGINE_MINOR_VERSION > 4
// Fixing this up to use the instance activation, but this function should be deprecated as it cannot work with InstancedPerExecution
UE_CLOG(Spec->Ability->GetInstancingPolicy() == EGameplayAbilityInstancingPolicy::InstancedPerExecution, LogAbilitySystem, Warning,
TEXT("%hs: %s is InstancedPerExecution. This is unreliable for Input as you may only interact with the latest spawned Instance"), __func__, *GetNameSafe(Spec->Ability));
TArray<UGameplayAbility*> Instances = Spec->GetAbilityInstances();
const FGameplayAbilityActivationInfo& ActivationInfo = Instances.IsEmpty() ? Spec->ActivationInfo : Instances.Last()->GetCurrentActivationInfoRef();
AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec->Handle, ActivationInfo.GetActivationPredictionKey());
#else
AbilitySystem->InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec->Handle, Spec->ActivationInfo.GetActivationPredictionKey());
#endif
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
}
}
bool UGGA_AbilitySystemFunctionLibrary::CanActivateAbility(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle AbilityToActivate, FGameplayTagContainer& RelevantTags)
{
if (!IsValid(AbilitySystem) || !AbilityToActivate.IsValid())
{
return false;
}
FGameplayTagContainer FailureTags;
FGameplayAbilitySpec* Spec = AbilitySystem->FindAbilitySpecFromHandle(AbilityToActivate);
if (!Spec)
{
ABILITY_LOG(Warning, TEXT("CanActivateAbility called with invalid Handle"));
return false;
}
// Lock ability list so our Spec doesn't get destroyed while activating
const FGameplayAbilityActorInfo* ActorInfo = AbilitySystem->AbilityActorInfo.Get();
UGameplayAbility* AbilityCDO = Spec->Ability;
if (!AbilityCDO)
{
ABILITY_LOG(Warning, TEXT("CanActivateAbility called with ability with invalid definition"));
return false;
}
// If it's instance once the instanced ability will be set, otherwise it will be null
UGameplayAbility* InstancedAbility = Spec->GetPrimaryInstance();
// If we have an instanced ability, call CanActivateAbility on it.
// Otherwise we always do a non instanced CanActivateAbility check using the CDO of the Ability.
UGameplayAbility* const CanActivateAbilitySource = InstancedAbility ? InstancedAbility : AbilityCDO;
return CanActivateAbilitySource->CanActivateAbility(AbilityToActivate, ActorInfo, nullptr, nullptr, &RelevantTags);
}
bool UGGA_AbilitySystemFunctionLibrary::SelectFirstCanActivateAbility(const UAbilitySystemComponent* AbilitySystem, TArray<FGameplayAbilitySpecHandle> Abilities,
FGameplayAbilitySpecHandle& OutAbilityHandle)
{
for (int32 i = 0; i < Abilities.Num(); i++)
{
static FGameplayTagContainer DummyTags;
DummyTags.Reset();
if (CanActivateAbility(AbilitySystem, Abilities[i], DummyTags))
{
OutAbilityHandle = Abilities[i];
return true;
}
}
return false;
}
void UGGA_AbilitySystemFunctionLibrary::CancelAbility(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return;
}
AbilitySystem->CancelAbilityHandle(Ability);
}
void UGGA_AbilitySystemFunctionLibrary::CancelAbilities(UAbilitySystemComponent* AbilitySystem, FGameplayTagContainer WithTags, FGameplayTagContainer WithoutTags)
{
if (!IsValid(AbilitySystem))
{
return;
}
AbilitySystem->CancelAbilities(&WithTags, &WithoutTags);
}
bool UGGA_AbilitySystemFunctionLibrary::IsAbilityInstanceActive(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return false;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
if (UGameplayAbility* AbilityInstance = AbilitySpec->GetPrimaryInstance())
{
return AbilityInstance->IsActive();
}
}
return false;
}
bool UGGA_AbilitySystemFunctionLibrary::IsAbilityActive(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return false;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
return AbilitySpec->IsActive();
}
return false;
}
TArray<UGameplayAbility*> UGGA_AbilitySystemFunctionLibrary::GetAbilityInstances(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
TArray<UGameplayAbility*> Abilities;
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return Abilities;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
Abilities = AbilitySpec->GetAbilityInstances();
return Abilities;
}
return Abilities;
}
const UGameplayAbility* UGGA_AbilitySystemFunctionLibrary::GetAbilityCDO(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return nullptr;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
return AbilitySpec->Ability;
}
return nullptr;
}
int32 UGGA_AbilitySystemFunctionLibrary::GetAbilityLevel(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return 0;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
return AbilitySpec->Level;
}
return 0;
}
int32 UGGA_AbilitySystemFunctionLibrary::GetAbilityInputId(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return -1;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
return AbilitySpec->InputID;
}
return -1;
}
UObject* UGGA_AbilitySystemFunctionLibrary::GetAbilitySourceObject(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return nullptr;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
if (AbilitySpec->SourceObject.IsValid())
{
return AbilitySpec->SourceObject.Get();
}
}
return nullptr;
}
FGameplayTagContainer UGGA_AbilitySystemFunctionLibrary::GetAbilityDynamicTags(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return FGameplayTagContainer::EmptyContainer;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
#if ENGINE_MINOR_VERSION > 4
return AbilitySpec->GetDynamicSpecSourceTags();
#else
return AbilitySpec->DynamicAbilityTags;
#endif
}
return FGameplayTagContainer::EmptyContainer;
}
UGameplayAbility* UGGA_AbilitySystemFunctionLibrary::GetAbilityPrimaryInstance(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability)
{
if (!IsValid(AbilitySystem) || !Ability.IsValid())
{
return nullptr;
}
if (FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromHandle(Ability))
{
return AbilitySpec->GetPrimaryInstance();
}
return nullptr;
}
UAttributeSet* UGGA_AbilitySystemFunctionLibrary::GetAttributeSetByClass(const UAbilitySystemComponent* AbilitySystem, const TSubclassOf<UAttributeSet> AttributeSetClass)
{
if (!IsValid(AbilitySystem) || !AttributeSetClass)
{
return nullptr;
}
for (UAttributeSet* SpawnedAttribute : AbilitySystem->GetSpawnedAttributes())
{
if (SpawnedAttribute && SpawnedAttribute->IsA(AttributeSetClass))
{
return SpawnedAttribute;
}
}
return nullptr;
}
float UGGA_AbilitySystemFunctionLibrary::GetValueAtLevel(const FScalableFloat& ScalableFloat, float Level, FString ContextString)
{
return ScalableFloat.GetValueAtLevel(Level, &ContextString);
}

View File

@@ -0,0 +1,71 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_GameplayAbilityFunctionLibrary.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Abilities/GameplayAbility.h"
bool UGGA_GameplayAbilityFunctionLibrary::IsAbilitySpecHandleValid(FGameplayAbilitySpecHandle Handle)
{
return Handle.IsValid();
}
const UGameplayAbility* UGGA_GameplayAbilityFunctionLibrary::GetAbilityCDOFromClass(TSubclassOf<UGameplayAbility> AbilityClass)
{
if (IsValid(AbilityClass))
{
return AbilityClass->GetDefaultObject<UGameplayAbility>();
}
return nullptr;
}
FGameplayAbilitySpecHandle UGGA_GameplayAbilityFunctionLibrary::GetCurrentAbilitySpecHandle(const UGameplayAbility* Ability)
{
return IsValid(Ability) ? Ability->GetCurrentAbilitySpecHandle() : FGameplayAbilitySpecHandle();
}
bool UGGA_GameplayAbilityFunctionLibrary::IsAbilityActive(const UGameplayAbility* Ability)
{
return IsValid(Ability) ? Ability->IsActive() : false;
}
EGameplayAbilityReplicationPolicy::Type UGGA_GameplayAbilityFunctionLibrary::GetReplicationPolicy(const UGameplayAbility* Ability)
{
return IsValid(Ability) ? Ability->GetReplicationPolicy() : EGameplayAbilityReplicationPolicy::ReplicateNo;
}
EGameplayAbilityInstancingPolicy::Type UGGA_GameplayAbilityFunctionLibrary::GetInstancingPolicy(const UGameplayAbility* Ability)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return IsValid(Ability) ? Ability->GetInstancingPolicy() : EGameplayAbilityInstancingPolicy::NonInstanced;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
FGameplayTagContainer UGGA_GameplayAbilityFunctionLibrary::GetAbilityTags(const UGameplayAbility* Ability)
{
#if ENGINE_MINOR_VERSION > 4
return IsValid(Ability) ? Ability->GetAssetTags() : FGameplayTagContainer::EmptyContainer;
#else
return IsValid(Ability) ? Ability->AbilityTags : FGameplayTagContainer::EmptyContainer;
#endif
}
bool UGGA_GameplayAbilityFunctionLibrary::IsPredictingClient(const UGameplayAbility* Ability)
{
return IsValid(Ability) ? Ability->IsPredictingClient() : false;
}
bool UGGA_GameplayAbilityFunctionLibrary::IsForRemoteClient(const UGameplayAbility* Ability)
{
return IsValid(Ability) ? Ability->IsForRemoteClient() : false;
}
bool UGGA_GameplayAbilityFunctionLibrary::HasAuthorityOrPredictionKey(const UGameplayAbility* Ability)
{
if (IsValid(Ability))
{
const FGameplayAbilityActivationInfo& ActivationInfo = Ability->GetCurrentActivationInfo();
return Ability->HasAuthorityOrPredictionKey(Ability->GetCurrentActorInfo(), &ActivationInfo);
}
return IsValid(Ability) ? Ability->IsForRemoteClient() : false;
}

View File

@@ -0,0 +1,75 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_GameplayAbilityTargetDataFunctionLibrary.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "GGA_GameplayAbilityTargetData_Payload.h"
FGameplayAbilityTargetDataHandle UGGA_GameplayAbilityTargetDataFunctionLibrary::AbilityTargetDataFromPayload(const FInstancedStruct& Payload)
{
// Construct TargetData
FGGA_GameplayAbilityTargetData_Payload* TargetData = new FGGA_GameplayAbilityTargetData_Payload(Payload);
// Give it a handle and return
FGameplayAbilityTargetDataHandle Handle;
Handle.Data.Add(TSharedPtr<FGameplayAbilityTargetData>(TargetData));
return Handle;
}
FInstancedStruct UGGA_GameplayAbilityTargetDataFunctionLibrary::GetPayloadFromTargetData(const FGameplayAbilityTargetDataHandle& TargetData, int32 Index)
{
if (TargetData.Data.IsValidIndex(Index))
{
if (TargetData.Data[Index]->GetScriptStruct() == FGGA_GameplayAbilityTargetData_Payload::StaticStruct())
{
if (FGGA_GameplayAbilityTargetData_Payload* Data = static_cast<FGGA_GameplayAbilityTargetData_Payload*>(TargetData.Data[Index].Get()))
{
return Data->Payload;
}
}
}
return FInstancedStruct();
}
FGameplayAbilityTargetDataHandle UGGA_GameplayAbilityTargetDataFunctionLibrary::AbilityTargetDataFromHitResults(const TArray<FHitResult>& HitResults, bool OneTargetPerHandle)
{
// Construct TargetData
if (OneTargetPerHandle)
{
FGameplayAbilityTargetDataHandle Handle;
for (int32 i = 0; i < HitResults.Num(); ++i)
{
if (::IsValid(HitResults[i].GetActor()))
{
FGameplayAbilityTargetDataHandle TempHandle = UAbilitySystemBlueprintLibrary::AbilityTargetDataFromHitResult(HitResults[i]);
Handle.Append(TempHandle);
}
}
return Handle;
}
else
{
FGameplayAbilityTargetDataHandle Handle;
for (const FHitResult& HitResult : HitResults)
{
FGameplayAbilityTargetData_SingleTargetHit* NewData = new FGameplayAbilityTargetData_SingleTargetHit(HitResult);
Handle.Add(NewData);
}
return Handle;
}
}
void UGGA_GameplayAbilityTargetDataFunctionLibrary::AddTargetDataToContext(FGameplayAbilityTargetDataHandle TargetData, FGameplayEffectContextHandle EffectContext)
{
for (auto Data : TargetData.Data)
{
if (Data.IsValid())
{
Data->AddTargetDataToContext(EffectContext, true);
}
}
}

View File

@@ -0,0 +1,27 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_GameplayCueFunctionLibrary.h"
#include "AbilitySystemGlobals.h"
#include "GameplayCueManager.h"
void UGGA_GameplayCueFunctionLibrary::ExecuteGameplayCueLocal(AActor* Actor, const FGameplayTag GameplayCueTag, const FGameplayCueParameters& GameplayCueParameters)
{
UAbilitySystemGlobals::Get().GetGameplayCueManager()->HandleGameplayCue(
Actor, GameplayCueTag, EGameplayCueEvent::Type::Executed,
GameplayCueParameters);
}
void UGGA_GameplayCueFunctionLibrary::AddGameplayCueLocal(AActor* Actor, const FGameplayTag GameplayCueTag, const FGameplayCueParameters& GameplayCueParameters)
{
UAbilitySystemGlobals::Get().GetGameplayCueManager()->HandleGameplayCue(Actor, GameplayCueTag, EGameplayCueEvent::Type::OnActive, GameplayCueParameters);
UAbilitySystemGlobals::Get().GetGameplayCueManager()->HandleGameplayCue(Actor, GameplayCueTag, EGameplayCueEvent::Type::WhileActive, GameplayCueParameters);
}
void UGGA_GameplayCueFunctionLibrary::RemoveGameplayCueLocal(AActor* Actor, const FGameplayTag GameplayCueTag, const FGameplayCueParameters& GameplayCueParameters)
{
UAbilitySystemGlobals::Get().GetGameplayCueManager()->HandleGameplayCue(
Actor, GameplayCueTag, EGameplayCueEvent::Type::Removed,
GameplayCueParameters);
}

View File

@@ -0,0 +1,172 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_GameplayEffectCalculationFunctionLibrary.h"
#include "AbilitySystemComponent.h"
const FGameplayEffectSpec& UGGA_GameplayEffectCalculationFunctionLibrary::GetOwningSpec(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetOwningSpec();
}
const FGameplayTagContainer& UGGA_GameplayEffectCalculationFunctionLibrary::GetPassedInTags(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetPassedInTags();
}
FGameplayEffectContextHandle UGGA_GameplayEffectCalculationFunctionLibrary::GetEffectContext(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetOwningSpec().GetEffectContext();
}
float UGGA_GameplayEffectCalculationFunctionLibrary::GetSetByCallerMagnitudeByTag(const FGameplayEffectCustomExecutionParameters& InParams, const FGameplayTag& Tag, bool WarnIfNotFound,
float DefaultIfNotFound)
{
return InParams.GetOwningSpec().GetSetByCallerMagnitude(Tag, WarnIfNotFound, DefaultIfNotFound);
}
float UGGA_GameplayEffectCalculationFunctionLibrary::GetSetByCallerMagnitudeByName(const FGameplayEffectCustomExecutionParameters& InParams, const FName& MagnitudeName, bool WarnIfNotFound,
float DefaultIfNotFound)
{
return InParams.GetOwningSpec().GetSetByCallerMagnitude(MagnitudeName, WarnIfNotFound, DefaultIfNotFound);
}
FGameplayTagContainer UGGA_GameplayEffectCalculationFunctionLibrary::GetSourceAggregatedTags(const FGameplayEffectCustomExecutionParameters& InParams)
{
return *InParams.GetOwningSpec().CapturedSourceTags.GetAggregatedTags();
}
FGameplayTagContainer UGGA_GameplayEffectCalculationFunctionLibrary::GetTargetAggregatedTags(const FGameplayEffectCustomExecutionParameters& InParams)
{
return *InParams.GetOwningSpec().CapturedTargetTags.GetAggregatedTags();
}
UAbilitySystemComponent* UGGA_GameplayEffectCalculationFunctionLibrary::GetTargetASC(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetTargetAbilitySystemComponent();
}
AActor* UGGA_GameplayEffectCalculationFunctionLibrary::GetTargetActor(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetTargetAbilitySystemComponent()->GetAvatarActor();
}
UAbilitySystemComponent* UGGA_GameplayEffectCalculationFunctionLibrary::GetSourceASC(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetSourceAbilitySystemComponent();
}
AActor* UGGA_GameplayEffectCalculationFunctionLibrary::GetSourceActor(const FGameplayEffectCustomExecutionParameters& InParams)
{
return InParams.GetSourceAbilitySystemComponent()->GetAvatarActor();
}
bool UGGA_GameplayEffectCalculationFunctionLibrary::AttemptCalculateCapturedAttributeMagnitude(const FGameplayEffectCustomExecutionParameters& InParams,
TArray<FGameplayEffectAttributeCaptureDefinition> InAttributeCaptureDefinitions,
FGameplayAttribute InAttribute, float& OutMagnitude)
{
FAggregatorEvaluateParameters EvaluationParams;
const FGameplayEffectSpec& EffectSpec = InParams.GetOwningSpec();
EvaluationParams.SourceTags = EffectSpec.CapturedSourceTags.GetAggregatedTags();
EvaluationParams.TargetTags = EffectSpec.CapturedTargetTags.GetAggregatedTags();
for (const FGameplayEffectAttributeCaptureDefinition& AttributeCaptureDefinition : InAttributeCaptureDefinitions)
{
if (AttributeCaptureDefinition.AttributeToCapture == InAttribute)
{
return InParams.AttemptCalculateCapturedAttributeMagnitude(AttributeCaptureDefinition, EvaluationParams, OutMagnitude);
}
}
return false;
}
bool UGGA_GameplayEffectCalculationFunctionLibrary::AttemptCalculateCapturedAttributeMagnitudeExt(const FGameplayEffectCustomExecutionParameters& InParams, const FGameplayTagContainer& SourceTags,
const FGameplayTagContainer& TargetTags,
TArray<FGameplayEffectAttributeCaptureDefinition> InAttributeCaptureDefinitions,
FGameplayAttribute InAttribute, float& OutMagnitude)
{
FAggregatorEvaluateParameters EvaluationParams;
EvaluationParams.SourceTags = &SourceTags;
EvaluationParams.TargetTags = &TargetTags;
for (const FGameplayEffectAttributeCaptureDefinition& AttributeCaptureDefinition : InAttributeCaptureDefinitions)
{
if (AttributeCaptureDefinition.AttributeToCapture == InAttribute)
{
return InParams.AttemptCalculateCapturedAttributeMagnitude(AttributeCaptureDefinition, EvaluationParams, OutMagnitude);
}
}
return false;
}
bool UGGA_GameplayEffectCalculationFunctionLibrary::AttemptCalculateCapturedAttributeMagnitudeWithBase(const FGameplayEffectCustomExecutionParameters& InParams,
TArray<FGameplayEffectAttributeCaptureDefinition> InAttributeCaptureDefinitions,
FGameplayAttribute InAttribute, float InBaseValue, float& OutMagnitude)
{
FAggregatorEvaluateParameters EvaluationParams;
const FGameplayEffectSpec& EffectSpec = InParams.GetOwningSpec();
EvaluationParams.SourceTags = EffectSpec.CapturedSourceTags.GetAggregatedTags();
EvaluationParams.TargetTags = EffectSpec.CapturedTargetTags.GetAggregatedTags();
for (const FGameplayEffectAttributeCaptureDefinition& AttributeCaptureDefinition : InAttributeCaptureDefinitions)
{
if (AttributeCaptureDefinition.AttributeToCapture == InAttribute)
{
return InParams.AttemptCalculateCapturedAttributeMagnitudeWithBase(AttributeCaptureDefinition, EvaluationParams, InBaseValue, OutMagnitude);
}
}
return false;
}
FGameplayEffectCustomExecutionOutput UGGA_GameplayEffectCalculationFunctionLibrary::AddOutputModifier(FGameplayEffectCustomExecutionOutput& InExecutionOutput, FGameplayAttribute InAttribute,
EGameplayModOp::Type InModifierOp, float InMagnitude)
{
if (InAttribute.IsValid())
{
FGameplayModifierEvaluatedData Data;
Data.Attribute = InAttribute;
Data.ModifierOp = InModifierOp;
Data.Magnitude = InMagnitude;
InExecutionOutput.AddOutputModifier(Data);
}
return InExecutionOutput;
}
void UGGA_GameplayEffectCalculationFunctionLibrary::MarkConditionalGameplayEffectsToTrigger(FGameplayEffectCustomExecutionOutput& InExecutionOutput)
{
InExecutionOutput.MarkConditionalGameplayEffectsToTrigger();
}
void UGGA_GameplayEffectCalculationFunctionLibrary::MarkGameplayCuesHandledManually(FGameplayEffectCustomExecutionOutput& InExecutionOutput)
{
InExecutionOutput.MarkGameplayCuesHandledManually();
}
void UGGA_GameplayEffectCalculationFunctionLibrary::MarkStackCountHandledManually(FGameplayEffectCustomExecutionOutput& InExecutionOutput)
{
InExecutionOutput.MarkStackCountHandledManually();
}
FGameplayEffectContextHandle UGGA_GameplayEffectCalculationFunctionLibrary::GetEffectContextFromSpec(const FGameplayEffectSpec& EffectSpec)
{
return EffectSpec.GetEffectContext();
}
void UGGA_GameplayEffectCalculationFunctionLibrary::AddAssetTagForPreMod(const FGameplayEffectCustomExecutionParameters& InParams, FGameplayTag NewGameplayTag)
{
if (FGameplayEffectSpec* Spec = InParams.GetOwningSpecForPreExecuteMod())
{
Spec->AddDynamicAssetTag(NewGameplayTag);
}
}
void UGGA_GameplayEffectCalculationFunctionLibrary::AddAssetTagsForPreMod(const FGameplayEffectCustomExecutionParameters& InParams, FGameplayTagContainer NewGameplayTags)
{
if (FGameplayEffectSpec* Spec = InParams.GetOwningSpecForPreExecuteMod())
{
Spec->AppendDynamicAssetTags(NewGameplayTags);
}
}

View File

@@ -0,0 +1,158 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_GameplayEffectContainerFunctionLibrary.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "GameplayAbilitySpec.h"
#include "AbilitySystemGlobals.h"
#include "GGA_LogChannels.h"
#include "TargetingSystem/TargetingSubsystem.h"
bool UGGA_GameplayEffectContainerFunctionLibrary::IsValidContainer(const FGGA_GameplayEffectContainer& Container)
{
return !Container.TargetGameplayEffectClasses.IsEmpty() && Container.TargetingPreset != nullptr;
}
bool UGGA_GameplayEffectContainerFunctionLibrary::HasValidEffects(const FGGA_GameplayEffectContainerSpec& ContainerSpec)
{
return ContainerSpec.HasValidEffects();
}
bool UGGA_GameplayEffectContainerFunctionLibrary::HasValidTargets(const FGGA_GameplayEffectContainerSpec& ContainerSpec)
{
return ContainerSpec.HasValidTargets();
}
FGGA_GameplayEffectContainerSpec UGGA_GameplayEffectContainerFunctionLibrary::AddTargets(const FGGA_GameplayEffectContainerSpec& ContainerSpec, const TArray<FHitResult>& HitResults,
const TArray<AActor*>& TargetActors)
{
FGGA_GameplayEffectContainerSpec NewSpec = ContainerSpec;
NewSpec.AddTargets(HitResults, TargetActors);
return NewSpec;
}
FGGA_GameplayEffectContainerSpec UGGA_GameplayEffectContainerFunctionLibrary::MakeEffectContainerSpec(const FGGA_GameplayEffectContainer& Container,
const FGameplayEventData& EventData, int32 OverrideGameplayLevel, UGameplayAbility* SourceAbility)
{
FGGA_GameplayEffectContainerSpec ReturnSpec;
if (SourceAbility== nullptr && EventData.Instigator == nullptr)
{
UE_LOG(LogGGA_AbilitySystem, Warning, TEXT("Missing instigator within EventData, It's required to look for Source AbilitySystemComponent!"))
return ReturnSpec;
}
// First figure out our actor info
UAbilitySystemComponent* SourceASC = SourceAbility?SourceAbility->GetAbilitySystemComponentFromActorInfo():UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(EventData.Instigator);
if (SourceASC && SourceASC->GetAvatarActor())
{
if (Container.TargetingPreset.Get())
{
if (UTargetingSubsystem* TargetingSubsystem = UTargetingSubsystem::Get(SourceASC->GetWorld()))
{
FTargetingSourceContext SourceContext;
SourceContext.SourceActor = SourceASC->GetAvatarActor();
FTargetingRequestHandle TargetingHandle = UTargetingSubsystem::MakeTargetRequestHandle(Container.TargetingPreset, SourceContext);
FTargetingRequestDelegate Delegate = FTargetingRequestDelegate::CreateLambda([&](FTargetingRequestHandle InTargetingHandle)
{
TArray<FHitResult> HitResults;
TArray<AActor*> TargetActors;
TargetingSubsystem->GetTargetingResults(InTargetingHandle, HitResults);
ReturnSpec.AddTargets(HitResults, TargetActors);
});
UE_LOG(LogGGA_AbilitySystem, VeryVerbose, TEXT("Starting immediate targeting task for EffectContainer."));
FTargetingImmediateTaskData& ImmediateTaskData = FTargetingImmediateTaskData::FindOrAdd(TargetingHandle);
ImmediateTaskData.bReleaseOnCompletion = true;
TargetingSubsystem->ExecuteTargetingRequestWithHandle(TargetingHandle, Delegate);
}
}
int32 Level = OverrideGameplayLevel >= 0 ? OverrideGameplayLevel : EventData.EventMagnitude;
// Build GameplayEffectSpecs for each applied effect
for (const TSubclassOf<UGameplayEffect>& EffectClass : Container.TargetGameplayEffectClasses)
{
FGameplayEffectSpecHandle SpecHandle = SourceAbility?SourceAbility->MakeOutgoingGameplayEffectSpec(EffectClass, Level):SourceASC->MakeOutgoingSpec(EffectClass, Level, SourceASC->MakeEffectContext());
FGameplayEffectContextHandle ContextHandle = UAbilitySystemBlueprintLibrary::GetEffectContext(SpecHandle);
if (SourceAbility==nullptr && EventData.OptionalObject)
{
ContextHandle.AddSourceObject(EventData.OptionalObject);
}
ReturnSpec.TargetGameplayEffectSpecs.Add(SpecHandle);
}
if (EventData.TargetData.Num() > 0)
{
ReturnSpec.TargetData.Append(EventData.TargetData);
}
}
return ReturnSpec;
}
TArray<FActiveGameplayEffectHandle> UGGA_GameplayEffectContainerFunctionLibrary::ApplyEffectContainerSpec(UGameplayAbility* ExecutingAbility, const FGGA_GameplayEffectContainerSpec& ContainerSpec)
{
TArray<FActiveGameplayEffectHandle> AllEffects;
if (!IsValid(ExecutingAbility) || !ExecutingAbility->IsInstantiated())
{
UE_LOG(LogGGA_Ability, Error, TEXT("Requires \"Executing ability\" to apply effect container spec."))
return AllEffects;
}
const FGameplayAbilityActorInfo* ActorInfo = ExecutingAbility->GetCurrentActorInfo();
const FGameplayAbilityActivationInfo& ActivationInfo = ExecutingAbility->GetCurrentActivationInfoRef();
// Iterate list of effect specs and apply them to their target data
for (const FGameplayEffectSpecHandle& SpecHandle : ContainerSpec.TargetGameplayEffectSpecs)
{
TArray<FActiveGameplayEffectHandle> EffectHandles;
if (SpecHandle.IsValid() && ExecutingAbility->HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo))
{
FScopedTargetListLock ActiveScopeLock(*ActorInfo->AbilitySystemComponent, *ExecutingAbility);
for (TSharedPtr<FGameplayAbilityTargetData> Data : ContainerSpec.TargetData.Data)
{
if (Data.IsValid())
{
AllEffects.Append(Data->ApplyGameplayEffectSpec(*SpecHandle.Data.Get(), ActorInfo->AbilitySystemComponent->GetPredictionKeyForNewAction()));
}
else
{
UE_LOG(LogGGA_Ability, Warning, TEXT("ApplyGameplayEffectSpecToTarget invalid target data passed in. Ability: %s"), *ExecutingAbility->GetPathName());
}
}
}
}
return AllEffects;
}
TArray<FActiveGameplayEffectHandle> UGGA_GameplayEffectContainerFunctionLibrary::ApplyExternalEffectContainerSpec(const FGGA_GameplayEffectContainerSpec& ContainerSpec)
{
TArray<FActiveGameplayEffectHandle> AllEffects;
// Iterate list of gameplay effects
for (const FGameplayEffectSpecHandle& SpecHandle : ContainerSpec.TargetGameplayEffectSpecs)
{
if (SpecHandle.IsValid())
{
// If effect is valid, iterate list of targets and apply to all
for (TSharedPtr<FGameplayAbilityTargetData> Data : ContainerSpec.TargetData.Data)
{
AllEffects.Append(Data->ApplyGameplayEffectSpec(*SpecHandle.Data.Get()));
}
}
}
return AllEffects;
}

View File

@@ -0,0 +1,284 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Utilities/GGA_GameplayEffectFunctionLibrary.h"
#include "GameplayEffect.h"
#include "Blueprint/BlueprintExceptionInfo.h"
#include "UObject/EnumProperty.h"
#include "GGA_GameplayEffectContext.h"
#include "GGA_LogChannels.h"
#define LOCTEXT_NAMESPACE "UGGA_GameplayEffectFunctionLibrary"
// UGameplayEffect* UGGA_GameplayEffectFunctionLibrary::MakeRuntimeGameplayEffect(FString UniqueName, EGameplayEffectDurationType DurationPolicy, TArray<FGameplayModifierInfo> AttributeModifiers)
// {
// UGameplayEffect* GameplayEffect = NewObject<UGameplayEffect>(GetTransientPackage(), FName("RuntimeGE_" + GetNameSafe(this) + UniqueName));
// GameplayEffect->DurationPolicy = DurationPolicy;
// GameplayEffect->Modifiers = AttributeModifiers;
// return GameplayEffect;
// }
float UGGA_GameplayEffectFunctionLibrary::GetSetByCallerMagnitudeByTag(FGameplayEffectSpecHandle SpecHandle, FGameplayTag DataTag, bool WarnIfNotFound, float DefaultIfNotFound)
{
FGameplayEffectSpec* Spec = SpecHandle.Data.Get();
if (Spec)
{
return Spec->GetSetByCallerMagnitude(DataTag, WarnIfNotFound, DefaultIfNotFound);
}
return 0.0f;
}
float UGGA_GameplayEffectFunctionLibrary::GetSetByCallerMagnitudeByTagFromSpec(const FGameplayEffectSpec& EffectSpec, FGameplayTag DataTag, bool WarnIfNotFound, float DefaultIfNotFound)
{
return EffectSpec.GetSetByCallerMagnitude(DataTag, WarnIfNotFound, DefaultIfNotFound);
}
float UGGA_GameplayEffectFunctionLibrary::GetSetByCallerMagnitudeByName(FGameplayEffectSpecHandle SpecHandle, FName DataName)
{
FGameplayEffectSpec* Spec = SpecHandle.Data.Get();
if (Spec)
{
return Spec->GetSetByCallerMagnitude(DataName, false);
}
return 0.0f;
}
bool UGGA_GameplayEffectFunctionLibrary::IsActiveGameplayEffectHandleValid(FActiveGameplayEffectHandle Handle)
{
return Handle.IsValid();
}
void UGGA_GameplayEffectFunctionLibrary::GetOwnedGameplayTags(FGameplayEffectContextHandle EffectContext, FGameplayTagContainer& ActorTagContainer, FGameplayTagContainer& SpecTagContainer)
{
return EffectContext.GetOwnedGameplayTags(ActorTagContainer, SpecTagContainer);
}
void UGGA_GameplayEffectFunctionLibrary::AddInstigator(FGameplayEffectContextHandle EffectContext, AActor* InInstigator, AActor* InEffectCauser)
{
EffectContext.AddInstigator(InInstigator, InEffectCauser);
}
void UGGA_GameplayEffectFunctionLibrary::SetEffectCauser(FGameplayEffectContextHandle EffectContext, AActor* InEffectCauser)
{
EffectContext.AddInstigator(EffectContext.GetInstigator(), InEffectCauser);
}
void UGGA_GameplayEffectFunctionLibrary::SetAbility(FGameplayEffectContextHandle EffectContext, const UGameplayAbility* InGameplayAbility)
{
EffectContext.SetAbility(InGameplayAbility);
}
const UGameplayAbility* UGGA_GameplayEffectFunctionLibrary::GetAbilityCDO(FGameplayEffectContextHandle EffectContext)
{
return EffectContext.GetAbility();
}
const UGameplayAbility* UGGA_GameplayEffectFunctionLibrary::GetAbilityInstance(FGameplayEffectContextHandle EffectContext)
{
return EffectContext.GetAbilityInstance_NotReplicated();
}
int32 UGGA_GameplayEffectFunctionLibrary::GetAbilityLevel(FGameplayEffectContextHandle EffectContext)
{
return EffectContext.GetAbilityLevel();
}
void UGGA_GameplayEffectFunctionLibrary::AddSourceObject(FGameplayEffectContextHandle EffectContext, const UObject* NewSourceObject)
{
if (NewSourceObject)
{
EffectContext.AddSourceObject(NewSourceObject);
}
}
bool UGGA_GameplayEffectFunctionLibrary::HasOrigin(FGameplayEffectContextHandle EffectContext)
{
return EffectContext.HasOrigin();
}
FGGA_GameplayEffectContext* UGGA_GameplayEffectFunctionLibrary::GetEffectContextPtr(FGameplayEffectContextHandle EffectContext)
{
if (!EffectContext.IsValid())
{
GGA_LOG(Warning, "Try access invalid effect context!")
return nullptr;
}
if (!EffectContext.Get()->GetScriptStruct()->IsChildOf(FGGA_GameplayEffectContext::StaticStruct()))
{
GGA_LOG(Warning, "The GameplayEffectContext type is not FGGA_GameplayEffectContext! "
"Make sure you are setting AbilitySystemGlobalsClassName as GGA_AbilitySystemGlobals in Gameplay Abilities Settings Under Project Settings! ")
return nullptr;
}
return static_cast<FGGA_GameplayEffectContext*>(EffectContext.Get());
}
UAbilitySystemComponent* UGGA_GameplayEffectFunctionLibrary::GetInstigatorAbilitySystemComponent(FGameplayEffectContextHandle EffectContext)
{
return EffectContext.GetInstigatorAbilitySystemComponent();
}
UAbilitySystemComponent* UGGA_GameplayEffectFunctionLibrary::GetOriginalInstigatorAbilitySystemComponent(FGameplayEffectContextHandle EffectContext)
{
return EffectContext.GetOriginalInstigatorAbilitySystemComponent();
}
bool UGGA_GameplayEffectFunctionLibrary::HasContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType)
{
if (const FGGA_GameplayEffectContext* Context = GetEffectContextPtr(EffectContext))
{
return Context->FindPayloadByType(PayloadType) != nullptr;
}
return false;
}
bool UGGA_GameplayEffectFunctionLibrary::GetContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType, FInstancedStruct& OutPayload)
{
if (FGGA_GameplayEffectContext* Context = GetEffectContextPtr(EffectContext))
{
if (FInstancedStruct* Found = Context->FindPayloadByType(PayloadType))
{
OutPayload = *Found;
return true;
}
}
return false;
}
FInstancedStruct UGGA_GameplayEffectFunctionLibrary::GetValidContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType, bool& bValid)
{
bValid = false;
if (FGGA_GameplayEffectContext* Context = GetEffectContextPtr(EffectContext))
{
if (FInstancedStruct* Found = Context->FindPayloadByType(PayloadType))
{
bValid = true;
return *Found;
}
}
return FInstancedStruct();
}
void UGGA_GameplayEffectFunctionLibrary::GetContextPayload(FGameplayEffectContextHandle EffectContext, const UScriptStruct* PayloadType, EGGA_ContextPayloadResult& ExecResult, int32& Value)
{
// We should never hit this! stubs to avoid NoExport on the class.
checkNoEntry();
}
DEFINE_FUNCTION(UGGA_GameplayEffectFunctionLibrary::execGetContextPayload)
{
P_GET_STRUCT_REF(FGameplayEffectContextHandle, EffectContext);
P_GET_OBJECT(const UScriptStruct, PayloadType);
P_GET_ENUM_REF(EGGA_ContextPayloadResult, ExecResult);
// Read wildcard Value input
Stack.MostRecentPropertyAddress = nullptr;
Stack.MostRecentPropertyContainer = nullptr;
Stack.StepCompiledIn<FStructProperty>(nullptr);
const FStructProperty* ValueProp = CastField<FStructProperty>(Stack.MostRecentProperty);
void* ValuePtr = Stack.MostRecentPropertyAddress;
P_FINISH;
P_NATIVE_BEGIN;
ExecResult = EGGA_ContextPayloadResult::NotValid;
if (!ValueProp || !ValuePtr || !PayloadType)
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AbortExecution,
LOCTEXT("InstancedStruct_GetInvalidValueWarning", "Failed to resolve the Value or PayloadType for Get Context Payload")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
else
{
FInstancedStruct OutPayload;
if (GetContextPayload(EffectContext, PayloadType, OutPayload))
{
if (OutPayload.IsValid() && OutPayload.GetScriptStruct()->IsChildOf(ValueProp->Struct))
{
// Copy the struct data to the output Value
ValueProp->Struct->CopyScriptStruct(ValuePtr, OutPayload.GetMemory());
ExecResult = EGGA_ContextPayloadResult::Valid;
}
else
{
ExecResult = EGGA_ContextPayloadResult::NotValid;
}
}
else
{
ExecResult = EGGA_ContextPayloadResult::NotValid;
}
}
P_NATIVE_END;
}
void UGGA_GameplayEffectFunctionLibrary::SetContextPayload(FGameplayEffectContextHandle EffectContext, EGGA_ContextPayloadResult& ExecResult, const int32& Value)
{
// We should never hit this! stubs to avoid NoExport on the class.
checkNoEntry();
}
DEFINE_FUNCTION(UGGA_GameplayEffectFunctionLibrary::execSetContextPayload)
{
P_GET_STRUCT_REF(FGameplayEffectContextHandle, EffectContext);
P_GET_ENUM_REF(EGGA_ContextPayloadResult, ExecResult);
// Read wildcard Value input
Stack.MostRecentPropertyAddress = nullptr;
Stack.MostRecentPropertyContainer = nullptr;
Stack.StepCompiledIn<FStructProperty>(nullptr);
const FStructProperty* ValueProp = CastField<FStructProperty>(Stack.MostRecentProperty);
const void* ValuePtr = Stack.MostRecentPropertyAddress;
P_FINISH;
P_NATIVE_BEGIN;
ExecResult = EGGA_ContextPayloadResult::NotValid;
if (!ValueProp || !ValuePtr || !EffectContext.IsValid())
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AbortExecution,
LOCTEXT("InstancedStruct_SetInvalidValueWarning", "Failed to resolve Value or EffectContext for Set Instanced Struct Value")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
else
{
// Create an FInstancedStruct from the input struct
FInstancedStruct Payload;
Payload.InitializeAs(ValueProp->Struct, static_cast<const uint8*>(ValuePtr));
if (Payload.IsValid())
{
// Call the existing SetPayload function
if (FGGA_GameplayEffectContext* ContextPtr = GetEffectContextPtr(EffectContext))
{
ContextPtr->AddOrOverwriteData(Payload);
ExecResult = EGGA_ContextPayloadResult::Valid;
}
}
else
{
FBlueprintExceptionInfo ExceptionInfo(
EBlueprintExceptionType::AbortExecution,
LOCTEXT("SetGameplayEffectContextPayload", "Failed to create valid InstancedStruct from Value")
);
FBlueprintCoreDelegates::ThrowScriptException(P_THIS, Stack, ExceptionInfo);
}
}
P_NATIVE_END;
}
#undef LOCTEXT_NAMESPACE