
- 클라이언트 접속 실패 로그
LogABNetwork: [SERVER] AABGameMode::PreLogin Begin LogABNetwork: [SERVER] AABGameMode::PreLogin End // 접속에 실패하여 STANDALONE으로 진행 LogABNetwork: [STANDALONE] AABGameMode::Login Begin LogABNetwork: [STANDALONE] AABGameMode::Login End LogABNetwork: [STANDALONE] AABGameMode::PostLogin Begin LogABNetwork: [STANDALONE] AABGameMode::PostLogin End LogABNetwork: [STANDALONE] AABGameMode::StartPlay Begin LogABNetwork: [STANDALONE] AABGameState::HandleBeginPlay Begin LogABNetwork: [STANDALONE] AABPlayerController::BeginPlay Begin LogABNetwork: [STANDALONE] AABPlayerController::BeginPlay End LogABNetwork: [STANDALONE] AABGameState::HandleBeginPlay End LogABNetwork: [STANDALONE] AABGameMode::StartPlay End
- 클라이언트 컨트롤러 초기화 로그
LogABNetwork: [SERVER] AABGameMode::PreLogin Begin LogABNetwork: [SERVER] AABGameMode::PreLogin End LogABNetwork: [SERVER] AABGameMode::Login Begin LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_1 LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents End LogABNetwork: [SERVER] AABPlayerController::BeginPlay Begin LogABNetwork: [SERVER] AABPlayerController::BeginPlay End LogABNetwork: [SERVER] AABGameMode::Login End LogABNetwork: [SERVER] AABGameMode::PostLogin Begin LogABNetwork: [SERVER] AABGameMode::PostLogin End LogABNetwork: [CLIENT1] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT1] AABPlayerController::PostInitializeComponents End LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit End // PostNetInit() 호출 후 BeginPlay() 호출되는 것 확인 LogABNetwork: [CLIENT1] AABGameState::OnRep_ReplicatedHasBegunPlay Begin LogABNetwork: [CLIENT1] AABPlayerController::BeginPlay Begin LogABNetwork: [CLIENT1] AABPlayerController::BeginPlay End LogABNetwork: [CLIENT1] AABGameState::OnRep_ReplicatedHasBegunPlay End

현재 월드에 넷드라이버가 있으면 클라이언트-서버, 아니면 스탠드얼론으로 판단함
서버는 UWorld::Listen() 함수를 호출해 넷드라이버를 생성함으로 네트워크 기능을 시작
// World.cpp
ENetMode UWorld::InternalGetNetMode() const
{
if (NetDriver != nullptr)
{
const bool bIsClientOnly = IsRunningClientOnly();
return bIsClientOnly ? NM_Client : NetDriver->GetNetMode();
}
// Use replay driver's net mode if we're in playback or ticking recording
if (DemoNetDriver && (DemoNetDriver->IsPlaying() || (DemoNetDriver->IsRecording() && DemoNetDriver->IsInTick())))
{
return DemoNetDriver->GetNetMode();
}
ENetMode URLNetMode = AttemptDeriveFromURL();
#if WITH_EDITOR
if (WorldType == EWorldType::PIE && (URLNetMode == NM_Standalone || PlayInEditorNetMode == NM_DedicatedServer))
{
// If we're early in startup before the net driver exists and there is no URL override
// or this is a dedicated server, use the mode we were first created with
// This is required for dedicated server/listen worlds so it is correct for InitWorld
return PlayInEditorNetMode;
}
#endif
return URLNetMode;
}
// NetDriver.cpp
ENetMode UNetDriver::GetNetMode() const
{
// Special case for PIE - forcing dedicated server behavior
#if WITH_EDITOR
if (World && World->WorldType == EWorldType::PIE && IsServer())
{
//@todo: world context won't be valid during seamless travel CopyWorldData
FWorldContext* WorldContext = GEngine->GetWorldContextFromWorld(World);
if (WorldContext && WorldContext->RunAsDedicated)
{
return NM_DedicatedServer;
}
}
#endif
// Normal
return (IsServer() ? (GIsClient ? NM_ListenServer : NM_DedicatedServer) : NM_Client);
}
bool UWorld::Listen( FURL& InURL )
{
#if WITH_SERVER_CODE
LLM_SCOPE(ELLMTag::Networking);
if( NetDriver )
{
GEngine->BroadcastNetworkFailure(this, NetDriver, ENetworkFailure::NetDriverAlreadyExists);
return false;
}
// Create net driver.
if (GEngine->CreateNamedNetDriver(this, NAME_GameNetDriver, NAME_GameNetDriver))
{
NetDriver = GEngine->FindNamedNetDriver(this, NAME_GameNetDriver);
NetDriver->SetWorld(this);
FLevelCollection* const SourceCollection = FindCollectionByType(ELevelCollectionType::DynamicSourceLevels);
if (SourceCollection)
{
SourceCollection->SetNetDriver(NetDriver);
}
FLevelCollection* const StaticCollection = FindCollectionByType(ELevelCollectionType::StaticLevels);
if (StaticCollection)
{
StaticCollection->SetNetDriver(NetDriver);
}
}
...
#endif // WITH_SERVER_CODE
}
넷드라이버는 다수의 커넷견을 관리하고 있으며, 서버와 클라이언트에 따라 다르게 동작함
클라이언트에서 넷드라이버는 항상 하나의 서버 커넥션을 가지며,
서버에서 넷드라이버는 다수의 클라이언트 커넥션을 가짐
bool UNetDriver::IsServer() const
{
// Client connections ALWAYS set the server connection object in InitConnect()
// @todo ONLINE improve this with a bool
return ServerConnection == NULL;
}
- 서버 생성 로그
LogABNetwork: [SERVER] AABGameMode::Login Begin LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_0 LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents End LogABNetwork: [SERVER] AABGameMode::Login End LogABNetwork: [SERVER] AABGameMode::PostLogin Begin LogABNetwork: [SERVER] AABGameMode::PostLogin No NetDriver // 자기 자신은 아직 넷드라이버가 생성되지 않은 상태에서 로그인 LogABNetwork: [SERVER] AABGameMode::PostLogin End
- 클라이언트 접속 로그
// 첫 번째 클라이언트 접속 LogABNetwork: [SERVER] AABGameMode::PreLogin ============================================================ LogABNetwork: [SERVER] AABGameMode::PreLogin Begin LogABNetwork: [SERVER] AABGameMode::PreLogin End LogABNetwork: [SERVER] AABGameMode::Login Begin LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_1 LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents End LogABNetwork: [SERVER] AABGameMode::Login End LogABNetwork: [SERVER] AABGameMode::PostLogin Begin LogABNetwork: [SERVER] AABGameMode::PostLogin Client Connections : IpConnection_5 LogABNetwork: [SERVER] AABGameMode::PostLogin End LogABNetwork: [CLIENT1] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT1] AABPlayerController::PostInitializeComponents End LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit Server Connection : IpConnection_4 LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit End // 두 번째 클라이언트 접속 LogABNetwork: [SERVER] AABGameMode::PreLogin ============================================================ LogABNetwork: [SERVER] AABGameMode::PreLogin Begin LogABNetwork: [SERVER] AABGameMode::PreLogin End LogABNetwork: [SERVER] AABGameMode::Login Begin LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_2 LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents End LogABNetwork: [SERVER] AABGameMode::Login End LogABNetwork: [SERVER] AABGameMode::PostLogin Begin LogABNetwork: [SERVER] AABGameMode::PostLogin Client Connections : IpConnection_5 // 클라이언트1 연결 LogABNetwork: [SERVER] AABGameMode::PostLogin Client Connections : IpConnection_7 // 클라이언트2 연결 LogABNetwork: [SERVER] AABGameMode::PostLogin End LogABNetwork: [CLIENT2] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT2] AABPlayerController::PostInitializeComponents End LogABNetwork: [CLIENT2] AABPlayerController::PostNetInit Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT2] AABPlayerController::PostNetInit Server Connection : IpConnection_6 // 클라이언트에선 서버 연결 단 하나 LogABNetwork: [CLIENT2] AABPlayerController::PostNetInit End
네트워크에서 주고 받는 데이터들은 다음과 같은 고도화 작업을 거침
데이터 통신을 관리하기 위한 대표 액터로 플레이어 컨트롤러가 주로 사용됨
커넥션을 담당하는 대표 액터는 커넥셔넹 대한 오너십을 가진다고 표현
어떤 액터가 통신을 하기 위해서는 자신을 소유한 액터가 커넥션을 소유하고 있어야 함
일반적으로 플레이어 컨트롤러는 넷커넥션을 소유하고 있고,
넷커넥션 역시 플레이어 컨트롤러를 소유하고 있음
// Actor.cpp
UNetConnection* AActor::GetNetConnection() const
{
// Owner는 Actor, Pawn, PlayerController가 될 수도 있음
return Owner ? Owner->GetNetConnection() : nullptr;
}
// Pawn.cpp
class UNetConnection* APawn::GetNetConnection() const
{
// if have a controller, it has the net connection
if ( Controller )
{
return Controller->GetNetConnection();
}
return Super::GetNetConnection();
}
// PlayerContorller.cpp
UNetConnection* APlayerController::GetNetConnection() const
{
// A controller without a player has no "owner"
return (Player != NULL) ? NetConnection : NULL;
}
플레이어 컨트롤러가 캐릭터에 빙의하면 캐릭터의 오너로 설정됨
이 때 캐릭터가 무기 액터를 소유하면 무기 액터는 통신이 가능한 상태가 됨
- 서버 생성 로그
LogABNetwork: [SERVER] AABGameMode::Login Begin LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_0 LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents End LogABNetwork: [SERVER] AABGameMode::Login End LogABNetwork: [SERVER] AABGameMode::PostLogin Begin // 서버 플레이어의 캐릭터 빙의 LogABNetwork: [SERVER] AABPlayerController::OnPossess Begin BP_ABPlayerController_C_0 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy Begin ABCharacterPlayer_0 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy No Owner // Super::PossessedBy()에서 Owner 세팅 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy Owner : BP_ABPlayerController_C_0 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy End ABCharacterPlayer_0 LogABNetwork: [SERVER] AABPlayerController::OnPossess End LogABNetwork: [SERVER] AABGameMode::PostLogin No NetDriver LogABNetwork: [SERVER] AABGameMode::PostLogin End
- 클라이언트 접속 로그
LogABNetwork: [SERVER] AABGameMode::PreLogin Begin LogABNetwork: [SERVER] AABGameMode::PreLogin End LogABNetwork: [SERVER] AABGameMode::Login Begin LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_1 LogABNetwork: [SERVER] AABPlayerController::PostInitializeComponents End LogABNetwork: [SERVER] AABGameMode::Login End LogABNetwork: [SERVER] AABGameMode::PostLogin Begin // 클라이언트 플레이어의 캐릭터 빙의 LogABNetwork: [SERVER] AABPlayerController::OnPossess Begin BP_ABPlayerController_C_1 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy Begin ABCharacterPlayer_1 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy No Owner // Super::PossessedBy()에서 Owner 세팅 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy Owner : BP_ABPlayerController_C_1 LogABNetwork: [SERVER] AABCharacterPlayer::PossessedBy End ABCharacterPlayer_1 LogABNetwork: [SERVER] AABPlayerController::OnPossess End LogABNetwork: [SERVER] AABGameMode::PostLogin Client Connections : IpConnection_11 LogABNetwork: [SERVER] AABGameMode::PostLogin End LogABNetwork: [CLIENT1] AABPlayerController::PostInitializeComponents Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT1] AABPlayerController::PostInitializeComponents End LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit Begin BP_ABPlayerController_C_0 LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit Server Connection : IpConnection_10 LogABNetwork: [CLIENT1] AABPlayerController::PostNetInit End // 서버에서 클라이언트의 캐릭터에 세팅된 Owner 복제 LogABNetwork: [CLIENT1] AABCharacterPlayer::OnRep_Owner Begin ABCharacterPlayer_0 LogABNetwork: [CLIENT1] AABCharacterPlayer::OnRep_Owner End ABCharacterPlayer_0 LogABNetwork: [CLIENT1] AABCharacterPlayer::PostNetInit Begin ABCharacterPlayer_0 LogABNetwork: [CLIENT1] AABCharacterPlayer::PostNetInit End // 서버의 캐릭터가 클라이언트에도 생성되지만 Owner는 복제되지 않음 (Ownership이 없음) LogABNetwork: [CLIENT1] AABCharacterPlayer::PostNetInit Begin ABCharacterPlayer_1 LogABNetwork: [CLIENT1] AABCharacterPlayer::PostNetInit End
https://github.com/dnjfs/ArenaBattle_Network/commit/1cf1cb92ce89696717ee8a464104bac695933e79