요약
| 개념 | 기준 | 역할 |
|---|---|---|
NetMode |
World / Process | 현재 실행 환경이 서버인지 클라이언트인지 구분 |
NetDriver |
World의 네트워크 드라이버 | Connection, RPC, Replication 관리 |
NetConnection |
머신 간 연결 | 서버-클라이언트 통신 경로 |
Ownership |
Actor 소유 관계 | Actor가 어떤 클라이언트 Connection에 속하는지 결정 |
Authority |
Actor 권한 | 이 Actor의 상태를 누가 최종 결정하는지 판단 |
| 항목 | 요약 |
|---|---|
NetMode |
현재 World가 Standalone, Client, ListenServer, DedicatedServer 중 어떤 모드인지 나타냄 |
NM_Standalone |
싱글플레이. 서버/클라이언트 로직이 한 프로세스에서 실행 |
NM_Client |
서버에 접속한 클라이언트. 서버 권한 로직은 실행하지 않음 |
NM_ListenServer |
서버이면서 로컬 플레이어도 있는 호스트 |
NM_DedicatedServer |
로컬 플레이어 없는 전용 서버 |
NetDriver |
네트워크 통신, Replication, RPC, Connection을 관리 |
NetConnection |
서버와 클라이언트 사이의 연결 객체 |
ServerConnection |
클라이언트가 서버와 통신하기 위해 가진 연결 |
ClientConnections |
서버가 접속한 클라이언트마다 가진 연결 배열 |
Ownership |
RPC와 Owner-only Replication의 기준이 되는 소유 관계 |
GameMode |
서버에만 존재. 클라이언트 GetGameMode()는 nullptr 가능 |
PlayerController |
서버와 소유 클라이언트에 존재. 다른 클라이언트에는 없음 |
Pawn / GameState / PlayerState |
서버와 클라이언트에 복제되어 존재 |
서버가 결과를 확정하고, 클라이언트는 요청과 표시를 담당한다. NetMode는 현재 코드가 어느 네트워크 실행 환경에서 돌고 있는지 확인하는 기준이고, NetConnection과 Ownership은 RPC와 Replication의 대상 클라이언트를 결정하는 기준이다.
Unreal의 네트워크 구조는 서버가 authoritative하게 게임 상태를 관리하고, 클라이언트는 서버로부터 복제된 상태를 받는 구조를 기본으로 한다.
flowchart LR
A[Client 입력] --> B[Server RPC]
B --> C[서버에서 검증 / 처리]
C --> D[HP 감소 / 상태 변경]
D --> E[Replication]
E --> F[Client 화면 갱신]
NetMode
NetMode는 현재 게임 프로세스 또는 World가 네트워크에서 어떤 역할로 실행 중인지 나타낸다.
| ENetMode | 의미 |
|---|---|
NM_Standalone |
싱글플레이 또는 로컬 플레이. 서버/클라이언트 로직을 같은 프로세스에서 처리 |
NM_Client |
서버에 접속한 클라이언트 |
NM_ListenServer |
서버이면서 로컬 플레이어도 직접 참여하는 호스트 |
NM_DedicatedServer |
로컬 플레이어 없이 서버 기능만 수행하는 전용 서버 |
ENetMode에는 NM_Standalone, NM_DedicatedServer, NM_ListenServer, NM_Client가 정의되어 있다. NM_ListenServer는 로컬 플레이어가 함께 존재하는 서버이고, NM_DedicatedServer는 로컬 플레이어 없이 원격 클라이언트 연결을 처리하는 서버다.
| NetMode | 서버 로직 | 클라이언트 로직 | 로컬 플레이어 |
|---|---|---|---|
NM_Standalone |
실행 | 실행 | 있음 |
NM_Client |
실행 안 함 | 실행 | 있음 |
NM_ListenServer |
실행 | 실행 | 있음 |
NM_DedicatedServer |
실행 | 실행 안 함 | 없음 |
NM_Standalone은 원격 클라이언트 연결이 없는 모드지만, 서버 측 로직과 클라이언트 측 로직이 함께 동작한다. 이 때문에 멀티플레이를 기준으로 작성한 로직이 싱글플레이 Standalone에서도 동작할 수 있다.
ENetMode확인하는 코드
ENetMode NetMode = GetWorld()->GetNetMode();
ENetMode NetMode = GetNetMode();
Component에서 확인
if (GetNetMode() == NM_Client)
{
// 클라이언트 전용 처리
}
if (GetNetMode() != NM_Client)
{
// 서버 또는 Standalone에서 처리
}
HasAuthority
특정 Actor에 대해 현재 머신이 권한을 가지고 있는지 확인
| 구분 | 기준 |
|---|---|
GetNetMode() |
현재 World가 Client인지, ListenServer인지, DedicatedServer인지 |
HasAuthority() |
이 Actor의 Authority가 현재 머신에 있는지 |
GetLocalRole() |
현재 머신에서 이 Actor가 가진 Role |
GetRemoteRole() |
원격 머신에서 이 Actor가 가질 Role |
서버 권한으로 실행되어야 하는 Actor 로직은 HasAuthority()로 방어한다.
void AMyCharacter::ApplyDamage_ServerOnly(float Damage)
{
if (!HasAuthority())
{
return;
}
Health -= Damage;
}
NetMode는 디버깅과 실행 환경 구분에 유용하고, HasAuthority()는 Actor 단위의 서버 권한 판단에 더 직접적이다.
멀티플레이에서는 같은 C++ 코드가 여러 프로세스에서 실행된다.
flowchart LR
A[Server Process] --> D[같은 BeginPlay 코드 실행]
B[Client 1 Process] --> D
C[Client 2 Process] --> D
APlayerCharacter::BeginPlay() 하나만 보더라도 서버, 내 클라이언트, 다른 클라이언트에서 각각 실행될 수 있다.
| 상황 | 확인할 것 |
|---|---|
| 코드가 몇 번 실행되는가 | 서버/클라이언트 각각 실행 여부 |
| 어느 컴퓨터에서 실행되는가 | GetNetMode() 로그 |
| 이 Actor를 누가 제어하는가 | Ownership / Role |
| 서버 권한이 있는가 | HasAuthority() |
| 특정 클라이언트 소유 Actor인가 | Owning Connection |
NetDriver
UObject와 FExec를 상속하는 네트워크 드라이버 클래스
네트워크 통신의 핵심 관리 객체
| 항목 | 설명 |
|---|---|
| 역할 | 네트워크 연결, 패킷 처리, Replication, RPC 전송 관리 |
| 생성 시점 | 멀티플레이 네트워크가 열릴 때 |
| 싱글플레이 | 일반적으로 NetDriver 없음 |
| 서버 | 접속한 클라이언트들의 Connection 관리 |
| 클라이언트 | 서버로 향하는 Connection 관리 |
서버가 ClientConnections 배열을 통해 클라이언트 연결들을 관리한다.
// 개념 구조
UWorld
└── UNetDriver
├── ServerConnection // 클라이언트일 때 서버와의 연결
└── ClientConnections[] // 서버일 때 클라이언트들과의 연결
NetDriver NetMode
UWorld는 NetDriver가 있으면 NetDriver를 통해 NetMode를 판단한다.
ENetMode UWorld::InternalGetNetMode() const
{
if (NetDriver != nullptr)
{
const bool bIsClientOnly = IsRunningClientOnly();
return bIsClientOnly ? NM_Client : NetDriver->GetNetMode();
}
// NetDriver가 없으면 Standalone 계열
}
NetDriver 입장에서 서버인지 클라이언트인지는 ServerConnection 유무로 구분할 수 있다.
bool UNetDriver::IsServer() const
{
return ServerConnection == nullptr;
}
| 상태 | 의미 |
|---|---|
ServerConnection == nullptr |
이 NetDriver는 서버 역할 |
ServerConnection != nullptr |
이 NetDriver는 클라이언트 역할 |
| 서버 + 로컬 플레이어 있음 | Listen Server |
| 서버 + 로컬 플레이어 없음 | Dedicated Server |
NetConnection
다른 머신과의 네트워크 연결을 나타내는 객체UPlayer를 상속하며, 자신을 소유한 NetDriver를 가진다.
| 위치 | Connection 구조 |
|---|---|
| 서버 | 접속한 클라이언트 수만큼 ClientConnections 보유 |
| 클라이언트 | 서버를 향한 ServerConnection 하나 보유 |
Driver는 owning net driver로 설명된다.
flowchart TD
A[Server NetDriver] --> B[ClientConnection 1]
A --> C[ClientConnection 2]
A --> D[ClientConnection 3]
E[Client 1 NetDriver] --> F[ServerConnection]
G[Client 2 NetDriver] --> H[ServerConnection]
서버, 클라이언트 Connection 구조
| 머신 | NetDriver | NetConnection |
|---|---|---|
| Dedicated Server | 있음 | ClientConnections[] |
| Listen Server | 있음 | ClientConnections[] + 로컬 플레이어 |
| Client | 있음 | ServerConnection |
| Standalone | 보통 없음 | 없음 |
서버는 여러 클라이언트와 연결되어 있으므로 ClientConnections를 여러 개 가진다.
클라이언트는 하나의 서버에 접속하므로 ServerConnection 하나를 가진다.
Ownership
Ownership은 어떤 클라이언트 Connection이 특정 Actor를 소유하는지를 결정하는 관계다.
| 개념 | 설명 |
|---|---|
| Owner | Actor의 소유자 Actor |
| Owning Connection | 해당 Actor를 소유한 클라이언트 연결 |
| PlayerController | 보통 클라이언트 Connection의 핵심 소유 Actor |
| Pawn | PlayerController가 Possess하면 Owner 경로를 통해 Connection을 찾을 수 있음 |
| Weapon / Item Actor | Owner를 Pawn 또는 Controller로 설정하면 소유 관계에 포함 가능 |
Actor의 owner와 owning connection은 RPC 실행 위치와 replication 대상 판단에 중요하다. Client RPC는 어느 클라이언트에서 실행할지 알아야 하며, 이때 Actor의 owning connection이 사용된다.
flowchart LR
A[ClientConnection] --> B[PlayerController]
B --> C[Pawn]
C --> D[Weapon Actor]
GetNetConnection
Actor는 자신의 Owner를 통해 NetConnection을 확인
UNetConnection* AActor::GetNetConnection() const
{
return Owner ? Owner->GetNetConnection() : nullptr;
}
Pawn은 Controller가 있으면 Controller의 NetConnection을 사용
UNetConnection* APawn::GetNetConnection() const
{
if (Controller)
{
return Controller->GetNetConnection();
}
return Super::GetNetConnection();
}
PlayerController는 Player가 있으면 자신의 NetConnection을 반환
UNetConnection* APlayerController::GetNetConnection() const
{
return (Player != nullptr) ? NetConnection : nullptr;
}
flowchart LR
A[Weapon Actor GetNetConnection] --> B[Owner: Pawn]
B --> C[Pawn Controller 확인]
C --> D[PlayerController]
D --> E[NetConnection 반환]
RPC와 Ownership
| RPC 종류 | 실행 위치 |
|---|---|
| Server RPC | 클라이언트가 서버에 요청 |
| Client RPC | 서버가 특정 owning client에서 실행 |
| NetMulticast RPC | 서버에서 호출해 서버와 클라이언트들에 전파 |
RPC는 valid owner와 owning connection이 있는 replicated actor 또는 actor component에서 실행되어야 한다.
| 상황 | 결과 |
|---|---|
| Client가 자신이 소유한 Actor에서 Server RPC 호출 | 서버에서 실행 가능 |
| Client가 소유하지 않은 Actor에서 Server RPC 호출 | 실행되지 않거나 무시될 수 있음 |
| Server가 Client RPC 호출 | Actor의 owning connection 클라이언트에서 실행 |
| Owning Connection 없음 | Client RPC 대상 불명확 |
Actor 존재 범위
| 객체 | 서버 | 소유 클라이언트 | 다른 클라이언트 |
|---|---|---|---|
GameMode |
⭕ | ❌ | ❌ |
GameState |
⭕ | ⭕ | ❌ |
PlayerController |
⭕ | ⭕ | ❌ |
PlayerState |
⭕ | ⭕ | ⭕ |
Pawn / Character |
⭕ | ⭕ | ⭕ |
| Replicated Actor | ⭕ | ⭕ | ⭕ |
| UI Widget | ❌ | ⭕ | ❌ |
GameMode는 서버에만 존재함
AGameModeBase* GM = UGameplayStatics::GetGameMode(this);
if (!IsValid(GM))
{
return;
}
클라이언트에서 GameMode 로직이 필요하면 서버 RPC로 요청하거나, 서버에서 실행되는 함수 내부에서 처리
if (HasAuthority())
{
AGameModeBase* GM = UGameplayStatics::GetGameMode(this);
}
GameMode, GameState
| 구분 | GameMode | GameState |
|---|---|---|
| 존재 위치 | 서버에만 존재 | 서버와 클라이언트에 존재 |
| 용도 | 게임 규칙, 승패 판정, 스폰 규칙 | 클라이언트도 알아야 하는 게임 상태 |
| 클라이언트 접근 | 불가 또는 nullptr | 가능 |
| 복제(Replication) | 직접 클라에 존재하지 않음 | 복제됨 |
클라이언트도 알아야 하는 점수, 남은 시간, 매치 상태는 GameState
'Unreal Engine' 카테고리의 다른 글
| UE Angel Script Override (0) | 2026.08.06 |
|---|---|
| 게임 프로젝트에도 UE Public/Private 구조가 필요할까? (0) | 2026.08.04 |
| MyaCat 정리 2 (0) | 2026.07.28 |
| MyaCat 정리 1 (0) | 2026.07.27 |
| AssetManager ⇄ Bundle System 구조 수정 (0) | 2026.07.13 |