2023-05-08 15:16:20 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Components/PIENetworkComponent.h"
# if ENABLE_PIE_NETWORK_TEST
2024-07-30 09:27:39 -04:00
2023-05-08 15:16:20 -04:00
# include "LevelEditor.h"
# include "Editor/UnrealEdEngine.h"
# include "Settings/LevelEditorPlaySettings.h"
# include "UnrealEdGlobals.h"
# include "Tests/AutomationEditorCommon.h"
# include "Engine/NetConnection.h"
# include "Engine/NetDriver.h"
# include "GameFramework/GameMode.h"
2023-09-05 13:32:32 -04:00
# include "Modules/ModuleManager.h"
2023-05-08 15:16:20 -04:00
# include "GameMapsSettings.h"
DEFINE_LOG_CATEGORY_STATIC ( LogNetworkTest , Log , All ) ;
FBasePIENetworkComponent : : FBasePIENetworkComponent ( FAutomationTestBase * InTestRunner , FTestCommandBuilder & InCommandBuilder , bool IsInitializing )
: TestRunner ( InTestRunner )
, CommandBuilder ( & InCommandBuilder )
{
if ( IsInitializing )
{
return ;
}
CommandBuilder
2023-11-14 14:46:24 -05:00
- > Do ( TEXT ( " Stop PIE " ) , [ this ] ( ) { StopPie ( ) ; } )
. Then ( TEXT ( " Create New Map " ) , [ this ] ( ) { FAutomationEditorCommonUtils : : CreateNewMap ( ) ; } )
. Then ( TEXT ( " Start PIE " ) , [ this ] ( ) { StartPie ( ) ; } )
2024-07-30 09:27:39 -04:00
. Until ( TEXT ( " Set Worlds " ) , [ this ] ( ) { return SetWorlds ( ) ; } )
. Then ( TEXT ( " Setup Packet Settings " ) , [ this ] ( ) { SetPacketSettings ( ) ; } )
. Then ( TEXT ( " Connect Clients to Server " ) , [ this ] ( ) { ConnectClientsToServer ( ) ; } )
. Until ( TEXT ( " Await Clients Ready " ) , [ this ] ( ) { return AwaitClientsReady ( ) ; } )
2023-05-15 10:54:19 -04:00
. OnTearDown ( TEXT ( " Restore Editor State " ) , [ this ] ( ) { RestoreState ( ) ; } ) ;
2023-05-08 15:16:20 -04:00
}
FBasePIENetworkComponent & FBasePIENetworkComponent : : Then ( TFunction < void ( ) > Action )
{
CommandBuilder - > Then ( Action ) ;
return * this ;
}
FBasePIENetworkComponent & FBasePIENetworkComponent : : Do ( TFunction < void ( ) > Action )
{
CommandBuilder - > Do ( Action ) ;
return * this ;
}
FBasePIENetworkComponent & FBasePIENetworkComponent : : Then ( const TCHAR * Description , TFunction < void ( ) > Action )
{
CommandBuilder - > Then ( Description , Action ) ;
return * this ;
}
FBasePIENetworkComponent & FBasePIENetworkComponent : : Do ( const TCHAR * Description , TFunction < void ( ) > Action )
{
CommandBuilder - > Do ( Description , Action ) ;
return * this ;
}
FBasePIENetworkComponent & FBasePIENetworkComponent : : Until ( TFunction < bool ( ) > Query , FTimespan Timeout )
{
CommandBuilder - > Until ( Query , Timeout ) ;
return * this ;
}
2024-07-30 09:27:39 -04:00
FBasePIENetworkComponent & FBasePIENetworkComponent : : Until ( const TCHAR * Description , TFunction < bool ( ) > Query , FTimespan Timeout )
2023-05-08 15:16:20 -04:00
{
CommandBuilder - > Until ( Description , Query , Timeout ) ;
return * this ;
}
FBasePIENetworkComponent & FBasePIENetworkComponent : : StartWhen ( TFunction < bool ( ) > Query , FTimespan Timeout )
{
CommandBuilder - > StartWhen ( Query , Timeout ) ;
return * this ;
}
2024-07-30 09:27:39 -04:00
FBasePIENetworkComponent & FBasePIENetworkComponent : : StartWhen ( const TCHAR * Description , TFunction < bool ( ) > Query , FTimespan Timeout )
2023-05-08 15:16:20 -04:00
{
CommandBuilder - > StartWhen ( Description , Query , Timeout ) ;
return * this ;
}
2023-11-14 14:46:24 -05:00
void FBasePIENetworkComponent : : StopPie ( )
2023-05-08 15:16:20 -04:00
{
if ( ServerState = = nullptr )
{
TestRunner - > AddError ( TEXT ( " Failed to initialize Network Component " ) ) ;
return ;
}
GUnrealEd - > RequestEndPlayMap ( ) ;
2023-11-14 14:46:24 -05:00
}
2023-05-08 15:16:20 -04:00
2023-11-14 14:46:24 -05:00
void FBasePIENetworkComponent : : StartPie ( )
{
2023-05-08 15:16:20 -04:00
ULevelEditorPlaySettings * PlaySettings = NewObject < ULevelEditorPlaySettings > ( ) ;
if ( ServerState - > bIsDedicatedServer )
{
PlaySettings - > SetPlayNetMode ( EPlayNetMode : : PIE_Client ) ;
PlaySettings - > SetPlayNumberOfClients ( ServerState - > ClientCount ) ;
}
else
{
PlaySettings - > SetPlayNetMode ( EPlayNetMode : : PIE_ListenServer ) ;
PlaySettings - > SetPlayNumberOfClients ( ServerState - > ClientCount + 1 ) ; // The listen server counts as a client, so we need to add one more to get a real client as well
}
PlaySettings - > bLaunchSeparateServer = ServerState - > bIsDedicatedServer ;
PlaySettings - > GameGetsMouseControl = false ;
PlaySettings - > SetRunUnderOneProcess ( true ) ;
FLevelEditorModule & LevelEditorModule = FModuleManager : : Get ( ) . GetModuleChecked < FLevelEditorModule > ( TEXT ( " LevelEditor " ) ) ;
FRequestPlaySessionParams SessionParams ;
SessionParams . WorldType = EPlaySessionWorldType : : PlayInEditor ;
SessionParams . DestinationSlateViewport = LevelEditorModule . GetFirstActiveViewport ( ) ;
SessionParams . EditorPlaySettings = PlaySettings ;
2023-06-15 13:34:39 -04:00
if ( GameMode ! = nullptr )
{
SessionParams . GameModeOverride = GameMode ;
}
else
{
SessionParams . GameModeOverride = AGameModeBase : : StaticClass ( ) ;
}
2023-05-08 15:16:20 -04:00
GUnrealEd - > RequestPlaySession ( SessionParams ) ;
GUnrealEd - > StartQueuedPlaySessionRequest ( ) ;
}
2024-07-30 09:27:39 -04:00
bool FBasePIENetworkComponent : : SetWorlds ( )
2023-05-08 15:16:20 -04:00
{
2024-07-30 09:27:39 -04:00
auto IsValidContext = [ ] ( const FWorldContext & Context ) - > bool {
return Context . WorldType = = EWorldType : : PIE & &
IsValid ( Context . World ( ) ) & &
IsValid ( Context . World ( ) - > GetNetDriver ( ) ) ;
} ;
2023-05-08 15:16:20 -04:00
2024-07-30 09:27:39 -04:00
auto IsValidServerWorld = [ this ] ( UWorld * World ) - > bool {
const bool bIsDedicated = ServerState - > bIsDedicatedServer ;
const bool bExpectsDedicated = World - > GetNetMode ( ) = = NM_DedicatedServer ;
return bExpectsDedicated = = bIsDedicated ;
} ;
auto IsClientWorldClaimed = [ this ] ( UWorld * World ) - > bool {
for ( const auto & State : ClientStates )
{
if ( IsValid ( State - > World ) & & State - > World = = World )
{
return true ;
}
}
return false ;
} ;
int32 ClientWorldCount = 0 ;
for ( const auto & WorldContext : GEngine - > GetWorldContexts ( ) )
2023-05-08 15:16:20 -04:00
{
2024-07-30 09:27:39 -04:00
if ( ! IsValidContext ( WorldContext ) )
2023-05-08 15:16:20 -04:00
{
continue ;
}
2024-07-30 09:27:39 -04:00
2023-05-08 15:16:20 -04:00
UWorld * World = WorldContext . World ( ) ;
if ( World - > GetNetDriver ( ) - > IsServer ( ) )
{
2024-07-30 09:27:39 -04:00
if ( ServerState - > World = = nullptr )
2023-05-08 15:16:20 -04:00
{
2024-07-30 09:27:39 -04:00
if ( ! IsValidServerWorld ( World ) )
{
TestRunner - > AddError ( TEXT ( " Failed to set up dedicated server. Does your game's editor module override the PIE settings? " ) ) ;
return true ;
}
2023-05-08 15:16:20 -04:00
2024-07-30 09:27:39 -04:00
ServerState - > World = World ;
2023-05-08 15:16:20 -04:00
}
}
else
{
2024-07-30 09:27:39 -04:00
if ( ! IsClientWorldClaimed ( World ) )
{
bool bClaimed = false ;
for ( const auto & State : ClientStates )
{
if ( State - > World = = nullptr )
{
State - > World = World ;
bClaimed = true ;
break ;
}
}
if ( ! bClaimed )
{
TestRunner - > AddError ( TEXT ( " Failed to claim client world. Network component was not able to be initialized. " ) ) ;
return true ;
}
2023-05-08 15:16:20 -04:00
2024-07-30 09:27:39 -04:00
}
ClientWorldCount + + ;
2023-05-08 15:16:20 -04:00
}
}
2024-07-30 09:27:39 -04:00
return IsValid ( ServerState - > World ) & & ClientWorldCount = = ServerState - > ClientCount ;
2023-05-08 15:16:20 -04:00
}
2024-07-30 09:27:39 -04:00
void FBasePIENetworkComponent : : SetPacketSettings ( ) const
2023-05-08 15:16:20 -04:00
{
2024-07-30 09:27:39 -04:00
if ( PacketSimulationSettings )
2023-05-08 15:16:20 -04:00
{
2024-07-30 09:27:39 -04:00
ServerState - > World - > GetNetDriver ( ) - > SetPacketSimulationSettings ( * PacketSimulationSettings ) ;
for ( const auto & ClientState : ClientStates )
{
ClientState - > World - > GetNetDriver ( ) - > SetPacketSimulationSettings ( * PacketSimulationSettings ) ;
}
}
}
void FBasePIENetworkComponent : : ConnectClientsToServer ( )
{
auto & ServerConnections = ServerState - > World - > GetNetDriver ( ) - > ClientConnections ;
for ( int32 ClientIndex = ServerState - > ClientConnections . Num ( ) ; ClientIndex < ServerState - > ClientCount ; ClientIndex + + )
{
const int32 ClientLocalPort = ClientStates [ ClientIndex ] - > World - > GetNetDriver ( ) - > GetLocalAddr ( ) - > GetPort ( ) ;
TObjectPtr < UNetConnection > * ServerConnection = ServerConnections . FindByPredicate ( [ ClientLocalPort ] ( UNetConnection * ClientConnection ) {
return ClientConnection - > GetRemoteAddr ( ) - > GetPort ( ) = = ClientLocalPort ;
} ) ;
if ( ServerConnection = = nullptr )
{
TestRunner - > AddError ( TEXT ( " Failed to find connection to server for client. Network component was not able to be initialized. " ) ) ;
return ;
}
ServerState - > ClientConnections [ ClientIndex ] = * ServerConnection ;
}
}
bool FBasePIENetworkComponent : : AwaitClientsReady ( ) const
{
if ( ServerState = = nullptr | | ! IsValid ( ServerState - > World ) )
{
TestRunner - > AddError ( TEXT ( " Failed to get server state. Network component was not able to be initialized. " ) ) ;
return true ;
2023-05-08 15:16:20 -04:00
}
if ( ServerState - > World - > GetNetDriver ( ) - > ClientConnections . Num ( ) ! = ServerState - > ClientCount )
{
return false ;
}
2024-07-30 09:27:39 -04:00
for ( const UNetConnection * ClientConnection : ServerState - > World - > GetNetDriver ( ) - > ClientConnections )
2023-05-08 15:16:20 -04:00
{
if ( ClientConnection - > ViewTarget = = nullptr )
{
return false ;
}
}
return true ;
}
2023-05-15 10:54:19 -04:00
void FBasePIENetworkComponent : : RestoreState ( )
{
if ( ServerState ! = nullptr )
{
GUnrealEd - > RequestEndPlayMap ( ) ;
StateRestorer . Restore ( ) ;
}
}
2024-07-30 09:27:39 -04:00
# endif // ENABLE_PIE_NETWORK_TEST