436 lines
12 KiB
C++
436 lines
12 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LyraPlayerController.h"
|
|
#include "LyraLogChannels.h"
|
|
#include "GameModes/LyraGameMode.h"
|
|
#include "LyraCheatManager.h"
|
|
#include "LyraPlayerState.h"
|
|
#include "Camera/LyraPlayerCameraManager.h"
|
|
#include "UI/LyraHUD.h"
|
|
#include "Character/LyraPawnData.h"
|
|
#include "AbilitySystem/LyraAbilitySystemComponent.h"
|
|
#include "EngineUtils.h"
|
|
#include "LyraGameplayTags.h"
|
|
#include "GameFramework/Pawn.h"
|
|
#include "AbilitySystemGlobals.h"
|
|
#include "CommonInputSubsystem.h"
|
|
#include "LevelEditorSubsystem.h"
|
|
#include "LyraLocalPlayer.h"
|
|
#include "Character/LyraCharacter.h"
|
|
#include "Settings/LyraSettingsShared.h"
|
|
#include "Development/LyraDeveloperSettings.h"
|
|
|
|
ALyraPlayerController::ALyraPlayerController(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
PlayerCameraManagerClass = ALyraPlayerCameraManager::StaticClass();
|
|
|
|
#if USING_CHEAT_MANAGER
|
|
CheatClass = ULyraCheatManager::StaticClass();
|
|
#endif // #if USING_CHEAT_MANAGER
|
|
}
|
|
|
|
void ALyraPlayerController::PreInitializeComponents()
|
|
{
|
|
Super::PreInitializeComponents();
|
|
}
|
|
|
|
void ALyraPlayerController::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
SetActorHiddenInGame(false);
|
|
}
|
|
|
|
void ALyraPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|
{
|
|
Super::EndPlay(EndPlayReason);
|
|
}
|
|
|
|
void ALyraPlayerController::Tick(float DeltaSeconds)
|
|
{
|
|
Super::Tick(DeltaSeconds);
|
|
|
|
|
|
ULevelEditorSubsystem* LevelEditorSubsystem = GEditor->GetEditorSubsystem<ULevelEditorSubsystem>();
|
|
AActor* ActorToPilot = LevelEditorSubsystem->GetPilotLevelActor();
|
|
if (Cast<ALyraCharacter>(ActorToPilot))
|
|
return;
|
|
|
|
for (ALyraCharacter* LyraCharacter : TActorRange<ALyraCharacter>(GetWorld()))
|
|
{
|
|
if(Cast<ALyraPlayerController>(LyraCharacter->GetController()))
|
|
continue;
|
|
|
|
ActorToPilot = LyraCharacter;
|
|
break;
|
|
}
|
|
|
|
if (!IsValid(ActorToPilot))
|
|
return;
|
|
|
|
LevelEditorSubsystem->PilotLevelActor(ActorToPilot);
|
|
}
|
|
|
|
void ALyraPlayerController::ReceivedPlayer()
|
|
{
|
|
Super::ReceivedPlayer();
|
|
}
|
|
|
|
void ALyraPlayerController::PlayerTick(float DeltaTime)
|
|
{
|
|
Super::PlayerTick(DeltaTime);
|
|
|
|
// If we are auto running then add some player input
|
|
if (GetIsAutoRunning())
|
|
{
|
|
if (APawn* CurrentPawn = GetPawn())
|
|
{
|
|
const FRotator MovementRotation(0.0f, GetControlRotation().Yaw, 0.0f);
|
|
const FVector MovementDirection = MovementRotation.RotateVector(FVector::ForwardVector);
|
|
CurrentPawn->AddMovementInput(MovementDirection, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
ALyraPlayerState* ALyraPlayerController::GetLyraPlayerState() const
|
|
{
|
|
return CastChecked<ALyraPlayerState>(PlayerState, ECastCheckedType::NullAllowed);
|
|
}
|
|
|
|
ULyraAbilitySystemComponent* ALyraPlayerController::GetLyraAbilitySystemComponent() const
|
|
{
|
|
const ALyraPlayerState* LyraPS = GetLyraPlayerState();
|
|
return (LyraPS ? LyraPS->GetLyraAbilitySystemComponent() : nullptr);
|
|
}
|
|
|
|
ALyraHUD* ALyraPlayerController::GetLyraHUD() const
|
|
{
|
|
return CastChecked<ALyraHUD>(GetHUD(), ECastCheckedType::NullAllowed);
|
|
}
|
|
|
|
void ALyraPlayerController::OnPlayerStateChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam)
|
|
{
|
|
ConditionalBroadcastTeamChanged(this, IntegerToGenericTeamId(OldTeam), IntegerToGenericTeamId(NewTeam));
|
|
}
|
|
|
|
void ALyraPlayerController::OnPlayerStateChanged()
|
|
{
|
|
// Empty, place for derived classes to implement without having to hook all the other events
|
|
}
|
|
|
|
void ALyraPlayerController::BroadcastOnPlayerStateChanged()
|
|
{
|
|
OnPlayerStateChanged();
|
|
|
|
// Unbind from the old player state, if any
|
|
FGenericTeamId OldTeamID = FGenericTeamId::NoTeam;
|
|
if (LastSeenPlayerState != nullptr)
|
|
{
|
|
if (ILyraTeamAgentInterface* PlayerStateTeamInterface = Cast<ILyraTeamAgentInterface>(LastSeenPlayerState))
|
|
{
|
|
OldTeamID = PlayerStateTeamInterface->GetGenericTeamId();
|
|
PlayerStateTeamInterface->GetTeamChangedDelegateChecked().RemoveAll(this);
|
|
}
|
|
}
|
|
|
|
// Bind to the new player state, if any
|
|
FGenericTeamId NewTeamID = FGenericTeamId::NoTeam;
|
|
if (PlayerState != nullptr)
|
|
{
|
|
if (ILyraTeamAgentInterface* PlayerStateTeamInterface = Cast<ILyraTeamAgentInterface>(PlayerState))
|
|
{
|
|
NewTeamID = PlayerStateTeamInterface->GetGenericTeamId();
|
|
PlayerStateTeamInterface->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnPlayerStateChangedTeam);
|
|
}
|
|
}
|
|
|
|
// Broadcast the team change (if it really has)
|
|
ConditionalBroadcastTeamChanged(this, OldTeamID, NewTeamID);
|
|
|
|
LastSeenPlayerState = PlayerState;
|
|
}
|
|
|
|
void ALyraPlayerController::InitPlayerState()
|
|
{
|
|
Super::InitPlayerState();
|
|
BroadcastOnPlayerStateChanged();
|
|
}
|
|
|
|
void ALyraPlayerController::CleanupPlayerState()
|
|
{
|
|
Super::CleanupPlayerState();
|
|
BroadcastOnPlayerStateChanged();
|
|
}
|
|
|
|
void ALyraPlayerController::OnRep_PlayerState()
|
|
{
|
|
Super::OnRep_PlayerState();
|
|
BroadcastOnPlayerStateChanged();
|
|
}
|
|
|
|
void ALyraPlayerController::SetPlayer(UPlayer* InPlayer)
|
|
{
|
|
Super::SetPlayer(InPlayer);
|
|
|
|
if (const ULyraLocalPlayer* LyraLocalPlayer = Cast<ULyraLocalPlayer>(InPlayer))
|
|
{
|
|
ULyraSettingsShared* UserSettings = LyraLocalPlayer->GetSharedSettings();
|
|
UserSettings->OnSettingChanged.AddUObject(this, &ThisClass::OnSettingsChanged);
|
|
|
|
OnSettingsChanged(UserSettings);
|
|
}
|
|
}
|
|
|
|
void ALyraPlayerController::OnSettingsChanged(ULyraSettingsShared* InSettings)
|
|
{
|
|
bForceFeedbackEnabled = InSettings->GetForceFeedbackEnabled();
|
|
}
|
|
|
|
void ALyraPlayerController::AddCheats(bool bForce)
|
|
{
|
|
#if USING_CHEAT_MANAGER
|
|
Super::AddCheats(true);
|
|
#else //#if USING_CHEAT_MANAGER
|
|
Super::AddCheats(bForce);
|
|
#endif // #else //#if USING_CHEAT_MANAGER
|
|
}
|
|
|
|
void ALyraPlayerController::ServerCheat_Implementation(const FString& Msg)
|
|
{
|
|
#if USING_CHEAT_MANAGER
|
|
if (CheatManager)
|
|
{
|
|
UE_LOG(LogLyra, Warning, TEXT("ServerCheat: %s"), *Msg);
|
|
ClientMessage(ConsoleCommand(Msg));
|
|
}
|
|
#endif // #if USING_CHEAT_MANAGER
|
|
}
|
|
|
|
bool ALyraPlayerController::ServerCheat_Validate(const FString& Msg)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ALyraPlayerController::ServerCheatAll_Implementation(const FString& Msg)
|
|
{
|
|
#if USING_CHEAT_MANAGER
|
|
if (CheatManager)
|
|
{
|
|
UE_LOG(LogLyra, Warning, TEXT("ServerCheatAll: %s"), *Msg);
|
|
for (TActorIterator<ALyraPlayerController> It(GetWorld()); It; ++It)
|
|
{
|
|
ALyraPlayerController* LyraPC = (*It);
|
|
if (LyraPC)
|
|
{
|
|
LyraPC->ClientMessage(LyraPC->ConsoleCommand(Msg));
|
|
}
|
|
}
|
|
}
|
|
#endif // #if USING_CHEAT_MANAGER
|
|
}
|
|
|
|
bool ALyraPlayerController::ServerCheatAll_Validate(const FString& Msg)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ALyraPlayerController::PreProcessInput(const float DeltaTime, const bool bGamePaused)
|
|
{
|
|
Super::PreProcessInput(DeltaTime, bGamePaused);
|
|
}
|
|
|
|
void ALyraPlayerController::PostProcessInput(const float DeltaTime, const bool bGamePaused)
|
|
{
|
|
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
|
|
{
|
|
LyraASC->ProcessAbilityInput(DeltaTime, bGamePaused);
|
|
}
|
|
|
|
Super::PostProcessInput(DeltaTime, bGamePaused);
|
|
}
|
|
|
|
void ALyraPlayerController::OnCameraPenetratingTarget()
|
|
{
|
|
bHideViewTargetPawnNextFrame = true;
|
|
}
|
|
|
|
void ALyraPlayerController::OnPossess(APawn* InPawn)
|
|
{
|
|
Super::OnPossess(InPawn);
|
|
|
|
#if WITH_SERVER_CODE && WITH_EDITOR
|
|
if (GIsEditor && (InPawn != nullptr) && (GetPawn() == InPawn))
|
|
{
|
|
for (const FLyraCheatToRun& CheatRow : GetDefault<ULyraDeveloperSettings>()->CheatsToRun)
|
|
{
|
|
if (CheatRow.Phase == ECheatExecutionTime::OnPlayerPawnPossession)
|
|
{
|
|
ConsoleCommand(CheatRow.Cheat, /*bWriteToLog=*/ true);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SetIsAutoRunning(false);
|
|
}
|
|
|
|
void ALyraPlayerController::SetIsAutoRunning(const bool bEnabled)
|
|
{
|
|
const bool bIsAutoRunning = GetIsAutoRunning();
|
|
if (bEnabled != bIsAutoRunning)
|
|
{
|
|
if (!bEnabled)
|
|
{
|
|
OnEndAutoRun();
|
|
}
|
|
else
|
|
{
|
|
OnStartAutoRun();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ALyraPlayerController::GetIsAutoRunning() const
|
|
{
|
|
bool bIsAutoRunning = false;
|
|
if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
|
|
{
|
|
bIsAutoRunning = LyraASC->GetTagCount(FLyraGameplayTags::Get().Status_AutoRunning) > 0;
|
|
}
|
|
return bIsAutoRunning;
|
|
}
|
|
|
|
void ALyraPlayerController::OnStartAutoRun()
|
|
{
|
|
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
|
|
{
|
|
LyraASC->SetLooseGameplayTagCount(FLyraGameplayTags::Get().Status_AutoRunning, 1);
|
|
K2_OnStartAutoRun();
|
|
}
|
|
}
|
|
|
|
void ALyraPlayerController::OnEndAutoRun()
|
|
{
|
|
if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent())
|
|
{
|
|
LyraASC->SetLooseGameplayTagCount(FLyraGameplayTags::Get().Status_AutoRunning, 0);
|
|
K2_OnEndAutoRun();
|
|
}
|
|
}
|
|
|
|
void ALyraPlayerController::UpdateForceFeedback(IInputInterface* InputInterface, const int32 ControllerId)
|
|
{
|
|
if (bForceFeedbackEnabled)
|
|
{
|
|
if (const UCommonInputSubsystem* CommonInputSubsystem = UCommonInputSubsystem::Get(GetLocalPlayer()))
|
|
{
|
|
const ECommonInputType CurrentInputType = CommonInputSubsystem->GetCurrentInputType();
|
|
if (CurrentInputType == ECommonInputType::Gamepad || CurrentInputType == ECommonInputType::Touch)
|
|
{
|
|
InputInterface->SetForceFeedbackChannelValues(ControllerId, ForceFeedbackValues);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
InputInterface->SetForceFeedbackChannelValues(ControllerId, FForceFeedbackValues());
|
|
}
|
|
|
|
void ALyraPlayerController::UpdateHiddenComponents(const FVector& ViewLocation, TSet<FPrimitiveComponentId>& OutHiddenComponents)
|
|
{
|
|
Super::UpdateHiddenComponents(ViewLocation, OutHiddenComponents);
|
|
|
|
if (bHideViewTargetPawnNextFrame)
|
|
{
|
|
AActor* const ViewTargetPawn = PlayerCameraManager ? Cast<AActor>(PlayerCameraManager->GetViewTarget()) : nullptr;
|
|
if (ViewTargetPawn)
|
|
{
|
|
// internal helper func to hide all the components
|
|
auto AddToHiddenComponents = [&OutHiddenComponents](const TInlineComponentArray<UPrimitiveComponent*>& InComponents)
|
|
{
|
|
// add every component and all attached children
|
|
for (UPrimitiveComponent* Comp : InComponents)
|
|
{
|
|
if (Comp->IsRegistered())
|
|
{
|
|
OutHiddenComponents.Add(Comp->ComponentId);
|
|
|
|
for (USceneComponent* AttachedChild : Comp->GetAttachChildren())
|
|
{
|
|
static FName NAME_NoParentAutoHide(TEXT("NoParentAutoHide"));
|
|
UPrimitiveComponent* AttachChildPC = Cast<UPrimitiveComponent>(AttachedChild);
|
|
if (AttachChildPC && AttachChildPC->IsRegistered() && !AttachChildPC->ComponentTags.Contains(NAME_NoParentAutoHide))
|
|
{
|
|
OutHiddenComponents.Add(AttachChildPC->ComponentId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//TODO Solve with an interface. Gather hidden components or something.
|
|
//TODO Hiding isn't awesome, sometimes you want the effect of a fade out over a proximity, needs to bubble up to designers.
|
|
|
|
// hide pawn's components
|
|
TInlineComponentArray<UPrimitiveComponent*> PawnComponents;
|
|
ViewTargetPawn->GetComponents(PawnComponents);
|
|
AddToHiddenComponents(PawnComponents);
|
|
|
|
//// hide weapon too
|
|
//if (ViewTargetPawn->CurrentWeapon)
|
|
//{
|
|
// TInlineComponentArray<UPrimitiveComponent*> WeaponComponents;
|
|
// ViewTargetPawn->CurrentWeapon->GetComponents(WeaponComponents);
|
|
// AddToHiddenComponents(WeaponComponents);
|
|
//}
|
|
}
|
|
|
|
// we consumed it, reset for next frame
|
|
bHideViewTargetPawnNextFrame = false;
|
|
}
|
|
}
|
|
|
|
void ALyraPlayerController::SetGenericTeamId(const FGenericTeamId& NewTeamID)
|
|
{
|
|
UE_LOG(LogLyraTeams, Error, TEXT("You can't set the team ID on a player controller (%s); it's driven by the associated player state"), *GetPathNameSafe(this));
|
|
}
|
|
|
|
FGenericTeamId ALyraPlayerController::GetGenericTeamId() const
|
|
{
|
|
if (const ILyraTeamAgentInterface* PSWithTeamInterface = Cast<ILyraTeamAgentInterface>(PlayerState))
|
|
{
|
|
return PSWithTeamInterface->GetGenericTeamId();
|
|
}
|
|
return FGenericTeamId::NoTeam;
|
|
}
|
|
|
|
FOnLyraTeamIndexChangedDelegate* ALyraPlayerController::GetOnTeamIndexChangedDelegate()
|
|
{
|
|
return &OnTeamChangedDelegate;
|
|
}
|
|
|
|
void ALyraPlayerController::OnUnPossess()
|
|
{
|
|
// Make sure the pawn that is being unpossessed doesn't remain our ASC's avatar actor
|
|
if (APawn* PawnBeingUnpossessed = GetPawn())
|
|
{
|
|
if (UAbilitySystemComponent* ASC = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(PlayerState))
|
|
{
|
|
if (ASC->GetAvatarActor() == PawnBeingUnpossessed)
|
|
{
|
|
ASC->SetAvatarActor(nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
Super::OnUnPossess();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// ALyraReplayPlayerController
|
|
|
|
void ALyraReplayPlayerController::SetPlayer(UPlayer* InPlayer)
|
|
{
|
|
Super::SetPlayer(InPlayer);
|
|
}
|