언리얼 엔진5 Advanced - 커넥션과 오너십

타입·2025년 3월 31일
0

언리얼 강의

목록 보기
25/47

원격 액터의 초기화 과정

  • PostInitializeComponents
    게임과 무관한 액터 설정의 초기화
  • PostNetInit
    원격 클라이언트에서 네트워크 관련 설정의 초기화
  • BeginPlay
    게임 진행에 필요한 초기화
  • 클라이언트 접속 실패 로그
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

언리얼 엔진에서의 커넥션 구성

  • 언리얼 엔진의 통신
    • 하이레벨
      게임을 구성하는 단위인 액터, 컴포넌트, 월드 등 오브젝트의 상태와 속성에 관련된 상위 개념
    • 로우레벨
      상태와 속성을 네트워크에 전달하기 위해 만들어진 데이터 스트림

네트워크 통신을 담당하는 주요 클래스

  • PlayerController
    네트워크 통신에 접근가능한 게임 내 대표 액터
  • UNetConnection
    주고받는 패킷 데이터의 인코딩/디코딩, 네트워크 통신량 조절, 채널 관리
  • UNetDriver
    로우레벨에서의 소켓 관리와 패킷 처리, 네트워크 통신 설정

서버의 네트워크 초기화 과정

현재 월드에 넷드라이버가 있으면 클라이언트-서버, 아니면 스탠드얼론으로 판단함
서버는 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

커넥션과 오너십

언리얼 엔진에서의 데이터 관리

네트워크에서 주고 받는 데이터들은 다음과 같은 고도화 작업을 거침

  • 커넥션 (Connection)
    모든 데이터를 전달하는 네트워크 통로
  • 패킷 (Packet)
    네트워크를 통해 전달되는 단위 데이터
  • 채널 (Channel)
    언리얼 엔진 아키텍쳐에 따라 구분된 데이터를 전달하는 논리적인 통로
  • 번치 (Bunch)
    언리얼 엔진의 아키텍쳐에 사용되는 데이터
    하나의 명령에 대응하는 데이터 묶음

데이터 통신을 관리하기 위한 대표 액터로 플레이어 컨트롤러가 주로 사용됨

커넥션을 담당하는 대표 액터는 커넥셔넹 대한 오너십을 가진다고 표현

액터와 플레이어 컨트롤러의 넷커넥션

어떤 액터가 통신을 하기 위해서는 자신을 소유한 액터가 커넥션을 소유하고 있어야 함

일반적으로 플레이어 컨트롤러는 넷커넥션을 소유하고 있고,
넷커넥션 역시 플레이어 컨트롤러를 소유하고 있음

넷커넥션

// 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;
}

플레이어 컨트롤러를 통한 설정 예시

플레이어 컨트롤러가 캐릭터에 빙의하면 캐릭터의 오너로 설정됨

  • 서버
    Possess() 함수를 호출해 오너십을 설정함
  • 클라이언트
    오너십이 설정된 캐릭터의 속성이 배포되면서 자신이 조종하는 캐릭터에 오너십이 설정됨

이 때 캐릭터가 무기 액터를 소유하면 무기 액터는 통신이 가능한 상태가 됨

  • 통신 가능
    • 플레이어 컨트롤러
    • 플레이어 컨트롤러가 소유한 액터
    • 플레이어 컨트롤러가 소유한 액터가 소유한 무기 액터
  • 서버 생성 로그
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

profile
주니어 언리얼 프로그래머

0개의 댓글