2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LyraGameplayAbility.h"
# include "LyraLogChannels.h"
# include "AbilitySystem/LyraAbilitySystemComponent.h"
2022-09-13 07:18:28 +00:00
# include "HAL/PlatformStackWalk.h"
2022-05-23 18:41:30 +00:00
# include "Player/LyraPlayerController.h"
# include "Character/LyraCharacter.h"
# include "LyraGameplayTags.h"
# include "LyraAbilityCost.h"
# include "Character/LyraHeroComponent.h"
# include "AbilitySystemBlueprintLibrary.h"
# include "AbilitySystemGlobals.h"
# include "LyraAbilitySimpleFailureMessage.h"
# include "GameFramework/GameplayMessageSubsystem.h"
# include "AbilitySystem/LyraAbilitySourceInterface.h"
# include "AbilitySystem/LyraGameplayEffectContext.h"
# include "Physics/PhysicalMaterialWithTags.h"
2022-09-13 07:18:28 +00:00
# include "GameFramework/PlayerState.h"
# include "HAL/PlatformStackWalk.h"
# include "Camera/LyraCameraMode.h"
2022-05-23 18:41:30 +00:00
UE_DEFINE_GAMEPLAY_TAG ( TAG_ABILITY_SIMPLE_FAILURE_MESSAGE , " Ability.UserFacingSimpleActivateFail.Message " ) ;
UE_DEFINE_GAMEPLAY_TAG ( TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE , " Ability.PlayMontageOnActivateFail.Message " ) ;
ULyraGameplayAbility : : ULyraGameplayAbility ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
{
ReplicationPolicy = EGameplayAbilityReplicationPolicy : : ReplicateNo ;
InstancingPolicy = EGameplayAbilityInstancingPolicy : : InstancedPerActor ;
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy : : LocalPredicted ;
NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy : : ClientOrServer ;
ActivationPolicy = ELyraAbilityActivationPolicy : : OnInputTriggered ;
ActivationGroup = ELyraAbilityActivationGroup : : Independent ;
2022-09-13 07:18:28 +00:00
bLogCancelation = false ;
2022-05-23 18:41:30 +00:00
ActiveCameraMode = nullptr ;
}
ULyraAbilitySystemComponent * ULyraGameplayAbility : : GetLyraAbilitySystemComponentFromActorInfo ( ) const
{
return ( CurrentActorInfo ? Cast < ULyraAbilitySystemComponent > ( CurrentActorInfo - > AbilitySystemComponent . Get ( ) ) : nullptr ) ;
}
ALyraPlayerController * ULyraGameplayAbility : : GetLyraPlayerControllerFromActorInfo ( ) const
{
return ( CurrentActorInfo ? Cast < ALyraPlayerController > ( CurrentActorInfo - > PlayerController . Get ( ) ) : nullptr ) ;
}
AController * ULyraGameplayAbility : : GetControllerFromActorInfo ( ) const
{
if ( CurrentActorInfo )
{
if ( AController * PC = CurrentActorInfo - > PlayerController . Get ( ) )
{
return PC ;
}
// Look for a player controller or pawn in the owner chain.
AActor * TestActor = CurrentActorInfo - > OwnerActor . Get ( ) ;
while ( TestActor )
{
if ( AController * C = Cast < AController > ( TestActor ) )
{
return C ;
}
if ( APawn * Pawn = Cast < APawn > ( TestActor ) )
{
return Pawn - > GetController ( ) ;
}
TestActor = TestActor - > GetOwner ( ) ;
}
}
return nullptr ;
}
ALyraCharacter * ULyraGameplayAbility : : GetLyraCharacterFromActorInfo ( ) const
{
return ( CurrentActorInfo ? Cast < ALyraCharacter > ( CurrentActorInfo - > AvatarActor . Get ( ) ) : nullptr ) ;
}
ULyraHeroComponent * ULyraGameplayAbility : : GetHeroComponentFromActorInfo ( ) const
{
return ( CurrentActorInfo ? ULyraHeroComponent : : FindHeroComponent ( CurrentActorInfo - > AvatarActor . Get ( ) ) : nullptr ) ;
}
void ULyraGameplayAbility : : NativeOnAbilityFailedToActivate ( const FGameplayTagContainer & FailedReason ) const
{
bool bSimpleFailureFound = false ;
for ( FGameplayTag Reason : FailedReason )
{
if ( ! bSimpleFailureFound )
{
if ( const FText * pUserFacingMessage = FailureTagToUserFacingMessages . Find ( Reason ) )
{
FLyraAbilitySimpleFailureMessage Message ;
Message . PlayerController = GetActorInfo ( ) . PlayerController . Get ( ) ;
Message . FailureTags = FailedReason ;
Message . UserFacingReason = * pUserFacingMessage ;
UGameplayMessageSubsystem & MessageSystem = UGameplayMessageSubsystem : : Get ( GetWorld ( ) ) ;
MessageSystem . BroadcastMessage ( TAG_ABILITY_SIMPLE_FAILURE_MESSAGE , Message ) ;
bSimpleFailureFound = true ;
}
}
if ( UAnimMontage * pMontage = FailureTagToAnimMontage . FindRef ( Reason ) )
{
FLyraAbilityMontageFailureMessage Message ;
Message . PlayerController = GetActorInfo ( ) . PlayerController . Get ( ) ;
Message . FailureTags = FailedReason ;
Message . FailureMontage = pMontage ;
UGameplayMessageSubsystem & MessageSystem = UGameplayMessageSubsystem : : Get ( GetWorld ( ) ) ;
MessageSystem . BroadcastMessage ( TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE , Message ) ;
}
}
}
bool ULyraGameplayAbility : : CanActivateAbility ( const FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo , const FGameplayTagContainer * SourceTags , const FGameplayTagContainer * TargetTags , FGameplayTagContainer * OptionalRelevantTags ) const
{
if ( ! ActorInfo | | ! ActorInfo - > AbilitySystemComponent . IsValid ( ) )
{
return false ;
}
ULyraAbilitySystemComponent * LyraASC = CastChecked < ULyraAbilitySystemComponent > ( ActorInfo - > AbilitySystemComponent . Get ( ) ) ;
const FLyraGameplayTags & GameplayTags = FLyraGameplayTags : : Get ( ) ;
if ( ! Super : : CanActivateAbility ( Handle , ActorInfo , SourceTags , TargetTags , OptionalRelevantTags ) )
{
return false ;
}
//@TODO Possibly remove after setting up tag relationships
if ( LyraASC - > IsActivationGroupBlocked ( ActivationGroup ) )
{
if ( OptionalRelevantTags )
{
OptionalRelevantTags - > AddTag ( GameplayTags . Ability_ActivateFail_ActivationGroup ) ;
}
return false ;
}
return true ;
}
void ULyraGameplayAbility : : SetCanBeCanceled ( bool bCanBeCanceled )
{
// The ability can not block canceling if it's replaceable.
if ( ! bCanBeCanceled & & ( ActivationGroup = = ELyraAbilityActivationGroup : : Exclusive_Replaceable ) )
{
UE_LOG ( LogLyraAbilitySystem , Error , TEXT ( " SetCanBeCanceled: Ability [%s] can not block canceling because its activation group is replaceable. " ) , * GetName ( ) ) ;
return ;
}
Super : : SetCanBeCanceled ( bCanBeCanceled ) ;
}
void ULyraGameplayAbility : : OnGiveAbility ( const FGameplayAbilityActorInfo * ActorInfo , const FGameplayAbilitySpec & Spec )
{
Super : : OnGiveAbility ( ActorInfo , Spec ) ;
K2_OnAbilityAdded ( ) ;
TryActivateAbilityOnSpawn ( ActorInfo , Spec ) ;
}
void ULyraGameplayAbility : : OnRemoveAbility ( const FGameplayAbilityActorInfo * ActorInfo , const FGameplayAbilitySpec & Spec )
{
K2_OnAbilityRemoved ( ) ;
Super : : OnRemoveAbility ( ActorInfo , Spec ) ;
}
void ULyraGameplayAbility : : ActivateAbility ( const FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo , const FGameplayAbilityActivationInfo ActivationInfo , const FGameplayEventData * TriggerEventData )
{
Super : : ActivateAbility ( Handle , ActorInfo , ActivationInfo , TriggerEventData ) ;
}
void ULyraGameplayAbility : : EndAbility ( const FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo , const FGameplayAbilityActivationInfo ActivationInfo , bool bReplicateEndAbility , bool bWasCancelled )
{
2022-09-13 07:18:28 +00:00
# if !UE_BUILD_SHIPPING
if ( bWasCancelled & & bLogCancelation )
{
UE_LOG ( LogLyraAbilitySystem , Warning , TEXT ( " ======== (%s) canceled with EndAbility (locally controlled? %i) ======== " ) , * GetName ( ) , IsLocallyControlled ( ) ) ;
if ( APlayerState * PS = Cast < APlayerState > ( GetOwningActorFromActorInfo ( ) ) )
{
UE_LOG ( LogLyraAbilitySystem , Log , TEXT ( " Player Name: %s " ) , * PS - > GetPlayerName ( ) ) ;
}
PrintScriptCallstack ( ) ;
const SIZE_T StackTraceSize = 65535 ;
ANSICHAR * StackTrace = ( ANSICHAR * ) FMemory : : SystemMalloc ( StackTraceSize ) ;
if ( StackTrace ! = nullptr )
{
StackTrace [ 0 ] = 0 ;
// Walk the stack and dump it to the allocated memory.
FPlatformStackWalk : : StackWalkAndDump ( StackTrace , StackTraceSize , 1 ) ;
UE_LOG ( LogLyraAbilitySystem , Log , TEXT ( " Call Stack: \n %s " ) , ANSI_TO_TCHAR ( StackTrace ) ) ;
FMemory : : SystemFree ( StackTrace ) ;
}
}
# endif // !UE_BUILD_SHIPPING
2022-05-23 18:41:30 +00:00
ClearCameraMode ( ) ;
Super : : EndAbility ( Handle , ActorInfo , ActivationInfo , bReplicateEndAbility , bWasCancelled ) ;
}
bool ULyraGameplayAbility : : CheckCost ( const FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo , OUT FGameplayTagContainer * OptionalRelevantTags ) const
{
if ( ! Super : : CheckCost ( Handle , ActorInfo , OptionalRelevantTags ) | | ! ActorInfo )
{
return false ;
}
// Verify we can afford any additional costs
for ( TObjectPtr < ULyraAbilityCost > AdditionalCost : AdditionalCosts )
{
if ( AdditionalCost ! = nullptr )
{
if ( ! AdditionalCost - > CheckCost ( this , Handle , ActorInfo , /*inout*/ OptionalRelevantTags ) )
{
return false ;
}
}
}
return true ;
}
void ULyraGameplayAbility : : ApplyCost ( const FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo , const FGameplayAbilityActivationInfo ActivationInfo ) const
{
Super : : ApplyCost ( Handle , ActorInfo , ActivationInfo ) ;
check ( ActorInfo ) ;
// Used to determine if the ability actually hit a target (as some costs are only spent on successful attempts)
auto DetermineIfAbilityHitTarget = [ & ] ( )
{
if ( ActorInfo - > IsNetAuthority ( ) )
{
if ( ULyraAbilitySystemComponent * ASC = Cast < ULyraAbilitySystemComponent > ( ActorInfo - > AbilitySystemComponent . Get ( ) ) )
{
FGameplayAbilityTargetDataHandle TargetData ;
ASC - > GetAbilityTargetData ( Handle , ActivationInfo , TargetData ) ;
for ( int32 TargetDataIdx = 0 ; TargetDataIdx < TargetData . Data . Num ( ) ; + + TargetDataIdx )
{
if ( UAbilitySystemBlueprintLibrary : : TargetDataHasHitResult ( TargetData , TargetDataIdx ) )
{
return true ;
}
}
}
}
return false ;
} ;
// Pay any additional costs
bool bAbilityHitTarget = false ;
bool bHasDeterminedIfAbilityHitTarget = false ;
for ( TObjectPtr < ULyraAbilityCost > AdditionalCost : AdditionalCosts )
{
if ( AdditionalCost ! = nullptr )
{
if ( AdditionalCost - > ShouldOnlyApplyCostOnHit ( ) )
{
if ( ! bHasDeterminedIfAbilityHitTarget )
{
bAbilityHitTarget = DetermineIfAbilityHitTarget ( ) ;
bHasDeterminedIfAbilityHitTarget = true ;
}
if ( ! bAbilityHitTarget )
{
continue ;
}
}
AdditionalCost - > ApplyCost ( this , Handle , ActorInfo , ActivationInfo ) ;
}
}
}
FGameplayEffectContextHandle ULyraGameplayAbility : : MakeEffectContext ( const FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo ) const
{
FGameplayEffectContextHandle ContextHandle = Super : : MakeEffectContext ( Handle , ActorInfo ) ;
FLyraGameplayEffectContext * EffectContext = FLyraGameplayEffectContext : : ExtractEffectContext ( ContextHandle ) ;
check ( EffectContext ) ;
check ( ActorInfo ) ;
AActor * EffectCauser = nullptr ;
const ILyraAbilitySourceInterface * AbilitySource = nullptr ;
float SourceLevel = 0.0f ;
GetAbilitySource ( Handle , ActorInfo , /*out*/ SourceLevel , /*out*/ AbilitySource , /*out*/ EffectCauser ) ;
UObject * SourceObject = GetSourceObject ( Handle , ActorInfo ) ;
AActor * Instigator = ActorInfo ? ActorInfo - > OwnerActor . Get ( ) : nullptr ;
EffectContext - > SetAbilitySource ( AbilitySource , SourceLevel ) ;
EffectContext - > AddInstigator ( Instigator , EffectCauser ) ;
EffectContext - > AddSourceObject ( SourceObject ) ;
return ContextHandle ;
}
void ULyraGameplayAbility : : ApplyAbilityTagsToGameplayEffectSpec ( FGameplayEffectSpec & Spec , FGameplayAbilitySpec * AbilitySpec ) const
{
Super : : ApplyAbilityTagsToGameplayEffectSpec ( Spec , AbilitySpec ) ;
if ( const FHitResult * HitResult = Spec . GetContext ( ) . GetHitResult ( ) )
{
if ( const UPhysicalMaterialWithTags * PhysMatWithTags = Cast < const UPhysicalMaterialWithTags > ( HitResult - > PhysMaterial . Get ( ) ) )
{
Spec . CapturedTargetTags . GetSpecTags ( ) . AppendTags ( PhysMatWithTags - > Tags ) ;
}
}
}
bool ULyraGameplayAbility : : DoesAbilitySatisfyTagRequirements ( const UAbilitySystemComponent & AbilitySystemComponent , const FGameplayTagContainer * SourceTags , const FGameplayTagContainer * TargetTags , OUT FGameplayTagContainer * OptionalRelevantTags ) const
{
// Specialized version to handle death exclusion and AbilityTags expansion via ASC
bool bBlocked = false ;
bool bMissing = false ;
UAbilitySystemGlobals & AbilitySystemGlobals = UAbilitySystemGlobals : : Get ( ) ;
const FGameplayTag & BlockedTag = AbilitySystemGlobals . ActivateFailTagsBlockedTag ;
const FGameplayTag & MissingTag = AbilitySystemGlobals . ActivateFailTagsMissingTag ;
// Check if any of this ability's tags are currently blocked
if ( AbilitySystemComponent . AreAbilityTagsBlocked ( AbilityTags ) )
{
bBlocked = true ;
}
const ULyraAbilitySystemComponent * LyraASC = Cast < ULyraAbilitySystemComponent > ( & AbilitySystemComponent ) ;
static FGameplayTagContainer AllRequiredTags ;
static FGameplayTagContainer AllBlockedTags ;
AllRequiredTags = ActivationRequiredTags ;
AllBlockedTags = ActivationBlockedTags ;
// Expand our ability tags to add additional required/blocked tags
if ( LyraASC )
{
LyraASC - > GetAdditionalActivationTagRequirements ( AbilityTags , AllRequiredTags , AllBlockedTags ) ;
}
// Check to see the required/blocked tags for this ability
if ( AllBlockedTags . Num ( ) | | AllRequiredTags . Num ( ) )
{
static FGameplayTagContainer AbilitySystemComponentTags ;
AbilitySystemComponentTags . Reset ( ) ;
AbilitySystemComponent . GetOwnedGameplayTags ( AbilitySystemComponentTags ) ;
if ( AbilitySystemComponentTags . HasAny ( AllBlockedTags ) )
{
const FLyraGameplayTags & GameplayTags = FLyraGameplayTags : : Get ( ) ;
if ( OptionalRelevantTags & & AbilitySystemComponentTags . HasTag ( GameplayTags . Status_Death ) )
{
// If player is dead and was rejected due to blocking tags, give that feedback
OptionalRelevantTags - > AddTag ( GameplayTags . Ability_ActivateFail_IsDead ) ;
}
bBlocked = true ;
}
if ( ! AbilitySystemComponentTags . HasAll ( AllRequiredTags ) )
{
bMissing = true ;
}
}
if ( SourceTags ! = nullptr )
{
if ( SourceBlockedTags . Num ( ) | | SourceRequiredTags . Num ( ) )
{
if ( SourceTags - > HasAny ( SourceBlockedTags ) )
{
bBlocked = true ;
}
if ( ! SourceTags - > HasAll ( SourceRequiredTags ) )
{
bMissing = true ;
}
}
}
if ( TargetTags ! = nullptr )
{
if ( TargetBlockedTags . Num ( ) | | TargetRequiredTags . Num ( ) )
{
if ( TargetTags - > HasAny ( TargetBlockedTags ) )
{
bBlocked = true ;
}
if ( ! TargetTags - > HasAll ( TargetRequiredTags ) )
{
bMissing = true ;
}
}
}
if ( bBlocked )
{
if ( OptionalRelevantTags & & BlockedTag . IsValid ( ) )
{
OptionalRelevantTags - > AddTag ( BlockedTag ) ;
}
return false ;
}
if ( bMissing )
{
if ( OptionalRelevantTags & & MissingTag . IsValid ( ) )
{
OptionalRelevantTags - > AddTag ( MissingTag ) ;
}
return false ;
}
return true ;
}
void ULyraGameplayAbility : : OnPawnAvatarSet ( )
{
K2_OnPawnAvatarSet ( ) ;
}
void ULyraGameplayAbility : : GetAbilitySource ( FGameplayAbilitySpecHandle Handle , const FGameplayAbilityActorInfo * ActorInfo , float & OutSourceLevel , const ILyraAbilitySourceInterface * & OutAbilitySource , AActor * & OutEffectCauser ) const
{
OutSourceLevel = 0.0f ;
OutAbilitySource = nullptr ;
OutEffectCauser = nullptr ;
OutEffectCauser = ActorInfo - > AvatarActor . Get ( ) ;
// If we were added by something that's an ability info source, use it
UObject * SourceObject = GetSourceObject ( Handle , ActorInfo ) ;
OutAbilitySource = Cast < ILyraAbilitySourceInterface > ( SourceObject ) ;
}
void ULyraGameplayAbility : : TryActivateAbilityOnSpawn ( const FGameplayAbilityActorInfo * ActorInfo , const FGameplayAbilitySpec & Spec ) const
{
const bool bIsPredicting = ( Spec . ActivationInfo . ActivationMode = = EGameplayAbilityActivationMode : : Predicting ) ;
// Try to activate if activation policy is on spawn.
if ( ActorInfo & & ! Spec . IsActive ( ) & & ! bIsPredicting & & ( ActivationPolicy = = ELyraAbilityActivationPolicy : : OnSpawn ) )
{
UAbilitySystemComponent * ASC = ActorInfo - > AbilitySystemComponent . Get ( ) ;
const AActor * AvatarActor = ActorInfo - > AvatarActor . Get ( ) ;
// If avatar actor is torn off or about to die, don't try to activate until we get the new one.
if ( ASC & & AvatarActor & & ! AvatarActor - > GetTearOff ( ) & & ( AvatarActor - > GetLifeSpan ( ) < = 0.0f ) )
{
const bool bIsLocalExecution = ( NetExecutionPolicy = = EGameplayAbilityNetExecutionPolicy : : LocalPredicted ) | | ( NetExecutionPolicy = = EGameplayAbilityNetExecutionPolicy : : LocalOnly ) ;
const bool bIsServerExecution = ( NetExecutionPolicy = = EGameplayAbilityNetExecutionPolicy : : ServerOnly ) | | ( NetExecutionPolicy = = EGameplayAbilityNetExecutionPolicy : : ServerInitiated ) ;
const bool bClientShouldActivate = ActorInfo - > IsLocallyControlled ( ) & & bIsLocalExecution ;
const bool bServerShouldActivate = ActorInfo - > IsNetAuthority ( ) & & bIsServerExecution ;
if ( bClientShouldActivate | | bServerShouldActivate )
{
ASC - > TryActivateAbility ( Spec . Handle ) ;
}
}
}
}
bool ULyraGameplayAbility : : CanChangeActivationGroup ( ELyraAbilityActivationGroup NewGroup ) const
{
if ( ! IsInstantiated ( ) | | ! IsActive ( ) )
{
return false ;
}
if ( ActivationGroup = = NewGroup )
{
return true ;
}
ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponentFromActorInfo ( ) ;
check ( LyraASC ) ;
if ( ( ActivationGroup ! = ELyraAbilityActivationGroup : : Exclusive_Blocking ) & & LyraASC - > IsActivationGroupBlocked ( NewGroup ) )
{
// This ability can't change groups if it's blocked (unless it is the one doing the blocking).
return false ;
}
if ( ( NewGroup = = ELyraAbilityActivationGroup : : Exclusive_Replaceable ) & & ! CanBeCanceled ( ) )
{
// This ability can't become replaceable if it can't be canceled.
return false ;
}
return true ;
}
bool ULyraGameplayAbility : : ChangeActivationGroup ( ELyraAbilityActivationGroup NewGroup )
{
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN ( ChangeActivationGroup , false ) ;
if ( ! CanChangeActivationGroup ( NewGroup ) )
{
return false ;
}
if ( ActivationGroup ! = NewGroup )
{
ULyraAbilitySystemComponent * LyraASC = GetLyraAbilitySystemComponentFromActorInfo ( ) ;
check ( LyraASC ) ;
LyraASC - > RemoveAbilityFromActivationGroup ( ActivationGroup , this ) ;
LyraASC - > AddAbilityToActivationGroup ( NewGroup , this ) ;
ActivationGroup = NewGroup ;
}
return true ;
}
void ULyraGameplayAbility : : SetCameraMode ( TSubclassOf < ULyraCameraMode > CameraMode )
{
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN ( SetCameraMode , ) ;
if ( ULyraHeroComponent * HeroComponent = GetHeroComponentFromActorInfo ( ) )
{
HeroComponent - > SetAbilityCameraMode ( CameraMode , CurrentSpecHandle ) ;
ActiveCameraMode = CameraMode ;
}
}
void ULyraGameplayAbility : : ClearCameraMode ( )
{
ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN ( ClearCameraMode , ) ;
if ( ActiveCameraMode )
{
if ( ULyraHeroComponent * HeroComponent = GetHeroComponentFromActorInfo ( ) )
{
HeroComponent - > ClearAbilityCameraMode ( CurrentSpecHandle ) ;
}
ActiveCameraMode = nullptr ;
}
}