2024-04-12 13:30:01 -07:00
# include " GasaPlayerController.h "
2024-04-21 15:56:57 -07:00
# include "GasaPlayerController_Inlines.h"
2024-04-23 15:54:17 -07:00
# include "Networking/GasaNetLibrary_Inlines.h"
2024-04-12 13:30:01 -07:00
2024-04-13 08:56:19 -07:00
# include "AbilitySystemComponent.h"
2024-04-12 13:30:01 -07:00
# include "Engine/LocalPlayer.h"
2024-04-12 14:53:47 -07:00
# include "EnhancedInputComponent.h"
2024-04-12 13:30:01 -07:00
# include "EnhancedInputSubsystems.h"
2024-04-12 23:31:49 -07:00
# include "Characters/GasaCharacter.h"
2024-04-23 15:54:17 -07:00
# include "Characters/PlayerCharacter.h"
2024-04-12 23:31:49 -07:00
# include "Components/CapsuleComponent.h"
2024-04-23 15:54:17 -07:00
# include "Interfaces/NetworkPredictionInterface.h"
2024-04-12 23:31:49 -07:00
# include "Kismet/KismetSystemLibrary.h"
2024-04-23 15:54:17 -07:00
# include "Net/UnrealNetwork.h"
# include "GameFramework/PawnMovementComponent.h"
# include "GasaDevOptions.h"
# include "GasaGameInstance.h"
# include "GasaGameState.h"
# include "GasaPlayerState.h"
# include "Actors/CameraMount.h"
# include "UI/GasaHUD.h"
# include "UI/WidgetController.h"
2024-04-21 06:51:51 -07:00
using namespace Gasa ;
2024-04-12 13:30:01 -07:00
AGasaPlayerController : : AGasaPlayerController ( )
{
2024-04-12 23:31:49 -07:00
PrimaryActorTick . bCanEverTick = true ;
bAutoManageActiveCameraTarget = false ;
// Replication
2024-04-12 13:30:01 -07:00
bReplicates = true ;
}
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : OnSeamlessTravelStart ( )
{
}
# pragma region GameFramework
void AGasaPlayerController : : Client_CheckIfOwnerReady ( )
{
if ( IsServer ( ) )
return ;
UGasaGameInstance * GI = GetGameInstance < UGasaGameInstance > ( ) ;
if ( ! GI - > IsGameFrameworkInitialized ( ) | | PlayerState = = NULL | | ! IsValid ( GetPawn ( ) ) )
return ;
NetOwner_OnReady ( ) ;
}
void AGasaPlayerController : : NetOwner_OnReady ( )
{
NetLog ( " Net Owner of controller is ready to play. " ) ;
if ( ! IsNetOwner ( ) | | bNetOwnerReady )
return ;
BP_NetOwner_OnReady ( ) ;
Event_NetOwner_OnReady . Broadcast ( this ) ;
bNetOwnerReady = true ;
AGasaGameState * GS = Cast < AGasaGameState > ( GetWorld ( ) - > GetGameState ( ) ) ;
if ( GS )
GS - > NotifyPlayerPawnReady ( GetPawn ( ) ) ;
if ( IsClient ( ) )
ServerRPC_R_NotifyOwningClientReady ( ) ;
AGasaPlayerState * PS = GetPlayerState ( ) ;
APlayerCharacter * PlayerChar = GetPawn < APlayerCharacter > ( ) ;
{
PlayerChar - > AbilitySystem = PS - > AbilitySystem ;
PlayerChar - > Attributes = PS - > Attributes ;
PlayerChar - > AbilitySystem - > InitAbilityActorInfo ( PS , this ) ;
Cam - > AttachToActor ( PlayerChar , FAttachmentTransformRules : : KeepRelativeTransform ) ;
}
}
void AGasaPlayerController : : OnGameFrameworkInitialized ( )
{
NetLog ( " Received game framework initialization. " ) ;
if ( IsNetOwner ( ) )
{
Server_SetNetOwner_GameFrameworkInitialized ( ) ;
Client_CheckIfOwnerReady ( ) ;
}
AGasaGameState * GS = GetGameState ( this ) ;
NullGuard_DEV ( GS , Log , " OnGameFrameworkInitialized: GS is null " ) ;
GS - > Event_OnSeamlessTravelStart . AddDynamic ( this , & ThisClass : : OnSeamlessTravelStart ) ;
BP_OnGameFrameworkInitialized ( ) ;
}
void AGasaPlayerController : : OnPawnReady ( )
{
NetLog ( " Player is ready. " ) ;
2024-04-21 15:56:57 -07:00
2024-04-23 15:54:17 -07:00
// Originally: Super::OnPossess(PawnToPossess);
{
ChangeState ( NAME_Playing ) ;
if ( bAutoManageActiveCameraTarget )
{
AutoManageActiveCameraTarget ( GetPawn ( ) ) ;
ResetCameraMode ( ) ;
}
}
// Override this and add your own conditions...
BP_OnPawnReady ( ) ;
if ( IsServer ( ) & & IsNetOwner ( ) )
{
// The server host doesn't have to wait for the player state to replicate.
NetOwner_OnReady ( ) ;
}
}
void AGasaPlayerController : : Server_SetupOnPawnReadyBinds ( APawn * PawnToBindTo )
{
if ( IsClient ( ) )
return ;
#if 0
if ( PawnToBindTo - > IsA ( AGasaPawn : : StaticClass ( ) ) )
{
Cast < AGasaPawn > ( PawnToBindTo ) - > Event_OnPawnReady . AddUniqueDynamic ( this , & ThisClass : : OnPawnReady ) ;
}
else
# endif
if ( PawnToBindTo - > IsA ( AGasaCharacter : : StaticClass ( ) ) )
{
Cast < AGasaCharacter > ( PawnToBindTo ) - > Event_OnPawnReady . AddUniqueDynamic ( this , & ThisClass : : OnPawnReady ) ;
}
}
void AGasaPlayerController : : Server_SetNetOwner_GameFrameworkInitialized ( )
{
if ( IsClient ( ) )
{
ServerRPC_R_SetNetOwner_GameFrameworkInitialized ( ) ;
return ;
}
bNetOwner_GameFrameworkInitialized = true ;
if ( Event_NetOwner_OnGameFrameworkInitialized . IsBound ( ) )
{
Event_NetOwner_OnGameFrameworkInitialized . Broadcast ( this ) ;
Event_NetOwner_OnGameFrameworkInitialized . Clear ( ) ;
}
}
void AGasaPlayerController : : ServerRPC_R_NotifyOwningClientReady_Implementation ( )
{
NetLog ( " Net Owner Ready: Notified via RPC. " ) ;
BP_NetOwner_OnReady ( ) ;
bNetOwnerReady = true ;
Event_NetOwner_OnReady . Broadcast ( this ) ;
Event_NetOwner_OnReady . Clear ( ) ;
AGasaGameState * GS = GetGameState ( this ) ;
if ( GS )
GS - > NotifyPlayerPawnReady ( GetPawn ( ) ) ;
}
void AGasaPlayerController : : ServerRPC_R_SetNetOwner_GameFrameworkInitialized_Implementation ( )
{
Server_SetNetOwner_GameFrameworkInitialized ( ) ;
}
# pragma endregion GameFramework
2024-04-21 15:56:57 -07:00
2024-04-21 06:51:51 -07:00
# pragma region Input
2024-04-12 14:53:47 -07:00
void AGasaPlayerController : : Move ( FInputActionValue const & ActionValue )
{
2024-04-12 16:55:34 -07:00
APawn * pawn = GetPawn < APawn > ( ) ;
if ( pawn = = nullptr )
return ;
2024-04-21 06:51:51 -07:00
2024-04-12 16:55:34 -07:00
// Note(Ed): I did the follow optimization for practice, they are completely unnecessary for this context.
2024-04-12 14:53:47 -07:00
#if 0
FVector2D AxisV = ActionValue . Get < FVector2D > ( ) ;
FRotator ControlRot = GetControlRotation ( ) ;
FRotator YawRot = FRotator ( 0.f , ControlRot . Yaw , 0.f ) ;
FVector FwdDir = FRotationMatrix ( YawRot ) . GetUnitAxis ( EAxis : : X ) ;
FVector RightDir = FRotationMatrix ( YawRot ) . GetUnitAxis ( EAxis : : Y ) ;
2024-04-12 16:55:34 -07:00
PPawn - > AddMovementInput ( FwdDir , AxisV . Y ) ;
PPawn - > AddMovementInput ( RightDir , AxisV . X ) ;
2024-04-12 14:53:47 -07:00
# else
FVector2f AxisV = FVector2f ( ActionValue . Get < FVector2D > ( ) ) ;
2024-04-12 16:55:34 -07:00
FQuat4f // FQuat isomorphic to FRotor (Hypothetical Def)
ControlRotor = FQuat4f ( GetControlRotation ( ) . Quaternion ( ) ) ;
2024-04-12 14:53:47 -07:00
// ControlRotor.Normalize(); // The Quaternion should always be a versor with UE...
2024-04-12 16:55:34 -07:00
FVector3f HorizontalForward = ControlRotor . RotateVector ( FVector3f : : ForwardVector ) ;
// HorizontalForward.Normalize();
// TODO(Ed): Profile which is faster just to know... (atan2 vs FindBetweenVectors)
// HorizontalForward.Z = 0;
// FQuat4f
// YawRotor = FQuat4f::FindBetweenVectors(FVector3f::ForwardVector, HorizontalForward);
2024-04-12 14:53:47 -07:00
// YawRotor.Normalize(); // The Quaternion should always be a versor with UE...
2024-04-12 16:55:34 -07:00
// Need only one axis of rotation so this might be a possible optimization
float YawAngle = FMath : : Atan2 ( HorizontalForward . Y , HorizontalForward . X ) ;
FQuat4f YawRotor = FQuat4f ( FVector3f : : UpVector , YawAngle ) ;
2024-04-12 14:53:47 -07:00
2024-04-12 16:55:34 -07:00
// Rotate the combined input by the yaw rotor to get the movement direction
FVector MoveDir = ( FVector ) YawRotor . RotateVector ( FVector3f ( AxisV . Y , AxisV . X , 0.f ) ) ;
pawn - > AddMovementInput ( MoveDir ) ;
2024-04-12 14:53:47 -07:00
# endif
}
2024-04-21 06:51:51 -07:00
# pragma endregion Input
# pragma region PlayerController
2024-04-23 15:54:17 -07:00
bool AGasaPlayerController : : CanRestartPlayer ( )
2024-04-21 06:51:51 -07:00
{
2024-04-23 15:54:17 -07:00
bool BaseCheck =
PlayerState & &
! PlayerState - > IsOnlyASpectator ( ) & &
HasClientLoadedCurrentWorld ( ) & &
PendingSwapConnection = = NULL
;
return BaseCheck & & bNetOwner_GameFrameworkInitialized ;
2024-04-21 06:51:51 -07:00
}
2024-04-12 14:53:47 -07:00
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : ClientSetHUD_Implementation ( TSubclassOf < AHUD > NewHUDClass )
2024-04-12 23:31:49 -07:00
{
2024-04-23 15:54:17 -07:00
Super : : ClientSetHUD_Implementation ( NewHUDClass ) ;
AGasaPlayerState * PS = GetPlayerState ( ) ;
AGasaHUD * HUD = GetHUD < AGasaHUD > ( ) ;
FWidgetControllerData Data = { this , PS , PS - > AbilitySystem , PS - > Attributes } ;
HUD - > InitHostWidget ( & Data ) ;
}
2024-04-12 23:31:49 -07:00
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : ClientUpdateLevelStreamingStatus_Implementation ( FName PackageName , bool bNewShouldBeLoaded , bool bNewShouldBeVisible ,
bool bNewShouldBlockOnLoad , int32 LODIndex , FNetLevelVisibilityTransactionId TransactionId , bool bNewShouldBlockOnUnload )
{
Super : : ClientUpdateLevelStreamingStatus_Implementation ( PackageName , bNewShouldBeLoaded , bNewShouldBeVisible , bNewShouldBlockOnLoad , LODIndex ,
TransactionId , bNewShouldBlockOnUnload ) ;
NetLog ( " ClientUpdateLevelStreamingStatus " ) ;
NetLog ( FString ( " PackageName : " ) + PackageName . ToString ( ) ) ;
NetLog ( FString ( " NewShouldBeLoaded : " ) + FString ( bNewShouldBeLoaded ? " true " : " false " ) ) ;
NetLog ( FString ( " NewShouldBeVisible : " ) + FString ( bNewShouldBeVisible ? " true " : " false " ) ) ;
NetLog ( FString ( " bNewShouldBlockOnLoad : " ) + FString ( bNewShouldBlockOnLoad ? " true " : " false " ) ) ;
NetLog ( FString ( " bNewShouldBlockOnUnload: " ) + FString ( bNewShouldBlockOnUnload ? " true " : " false " ) ) ;
NetLog ( FString ( " LODIndex : " ) + FString : : FromInt ( LODIndex ) ) ;
}
2024-04-13 08:56:19 -07:00
2024-04-23 15:54:17 -07:00
// TODO(Ed): We need to setup Net Slime...
void AGasaPlayerController : : OnPossess ( APawn * PawnPossesed )
{
// Super::OnPossess(PawnPossesed);
2024-04-13 08:56:19 -07:00
{
2024-04-23 15:54:17 -07:00
if ( PawnPossesed & & ( PlayerState = = NULL | | ! PlayerState - > IsOnlyASpectator ( ) ) )
{
// ====================================================================Originally: Super::OnPossess(PawnToPossess);
const bool bNewPawn = ( GetPawn ( ) ! = PawnPossesed ) ;
if ( GetPawn ( ) & & bNewPawn )
UnPossess ( ) ;
if ( PawnPossesed - > Controller ! = NULL )
PawnPossesed - > Controller - > UnPossess ( ) ;
PawnPossesed - > PossessedBy ( this ) ;
// update rotation to match possessed pawn's rotation
SetControlRotation ( PawnPossesed - > GetActorRotation ( ) ) ;
SetPawn ( PawnPossesed ) ;
check ( GetPawn ( ) ! = NULL ) ;
if ( GetPawn ( ) & & GetPawn ( ) - > PrimaryActorTick . bStartWithTickEnabled )
GetPawn ( ) - > SetActorTickEnabled ( true ) ;
INetworkPredictionInterface * NetworkPredictionInterface = GetPawn ( )
? Cast < INetworkPredictionInterface > ( GetPawn ( ) - > GetMovementComponent ( ) )
: nullptr ;
if ( NetworkPredictionInterface )
NetworkPredictionInterface - > ResetPredictionData_Server ( ) ;
AcknowledgedPawn = NULL ;
// Local PCs will have the Restart() triggered right away in ClientRestart (via PawnClientRestart()), but the server should call Restart() locally for remote PCs.
// We're really just trying to avoid calling Restart() multiple times.
if ( ! IsLocalPlayerController ( ) )
GetPawn ( ) - > Restart ( ) ;
ClientRestart ( GetPawn ( ) ) ;
// Moved to: void AGasaPlayerController::OnPawnReady
#if 0
ChangeState ( NAME_Playing ) ;
if ( bAutoManageActiveCameraTarget )
{
AutoManageActiveCameraTarget ( GetPawn ( ) ) ;
ResetCameraMode ( ) ;
}
# endif
//==========================================================End of=================== Originally: Super::OnPossess(PawnToPossess);
NetLog ( " OnPossess " ) ;
Server_SetupOnPawnReadyBinds ( PawnPossesed ) ;
Event_OnPawnPossessed . Broadcast ( ) ;
}
2024-04-13 08:56:19 -07:00
}
2024-04-12 23:31:49 -07:00
}
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : OnRep_Pawn ( )
{
Super : : OnRep_Pawn ( ) ;
NetLog ( " OnRep_Pawn " ) ;
Client_CheckIfOwnerReady ( ) ;
}
2024-04-12 23:31:49 -07:00
void AGasaPlayerController : : OnUnPossess ( )
{
Super : : OnUnPossess ( ) ;
}
2024-04-12 19:05:09 -07:00
void AGasaPlayerController : : PlayerTick ( float DeltaTime )
{
Super : : PlayerTick ( DeltaTime ) ;
// Cursor Trace
for ( int32 do_once = 0 ; do_once ! = 1 ; + + do_once )
{
FHitResult CursorHit ;
GetHitResultUnderCursor ( ECC_Pawn , false , CursorHit ) ;
if ( ! CursorHit . bBlockingHit )
break ;
HoverPrev = HoverCurr ;
HoverCurr = Cast < AGasaCharacter > ( CursorHit . GetActor ( ) ) ;
if ( HoverPrev = = nullptr )
{
// We didn't have a prev to de-highlight so we just need to highlight newly detected character.
if ( HoverCurr )
HoverCurr - > Highlight ( ) ;
// No matter what we need to not go to the next case as there is no previous.
break ;
}
//else Previous is valid...
// We are no longer hovering the previous with no new character, we just need to de-highlight previous.
if ( HoverCurr = = nullptr )
HoverPrev - > Dehighlight ( ) ;
// We had a prev and curr change between frames. They both don't match; we need to switch highlighting.
else if ( HoverPrev ! = HoverCurr )
{
HoverPrev - > Dehighlight ( ) ;
HoverCurr - > Highlight ( ) ;
}
}
}
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : PostSeamlessTravel ( )
{
Super : : PostSeamlessTravel ( ) ;
}
2024-04-12 14:53:47 -07:00
void AGasaPlayerController : : SetupInputComponent ( )
{
Super : : SetupInputComponent ( ) ;
UEnhancedInputComponent *
EIC = CastChecked < UEnhancedInputComponent > ( InputComponent ) ;
{
EIC - > BindAction ( IA_Move , ETriggerEvent : : Triggered , this , & ThisClass : : Move ) ;
}
}
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : SpawnDefaultHUD ( )
{
Super : : SpawnDefaultHUD ( ) ;
}
2024-04-12 14:53:47 -07:00
# pragma endregion PlayerController
# pragma region Actor
2024-04-12 13:30:01 -07:00
void AGasaPlayerController : : BeginPlay ( )
{
Super : : BeginPlay ( ) ;
2024-04-23 15:54:17 -07:00
NetLog ( " BeginPlay " ) ;
UGasaGameInstance * GI = GetGameInstance < UGasaGameInstance > ( ) ;
GI - > Event_OnGameFrameworkInitialized . AddUniqueDynamic ( this , & AGasaPlayerController : : OnGameFrameworkInitialized ) ;
GI - > NotifyGameFrameworkClassReady ( EGameFrameworkClassFlag : : PlayerController ) ;
2024-04-12 13:30:01 -07:00
2024-04-22 22:10:02 -07:00
if ( IsLocalController ( ) )
2024-04-12 13:30:01 -07:00
{
2024-04-22 22:10:02 -07:00
check ( IMC ) ;
UEnhancedInputLocalPlayerSubsystem *
EILP_Subsystem = ULocalPlayer : : GetSubsystem < UEnhancedInputLocalPlayerSubsystem > ( GetLocalPlayer ( ) ) ;
check ( EILP_Subsystem ) ;
EILP_Subsystem - > AddMappingContext ( IMC , 0 ) ;
{
bShowMouseCursor = true ;
DefaultMouseCursor = EMouseCursor : : Default ;
FInputModeGameAndUI MouseMode ;
MouseMode . SetLockMouseToViewportBehavior ( EMouseLockMode : : DoNotLock ) ;
MouseMode . SetHideCursorDuringCapture ( false ) ;
SetInputMode ( MouseMode ) ;
}
2024-04-12 13:30:01 -07:00
}
}
2024-04-12 23:31:49 -07:00
void AGasaPlayerController : : PostInitializeComponents ( )
{
Super : : PostInitializeComponents ( ) ;
2024-04-21 06:51:51 -07:00
Cam = GetWorld ( ) - > SpawnActor < ACameraMount > ( GetDevOptions ( ) - > Template_PlayerCamera . Get ( ) , FActorSpawnParameters ( ) ) ;
2024-04-12 23:31:49 -07:00
SetViewTarget ( Cam ) ;
}
void AGasaPlayerController : : Tick ( float DeltaSeconds )
{
Super : : Tick ( DeltaSeconds ) ;
#if 0
switch ( HighlightState )
{
case EHighlight : : Disabled :
break ;
case EHighlight : : Enabled :
{
UCapsuleComponent * Capsule = GetCapsuleComponent ( ) ;
UKismetSystemLibrary : : DrawDebugCapsule ( this
, Capsule - > GetComponentLocation ( )
, Capsule - > GetScaledCapsuleHalfHeight ( )
, Capsule - > GetScaledCapsuleRadius ( )
, Capsule - > GetComponentRotation ( )
, HighlightColor
, 0.f
, 1.f
) ;
}
break ;
}
# endif
}
2024-04-23 15:54:17 -07:00
void AGasaPlayerController : : GetLifetimeReplicatedProps ( TArray < FLifetimeProperty > & OutLifetimeProps ) const
{
Super : : GetLifetimeReplicatedProps ( OutLifetimeProps ) ;
DOREPLIFETIME ( AGasaPlayerController , bNetOwner_GameFrameworkInitialized ) ;
}
2024-04-12 14:53:47 -07:00
# pragma endregion Actor