언리얼 Networking Overview

tttkim·2021년 7월 28일
post-thumbnail

언리얼 공식문서의 Networking Overview 문서 정리

Plan for multiplayer early

  • 멀티플레이어 기능이 필요할 경우 프로젝트를 시작할 때부터 그에 맞춰 게임플레이를 구현해야 함.
  • 처음부터 꾸준히 멀티플레이를 위한 기능을 넣으면 싱글플레이 게임과 비슷한 정도의 시간이 들 것이며, 장기적으로 디버그와 서비스가 쉬워질 것.
  • 네트워크 기능 없이 구현한 코드 베이스를 리팩토링하는 것은 거의 코드를 갈아엎는 것과 비슷할 것.
  • 그러므로 네트워크 기능이 없는 것이 확실한 경우를 제외하면 항상 멀티플레이를 염두에 두고 프로젝트를 진행하는 것을 추천함.

The Client-Server Model

  • 싱글 플레이어나 로컬 멀티플레이어 모드에서 게임은 standalone 모드로 돌아감. 하나의 컴퓨터에 여러 명의 플레이어가 입력을 연결하고 직접적으로 모든 것을 제어함. 액터, 월드, 각 플레이어를 위한 UI를 포함한 모든 것은 로컬 머신에 존재.
  • 네트워크 멀티플레이어 게임에서 언리얼 엔진은 Client-Server 모델을 사용함. 네트워크의 한 컴퓨터가 서버로서 멀티플레이어 게임의 세션을 호스트하고, 다른 플레이어들은 서버에 클라이언트로서 연결함. 서버는 각각의 클라이언트에 game state 정보를 공유하고, 서로와 통신할 수 있는 수단을 제공함.
  • 서버는 게임의 호스트로서 유일하게 모든 권한을 가진(authoritative) game state를 소유한다(서버가 게임이 실제로 일어나는 곳임).
  • 클라이언트들은 각자 자신들이 서버에 소유하고 있는 Pawn을 원격 조종하고, 게임에서 행동하게 만들기 위해 프로시저 콜을 전송함.
  • 서버는 클라이언트의 모니터에 직접적으로 이미지를 스트림하지 않고, 게임 스테이트에 대한 정보를 클라이언트에 replicate하여 어떤 액터가 존재해야 하고, 어떻게 액터들이 동작해야 하고, 어떤 변수들이 어떤 값을 가져야 하는지를 알려줌.
  • 각 클라이언트는 replicate된 정보를 가지고 서버에서 일어나는 일을 거의 비슷하게 시뮬레이트함.

Fundamental Networking Concepts

Network Modes and Server Types

  • 네트워크 모드 : 네트워크 멀티플레이어 세션에 대한 컴퓨터의 관계
네트워크 모드설명
Standalone원격 클라이언트 연결을 허용하지 않는 서버로서 게임 실행. 로컬 플레이어만 게임에 참여 가능. 싱글 플레이어나 로컬 멀티플레이어 게임에 사용됨. 서버 사이드 로직과 클라이언트 사이드 로직 중 적절한 것을 실행함.
Client네트워크 멀티플레이어 세션에 있는 서버에 연결된 클라이언트로서 게임 실행. 서버 사이드 로직은 실행하지 않음.
Listen Server네트워크 멀티플레이어 세션을 호스팅하는 서버로서 게임 실행. 원격 클라이언트로부터의 연결을 허용하고 서버에 로컬 플레이어 직접 연결도 가능. 캐주얼 협동, 경쟁 멀티플레이어 게임에 사용됨.
Dedicated Server네트워크 멀티플레이어 세션을 호스팅하는 서버로서 게임 실행. 원격 클라이언트 연결을 허용하지만 로컬 플레이어 직접 연결은 할 수 없음. 그래픽, 사운드, 입력 등 다른 플레이어 중심 기능은 효율적인 실행을 위해 포기함. 더 장시간 이루어지거나, 더 안정적으로 이루어지거나, 더 대규모로 멀티플레이어 게임을 해야 할 때 사용됨.

Listen server

  • Listen server는 유저들이 스스로 설정하기 수월함.
  • 서버에서 직접 플레이하는 유저들이 더 유리할 가능성이 있음.
  • 서버를 검색하거나 시작하는 인게임 UI가 있음.
  • 서버에서 여러가지 추가적인 플레이어 관련 연산이 진행되기 때문에 네트워크 부하가 큰 게임을 실행하기는 어려우나 소규모 플레이어들이 경쟁하거나 협력하는 게임에는 적합함.

Dedicated server

  • 더 비싸고 구성하기 어려움. 모든 플레이어가 컴퓨터를 따로 가지고 있어야 하고, 각자가 네트워크에 연결되어 있어야 함.
  • 게임에 참여하는 모든 플레이어들이 같은 종류의 연결로 게임을 경험하므로 더 공정함.
  • 서버가 로컬 플레이어에 관련된 연산을 진행하지 않기 때문에 게임플레이와 네트워킹이 더 효율적임.
  • 대규모, 고사양 멀티플레이어 게임에 적합함.

Actor Replication

  • Replication은 게임 스테이트 정보를 네트워크 세션에 있는 다른 머신들간에 재생산하는 과정임.
  • Replication이 제대로 형성된다면 각각의 머신들의 게임 인스턴스들이 연동됨.
  • 기본적으로 대부분의 액터들은 replication이 비활성화 되어 있고, 로컬에서만 기능함.
  • 액터 블루프린트 세팅의 Replicates 항목을 true로 설정하거나 C++ 액터 클래스에서 bㄴReplicates 변수를 설정하여 replication을 활성화할 수 있다.
Replication Feature설명
Creation and Destruction서버에 authoritative version으로 replicate된 액터가 스폰되면, 연결된 모든 클라이언트에 원격 복사본을 생성하고 복사본에 정보를 replicate함. authoritative 액터를 삭제하면 연결된 모든 클라이언트에 있는 복사본을 삭제함.
Movement Replicationauthoritative 액터의 블루프린트에 Replicate Movement 옵션이 활성화 되어 있거나 C++에서 bReplicateMovement가 true라면 자동으로 위치, 회전, 속도를 replicate함.
Variable Replicationreplicate 되도록 설정된 변수들은 자동으로 authoritative 액터의 변경 사항을 복사본에 업데이트함.
Component Replication액터 컴포넌트는 부착된 액터의 일부로서 replicate됨. 컴포넌트에 있는 replicate되도록 설정된 모든 변수는 replicate됨. 컴포넌트에서 호출된 RPC는 액터 클래스에서 호출되는 RPC에 따라 움직임.
Remote Procedure Calls(RPCs)RPC는 네트워크 게임의 특정 머신에 전송되는 특별한 함수임. RPC가 어떤 머신에서 먼저 호출되었든, 작동하도록 설정된 머신에서만 실행됨. 서버에서만 실행되거나, 클라이언트에서만 실행되거나, 서버와 그에 연결된 모든 머신에서 실행될 수 있음(멀티캐스트)
  • 생성, 소멸, 움직임같은 일반적인 경우 자동으로 다뤄지지만, 다른 게임플레이 기능들은 replication을 활성화하더라도 기본적으로 자동으로 replicate되지 않음. 어떤 함수와 변수를 replicate할지를 명백하게 정해야 함.
  • replicate되지 않는 기능
    • Skeletal Mesh, Static Mesh Components
    • Materials
    • Animation Blueprints
    • Particle Systems
    • Sound Emitters
    • Physics Objects
  • 기본적으로 각 클라이언트에서 따로따로 실행되지만 replicate되면 모든 클라이언트가 같은 정보를 가지게 되고 거의 같은 방식으로 시뮬레이트하게 됨.

Network Role and Authority

  • 액터의 Network role은 어떤 머신이 액터의 컨트롤을 갖는지를 결정함.
  • authoritative 액터가 액터의 상태 컨트롤 권한을 가지고 있고, 네트워크 멀티플레이 세션의 다른 머신에 정보를 replicate함.
  • remote proxy는 원격 머신에 있는 액터 복사본이며, authoritative 액터로부터 replicate된 정보를 받음.
  • Local Role과 Remote Role 변수를 통해 추적됨.
Network RoleDescription
None액터는 네트워크 게임에서 역할이 없으며 replicate되지 않음
Authority액터는 authoritative이며, 다른 머신들에 있는 복사본에 정보를 replicate함
Simulated Proxy액터는 authoritative 액터에 의해 완전히 통제되는 원격 복사본임. 픽업, 투사체, 상호작용 가능한 오브젝트같은 대부분의 액터는 원격 클라이언트에서 Simulated Proxy로 나타남
Autonomous Proxy액터는 몇몇 기능을 로컬에서 수행할 수 있지만, authoritative 액터의 수정사항을 받음. Autonomous Proxy는 Pawn같이 플레이어의 직접적인 컨트롤이 필요한 것들을 위한 것임.
  • 언리얼 엔진에서 사용되는 기본 모델은 서버가 항상 게임스테이트에 대해 권한을 갖는 server-authoritative임.
  • 정보는 항상 서버에서 클라이언트로 replicate됨.
  • 서버에 있는 액터는 Local Role of Authority를 가질 것이고, 원격 클라이언트에 있는 복사본은 Local Role of (Simulated | Autonomous) Proxy를 가질 것임.

Client Ownership

  • 네트워크 게임의 폰은 특정 클라이언트의 머신에 있는 PlayerController가 소유함.
  • 폰이 클라이언트 전용 함수를 호출할 때마다, 해당되는 플레이어의 머신에서만 실행됨.
  • Owner 변수가 특정 폰으로 설정된 액터는 해당 폰을 소유하는 클라이언트에 속할 것이며, 클라이언트 전용 함수를 owner의 머신에서 실행되게 함.
  • 클라이언트가 폰을 제어하게 하기 위해서 C++에서 IsLocallyControlled 함수를 사용하거나 블루프린트에서 Is Locally Controlled 노드를 사용할 수 있음.

커스텀 폰 클래스의 생성자에 IsLocallyControlled를 사용할 경우 생성 도중 폰에 컨트롤러가 배정되지 않을 수 있으므로 주의할 것.

Relevance and Priority

  • Relevance는 멀티플레이어 게임 중 액터를 replicate할 필요가 있는지를 정하는 데에 사용.
  • 대역폭을 절약해 replicate되어야하는 액터들만 replicate되게 함.
  • 액터가 어떤 플레이어에 의해서도 소유되지 않고 어떤 플레이어 근처에도 있지 않다면 관련성이 없다고 판단되어 replicate되지 않음.
  • 관련성 없는 액터는 서버에는 계속 존재하며 authoritative game state에 영향을 끼칠 수 있지만 플레이어가 가까이 오지 않는한 클라이언트에 정보를 전달하지는 않음.
  • IsNetRelevantFor를 override하여 수동으로 관련성을 제어할 수 있으며, NetCullDistanceSquared를 통해 액터의 관련성과 연관 있는 거리를 결정할 수 있음.
  • 게임 플레이 도중 대역폭이 부족해 한 프레임에 관련성 있는 모든 액터를 replicate할 수 없는 경우가 있음.
  • 따라서 액터는 Priority 값을 가지며, replicate 우선권이 정해져있음.
  • 기본적으로 Pawn과 PlayerController의 NetPriority는 3.0이며, 이는 가장 우선적으로 replicate됨을 의미함. 일반적인 액터의 NetPriority는 1.0임.
  • 액터가 replicated되지 않을 때마다 priority가 늘어남.

Variable Replication

  • C++에서 UPROPERTY 매크로에 Replicated 나 ReplicateUsing 지정자를 사용하거나 블루프린트 디테일 패널에서 Replicated를 지정하여 변수와 오브젝트 레퍼런스에 replication을 추가할 수 있음.
  • authoritative 액터의 replicate 된 변수 값이 변할 때마다, 해당 정보가 자동으로 authoritative Actor로부터 섹션에 연결된 원격 복사본으로 전달됨.

RepNotifies

  • 액터가 특정 변수의 replicate된 정보를 성공적으로 전달받은 경우 호출되는 RepNotify 함수를 설정할 수 있음.
  • RepNotify는 어떤 변수가 업데이트되면 로컬에서만 작동해서 authoritative 액터의 변수 값 변경으로 인한 게임플레이 로직을 적은 오버헤드를 통해 작동시킴.
  • C++에서 ReplicatedUsing 지정자를 변수의 UPROPERTY 매크로에 지정하거나, 블루프린트에서 해당 변수의 replication 설정을 변경하여 RepNotify 기능을 사용할 수 있다.

RepNotify 기능은 RPC나 replicated function을 대상으로 사용하는 것이 적합하다. 다른 게임플레이 기능과 상관없이 replicate되어야 하는 변수에 추가되어 추가적인 네트워크 호출에 따르는 상당한 양의 대역폭을 아낄 수 있기 때문이다.

Remote Procedure Calls(RPCs)

  • RPC는 replicate된 함수이며, 어떤 머신에서든 호출될 수 있지만 네트워크 세션에 연결된 특정 머신에서만 실행된다.
  • RPC의 종류
RPC 종류설명
Server서버에서만 호출됨
Client함수가 속해있는 액터를 소유한 클라이언트에서 호출됨. 액터에 연결된 커넥션이 없다면 로직은 실행되지 않음.
NetMulticast서버 및 서버에 연결된 모든 클라이언트에서 호출됨
  • 블루프린트의 이벤트와 함수는 디테일 패널의 Replicates 드롭다운 메뉴에서 위의 세 종류 중 하나를 선택할 수 있다.

  • C++의 함수는 UFUNCTION 매크로에 Server, Client, NetMulticast 지정자를 포함시켜 설정할 수 있다. 실제 구현 시에는 _Implementation 접미사를 붙여 구현한다.

  • 함수를 RPC로 설정하면 게임플레이 로직을 부여할 수 있고 다른 함수들처럼 호출할 수 있다.

Reliablity

  • RPC는 reliable 또는 unreliable 둘 중 하나로 설정해야 한다.
  • 블루프린트에서 함수와 이벤트는 기본적으로 unreliable로 설정되어 있다. 디테일 패널에서 Reliable 항목에서 해당 함수를 reliable로 설정할 수 있다.
  • C++에서는 UFUNCTION 매크로의 RPC 종류 지정자와 더불어 Reliable 또는 Unreliable 지정자를 추가해 설정할 수 있다.
  • Unreliable RPC는 의도된 머신에 전달되지 않을 가능성이 있지만 reliable RPC보다 더 빨리, 자주 전송된다. 게임플레이에 치명적이지 않거나 자주 호출되는 함수에 적합하다. 액터 움직임의 경우 매 프레임마다 변하므로 unreliable RPC를 사용한다.
  • Reliable RPC는 의도된 머신에 전달되도록 보장되며, 수신 성공될 때까지 큐에 남아있는다. 게임플레이에 치명적인 함수에 적합하지만 자주 호출되지는 않는다. 콜리젼, 무기 발사의 시작과 끝, 액터 스폰 등에 사용된다.

Reliable 함수를 너무 많이 사용하면 큐에서 오버플로우가 일어날 수 있다. 이는 강제 종료로 이어진다. replicated 함수를 프레임마다 호출하려고 한다면 unreliable로 설정해야 한다. 플레이어 입력에 따라 호출되는 reliable 함수가 있다면, 호출할 수 있는 빈도를 제한해야 한다.

Validation

  • WithValidation 지정자는 함수의 구현에 더해 함수 호출 데이터를 검증하는 함수가 추가된다는 것을 나타낸다.
  • 검증 함수는 검증되는 함수와 같은 signature(매개변수 리스트)를 가지지만 원래 리턴값 대신 boolean 값을 리턴한다.
  • true를 리턴한다면 RPC의 _Implementation 함수가 실행되고, false를 리턴하면 실행되지 않는다.

Tips and Further Reading

Basic Replicated Actor Checklist

  • replicate된 액터를 생성하기 위한 단계
  1. 액터의 Replicated 항목을 True로 설정할 것
  2. replicate된 액터가 움직여야 한다면, Replicates Movement 항목을 True로 설정할 것
  3. 머신들간에 공유되어야 하는 변수를 설정할 것. 주로 게임플레이에 필수적인 변수들이 해당됨.
  4. 언리얼엔진에 미리 만들어져있는 Movement Component들은 이미 replication을 위해 빌드되었으므로 되도록이면 해당 Component들을 사용할 것
  5. server-authoritative 모델을 사용하고 있다면, 플레이어가 수행할 수 있는 새로운 액션은 서버에 있는 함수가 실행하도록 만들 것.

Networking Tips

  • 가능한한 RPC나 replicate된 Blueprint를 적게 사용할 것. RepNotify로 대신할 수 있다면 반드시 대신할 것.
  • 멀티캐스트 함수는 연결된 클라이언트마다 추가적인 네트워크 트래픽을 발생시키므로 최대한 적게 사용할 것.
  • replicate되지 않은 함수가 서버에서만 작동되는 것이 확실하다면 서버에만 적용되는 로직을 서버 RPC에 넣을 필요는 없음.
  • reliable RPC를 플레이어 입력에 바인드할 때는 조심해야 함. 플레이어들은 버튼을 매우 빠르게 반복해서 누를 수 있고, reliable RPC 큐의 오버플로우를 낳을 수 있음. 플레이어들의 RPC 빈도를 제한해야 함.
  • 게임이 RPC나 replicate된 함수를 매우 자주 호출한다면(Tick처럼), Unreliable로 설정해야 함.
  • 어떤 함수는 게임플레이 로직에 대응해서 호출한 뒤 RepNotify에 대응하게 다시 호출하여 클라이언트와 서버가 병렬 실행되게 할 수 있음.
  • 액터의 네트워크 역할이 ROLE_Authority인지 체크하여 서버와 클라이언트 모두에서 실행되는 함수에서 실행을 필터링하는 데에 사용할 수 있음.
  • C++의 IsLocallyControlled 함수를 통해 폰이 로컬에서 컨트롤되는지 알 수 있음. 소유하는 클라이언트에 따라 실행을 필터링하는데에 유용함.
  • 폰이 생성되는 도중에는 컨트롤러가 배정되지 않았을 수 있으므로 생성자에서 IsLocallyControlled를 사용하지 말 것.
profile
Daily Struggling

0개의 댓글