Unreal: 네트워크 기초 (Network Basics)
Unreal: 네트워크 기초 (Network Basics)
네트워크 게임 만들기
언리얼 엔진에선 미리 만들어진 네트워크 기능들을 제공한다. 이전에 써봤던 게임모드나 게임 스테이트, 컨트롤러, GAS같은 개념들을 왜 굳이 복잡하게 나눠놨을까 싶었다면, 네트워크 게임을 만드는데 있어서 용이한 구조이기 때문에 그렇게 처음부터 구축되었다고 생각하면 편하다. 멀티플레이어/온라인 게임이 싱글플레이어에 기능이 추가로 붙는다기 보단, 싱글플레이어 게임이 기능이 단순화된 멀티플레이어 게임이라고 이해하는게 더 쉽게 받아들일 수 있을 것이다.
서버의 종류
- 서버는 가장 간단하게 말하면 단순히 컴퓨터이다. 다만 보다 정확히는 네트워크로 여러대의 컴퓨터가 연결된 구조 상에서, 기능을 요청하는 측이 아닌 기능을 수행하는 측의 컴퓨터를 서버라고 부르고, 그 반대를 클라이언트라고 부른다. 백엔드/프론트엔드로 구분하기도 하는데, 게임 개발에선 보통 해당 단어를 사용하기보단 서버/클라이언트로 더 많이 부르는 것 같다.
- P2P(Peer to Peer)
- 서버와 클라이언트가 별도로 구분되지 않는다. 모든 컴퓨터가 정보를 분산하여 저장/처리하고, 네트워크상에서의 수신과 송출을 모두 하게된다.
- 대표적인 예시로는 토렌트를 이용한 파일 공유나, 다크소울의 멀티플레이어를 들 수 있겠따.
- 리슨 서버(Listen Server)
- 네트워크에 참가중인 클라이언트 1명이 서버 역할을 겸하게 된다.
- 스타크래프트, 마인크래프트, 어몽어스등이 예시가 될 수 있다.
- 데디케이티드 서버(Dedicated Server)
- 서버의 역할만 수행하는 독립적인 컴퓨터가 존재한다.
- 와우, 로스트아크같은 많은 온라인 RPG, 배틀그라운드등 규모가 있는 게임에서 보통 많이 사용한다.
- 단순히 멀티플레이어 기능을 부가적으로 가진 게임을 만들고자 한다면 리슨 서버가 더 좋을 수 있다. 스팀이나 에픽 스토어등 온라인에서 멀티플레이어를 위한 친구목록/개설된 방 중개등의 기능을 제공한다. 하지만 보다 안정적이고, 보안이 중요한 환경이며 별도의 서버를 둘 비용을 충당할 수 있는 상황이라면 데디케이티드 서버가 더 좋을것이다.
서버의 흐름
- 먼저 서버 프로세스가 실행되면서 할당된 레벨을 불러온다. 싱글플레이가 아니라면 다른 클라이언트와 통신할 수 있도록 소켓을 열어둔다.
- 레벨의 WorldSettings에서 정해둔 게임모드와 게임 스테이트를 생성한다.
- 게임모드는 서버에서만 생성되고 클라이언트로 복제되지 않는다. 때문에 언리얼 서버를 기준으론 게임모드는 서버와 동일시 되기도 한다.
- 클라이언트 측에선 서버의 IP주소, 포트번호를 바탕으로 접속하고, 생성해놓은 레벨의 정보를 넘겨준다. 클라이언트에선 레벨을 열고 성공 여부를 서버에 알린다.
- 클라이언트에서 레벨이 열리면 해당 클라이언트 전용으로 쓰일 PlayerState, PlayerController, PlayerCharacter가 생성된다. 이것들과 GameState까지 4개가 클라이언트에 복제된다.
- 이 클라이언트 접속과정을 새로운 클라이언트 접속시마다 반복한다.
- 반복하는 과정에서, 새로운 클라이언트를 위해 생성되는 PlayerState, PlayerCharacter는 다른 클라이언트의 컴퓨터에도 복제된다.
- 클라이언트 간의 직접적인 통신은 불가능하다. 모든 통신은 서버를 거쳐서만 가능하다.
- 이를 구현하고 활용하기 위해 RemoteProcedureCall(RPC)나 Replicated 개념을 활용해 클라이언트와 서버의 작동 구조를 설계/구현하게 된다.
NetMode
- 게임 프로세스가 가지는 역할을 나타낸다.
- 클라이언트가 서버에 접속했을 때 통신을 중계해주는 객체로 UNetConnection 클래스를 가진다.
- 클라이언트 측에는 ServerConnection, 서버측에는 ClientConnetion이 생성한다.
- 서버는 여러 ClientConnetion를 가질 수 있고, 클라이언트는 하나의 ServerConnection만 가진다.
- 양측은 UNetConnection을 통해 통신하며, 이 때 UNetDriver에서 이를 소유하고 관리한다.
NetDriver
- 로우레벨 수준에서 언리얼의 네트워크 통신을 관리하는 클래스이다.
- 멀티플레이어에서만 UWorld::Listen()를 통해 레벨이 만들어질 때 생성된다.
- 각 NetDriver는 하나의 ServerConnection와 여러개의 ClientConnetion를 가질 수 있으며, 이는 서버인지 클라이언트인지에 따라 할당되는 내용이 달라진다.
소유권 (Ownership)
- 각 ClientConnetion는 하나의 PlayerController를 소유하게 된다.
- PlayerController는 PlayerCharacter를 소유한다.
- PlayerCharacter는 무기나 장비등 게임에 필요한 액터를 소유할 수 있다.
- 일련의 관계를 통해 이들은 하나의 그룹으로 묶이며, 이를 패밀리(Family)로 부른다.
- 해당 패밀리 안에서 어떤 액터든 AActor::GetNetConnection()를 통해 어떤 ClientConnetion의 소유인지 확인할 수 있다.
NetRole
- 네트워크 상에서 어떤 상태로 동작중인지를 나타내는 값이다.
- None
- 레플리케이트 되지 않는 액터들이다.
- Authority
- 게임 로직에 핵심적인 액터들로, 수정/편집할 권한을 가진다.
- Ex) 자기 자신의 플레이어의 캐릭터
- AutonomousProxy
- Authority의 복제이지만, 서버측과 송신과 수신 모두 가능하다.
- Ex) 자기 자신의 플레이어의 캐릭터
- SimulatedProxy
- Authority의 복제로, 서버측의 값으로 동기화되는 수신만 가능하다.
- Ex) 다른 플레이어의 캐릭터(위치, 동작, 방향등)
- None
로컬 롤/리모트 롤 (Local Role, Remote Role)
- 각 액터는 NetRole에서 실행중인 컴퓨터에서의 역할인 로컬 롤(Local Role)과 통신중인 다른 컴퓨터에서의 역할인 리모트 롤(Remote Role)을 가진다. 이를 바탕으로 실행중인 컴퓨터가 서버인지/클라이언트인지 구별하고 액터에 대한 동작을 결정할 수 있다.
- 이 둘은 상대방 컴퓨터로 넘어가면 서로 반대로 바뀌는 관계가 된다.
- 서버에서는 모든 액터를 소유하기에 무조건적으로 Authority를 가진다.
- LocalRole - Authority
- RemoteRole - None/AutonomousProxy/SimulatedProxy
- 클라이언트에선 조건에 따라 None이나 Proxy등의 값을 가지며, 이는 서버에서 가지는 롤의 반대 관계이다.
- RemoteRole - Authority
- LocalRole- None/AutonomousProxy/SimulatedProxy
This post is licensed under CC BY 4.0 by the author.