// 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 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 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 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& MatchingGameplayAbilities, bool bOnlyAbilitiesThatSatisfyTagRequirements) { if (!IsValid(AbilitySystem) || Tags.IsEmpty()) { return; } MatchingGameplayAbilities.Empty(); TArray 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& MatchingGameplayAbilities, bool bOnlyAbilitiesThatSatisfyTagRequirements) { if (SourceObject == nullptr) { GetActivatableGameplayAbilitySpecsByAllMatchingTags(AbilitySystem, Tags, MatchingGameplayAbilities, bOnlyAbilitiesThatSatisfyTagRequirements); return; } if (!IsValid(AbilitySystem) || Tags.IsEmpty()) { return; } TArray 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& MatchingAbilityInstances) { if (!IsValid(AbilitySystem) || Tags.IsEmpty()) { return; } TArray 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 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 Tags, TArray& OutAbilityHandles, bool bExactMatch) { if (!IsValid(AbilitySystem) || Tags.IsEmpty()) { return false; } // ensure the output array is empty OutAbilityHandles.Empty(); for (const FGameplayTag& Tag : Tags) { TArray 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 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(&Spec); } } return nullptr; } bool UGGA_AbilitySystemFunctionLibrary::FindAbilityFromClass(const UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle& OutAbilityHandle, TSubclassOf 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 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 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 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 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 UGGA_AbilitySystemFunctionLibrary::GetAbilityInstances(UAbilitySystemComponent* AbilitySystem, FGameplayAbilitySpecHandle Ability) { TArray 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 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); }