📝 TIL: 언리얼 엔진 멀티플레이어 핵심 원리 및 구현 (숫자야구 게임)
📌 1. 멀티플레이어 개요 & 프레임워크 역할 분담
언리얼 엔진의 멀티플레이어는 데디케이티드/리스닝 서버(Server) - 클라이언트(Client) 구조로 동작하며, 보안과 네트워크 효율을 위해 클래스별 역할이 철저히 분리되어 있다.
- AGameModeBase (서버 전용)
- 오직 서버에만 존재하며 클라이언트에는 존재하지 않는다.
- 정답 생성(GenerateSecretNumber), 승패 판정(JudgeGame), 게임 리셋(ResetGame) 등 핵심 게임 규칙과 보안이 중요한 데이터를 관리한다. (클라이언트가 정답을 훔쳐볼 수 없음)
- APlayerController (서버 + 해당 로컬 클라이언트)
- 유저와 게임 세상을 연결하는 통로.
- IsLocalController() 검사를 통해 로컬 플레이어 전용 UI(채팅창, 알림)를 생성한다.
- 클라이언트의 요청을 서버로 보내거나(Server RPC), 서버의 응답을 클라이언트로 전달(Client RPC)하는 네트워크 통신 창구 역할을 한다.
- APlayerState (서버 + 모든 클라이언트)
- 플레이어 개개인의 상태 정보(이름, 시도 횟수 CurrentGuessCount, 최대 기회 MaxGuessCount 등)를 저장한다.
- 네트워크 복제(Replication)되어 접속한 모든 플레이어가 서로의 정보를 확인할 수 있다.
- AGameStateBase (서버 + 모든 클라이언트)
- 모든 플레이어가 공유하는 전체 게임 세션 상태를 다룬다.
- 새로운 유저가 접속했을 때 모든 클라이언트에게 알림을 방송(NetMulticast)하는 등에 활용된다.
🌐 2. 네트워크 통신 기법 (RPC & Replication)
① RPC (Remote Procedure Call, 원격 프로시저 호출)
다른 단말기(서버 또는 특정 클라이언트)에서 함수를 실행시키기 위한 네트워크 명령.
- Server RPC (UFUNCTION(Server, Reliable))
- 호출: 클라이언트 -> 실행: 서버
- 클라이언트가 서버에게 상태 변경이나 판정을 요청할 때 사용. (예: ServerRPCPrintChatMessageString)
- 조건: 호출하는 클라이언트가 소유(Owned)한 액터(PlayerController 등)여야 함.
- Client RPC (UFUNCTION(Client, Reliable))
- 호출: 서버 -> 실행: 특정 클라이언트
- 서버에서 처리된 결과를 해당 클라이언트의 화면에 띄우거나 UI를 업데이트할 때 사용. (예: ClientRPCPrintChatMessageString)
- NetMulticast RPC (UFUNCTION(NetMulticast, Reliable))
- 호출: 서버 -> 실행: 서버 + 연결된 모든 클라이언트
- 접속 알림 메시지처럼 모든 유저에게 일괄 전달해야 하는 상황에 사용. (예: MulticastRPCBroadcastLoginMessage)
- Reliable 키워드
- 패킷 손실이 발생하더라도 재전송하여 반드시 도착하도록 보장함. (채팅, 판정 등 중요한 통신에 필수)
② 변수 복제 (Replication)
서버에서 변수 값을 변경하면, 클라이언트에 해당 변수 값이 자동으로 동기화되는 기능.
C++
// 1. 헤더 파일 선언
UPROPERTY(Replicated)
int32 CurrentGuessCount;
// 2. CPP 파일 등록
void AMyPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ThisClass, CurrentGuessCount);
}
🔄 3. 전체 데이터 흐름 (숫자야구 입력 ~ 결과 출력)
- [UI] UChatInputWidget: 플레이어가 입력창에 숫자를 치고 엔터를 누르면 OnTextCommitted 이벤트가 감지되어 컨트롤러의 SetChatMessageString() 호출.
- [Client PC] AMyPlayerController: PlayerState에서 작성자 정보(Player1(0/3))를 가져와 문장을 만든 뒤, ServerRPCPrintChatMessageString (Server RPC)을 통해 서버로 발송.
- [Server] AMyGameModeBase:
- 서버가 RPC를 수신하여 입력받은 문자열 검증 (IsGuessNumberString).
- PlayerState 내 시도 횟수 차감 및 정답 판정 (JudgeResult).
- 승패/무승부 여부 확인 (JudgeGame).
- ClientRPCPrintChatMessageString (Client RPC)으로 판정 결과를 클라이언트들에게 전파.
- [Client 화면] NBC_CH6FunctionLibrary: 클라이언트가 Client RPC를 받아 GEngine->AddOnScreenDebugMessage 또는 UE_LOG로 채팅 및 야구 결과를 출력.
💡 4. 핵심 요약 및 느낀 점 (Key Takeaways)
- 권한 분리 (Authority): 정답과 승패 판단 같은 보안 로직은 반드시 서버(GameMode)에 두고, 유저는 서버에게 RPC로 요청만 해야 핵/어뷰징을 막을 수 있다.
- 복제 대상 구분:
- PlayerController는 나만 조종하는 로컬 중심 액터.
- PlayerState는 남들에게도 보여야 하는 내 정보를 담는 복제 액터.
'내일배움캠프_언리얼9기' 카테고리의 다른 글
| Unreal Engine 네트워크 Replication 시행착오 (0) | 2026.09.02 |
|---|---|
| 내일배움캠프 72일차 TIL 2026/08/04 (0) | 2026.08.04 |
| 내일배움캠프 70일차 TIL 2026/07/31 (0) | 2026.07.31 |
| 내일배움캠프 69일차 TIL 2026/07/30 (0) | 2026.07.30 |
| 내일배움캠프 68일차 TIL 2026/07/29 (0) | 2026.07.29 |