2025-01-04 16:41:49 +00:00
// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.
# include "AbilitySystem/OLSAbilitySystemComponent.h"
# include "AbilitySystemGlobals.h"
# include "GameplayCueManager.h"
2025-01-16 19:05:19 +00:00
# include "OLSLog.h"
2025-01-04 16:41:49 +00:00
# include "AbilitySystem/OLSBatchGameplayAbilityInterface.h"
# include "AbilitySystem/OLSGlobaAbilitySubsystem.h"
2025-01-16 23:04:14 +00:00
# include "AbilitySystem/Abilities/OLSGameplayAbility.h"
2025-01-04 16:41:49 +00:00
# include "AnimInstances/OLSBaseLayerAnimInstance.h"
2025-01-16 23:04:14 +00:00
# include "DataAssets/OLSAbilityTagRelationshipMappingDataAsset.h"
# include "DataAssets/OLSGameDataAsset.h"
# include "Systems/OLSAssetManager.h"
2025-01-04 16:41:49 +00:00
2025-01-16 19:05:19 +00:00
DEFINE_LOG_CATEGORY ( LogOLSAbilitySystemComponent ) ;
2025-01-04 16:41:49 +00:00
2025-01-16 23:04:14 +00:00
UE_DEFINE_GAMEPLAY_TAG ( TAG_Gameplay_AbilityInputBlocked , " Gameplay.AbilityInputBlocked " ) ;
2025-01-04 16:41:49 +00:00
// Sets default values for this component's properties
UOLSAbilitySystemComponent : : UOLSAbilitySystemComponent ( )
{
static constexpr bool isReplicated = true ;
SetIsReplicatedByDefault ( isReplicated ) ;
bShouldEnableBatchRPC = true ;
}
void UOLSAbilitySystemComponent : : InitAbilityActorInfo ( AActor * ownerActor , AActor * avatarActor )
{
FGameplayAbilityActorInfo * actorInfo = AbilityActorInfo . Get ( ) ;
check ( actorInfo ) ;
check ( ownerActor ) ;
// Guard condition to ensure we should clear/init for this new Avatar Actor.
const bool hasAvatarChanged = avatarActor & & Cast < APawn > ( avatarActor ) & & ( avatarActor ! = actorInfo - > AvatarActor ) ;
Super : : InitAbilityActorInfo ( ownerActor , avatarActor ) ;
// Apply the new defaults obtained from the owner's interface.
if ( hasAvatarChanged )
{
if ( const TObjectPtr < UOLSGlobaAbilitySubsystem > globalAbilitySystem = UWorld : : GetSubsystem < UOLSGlobaAbilitySubsystem > ( GetWorld ( ) ) )
{
globalAbilitySystem - > RegisterASC ( this ) ;
}
if ( const TObjectPtr < UOLSBaseLayerAnimInstance > animInstance = Cast < UOLSBaseLayerAnimInstance > ( GetAnimInstanceFromActorInfo ( ) ) )
{
animInstance - > InitializeWithAbilitySystem ( this ) ;
}
TryActivateAbilitiesOnSpawn ( ) ;
}
}
bool UOLSAbilitySystemComponent : : ShouldDoServerAbilityRPCBatch ( ) const
{
return bShouldEnableBatchRPC ;
}
float UOLSAbilitySystemComponent : : PlayMontage (
UGameplayAbility * animatingAbility ,
FGameplayAbilityActivationInfo activationInfo ,
UAnimMontage * montage ,
float playRate ,
FName startSectionName ,
float startTimeSeconds )
{
if ( GEnableDefaultPlayMontage )
{
// Always useful to still allow the default flow, if there are some meaningful changes in the core system
// that were not yet reflect in this custom implementation. Can be enabled with CVar "GEnableDefaultPlayMontage".
//
return Super : : PlayMontage ( animatingAbility , activationInfo , montage , playRate , startSectionName , startTimeSeconds ) ;
}
float duration = - 1.f ;
// This method was re-written just to ensure that the Animation Instance is retrieved from the Actor Info
// by default, but also, other scenarios can be supported. Biggest example being an IK Runtime Retarget.
//
// This virtual "GetAnimInstanceFromActorInfo" provides some flexibility on how the Anim Instance is
// retrieved. It can be extended in projects that should support IK Runtime Retargets and also traditional
// Anim Instances set in the Actor Info.
//
const TObjectPtr < UAnimInstance > animInstance = GetAnimInstanceFromActorInfo ( ) ;
if ( animInstance & & montage )
{
duration = animInstance - > Montage_Play (
montage ,
playRate ,
EMontagePlayReturnType : : MontageLength ,
startTimeSeconds ) ;
if ( duration > 0.f )
{
if ( montage - > HasRootMotion ( ) & & animInstance - > GetOwningActor ( ) )
{
UE_LOG ( LogRootMotion , Log , TEXT ( " UAbilitySystemComponent::PlayMontage %s, Role: %s " )
, * GetNameSafe ( montage )
, * UEnum : : GetValueAsString ( TEXT ( " Engine.ENetRole " ) , animInstance - > GetOwningActor ( ) - > GetLocalRole ( ) )
) ;
}
LocalAnimMontageInfo . AnimMontage = montage ;
LocalAnimMontageInfo . AnimatingAbility = animatingAbility ;
LocalAnimMontageInfo . PlayInstanceId = ( LocalAnimMontageInfo . PlayInstanceId < UINT8_MAX ? LocalAnimMontageInfo . PlayInstanceId + 1 : 0 ) ;
if ( animatingAbility )
{
animatingAbility - > SetCurrentMontage ( montage ) ;
}
// Start at a given Section.
if ( startSectionName ! = NAME_None )
{
animInstance - > Montage_JumpToSection ( startSectionName , montage ) ;
}
// Replicate for non-owners and for replay recordings
// The data we set from GetRepAnimMontageInfo_Mutable() is used both by the server to replicate to clients and by clients to record replays.
// We need to set this data for recording clients because there exists network configurations where an abilities montage data will not replicate to some clients (for example: if the client is an autonomous proxy.)
if ( ShouldRecordMontageReplication ( ) )
{
FGameplayAbilityRepAnimMontage & mutableRepAnimMontageInfo = GetRepAnimMontageInfo_Mutable ( ) ;
SetReplicatedMontageInfo ( mutableRepAnimMontageInfo , montage , startSectionName ) ;
// Update parameters that change during Montage lifetime.
AnimMontage_UpdateReplicatedData ( ) ;
}
// Replicate to non-owners
if ( IsOwnerActorAuthoritative ( ) )
{
// Force net update on our avatar actor.
if ( AbilityActorInfo - > AvatarActor ! = nullptr )
{
AbilityActorInfo - > AvatarActor - > ForceNetUpdate ( ) ;
}
}
else
{
// If this prediction key is rejected, we need to end the preview
FPredictionKey predictionKey = GetPredictionKeyForNewAction ( ) ;
if ( predictionKey . IsValidKey ( ) )
{
predictionKey . NewRejectedDelegate ( ) . BindUObject ( this , & ThisClass : : OnPredictiveMontageRejected , montage ) ;
}
}
}
}
return duration ;
}
UAnimInstance * UOLSAbilitySystemComponent : : GetAnimInstanceFromActorInfo ( ) const
{
if ( ! AbilityActorInfo . IsValid ( ) )
{
return nullptr ;
}
const FGameplayAbilityActorInfo * actorInfo = AbilityActorInfo . Get ( ) ;
if ( actorInfo - > AnimInstance . IsValid ( ) & & actorInfo - > AnimInstance - > IsValidLowLevelFast ( ) )
{
// Return the one that was deliberately set in the Actor Info.
return actorInfo - > AnimInstance . Get ( ) ;
}
// Otherwise, let the getter method try to figure out the animation instance.
return actorInfo - > GetAnimInstance ( ) ;
}
FActiveGameplayEffectHandle UOLSAbilitySystemComponent : : ApplyGameplayEffectClassToSelf (
TSubclassOf < UGameplayEffect > effectClass ,
float level )
{
FActiveGameplayEffectHandle handle ;
if ( IsValid ( effectClass ) )
{
FGameplayEffectContextHandle contextHandle = MakeEffectContext ( ) ;
contextHandle . AddSourceObject ( GetOwner ( ) ) ;
const FGameplayEffectSpecHandle specHandle = MakeOutgoingSpec ( effectClass , level , contextHandle ) ;
if ( specHandle . IsValid ( ) )
{
handle = ApplyGameplayEffectSpecToSelf ( * specHandle . Data . Get ( ) ) ;
2025-01-16 19:05:19 +00:00
OLS_LOG ( LogOLSAbilitySystemComponent , Verbose , TEXT ( " [%s] Effect '%s' granted at level %f. " ) ,
GET_UOBJECT_NAME ( GetAvatarActor ( ) ) , GET_UOBJECT_NAME ( effectClass ) , level ) ;
2025-01-04 16:41:49 +00:00
}
}
return handle ;
}
FGameplayAbilitySpecHandle UOLSAbilitySystemComponent : : GiveAbilityFromClass (
const TSubclassOf < UGameplayAbility > abilityClass ,
int32 level ,
int32 input )
{
FGameplayAbilitySpecHandle handle ;
if ( IsValid ( abilityClass ) )
{
const FGameplayAbilitySpec newAbilitySpec ( FGameplayAbilitySpec ( abilityClass , level , input , GetOwner ( ) ) ) ;
handle = GiveAbility ( newAbilitySpec ) ;
2025-01-16 19:05:19 +00:00
OLS_LOG ( LogOLSAbilitySystemComponent , Log , TEXT ( " [%s] Ability '%s' %s at level %d. " ) ,
GET_UOBJECT_NAME ( GetAvatarActor ( ) ) , GET_UOBJECT_NAME ( abilityClass ) ,
2025-01-04 16:41:49 +00:00
handle . IsValid ( ) ? TEXT ( " successfully granted " ) : TEXT ( " failed to be granted " ) , level ) ;
}
return handle ;
}
bool UOLSAbilitySystemComponent : : TryBatchActivateAbility (
FGameplayAbilitySpecHandle abilityHandle ,
bool shouldEndAbilityImmediately )
{
bool isAbilityActivated = false ;
if ( abilityHandle . IsValid ( ) )
{
2025-01-16 19:05:19 +00:00
OLS_LOG ( LogAbilitySystemComponent , Warning , TEXT ( " Ability handle is invalid! " ) ) ;
2025-01-04 16:41:49 +00:00
return isAbilityActivated ;
}
FScopedServerAbilityRPCBatcher batch ( this , abilityHandle ) ;
isAbilityActivated = TryActivateAbility ( abilityHandle , true ) ;
if ( ! shouldEndAbilityImmediately )
{
const FGameplayAbilitySpec * abilitySpec = FindAbilitySpecFromHandle ( abilityHandle ) ;
if ( abilitySpec ! = nullptr )
{
UGameplayAbility * ability = abilitySpec - > GetPrimaryInstance ( ) ;
if ( IsValid ( ability ) & & ability - > Implements < UOLSBatchGameplayAbilityInterface > ( ) )
{
IOLSBatchGameplayAbilityInterface : : Execute_EndAbilityFromBatch ( ability ) ;
}
else
{
2025-01-16 19:05:19 +00:00
OLS_LOG ( LogAbilitySystemComponent , Error ,
TEXT ( " %s does not implement Batch Gameplay Ability Interface " ) , GET_UOBJECT_NAME ( ability ) ) ;
2025-01-04 16:41:49 +00:00
}
}
}
return isAbilityActivated ;
}
void UOLSAbilitySystemComponent : : CancelAbilitiesByTags (
FGameplayTagContainer abilityTags ,
FGameplayTagContainer cancelFilterTags )
{
CancelAbilities ( & abilityTags , & cancelFilterTags ) ;
}
void UOLSAbilitySystemComponent : : ExecuteGameplayCueLocal (
const FGameplayTag gameplayCueTag ,
const FGameplayCueParameters & gameplayCueParameters ) const
{
const TObjectPtr < UGameplayCueManager > cueManager = UAbilitySystemGlobals : : Get ( ) . GetGameplayCueManager ( ) ;
cueManager - > HandleGameplayCue (
GetOwner ( ) ,
gameplayCueTag ,
EGameplayCueEvent : : Type : : Executed ,
gameplayCueParameters ) ;
}
void UOLSAbilitySystemComponent : : AddGameplayCueLocally (
const FGameplayTag gameplayCueTag ,
const FGameplayCueParameters & gameplayCueParameters ) const
{
const TObjectPtr < UGameplayCueManager > cueManager = UAbilitySystemGlobals : : Get ( ) . GetGameplayCueManager ( ) ;
cueManager - > HandleGameplayCue (
GetOwner ( ) ,
gameplayCueTag ,
EGameplayCueEvent : : Type : : OnActive ,
gameplayCueParameters ) ;
cueManager - > HandleGameplayCue (
GetOwner ( ) ,
gameplayCueTag ,
EGameplayCueEvent : : Type : : WhileActive ,
gameplayCueParameters ) ;
}
void UOLSAbilitySystemComponent : : RemoveGameplayCueLocally (
const FGameplayTag gameplayCueTag ,
const FGameplayCueParameters & gameplayCueParameters ) const
{
const TObjectPtr < UGameplayCueManager > cueManager = UAbilitySystemGlobals : : Get ( ) . GetGameplayCueManager ( ) ;
cueManager - > HandleGameplayCue ( GetOwner ( ) , gameplayCueTag , EGameplayCueEvent : : Type : : Removed , gameplayCueParameters ) ;
}
void UOLSAbilitySystemComponent : : TryActivateAbilitiesOnSpawn ( )
{
ABILITYLIST_SCOPE_LOCK ( ) ;
2025-01-16 23:04:14 +00:00
for ( const FGameplayAbilitySpec & abilitySpec : ActivatableAbilities . Items )
{
if ( const UOLSGameplayAbility * abilityCDO = Cast < UOLSGameplayAbility > ( abilitySpec . Ability ) )
{
// @TODO: Implement UOLSGameplayAbility.
// abilityCDO->TryActivateAbilityOnSpawn(AbilityActorInfo.Get(), abilitySpec);
}
}
}
void UOLSAbilitySystemComponent : : AbilitySpecInputPressed ( FGameplayAbilitySpec & spec )
{
Super : : AbilitySpecInputPressed ( spec ) ;
// We don't support UGameplayAbility::bReplicateInputDirectly.
// Use replicated events instead so that the WaitInputPress ability task works.
if ( spec . IsActive ( ) )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const UGameplayAbility * instance = spec . GetPrimaryInstance ( ) ;
FPredictionKey originalPredictionKey = instance
? instance - > GetCurrentActivationInfo ( ) . GetActivationPredictionKey ( )
: spec . ActivationInfo . GetActivationPredictionKey ( ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
// Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server.
InvokeReplicatedEvent ( EAbilityGenericReplicatedEvent : : InputPressed , spec . Handle , originalPredictionKey ) ;
}
}
2025-01-04 16:41:49 +00:00
2025-01-16 23:04:14 +00:00
void UOLSAbilitySystemComponent : : AbilitySpecInputReleased ( FGameplayAbilitySpec & spec )
{
Super : : AbilitySpecInputReleased ( spec ) ;
// We don't support UGameplayAbility::bReplicateInputDirectly.
// Use replicated events instead so that the WaitInputRelease ability task works.
if ( spec . IsActive ( ) )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const UGameplayAbility * instance = spec . GetPrimaryInstance ( ) ;
FPredictionKey originalPredictionKey = instance
? instance - > GetCurrentActivationInfo ( ) . GetActivationPredictionKey ( )
: spec . ActivationInfo . GetActivationPredictionKey ( ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
// Invoke the InputReleased event. This is not replicated here. If someone is listening, they may replicate the InputReleased event to the server.
InvokeReplicatedEvent ( EAbilityGenericReplicatedEvent : : InputReleased , spec . Handle , originalPredictionKey ) ;
}
}
void UOLSAbilitySystemComponent : : NotifyAbilityActivated ( const FGameplayAbilitySpecHandle handle ,
UGameplayAbility * ability )
{
Super : : NotifyAbilityActivated ( handle , ability ) ;
if ( UOLSGameplayAbility * olsAbility = Cast < UOLSGameplayAbility > ( ability ) )
2025-01-04 16:41:49 +00:00
{
2025-01-16 23:04:14 +00:00
// @TODO: Implement UOLSGameplayAbility.
// AddAbilityToActivationGroup(olsAbility->GetActivationGroup(), ability);
}
}
void UOLSAbilitySystemComponent : : NotifyAbilityFailed ( const FGameplayAbilitySpecHandle handle ,
UGameplayAbility * ability ,
const FGameplayTagContainer & failureReason )
{
Super : : NotifyAbilityFailed ( handle , ability , failureReason ) ;
if ( APawn * avatar = Cast < APawn > ( GetAvatarActor ( ) ) )
{
if ( ! avatar - > IsLocallyControlled ( ) & & ability - > IsSupportedForNetworking ( ) )
{
ClientNotifyAbilityFailed ( ability , failureReason ) ;
return ;
}
}
HandleAbilityFailed ( ability , failureReason ) ;
}
void UOLSAbilitySystemComponent : : NotifyAbilityEnded ( FGameplayAbilitySpecHandle handle , UGameplayAbility * Ability ,
bool wasCancelled )
{
Super : : NotifyAbilityEnded ( handle , Ability , wasCancelled ) ;
if ( UOLSGameplayAbility * olsAbility = Cast < UOLSGameplayAbility > ( Ability ) )
{
// @TODO: Implement UOLSGameplayAbility.
// RemoveAbilityFromActivationGroup(olsAbility->GetActivationGroup(), olsAbility);
}
}
void UOLSAbilitySystemComponent : : ApplyAbilityBlockAndCancelTags ( const FGameplayTagContainer & abilityTags ,
UGameplayAbility * requestingAbility ,
bool shouldEnableBlockTags ,
const FGameplayTagContainer & blockTags ,
bool shouldExecuteCancelTags ,
const FGameplayTagContainer & cancelTags )
{
FGameplayTagContainer modifiedBlockTags = blockTags ;
FGameplayTagContainer modifiedCancelTags = cancelTags ;
if ( TagRelationshipMapping )
{
// Use the mapping to expand the ability tags into block and cancel tag
TagRelationshipMapping - > GetAbilityTagsToBlockAndCancel ( abilityTags , & modifiedBlockTags , & modifiedCancelTags ) ;
}
Super : : ApplyAbilityBlockAndCancelTags ( abilityTags , requestingAbility , shouldEnableBlockTags , modifiedBlockTags ,
shouldExecuteCancelTags , modifiedCancelTags ) ;
//@TODO: Apply any special logic like blocking input or movement
}
void UOLSAbilitySystemComponent : : HandleChangeAbilityCanBeCanceled ( const FGameplayTagContainer & abilityTags ,
UGameplayAbility * requestingAbility ,
bool canBeCanceled )
{
Super : : HandleChangeAbilityCanBeCanceled ( abilityTags , requestingAbility , canBeCanceled ) ;
//@TODO: Apply any special logic like blocking input or movement
}
void UOLSAbilitySystemComponent : : ClientNotifyAbilityFailed_Implementation ( const UGameplayAbility * ability ,
const FGameplayTagContainer & failureReason )
{
HandleAbilityFailed ( ability , failureReason ) ;
}
void UOLSAbilitySystemComponent : : HandleAbilityFailed ( const UGameplayAbility * ability ,
const FGameplayTagContainer & failureReason )
{
if ( const UOLSGameplayAbility * olsAbility = Cast < const UOLSGameplayAbility > ( ability ) )
{
// @TODO: Implement UOLSGameplayAbility.
// olsAbility->OnAbilityFailedToActivate(failureReason);
2025-01-04 16:41:49 +00:00
}
}
void UOLSAbilitySystemComponent : : SetReplicatedMontageInfo (
FGameplayAbilityRepAnimMontage & mutableRepAnimMontageInfo ,
UAnimMontage * newMontageToPlay ,
const FName & startSectionName )
{
const uint8 playInstanceId = mutableRepAnimMontageInfo . PlayInstanceId < UINT8_MAX ? mutableRepAnimMontageInfo . PlayInstanceId + 1 : 0 ;
const uint8 sectionIdToPlay = newMontageToPlay - > GetSectionIndex ( startSectionName ) + 1 ;
TObjectPtr < UAnimSequenceBase > animation = newMontageToPlay ;
if ( newMontageToPlay - > IsDynamicMontage ( ) )
{
animation = newMontageToPlay - > GetFirstAnimReference ( ) ;
check ( ! newMontageToPlay - > SlotAnimTracks . IsEmpty ( ) ) ;
mutableRepAnimMontageInfo . SlotName = newMontageToPlay - > SlotAnimTracks [ 0 ] . SlotName ;
mutableRepAnimMontageInfo . BlendOutTime = newMontageToPlay - > GetDefaultBlendInTime ( ) ;
}
mutableRepAnimMontageInfo . Animation = animation ;
mutableRepAnimMontageInfo . PlayInstanceId = playInstanceId ;
mutableRepAnimMontageInfo . SectionIdToPlay = 0 ;
if ( mutableRepAnimMontageInfo . Animation & & startSectionName ! = NAME_None )
{
mutableRepAnimMontageInfo . SectionIdToPlay = sectionIdToPlay ;
}
}
2025-01-16 23:04:14 +00:00
void UOLSAbilitySystemComponent : : CancelAbilitiesByFunc ( TShouldCancelAbilityFunc shouldCancelFunc ,
bool shouldReplicateCancelAbility )
{
ABILITYLIST_SCOPE_LOCK ( ) ;
for ( const FGameplayAbilitySpec & abilitySpec : ActivatableAbilities . Items )
{
if ( ! abilitySpec . IsActive ( ) )
{
continue ;
}
UOLSGameplayAbility * abilityCDO = Cast < UOLSGameplayAbility > ( abilitySpec . Ability ) ;
if ( ! abilityCDO )
{
OLS_LOG ( LogOLSAbilitySystemComponent , Error ,
TEXT ( " CancelAbilitiesByFunc: Non-LyraGameplayAbility %s was Granted to ASC. Skipping. " ) ,
GET_UOBJECT_NAME ( abilitySpec . Ability ) ) ;
continue ;
}
PRAGMA_DISABLE_DEPRECATION_WARNINGS
ensureMsgf ( abilitySpec . Ability - > GetInstancingPolicy ( ) ! = EGameplayAbilityInstancingPolicy : : NonInstanced , TEXT ( " CancelAbilitiesByFunc: All Abilities should be Instanced (NonInstanced is being deprecated due to usability issues). " ) ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
// Cancel all the spawned instances.
TArray < UGameplayAbility * > Instances = abilitySpec . GetAbilityInstances ( ) ;
for ( UGameplayAbility * AbilityInstance : Instances )
{
UOLSGameplayAbility * abilityInstance = CastChecked < UOLSGameplayAbility > ( AbilityInstance ) ;
if ( shouldCancelFunc ( abilityInstance , abilitySpec . Handle ) )
{
if ( abilityInstance - > CanBeCanceled ( ) )
{
abilityInstance - > CancelAbility ( abilitySpec . Handle , AbilityActorInfo . Get ( ) , abilityInstance - > GetCurrentActivationInfo ( ) , shouldReplicateCancelAbility ) ;
}
else
{
OLS_LOG ( LogOLSAbilitySystemComponent , Error ,
TEXT ( " CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false. " ) ,
GET_UOBJECT_NAME ( abilityInstance ) ) ;
}
}
}
}
}
void UOLSAbilitySystemComponent : : CancelInputActivatedAbilities ( bool shouldReplicateCancelAbility )
{
// @TODO: Implement UOLSGameplayAbility
// auto shouldCancelFunc = [this](const UOLSGameplayAbility* ability, FGameplayAbilitySpecHandle handle)
// {
// const ELyraAbilityActivationPolicy ActivationPolicy = ability->GetActivationPolicy();
// return ((ActivationPolicy == ELyraAbilityActivationPolicy::OnInputTriggered) || (ActivationPolicy == ELyraAbilityActivationPolicy::WhileInputActive));
// };
//
// CancelAbilitiesByFunc(shouldCancelFunc, shouldReplicateCancelAbility);
}
void UOLSAbilitySystemComponent : : AbilityInputTagPressed ( const FGameplayTag & inputTag )
{
if ( inputTag . IsValid ( ) )
{
for ( const FGameplayAbilitySpec & abilitySpec : ActivatableAbilities . Items )
{
if ( abilitySpec . Ability & & ( abilitySpec . GetDynamicSpecSourceTags ( ) . HasTagExact ( inputTag ) ) )
{
InputPressedSpecHandles . AddUnique ( abilitySpec . Handle ) ;
InputHeldSpecHandles . AddUnique ( abilitySpec . Handle ) ;
}
}
}
}
void UOLSAbilitySystemComponent : : AbilityInputTagReleased ( const FGameplayTag & inputTag )
{
if ( inputTag . IsValid ( ) )
{
for ( const FGameplayAbilitySpec & abilitySpec : ActivatableAbilities . Items )
{
if ( abilitySpec . Ability & & ( abilitySpec . GetDynamicSpecSourceTags ( ) . HasTagExact ( inputTag ) ) )
{
InputReleasedSpecHandles . AddUnique ( abilitySpec . Handle ) ;
InputHeldSpecHandles . Remove ( abilitySpec . Handle ) ;
}
}
}
}
void UOLSAbilitySystemComponent : : ProcessAbilityInput ( float deltaTime , bool shouldGamePaused )
{
if ( HasMatchingGameplayTag ( TAG_Gameplay_AbilityInputBlocked ) )
{
ClearAbilityInput ( ) ;
return ;
}
static TArray < FGameplayAbilitySpecHandle > abilitiesToActivate ;
abilitiesToActivate . Reset ( ) ;
//@TODO: See if we can use FScopedServerAbilityRPCBatcher ScopedRPCBatcher in some of these loops
//
// Process all abilities that activate when the input is held.
//
for ( const FGameplayAbilitySpecHandle & specHandle : InputHeldSpecHandles )
{
if ( const FGameplayAbilitySpec * abilitySpec = FindAbilitySpecFromHandle ( specHandle ) )
{
if ( abilitySpec - > Ability & & ! abilitySpec - > IsActive ( ) )
{
const UOLSGameplayAbility * abilityCDO = Cast < UOLSGameplayAbility > ( abilitySpec - > Ability ) ;
// @TODO: Implement UOLSGameplayAbility.
// if (abilityCDO && abilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::WhileInputActive)
// {
// AbilitiesToActivate.AddUnique(AbilitySpec->Handle);
// }
}
}
}
//
// Process all abilities that had their input pressed this frame.
//
for ( const FGameplayAbilitySpecHandle & specHandle : InputPressedSpecHandles )
{
if ( FGameplayAbilitySpec * abilitySpec = FindAbilitySpecFromHandle ( specHandle ) )
{
if ( abilitySpec - > Ability )
{
abilitySpec - > InputPressed = true ;
if ( abilitySpec - > IsActive ( ) )
{
// Ability is active so pass along the input event.
AbilitySpecInputPressed ( * abilitySpec ) ;
}
else
{
const UOLSGameplayAbility * abilityCDO = Cast < UOLSGameplayAbility > ( abilitySpec - > Ability ) ;
// @TODO: Implement UOLSGameplayAbility.
// if (abilityCDO && abilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::OnInputTriggered)
// {
// abilitiesToActivate.AddUnique(abilitySpec->Handle);
// }
}
}
}
}
//
// Try to activate all the abilities that are from presses and holds.
// We do it all at once so that held inputs don't activate the ability
// and then also send a input event to the ability because of the press.
//
for ( const FGameplayAbilitySpecHandle & abilitySpecHandle : abilitiesToActivate )
{
TryActivateAbility ( abilitySpecHandle ) ;
}
//
// Process all abilities that had their input released this frame.
//
for ( const FGameplayAbilitySpecHandle & specHandle : InputReleasedSpecHandles )
{
if ( FGameplayAbilitySpec * abilitySpec = FindAbilitySpecFromHandle ( specHandle ) )
{
if ( abilitySpec - > Ability )
{
abilitySpec - > InputPressed = false ;
if ( abilitySpec - > IsActive ( ) )
{
// Ability is active so pass along the input event.
AbilitySpecInputReleased ( * abilitySpec ) ;
}
}
}
}
//
// Clear the cached ability handles.
//
InputPressedSpecHandles . Reset ( ) ;
InputReleasedSpecHandles . Reset ( ) ;
}
void UOLSAbilitySystemComponent : : ClearAbilityInput ( )
{
InputPressedSpecHandles . Reset ( ) ;
InputReleasedSpecHandles . Reset ( ) ;
InputHeldSpecHandles . Reset ( ) ;
}
void UOLSAbilitySystemComponent : : AddDynamicTagGameplayEffect ( const FGameplayTag & tag )
{
const TSubclassOf < UGameplayEffect > dynamicTagGE = UOLSAssetManager : : GetSubclass ( UOLSGameDataAsset : : Get ( ) . DynamicTagGameplayEffect ) ;
if ( ! dynamicTagGE )
{
OLS_LOG ( LogOLSAbilitySystemComponent , Warning ,
TEXT ( " AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]. " ) ,
* UOLSGameDataAsset : : Get ( ) . DynamicTagGameplayEffect . GetAssetName ( ) ) ;
return ;
}
const FGameplayEffectSpecHandle specHandle = MakeOutgoingSpec ( dynamicTagGE , 1.0f , MakeEffectContext ( ) ) ;
FGameplayEffectSpec * spec = specHandle . Data . Get ( ) ;
if ( ! spec )
{
OLS_LOG ( LogOLSAbilitySystemComponent , Warning ,
TEXT ( " AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]. " ) ,
GET_UOBJECT_NAME ( dynamicTagGE ) ) ;
return ;
}
spec - > DynamicGrantedTags . AddTag ( tag ) ;
ApplyGameplayEffectSpecToSelf ( * spec ) ;
}
void UOLSAbilitySystemComponent : : RemoveDynamicTagGameplayEffect ( const FGameplayTag & Tag )
{
const TSubclassOf < UGameplayEffect > dynamicTagGE = UOLSAssetManager : : GetSubclass ( UOLSGameDataAsset : : Get ( ) . DynamicTagGameplayEffect ) ;
if ( ! dynamicTagGE )
{
OLS_LOG ( LogOLSAbilitySystemComponent , Warning ,
TEXT ( " RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]. " ) ,
2025-01-17 22:14:51 +00:00
* UOLSGameDataAsset : : Get ( ) . DynamicTagGameplayEffect . GetAssetName ( ) ) ;
2025-01-16 23:04:14 +00:00
return ;
}
FGameplayEffectQuery query = FGameplayEffectQuery : : MakeQuery_MatchAnyOwningTags ( FGameplayTagContainer ( Tag ) ) ;
query . EffectDefinition = dynamicTagGE ;
RemoveActiveEffects ( query ) ;
}
void UOLSAbilitySystemComponent : : GetAbilityTargetData ( const FGameplayAbilitySpecHandle abilityHandle ,
FGameplayAbilityActivationInfo activationInfo ,
FGameplayAbilityTargetDataHandle & outTargetDataHandle )
{
TSharedPtr < FAbilityReplicatedDataCache > replicatedData = AbilityTargetDataMap . Find (
FGameplayAbilitySpecHandleAndPredictionKey ( abilityHandle , activationInfo . GetActivationPredictionKey ( ) ) ) ;
if ( replicatedData . IsValid ( ) )
{
outTargetDataHandle = replicatedData - > TargetData ;
}
}
void UOLSAbilitySystemComponent : : SetTagRelationshipMapping ( UOLSAbilityTagRelationshipMappingDataAsset * newMapping )
{
TagRelationshipMapping = newMapping ;
}
void UOLSAbilitySystemComponent : : GetAdditionalActivationTagRequirements ( const FGameplayTagContainer & abilityTags ,
FGameplayTagContainer & outActivationRequired ,
FGameplayTagContainer & outActivationBlocked ) const
{
if ( TagRelationshipMapping )
{
TagRelationshipMapping - > GetRequiredAndBlockedActivationTags ( abilityTags , & outActivationRequired , & outActivationBlocked ) ;
}
}
2025-01-04 16:41:49 +00:00