2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LyraHeroComponent.h"
# include "LyraLogChannels.h"
# include "GameFramework/Pawn.h"
# include "EnhancedInputComponent.h"
# include "EnhancedInputSubsystems.h"
# include "Player/LyraPlayerController.h"
# include "Player/LyraPlayerState.h"
2022-09-13 07:18:28 +00:00
# include "Player/LyraLocalPlayer.h"
2022-05-23 18:41:30 +00:00
# include "Character/LyraPawnExtensionComponent.h"
# include "Character/LyraPawnData.h"
# include "Character/LyraCharacter.h"
# include "AbilitySystem/LyraAbilitySystemComponent.h"
# include "Input/LyraInputConfig.h"
# include "Input/LyraInputComponent.h"
# include "Camera/LyraCameraComponent.h"
# include "LyraGameplayTags.h"
# include "Engine/LocalPlayer.h"
# include "Components/GameFrameworkComponentManager.h"
# include "Settings/LyraSettingsLocal.h"
# include "System/LyraAssetManager.h"
# include "PlayerMappableInputConfig.h"
2022-09-13 07:18:28 +00:00
# include "Camera/LyraCameraMode.h"
2022-05-23 18:41:30 +00:00
# if WITH_EDITOR
# include "Misc/UObjectToken.h"
# endif // WITH_EDITOR
namespace LyraHero
{
static const float LookYawRate = 300.0f ;
static const float LookPitchRate = 165.0f ;
} ;
const FName ULyraHeroComponent : : NAME_BindInputsNow ( " BindInputsNow " ) ;
2022-09-13 07:18:28 +00:00
const FName ULyraHeroComponent : : NAME_ActorFeatureName ( " Hero " ) ;
2022-05-23 18:41:30 +00:00
ULyraHeroComponent : : ULyraHeroComponent ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
{
AbilityCameraMode = nullptr ;
bReadyToBindInputs = false ;
}
void ULyraHeroComponent : : OnRegister ( )
{
Super : : OnRegister ( ) ;
2022-09-13 07:18:28 +00:00
if ( ! GetPawn < APawn > ( ) )
2022-05-23 18:41:30 +00:00
{
UE_LOG ( LogLyra , Error , TEXT ( " [ULyraHeroComponent::OnRegister] This component has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint. " ) ) ;
# if WITH_EDITOR
if ( GIsEditor )
{
static const FText Message = NSLOCTEXT ( " LyraHeroComponent " , " NotOnPawnError " , " has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint. This will cause a crash if you PIE! " ) ;
static const FName HeroMessageLogName = TEXT ( " LyraHeroComponent " ) ;
FMessageLog ( HeroMessageLogName ) . Error ( )
- > AddToken ( FUObjectToken : : Create ( this , FText : : FromString ( GetNameSafe ( this ) ) ) )
- > AddToken ( FTextToken : : Create ( Message ) ) ;
FMessageLog ( HeroMessageLogName ) . Open ( ) ;
}
# endif
}
2022-09-13 07:18:28 +00:00
else
{
// Register with the init state system early, this will only work if this is a game world
RegisterInitStateFeature ( ) ;
}
2022-05-23 18:41:30 +00:00
}
2022-09-13 07:18:28 +00:00
bool ULyraHeroComponent : : CanChangeInitState ( UGameFrameworkComponentManager * Manager , FGameplayTag CurrentState , FGameplayTag DesiredState ) const
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
check ( Manager ) ;
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
const FLyraGameplayTags & InitTags = FLyraGameplayTags : : Get ( ) ;
APawn * Pawn = GetPawn < APawn > ( ) ;
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
if ( ! CurrentState . IsValid ( ) & & DesiredState = = InitTags . InitState_Spawned )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
// As long as we have a real pawn, let us transition
if ( Pawn )
{
return true ;
}
2022-05-23 18:41:30 +00:00
}
2022-09-13 07:18:28 +00:00
else if ( CurrentState = = InitTags . InitState_Spawned & & DesiredState = = InitTags . InitState_DataAvailable )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
// The player state is required.
if ( ! GetPlayerState < ALyraPlayerState > ( ) )
{
return false ;
}
// If we're authority or autonomous, we need to wait for a controller with registered ownership of the player state.
if ( Pawn - > GetLocalRole ( ) ! = ROLE_SimulatedProxy )
{
AController * Controller = GetController < AController > ( ) ;
const bool bHasControllerPairedWithPS = ( Controller ! = nullptr ) & & \
( Controller - > PlayerState ! = nullptr ) & & \
( Controller - > PlayerState - > GetOwner ( ) = = Controller ) ;
if ( ! bHasControllerPairedWithPS )
{
return false ;
}
}
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
const bool bIsLocallyControlled = Pawn - > IsLocallyControlled ( ) ;
const bool bIsBot = Pawn - > IsBotControlled ( ) ;
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
if ( bIsLocallyControlled & & ! bIsBot )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
ALyraPlayerController * LyraPC = GetController < ALyraPlayerController > ( ) ;
// The input component and local player is required when locally controlled.
if ( ! Pawn - > InputComponent | | ! LyraPC | | ! LyraPC - > GetLocalPlayer ( ) )
{
return false ;
}
2022-05-23 18:41:30 +00:00
}
2022-09-13 07:18:28 +00:00
return true ;
2022-05-23 18:41:30 +00:00
}
2022-09-13 07:18:28 +00:00
else if ( CurrentState = = InitTags . InitState_DataAvailable & & DesiredState = = InitTags . InitState_DataInitialized )
{
// Wait for player state and extension component
ALyraPlayerState * LyraPS = GetPlayerState < ALyraPlayerState > ( ) ;
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
return LyraPS & & Manager - > HasFeatureReachedInitState ( Pawn , ULyraPawnExtensionComponent : : NAME_ActorFeatureName , InitTags . InitState_DataInitialized ) ;
}
else if ( CurrentState = = InitTags . InitState_DataInitialized & & DesiredState = = InitTags . InitState_GameplayReady )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
// TODO add ability initialization checks?
return true ;
2022-05-23 18:41:30 +00:00
}
2022-09-13 07:18:28 +00:00
return false ;
2022-05-23 18:41:30 +00:00
}
2022-09-13 07:18:28 +00:00
void ULyraHeroComponent : : HandleChangeInitState ( UGameFrameworkComponentManager * Manager , FGameplayTag CurrentState , FGameplayTag DesiredState )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
const FLyraGameplayTags & InitTags = FLyraGameplayTags : : Get ( ) ;
if ( CurrentState = = FLyraGameplayTags : : Get ( ) . InitState_DataAvailable & & DesiredState = = FLyraGameplayTags : : Get ( ) . InitState_DataInitialized )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
APawn * Pawn = GetPawn < APawn > ( ) ;
ALyraPlayerState * LyraPS = GetPlayerState < ALyraPlayerState > ( ) ;
if ( ! ensure ( Pawn & & LyraPS ) )
{
return ;
}
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
const bool bIsLocallyControlled = Pawn - > IsLocallyControlled ( ) ;
const ULyraPawnData * PawnData = nullptr ;
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
if ( ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( Pawn ) )
{
PawnData = PawnExtComp - > GetPawnData < ULyraPawnData > ( ) ;
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
// The player state holds the persistent data for this player (state that persists across deaths and multiple pawns).
// The ability system component and attribute sets live on the player state.
PawnExtComp - > InitializeAbilitySystem ( LyraPS - > GetLyraAbilitySystemComponent ( ) , LyraPS ) ;
}
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
if ( ALyraPlayerController * LyraPC = GetController < ALyraPlayerController > ( ) )
{
if ( Pawn - > InputComponent ! = nullptr )
{
InitializePlayerInput ( Pawn - > InputComponent ) ;
}
}
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
if ( bIsLocallyControlled & & PawnData )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
if ( ULyraCameraComponent * CameraComponent = ULyraCameraComponent : : FindCameraComponent ( Pawn ) )
{
CameraComponent - > DetermineCameraModeDelegate . BindUObject ( this , & ThisClass : : DetermineCameraMode ) ;
}
2022-05-23 18:41:30 +00:00
}
}
2022-09-13 07:18:28 +00:00
}
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
void ULyraHeroComponent : : OnActorInitStateChanged ( const FActorInitStateChangedParams & Params )
{
if ( Params . FeatureName = = ULyraPawnExtensionComponent : : NAME_ActorFeatureName )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
if ( Params . FeatureState = = FLyraGameplayTags : : Get ( ) . InitState_DataInitialized )
2022-05-23 18:41:30 +00:00
{
2022-09-13 07:18:28 +00:00
// If the extension component says all all other components are initialized, try to progress to next state
CheckDefaultInitialization ( ) ;
2022-05-23 18:41:30 +00:00
}
}
2022-09-13 07:18:28 +00:00
}
2022-05-23 18:41:30 +00:00
2022-09-13 07:18:28 +00:00
void ULyraHeroComponent : : CheckDefaultInitialization ( )
{
const FLyraGameplayTags & InitTags = FLyraGameplayTags : : Get ( ) ;
static const TArray < FGameplayTag > StateChain = { InitTags . InitState_Spawned , InitTags . InitState_DataAvailable , InitTags . InitState_DataInitialized , InitTags . InitState_GameplayReady } ;
// This will try to progress from spawned (which is only set in BeginPlay) through the data initialization stages until it gets to gameplay ready
ContinueInitStateChain ( StateChain ) ;
2022-05-23 18:41:30 +00:00
}
void ULyraHeroComponent : : BeginPlay ( )
{
Super : : BeginPlay ( ) ;
2022-09-13 07:18:28 +00:00
// Listen for when the pawn extension component changes init state
BindOnActorInitStateChanged ( ULyraPawnExtensionComponent : : NAME_ActorFeatureName , FGameplayTag ( ) , false ) ;
// Notifies that we are done spawning, then try the rest of initialization
ensure ( TryToChangeInitState ( FLyraGameplayTags : : Get ( ) . InitState_Spawned ) ) ;
CheckDefaultInitialization ( ) ;
2022-05-23 18:41:30 +00:00
}
void ULyraHeroComponent : : EndPlay ( const EEndPlayReason : : Type EndPlayReason )
{
2022-09-13 07:18:28 +00:00
UnregisterInitStateFeature ( ) ;
2022-05-23 18:41:30 +00:00
Super : : EndPlay ( EndPlayReason ) ;
}
void ULyraHeroComponent : : InitializePlayerInput ( UInputComponent * PlayerInputComponent )
{
check ( PlayerInputComponent ) ;
const APawn * Pawn = GetPawn < APawn > ( ) ;
if ( ! Pawn )
{
return ;
}
const APlayerController * PC = GetController < APlayerController > ( ) ;
check ( PC ) ;
2022-09-13 07:18:28 +00:00
const ULyraLocalPlayer * LP = Cast < ULyraLocalPlayer > ( PC - > GetLocalPlayer ( ) ) ;
2022-05-23 18:41:30 +00:00
check ( LP ) ;
UEnhancedInputLocalPlayerSubsystem * Subsystem = LP - > GetSubsystem < UEnhancedInputLocalPlayerSubsystem > ( ) ;
check ( Subsystem ) ;
Subsystem - > ClearAllMappings ( ) ;
if ( const ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( Pawn ) )
{
if ( const ULyraPawnData * PawnData = PawnExtComp - > GetPawnData < ULyraPawnData > ( ) )
{
if ( const ULyraInputConfig * InputConfig = PawnData - > InputConfig )
{
const FLyraGameplayTags & GameplayTags = FLyraGameplayTags : : Get ( ) ;
// Register any default input configs with the settings so that they will be applied to the player during AddInputMappings
for ( const FMappableConfigPair & Pair : DefaultInputConfigs )
{
2022-09-13 07:18:28 +00:00
if ( Pair . bShouldActivateAutomatically & & Pair . CanBeActivated ( ) )
{
FModifyContextOptions Options = { } ;
Options . bIgnoreAllPressedKeysUntilRelease = false ;
// Actually add the config to the local player
Subsystem - > AddPlayerMappableConfig ( Pair . Config . LoadSynchronous ( ) , Options ) ;
}
2022-05-23 18:41:30 +00:00
}
ULyraInputComponent * LyraIC = CastChecked < ULyraInputComponent > ( PlayerInputComponent ) ;
LyraIC - > AddInputMappings ( InputConfig , Subsystem ) ;
TArray < uint32 > BindHandles ;
LyraIC - > BindAbilityActions ( InputConfig , this , & ThisClass : : Input_AbilityInputTagPressed , & ThisClass : : Input_AbilityInputTagReleased , /*out*/ BindHandles ) ;
LyraIC - > BindNativeAction ( InputConfig , GameplayTags . InputTag_Move , ETriggerEvent : : Triggered , this , & ThisClass : : Input_Move , /*bLogIfNotFound=*/ false ) ;
LyraIC - > BindNativeAction ( InputConfig , GameplayTags . InputTag_Look_Mouse , ETriggerEvent : : Triggered , this , & ThisClass : : Input_LookMouse , /*bLogIfNotFound=*/ false ) ;
LyraIC - > BindNativeAction ( InputConfig , GameplayTags . InputTag_Look_Stick , ETriggerEvent : : Triggered , this , & ThisClass : : Input_LookStick , /*bLogIfNotFound=*/ false ) ;
LyraIC - > BindNativeAction ( InputConfig , GameplayTags . InputTag_Crouch , ETriggerEvent : : Triggered , this , & ThisClass : : Input_Crouch , /*bLogIfNotFound=*/ false ) ;
LyraIC - > BindNativeAction ( InputConfig , GameplayTags . InputTag_AutoRun , ETriggerEvent : : Triggered , this , & ThisClass : : Input_AutoRun , /*bLogIfNotFound=*/ false ) ;
}
}
}
if ( ensure ( ! bReadyToBindInputs ) )
{
bReadyToBindInputs = true ;
}
2022-09-13 07:18:28 +00:00
2022-05-23 18:41:30 +00:00
UGameFrameworkComponentManager : : SendGameFrameworkComponentExtensionEvent ( const_cast < APlayerController * > ( PC ) , NAME_BindInputsNow ) ;
UGameFrameworkComponentManager : : SendGameFrameworkComponentExtensionEvent ( const_cast < APawn * > ( Pawn ) , NAME_BindInputsNow ) ;
}
void ULyraHeroComponent : : AddAdditionalInputConfig ( const ULyraInputConfig * InputConfig )
{
TArray < uint32 > BindHandles ;
const APawn * Pawn = GetPawn < APawn > ( ) ;
if ( ! Pawn )
{
return ;
}
ULyraInputComponent * LyraIC = Pawn - > FindComponentByClass < ULyraInputComponent > ( ) ;
check ( LyraIC ) ;
const APlayerController * PC = GetController < APlayerController > ( ) ;
check ( PC ) ;
const ULocalPlayer * LP = PC - > GetLocalPlayer ( ) ;
check ( LP ) ;
UEnhancedInputLocalPlayerSubsystem * Subsystem = LP - > GetSubsystem < UEnhancedInputLocalPlayerSubsystem > ( ) ;
check ( Subsystem ) ;
if ( const ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( Pawn ) )
{
LyraIC - > BindAbilityActions ( InputConfig , this , & ThisClass : : Input_AbilityInputTagPressed , & ThisClass : : Input_AbilityInputTagReleased , /*out*/ BindHandles ) ;
}
}
void ULyraHeroComponent : : RemoveAdditionalInputConfig ( const ULyraInputConfig * InputConfig )
{
//@TODO: Implement me!
}
bool ULyraHeroComponent : : IsReadyToBindInputs ( ) const
{
return bReadyToBindInputs ;
}
void ULyraHeroComponent : : Input_AbilityInputTagPressed ( FGameplayTag InputTag )
{
if ( const APawn * Pawn = GetPawn < APawn > ( ) )
{
if ( const ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( Pawn ) )
{
if ( ULyraAbilitySystemComponent * LyraASC = PawnExtComp - > GetLyraAbilitySystemComponent ( ) )
{
LyraASC - > AbilityInputTagPressed ( InputTag ) ;
}
}
}
}
void ULyraHeroComponent : : Input_AbilityInputTagReleased ( FGameplayTag InputTag )
{
const APawn * Pawn = GetPawn < APawn > ( ) ;
if ( ! Pawn )
{
return ;
}
if ( const ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( Pawn ) )
{
if ( ULyraAbilitySystemComponent * LyraASC = PawnExtComp - > GetLyraAbilitySystemComponent ( ) )
{
LyraASC - > AbilityInputTagReleased ( InputTag ) ;
}
}
}
void ULyraHeroComponent : : Input_Move ( const FInputActionValue & InputActionValue )
{
APawn * Pawn = GetPawn < APawn > ( ) ;
AController * Controller = Pawn ? Pawn - > GetController ( ) : nullptr ;
// If the player has attempted to move again then cancel auto running
if ( ALyraPlayerController * LyraController = Cast < ALyraPlayerController > ( Controller ) )
{
LyraController - > SetIsAutoRunning ( false ) ;
}
if ( Controller )
{
const FVector2D Value = InputActionValue . Get < FVector2D > ( ) ;
const FRotator MovementRotation ( 0.0f , Controller - > GetControlRotation ( ) . Yaw , 0.0f ) ;
if ( Value . X ! = 0.0f )
{
const FVector MovementDirection = MovementRotation . RotateVector ( FVector : : RightVector ) ;
Pawn - > AddMovementInput ( MovementDirection , Value . X ) ;
}
if ( Value . Y ! = 0.0f )
{
const FVector MovementDirection = MovementRotation . RotateVector ( FVector : : ForwardVector ) ;
Pawn - > AddMovementInput ( MovementDirection , Value . Y ) ;
}
}
}
void ULyraHeroComponent : : Input_LookMouse ( const FInputActionValue & InputActionValue )
{
APawn * Pawn = GetPawn < APawn > ( ) ;
if ( ! Pawn )
{
return ;
}
const FVector2D Value = InputActionValue . Get < FVector2D > ( ) ;
if ( Value . X ! = 0.0f )
{
Pawn - > AddControllerYawInput ( Value . X ) ;
}
if ( Value . Y ! = 0.0f )
{
Pawn - > AddControllerPitchInput ( Value . Y ) ;
}
}
void ULyraHeroComponent : : Input_LookStick ( const FInputActionValue & InputActionValue )
{
APawn * Pawn = GetPawn < APawn > ( ) ;
if ( ! Pawn )
{
return ;
}
const FVector2D Value = InputActionValue . Get < FVector2D > ( ) ;
const UWorld * World = GetWorld ( ) ;
check ( World ) ;
if ( Value . X ! = 0.0f )
{
Pawn - > AddControllerYawInput ( Value . X * LyraHero : : LookYawRate * World - > GetDeltaSeconds ( ) ) ;
}
if ( Value . Y ! = 0.0f )
{
Pawn - > AddControllerPitchInput ( Value . Y * LyraHero : : LookPitchRate * World - > GetDeltaSeconds ( ) ) ;
}
}
void ULyraHeroComponent : : Input_Crouch ( const FInputActionValue & InputActionValue )
{
if ( ALyraCharacter * Character = GetPawn < ALyraCharacter > ( ) )
{
Character - > ToggleCrouch ( ) ;
}
}
void ULyraHeroComponent : : Input_AutoRun ( const FInputActionValue & InputActionValue )
{
if ( APawn * Pawn = GetPawn < APawn > ( ) )
{
if ( ALyraPlayerController * Controller = Cast < ALyraPlayerController > ( Pawn - > GetController ( ) ) )
{
// Toggle auto running
Controller - > SetIsAutoRunning ( ! Controller - > GetIsAutoRunning ( ) ) ;
}
}
}
TSubclassOf < ULyraCameraMode > ULyraHeroComponent : : DetermineCameraMode ( ) const
{
if ( AbilityCameraMode )
{
return AbilityCameraMode ;
}
const APawn * Pawn = GetPawn < APawn > ( ) ;
if ( ! Pawn )
{
return nullptr ;
}
if ( ULyraPawnExtensionComponent * PawnExtComp = ULyraPawnExtensionComponent : : FindPawnExtensionComponent ( Pawn ) )
{
if ( const ULyraPawnData * PawnData = PawnExtComp - > GetPawnData < ULyraPawnData > ( ) )
{
return PawnData - > DefaultCameraMode ;
}
}
return nullptr ;
}
void ULyraHeroComponent : : SetAbilityCameraMode ( TSubclassOf < ULyraCameraMode > CameraMode , const FGameplayAbilitySpecHandle & OwningSpecHandle )
{
if ( CameraMode )
{
AbilityCameraMode = CameraMode ;
AbilityCameraModeOwningSpecHandle = OwningSpecHandle ;
}
}
void ULyraHeroComponent : : ClearAbilityCameraMode ( const FGameplayAbilitySpecHandle & OwningSpecHandle )
{
if ( AbilityCameraModeOwningSpecHandle = = OwningSpecHandle )
{
AbilityCameraMode = nullptr ;
AbilityCameraModeOwningSpecHandle = FGameplayAbilitySpecHandle ( ) ;
}
}