RealtimeStyleTransferRuntime/Source/LyraGame/Character/LyraHeroComponent.cpp

503 lines
15 KiB
C++
Raw Normal View History

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"
#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"
#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");
ULyraHeroComponent::ULyraHeroComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
AbilityCameraMode = nullptr;
bPawnHasInitialized = false;
bReadyToBindInputs = false;
}
void ULyraHeroComponent::OnRegister()
{
Super::OnRegister();
if (const APawn* Pawn = GetPawn<APawn>())
{
if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn))
{
PawnExtComp->OnPawnReadyToInitialize_RegisterAndCall(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnPawnReadyToInitialize));
}
}
else
{
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
}
}
bool ULyraHeroComponent::IsPawnComponentReadyToInitialize() const
{
// The player state is required.
if (!GetPlayerState<ALyraPlayerState>())
{
return false;
}
const APawn* Pawn = GetPawn<APawn>();
// A pawn is required.
if (!Pawn)
{
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;
}
}
const bool bIsLocallyControlled = Pawn->IsLocallyControlled();
const bool bIsBot = Pawn->IsBotControlled();
if (bIsLocallyControlled && !bIsBot)
{
// The input component is required when locally controlled.
if (!Pawn->InputComponent)
{
return false;
}
}
return true;
}
void ULyraHeroComponent::OnPawnReadyToInitialize()
{
if (!ensure(!bPawnHasInitialized))
{
// Don't initialize twice
return;
}
APawn* Pawn = GetPawn<APawn>();
if (!Pawn)
{
return;
}
const bool bIsLocallyControlled = Pawn->IsLocallyControlled();
ALyraPlayerState* LyraPS = GetPlayerState<ALyraPlayerState>();
check(LyraPS);
const ULyraPawnData* PawnData = nullptr;
if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn))
{
PawnData = PawnExtComp->GetPawnData<ULyraPawnData>();
// 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);
}
if (ALyraPlayerController* LyraPC = GetController<ALyraPlayerController>())
{
if (Pawn->InputComponent != nullptr)
{
InitializePlayerInput(Pawn->InputComponent);
}
}
if (bIsLocallyControlled && PawnData)
{
if (ULyraCameraComponent* CameraComponent = ULyraCameraComponent::FindCameraComponent(Pawn))
{
CameraComponent->DetermineCameraModeDelegate.BindUObject(this, &ThisClass::DetermineCameraMode);
}
}
bPawnHasInitialized = true;
}
void ULyraHeroComponent::BeginPlay()
{
Super::BeginPlay();
}
void ULyraHeroComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (const APawn* Pawn = GetPawn<APawn>())
{
if (ULyraPawnExtensionComponent* PawnExtComp = ULyraPawnExtensionComponent::FindPawnExtensionComponent(Pawn))
{
PawnExtComp->UninitializeAbilitySystem();
}
}
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);
const ULocalPlayer* LP = PC->GetLocalPlayer();
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)
{
FMappableConfigPair::ActivatePair(Pair);
}
ULyraInputComponent* LyraIC = CastChecked<ULyraInputComponent>(PlayerInputComponent);
LyraIC->AddInputMappings(InputConfig, Subsystem);
if (ULyraSettingsLocal* LocalSettings = ULyraSettingsLocal::Get())
{
LocalSettings->OnInputConfigActivated.AddUObject(this, &ULyraHeroComponent::OnInputConfigActivated);
LocalSettings->OnInputConfigDeactivated.AddUObject(this, &ULyraHeroComponent::OnInputConfigDeactivated);
}
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;
}
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast<APlayerController*>(PC), NAME_BindInputsNow);
UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast<APawn*>(Pawn), NAME_BindInputsNow);
}
void ULyraHeroComponent::OnInputConfigActivated(const FLoadedMappableConfigPair& ConfigPair)
{
if (ALyraPlayerController* LyraPC = GetController<ALyraPlayerController>())
{
if (APawn* Pawn = GetPawn<APawn>())
{
if (ULyraInputComponent* LyraIC = Cast<ULyraInputComponent>(Pawn->InputComponent))
{
if (const ULocalPlayer* LP = LyraPC->GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
LyraIC->AddInputConfig(ConfigPair, Subsystem);
}
}
}
}
}
}
void ULyraHeroComponent::OnInputConfigDeactivated(const FLoadedMappableConfigPair& ConfigPair)
{
if (ALyraPlayerController* LyraPC = GetController<ALyraPlayerController>())
{
if (APawn* Pawn = GetPawn<APawn>())
{
if (ULyraInputComponent* LyraIC = Cast<ULyraInputComponent>(Pawn->InputComponent))
{
if (const ULocalPlayer* LP = LyraPC->GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
LyraIC->RemoveInputConfig(ConfigPair, Subsystem);
}
}
}
}
}
}
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::HasPawnInitialized() const
{
return bPawnHasInitialized;
}
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();
}
}