멀티플레이어의 이해
게임을 하면서 '멀티플레이어'라는 용어를 많이 들어봤을 것이다.
이 용어가 개발자에게는 어떤 의미냐 하면,
실제로 멀티플레이어를 구현하기 위해서는
서버와 서버에 연결된 클라이언트 사이의 네트워크를 통해 전송되는 일련의 명령을 의미한다.
이를 통해 구현해내면,
개발자는 플레이어에게 다른 플레이어들과 세계를 공유하는 경험을 제공할 수 있다.
서버와 클라이언트 사이의 이러한 양방향 통신의 한 예로는
플레이어가 게임 중에 무기를 발사하려고 시도하는 시점을 들 수 있다.
- 플레이어가 마우스 왼쩍 버튼을 누르고 있으면,
클라이언트가 서버에 무기 발사를 원한다는 의사를 전달한다. - 서버는 다음 항목을 확인해 플레이어가 무기를 발사할 수 있는지 확인한다.
- 플레이어가 살아 있는가?
- 플레이어가 무기를 장착했는가?
- 플레이어가 충분한 탄약을 갖고 있는가?
- 모든 검사를 통과하면 서버는 다음을 수행한다.
- 탄약의 수를 감소시키는 로직을 실행한다.
- 모든 클라이언트에 자동으로 전송되는 발사체 액터를 서버에 생성한다.
- 모든 클라이언트의 캐릭터 인스턴스에서 발사 애니메이션을 재생해
클라이언트 간의 동기화를 보장한다.
이는 동일한 월드에서 게임을 즐긴다는 생각을 갖도록 하는 데 도움을 준다.(실제로 그렇지 않더라도)
- 검사 항목 중 하나라도 실패하면,
서버는 특정 클라이언트에게 수행할 작업을 알려준다.- 플레이어가 죽은 경우 : 아무것도 하지 않음
- 플레이어가 무기를 장착하지 않은 경우 : 아무것도 하지 않음
- 플레이어가 충분한 탄약을 갖지 않은 경우 : 탄약이 비었을 때의 사운드 재생
만약 개발자가 멀티플레이어를 지원하는 게임을 개발하고 싶다면,
개발 주기에서 최대한 빠릴 멀티플레이어를 지원하도록 구성하는 것이 좋다는 점을 기억하자.
멀티플레이어가 활성화된 상태에서 싱글 플레이어 프로젝트를 실행하면
일부 기능이 제대로 작동하지 않게 되거나 예상대로 동작하지 않을 수 있다.
이는 싱글 플레이어에서 게임을 실행하면 코드가 로컬(사용자 PC)에서 그 즉시 실행되기 때문이다.
반면 게임에 멀티플레이어를 추가하면,
지연 시간이 있는 네트워크에서 클라이언트와의 통신 권하닝 있는 서버 같은 외부 요인이 추가된다.
모든 기능을 제대로 작동시키려면 기존 코드를 다음과 같이 분리해야 한다.
- 서버에서만 동작하는 코드
- 클라이언트에서만 동작하는 코드
- 서버와 클라이언트 모두에서 동작하는 코드
UE5는 게임에 멀티플레이어 기능을 지원하기 위해
서버 - 클라이언트 아키텍처를 사용해 매우 강력하고 대역폭에 효율적인
내장 네트워크 프레임워크를 제공하고 있다.
다음 그림을 참고하면 효율적으로 이해 가능 할 것이다.
이는 UE5에서 동작하는 서버 - 클라이언트 아키텍처이다.
각 플레이어는 양방향 연결을 사용해 서버와 통신하는 클라이언트를 제어한다.
서버는 게임 모드(서버에만 존재)를 가진 특정 레벨을 실행하며,
클라이언트가 게임 월드에서 서로를 바라보고 상호작용할 수 있도록 정보의 흐름을 제어한다.
서버 이해하기
서버는 대부분의 작업을 처리하고 주용한 결정을 내리기 떄문에
서버-클라이언트 아키텍처에서 가장 중요한 부분을 차지한다.
다음은 서버가 담당하는 주요 작업에 대한 내용이다.
- 공유 월드 인스턴스의 생성 및 관리 :
서버는 특정 레벨 및 게임 모드에서 게임의 자체 인스턴스를 실행하며
연결된 모든 클라이언트 간의 공유되는 월드를 제공한다.
사용하는 레벨은 언제든 변경 가능하며,
가능한 경우 서버는 자동으로 연걸결된 모든 클라이언트를 다른 레벨로 가져올 수 있다. - 클라이언트의 참가 및 퇴장 요청 처리 :
클라이언트가 서버에 연결하라면 권한을 요청해야 한다.
이를 위해 클라이언트는 직접 IP 연결 또는 스트림과 같은
온라인 하위 시스템을 통해 서버에 참가 요청을 보낸다.
참가 요청이 서버에 도달하면 몇 가지 유효성 검사를 통해 요청을 수락할지 거부할지 여부를 결정한다.
하지만 서버가 게임 참가 요청을 거후라며는 몇 가지 이유로
가장 일반적인 상황은 서버가 수용할 수 있는 최대치의 연결이 발생했고
더 이상의 클라이언트를 수용할 수 없거나
클라이언트가 호환되지 않는 오래된 게임 버전을 사용하는 경우이다.
서버가 요청을 수락하면, 연결된 플레이어 컨트롤러가 클라이언트에 할당되고
게임 모드의 PostLogin 함수가 호출된다.
그 시점부터 클라이언트는 게임에 입장해 플레이어가 다른 클라이언트를 보며
서로 상호작용할 수 있는 공유 월드의 일원이된다.
클라이언트가 어느 시점이든 연결이 끊기면,
다른 모든 클라이언트에게 알림을 전송하고 게임 모드의 Logout 함수가 호출된다. - 모든 클라이언트가 알아야 하는 액터의 생성 :
모든 클라이언트에 존재하는 액터를 생성하려면, 생성 작업을 서버에서 진행해야 한다.
이는 모든 클라이언트에게
액터의 인스턴스를 생성하도록 지시할 수 있는 권한을 가진 유일한 대상이 서버이기 때문인다.
대부분의 액터가 모든 클라이언트에 존재해야 하므로 서버에서 액터를 생성하느 ㄴ것이
멀티플레이어 게임에서 가장 일반적인 방법이다.
모든 클라이언트가 볼 수 있고 상호작용 가능한 파워업 아이템을 예로 들 수 있다. - 중요한 게임플레이 로직의 실행 :
게임이 모든 클라이언트에게 공정하도록 만들려면
중요한 게임플레이 로직을 서버에서만 실행해야 한다.
예를 들어,
클라이언트가 체력을 낮추는(깍는) 로직의 처리를 담당한다면
플레이어가 어떤 도구를 사용해 메모리에서 현재 체력 값을 100%로 항상 변경할 수 있고,
이 경우 해등 플레이어는 게임에서 절대로 죽지 않는 핵을 쓰는 유저가 될 것이다. - 변수 리플리케이션 처리 :
리플리케이션이 필요한 변수가 있는 경우에 해당 변수의 값은 서버에서만 변경해야 한다.
이렇게 하면 모든 클라이언트의 값이 자동으로 업데이트가 될 것이다.
여전히 클라이언트에서 값을 변경할 수 있지만,
부정행위를 방지하고 모든 클라이언트를 동기화하도록 항상 서버의 최신 값으로 대체한다. - 클라이언트 RPC 처리 :
서버는 클라이언트에서 보낸 RPC를 처리해야 한다.
데디케이트 서버
데디케이트 서버는 서버 로직만 실행하므로
로컬 플레이어로서 캐릭터를 제어하는 게임이 실행되는 일반적인 창은 볼 수 없다.
즉, 모든 클라이언트는 이 서버에 연결하며,
서버는 클라이언트들과 소통하고 중요한 게임플레이 로직을 실행하는 일만 담당한다.
또한 -log 명령 프롬프트를 사용해 데디케이트 서버를 실행하면,
클라이언트가 연결됐는지 또는 연결이 해체됐는지 등 서버에서 발생하는 이벤트에 대한
관련 정보들을 출력해주는 콘솔 창이 나타난다.
개발자로서 UE_LOG 매크로를 사용해 자신만의 정보를 기록할 수도 있다.
데디케이트 서버를 사용하는 것은 멀티플레이어 게임용 서버를 제작하는 매우 일반적인 방법이며,
리슨 서버보다 가볍기 때문에 서버 스택에서 호스팅하고 실행 상태로 둘 수 있다.
데디케이트 서버의 또 다른 장점은 네트워크 상태가 모두에게 동일하므로
모든 플레이어에게 좀 더 공평하다는 점이 있다.
또한 클라이언트에는 권한이 없으므로 해킹의 가능성도 줄일 수 있다.
UE5에서 데디케이트 서버를 시작하려면 다음의 명령 인자를 사용할 수 있다.
- 바로가기나 명령 프롬프트를 통해 다음 명령어를 실행함으로써
에디터 안에서 데디케이트 서버를 실행한다.
"<UE5 설치 경로>\Engine\Binaries\Win64\UnrealEditor.exe"
"<UProject 위치>" <맵 이름> -server -game -log
리슨 서버
리슨 서버는 서버 역할과 클라이언트 역할을 동시에 수행한다.
따라서 리슨 서버를 사용하면 클라이언트로 게임을 플레이할 수 있는 창이 나타난다.
또한 서버를 실해앟는 가장 빠른 방법이라는 장점이 있다.
하지만 리슨 서버는 데디케이트 서버만큼 가볍지 않다.
따라서 동시에 접속할 수 있는 클라이언트의 수가 제한된다.
리슨 서버를 제작하려면 다음과 같은 명령 인자를 사용할 수 있다.
- 바로가기나 명령 프롬프트를 통해 에디터 안에서 데티케이트 서버를 시작한다.
"<UE5 설치 경로>\Engine\Binaries\Win64\UnrealEditor.exe"
"<UProject 위치>" <맵 이름> -server -game -log
- 패키징된 개발 빌드는 바로가기나 명령 프롬프트를 통해 리슨 서버를 실행할 수 있다.
"<프로젝트 이름>.exe" <맵 이름>?Listen -game
해당 게시글은 Elevating Game Experiences with Unreal Engine 5 Second Edition을 기반으로 작성되었습니다.
'UE5' 카테고리의 다른 글
레이캐스트와 트레이스 (2) | 2024.01.11 |
---|---|
Survival - 0102 - 작업 메모 (0) | 2024.01.02 |
Survival - UE5 - Multiplayer의 작동 (1) | 2023.12.31 |
GitHub에 프로젝트 저장하기 (0) | 2023.12.29 |
Delegate 사용방법 (1) | 2023.12.05 |