// 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(); AActor* ActorToPilot = LevelEditorSubsystem->GetPilotLevelActor(); if (Cast(ActorToPilot)) return; for (ALyraCharacter* LyraCharacter : TActorRange(GetWorld())) { if(Cast(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(PlayerState, ECastCheckedType::NullAllowed); } ULyraAbilitySystemComponent* ALyraPlayerController::GetLyraAbilitySystemComponent() const { const ALyraPlayerState* LyraPS = GetLyraPlayerState(); return (LyraPS ? LyraPS->GetLyraAbilitySystemComponent() : nullptr); } ALyraHUD* ALyraPlayerController::GetLyraHUD() const { return CastChecked(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(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(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(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 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()->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& OutHiddenComponents) { Super::UpdateHiddenComponents(ViewLocation, OutHiddenComponents); if (bHideViewTargetPawnNextFrame) { AActor* const ViewTargetPawn = PlayerCameraManager ? Cast(PlayerCameraManager->GetViewTarget()) : nullptr; if (ViewTargetPawn) { // internal helper func to hide all the components auto AddToHiddenComponents = [&OutHiddenComponents](const TInlineComponentArray& 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(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 PawnComponents; ViewTargetPawn->GetComponents(PawnComponents); AddToHiddenComponents(PawnComponents); //// hide weapon too //if (ViewTargetPawn->CurrentWeapon) //{ // TInlineComponentArray 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(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); }