Post

Unreal: 네트워크 기초 (Network Basics)

Unreal: 네트워크 기초 (Network Basics)

네트워크 게임 만들기

언리얼 엔진에선 미리 만들어진 네트워크 기능들을 제공한다. 이전에 써봤던 게임모드나 게임 스테이트, 컨트롤러, GAS같은 개념들을 왜 굳이 복잡하게 나눠놨을까 싶었다면, 네트워크 게임을 만드는데 있어서 용이한 구조이기 때문에 그렇게 처음부터 구축되었다고 생각하면 편하다. 멀티플레이어/온라인 게임이 싱글플레이어에 기능이 추가로 붙는다기 보단, 싱글플레이어 게임이 기능이 단순화된 멀티플레이어 게임이라고 이해하는게 더 쉽게 받아들일 수 있을 것이다.

서버의 종류

  • 서버는 가장 간단하게 말하면 단순히 컴퓨터이다. 다만 보다 정확히는 네트워크로 여러대의 컴퓨터가 연결된 구조 상에서, 기능을 요청하는 측이 아닌 기능을 수행하는 측의 컴퓨터를 서버라고 부르고, 그 반대를 클라이언트라고 부른다. 백엔드/프론트엔드로 구분하기도 하는데, 게임 개발에선 보통 해당 단어를 사용하기보단 서버/클라이언트로 더 많이 부르는 것 같다.
  • P2P(Peer to Peer)
    • 서버와 클라이언트가 별도로 구분되지 않는다. 모든 컴퓨터가 정보를 분산하여 저장/처리하고, 네트워크상에서의 수신과 송출을 모두 하게된다.
    • 대표적인 예시로는 토렌트를 이용한 파일 공유나, 다크소울의 멀티플레이어를 들 수 있겠따.
  • 리슨 서버(Listen Server)
    • 네트워크에 참가중인 클라이언트 1명이 서버 역할을 겸하게 된다.
    • 스타크래프트, 마인크래프트, 어몽어스등이 예시가 될 수 있다.
  • 데디케이티드 서버(Dedicated Server)
    • 서버의 역할만 수행하는 독립적인 컴퓨터가 존재한다.
    • 와우, 로스트아크같은 많은 온라인 RPG, 배틀그라운드등 규모가 있는 게임에서 보통 많이 사용한다.
  • 단순히 멀티플레이어 기능을 부가적으로 가진 게임을 만들고자 한다면 리슨 서버가 더 좋을 수 있다. 스팀이나 에픽 스토어등 온라인에서 멀티플레이어를 위한 친구목록/개설된 방 중개등의 기능을 제공한다. 하지만 보다 안정적이고, 보안이 중요한 환경이며 별도의 서버를 둘 비용을 충당할 수 있는 상황이라면 데디케이티드 서버가 더 좋을것이다.

서버의 흐름

  1. 먼저 서버 프로세스가 실행되면서 할당된 레벨을 불러온다. 싱글플레이가 아니라면 다른 클라이언트와 통신할 수 있도록 소켓을 열어둔다.
  2. 레벨의 WorldSettings에서 정해둔 게임모드와 게임 스테이트를 생성한다.
    • 게임모드는 서버에서만 생성되고 클라이언트로 복제되지 않는다. 때문에 언리얼 서버를 기준으론 게임모드는 서버와 동일시 되기도 한다.
  3. 클라이언트 측에선 서버의 IP주소, 포트번호를 바탕으로 접속하고, 생성해놓은 레벨의 정보를 넘겨준다. 클라이언트에선 레벨을 열고 성공 여부를 서버에 알린다.
  4. 클라이언트에서 레벨이 열리면 해당 클라이언트 전용으로 쓰일 PlayerState, PlayerController, PlayerCharacter가 생성된다. 이것들과 GameState까지 4개가 클라이언트에 복제된다.
  5. 이 클라이언트 접속과정을 새로운 클라이언트 접속시마다 반복한다.
  6. 반복하는 과정에서, 새로운 클라이언트를 위해 생성되는 PlayerState, PlayerCharacter는 다른 클라이언트의 컴퓨터에도 복제된다.
  • 클라이언트 간의 직접적인 통신은 불가능하다. 모든 통신은 서버를 거쳐서만 가능하다.
    • 이를 구현하고 활용하기 위해 RemoteProcedureCall(RPC)나 Replicated 개념을 활용해 클라이언트와 서버의 작동 구조를 설계/구현하게 된다.

NetMode

  • 게임 프로세스가 가지는 역할을 나타낸다.
    • NM_StandAlone
      • NetDriver가 설정되어 있지 않을 때 -> 혼자 플레이할 때
      • 모든 로직을 해당 컴퓨터에서 수행한다.
    • NM_Listen
      • 서버이면서 동시에 클라이언트일 때
      • 서버의 로직과 클라이언트의 로직을 모두 수행한다.
    • NM_DedicatedServer
      • 서버이지만 클라이언트는 아닐 때
      • 서버의 로직만 수행한다.
    • NM_Client
      • 서버가 아닐 때
      • 서버의 로직을 실행하지 않는다.

        NetConnection

  • 클라이언트가 서버에 접속했을 때 통신을 중계해주는 객체로 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) 다른 플레이어의 캐릭터(위치, 동작, 방향등)

로컬 롤/리모트 롤 (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.