第一次提交
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user