내일배움캠프 73일차 - 언리얼 엔진 C++ 멀티플레이어: NetMode, NetConnection, NetDriver, NetRole

NetMode

해당 게임 프로세스가 네트워크 상에서 어떤 역할을 하고 있는 지를 의미한다.

 - 싱글(NM_StandAlone)
 : 게임이 원격 클라이언트의 연결을 허용하지 않는 서버로 실행 중.
 : 즉, 커넥션이 없음. 게임에 참여하는 모든 플레이어는 로컬 플레이어다.
 : 이 모드는 싱글 플레이 및 로컬 플레이 게임에 사용된다.
 : 로컬 플레이어에 맞게 서버 측 로직과 클라이언트측 로직을 모두 실행한다.

 - 서버(NM_Listen, NM_DedicatedServer)
 └ Listen Server
       : 게임이 네트워크 멀티플레이어 세션을 호스팅 하는 서버로 실행 중.
       : 원격 클라이언트의 연결을 수락하고 로컬 플레이어를 서버에 직접 배치한다.
       → 즉, 서버 자기 자신도 게임에 직접 참여한다는 뜻.
       : 이 모드는 캐주얼 협동 및 경쟁 멀티플레이어에 자주 사용된다.

 └ Dedicated Server
       : 게임이 네트워크 멀티플레이 세션을 호스팅 하는 서버로 실행된다.
       : 원격 클라이언트의 연결을 허용하지만 로컬 플레이어가 없음.
       → 따라서 그래픽, 사운드, 입력 및 기타 플레이어 중심 기능이 필요없으므로 삭제된다.
       : 이 모드는 지속적이고 안전한 대규모 멀티플레이어가 필요한 게임에 주로 사용된다.

 - 클라이언트(NM_Client)
 : 게임이 네트워크 멀티플레이 세션에서 서버에 연결된 클라이언트로 실행된다.
 : 서버 측 로직을 실행하지 않는다. 서버로부터 복제된 Proxy를 보여주는 역할.

멀티플레이 개발 시에 같은 코드가 여러 PC(내 클라이언트, 다른 클라이언트, 서버)에서 동작할 수 있는데, 어디서 해당 코드가 실행되는지 디버깅하기 위해 NetMode가 필요하다.

Q) 대미지를 입어서 HP가 줄어드는 로직을 어느 컴퓨터에서 처리해야할까?

 - 클라이언트 컴퓨터에서 한다면 해킹에 취약해진다. 온라인 게임 핵은 서버와 클라이언트가 주고 받는 패킷을 WireShark 등으로 가로채 분석하고 대미지인 것 같은 패킷을 찾아 수치를 조작해서 서버로 보내는 방식이기 때문이다.

 - 때문에 해킹 방지를 위해서, 대미지 처리 로직은 서버 컴퓨터에서만 처리해야 한다. 그럼 적어도 대미지 값이 패킷에 담기지 않는다.


NetMode의 기준

NetMode는 NetDriver의 유무나 NetConnection등 여러 관계에 의해 결정된다.
이 둘은 NetMode뿐만 아니라 NetRole에 관해서도 깊게 연관되어있다.

※ NetDriver가 nullptr이라면 NetMode는 NM_StandAlone일 가능성이 높고, 그렇지 않다면 멀티플레이를 할 수 있으므로 서버(NM_Listen / NM_DedicatedServer) 혹은 NM_Client일 것이다.

※ 클라이언트는 항상 ServerConnection을 가지고있다. (≠nullptr)
 : nullptr이면 서버라는 뜻

NetMode에 따른 액터 위치

서버에만 존재하는 액터
 : 게임 모드

서버와 모든 클라이언트에 존재하는 액터
 : 배경 액터
 : 폰
 : 애니메이션 블루프린트

서버와 내 클라이언트에만 존재하는 액터
 : 플레이어 컨트롤러

각 클라이언트에만 존재하는 언리얼 오브젝트
 : UI

Q) 클라이언트에서 GetGameMode() 함수를 호출할 수 있는가?

클라이언트에는 게임 모드 액터가 없으므로 nullptr이다.

만약에 게임 모드에 접근하려면 Server RPC 함수 내에서 접근하거나, 서버에서도 수행되는 함수 내에서 HasAuthority() 함수로 서버임을 확인하고 접근해야 한다.

NetConnection

다른 PC와의 연결이 발생하면 그에 대응하는 UNetConnection 객체도 함께 생성된다.
UNetDriver는 생성된 UNetConnection 객체를 소유하고 관리한다.

 - 서버에는 ClientConnection 객체가 생성된다.
 : 서버의 UNetDriver는 접속한 클라이언트의 수 만큼 ClinetConnection을 관리한다.

 - 클라이언트에는 ServerConnection 객체가 생성된다.
 : 클라이언트의 UNetDrvier는 ServerConnection 단 하나만을 관리한다.

 - 두 PC는 각자 보유한 UNetConnection 객체를 통해 통신하게 된다.

클라이언트가 보유하는 ServerConnection은 단일 개체.
서버가 보유하는 ClientConnections은 배열 개체다.

언리얼에서의 Ownership

 - 하나의 ClientConnection은 하나의 PlayerController를 소유한다.

 : 즉, PlayerController의 Owning Connection은 ClientConnection인 셈이다.

 - PlayerController가 폰에 빙의할 때, 폰의 Owner는 해당 PlayerController로 설정된다.
 : 폰에 무기 액터 등이 생성되고, 무기 액터의 Owner 속성에 해당 폰을 설정할 수도 있다.

 - 이러한 소유관계를 Ownership이라고 하며, ClientConnection에서부터 무기 액터에 이르는 소유 관계를 패밀리라고도 부른다.

 - 소유 관계 속에 있는 액터가 본인의 Owning Connection을 얻으려면 AActor::GetNetConnection()함수를 호출하면 된다.

 - 이 소유 관계가 RPC와 Property Replication과 관련이 있다.

NetDriver

 - 언리얼 네트워크 통신에서 로우레벨 동작들을 관리하는 클래스다.
 : 그래픽 연산을 위해 그래픽 드라이버를 설치하듯이, 멀티플레이 위해 NetDriver를 설치하는 것이다.

 - 싱글 플레이에서는 UNetDriver가 생성되지 않는다. (멀티플레이x)

 - 멀티 플레이에서만 UWorld::Listen() 함수를 통해 UNetDriver 객체가 생성된다.

 - 멀티 플레이에 참여하는 각 PC마다 UNetDriver 객체가 생성된다.

NetRole

게임에 중대한 영향을 끼치는 로직은 서버에서 처리해야 한다.

NetMode는 서버 PC의 월드인지, 클라이언트 PC의 월드인지를 파악해서 현재 로직이 둘 중 어디서 도는지 알 수 있다.

하지만 로직은 일반적으로 월드 자체가 아닌 액터, 컴포넌트 등에서 작성하기 때문에 그 액터가 서버PC에 스폰되어있는지, 클라이언트 PC에 스폰되어있는지 확인해야 하는데, 이때 활용되는 것이 NetRole이다.

Authority와 Proxy

서버에 스폰된 액터가 가진 NetRole의 속성 값은 언제나 Authority(권한)이다.
즉, 서버 액터는 '권한'을 가지므로 중요한 로직은 NetRole이 Authority일때 수행해야 한다.

반대로 클라이언트에 복제된 액터의 NetRole 속성값은 Proxy(허상)이다.
NetRole이 Proxy일때는 중요한 로직은 수행하면 안된다.

로컬 롤, 리모트 롤

액터 옆 글씨들 중 위(로컬 롤), 아래(리모트 롤).

내 컴퓨터의 NetRole을 로컬 롤(Local Role), NetConnection으로 연결된 상대 컴퓨터의 NetRole을 리모트 롤(Remote Role)이라고 한다.

위 롤들은 액터가 어떤 컴퓨터에서 스폰되고 동작하는지 구분해준다.

NetRole의 종류

None
 : 일반적으로, 레플리케이션 되지 않는 액터를 뜻한다. (다만 무조건적이지 않음)
 ex) LocalRole은 Authority이고 RemoteRole이 None이라면, 서버에서 스폰되고, 클라쪽으로 레플리케이션 되지 않는 액터라고 볼 수 있다.

Authority
 : 게임에 중대한 영향을 끼칠 수 있는 권한을 가진 액터.
 : 서버에서 스폰되는 액터가 LocalRole으로 Authority를 가질 수 있다.
 ex) GameMode

Proxy (Autonomous) - 위 사진에서의 반실선
 : Authority 액터의 복제본.
 : 서버로부터 데이터를 수신&동기화 및 서버로 송신이 가능하다.
 ex) PlayerController

Proxy (Simulated) - 위 사진에서의 점선
 : Authority 액터의 복제본.
 : 서버로부터 데이터를 수신&동기화만 받는다.
 ex) 내 화면에 보이는 타인의 PlayerCharacter

각 PC별 Pawn의 NetRole: [로컬 롤 / 리모트 롤]

Pawn이 생성될 때 서버에서는 [로컬:Authority, 리모트:SimulatedProxy]로 생성 되었다가, 컨트롤러에 의해 빙의(Possessed)되면 [로컬:Authority, 리모트:AutonomousProxy]로 변경된다.

이는 빙의과정에서 Ownership이 설정되면서 컨트롤러가 ClientConnection를 소유, [ClientConnection, 폰,  컨트롤러]가 하나의 패밀리가 되었기 때문에 패밀리에 들어간 된 폰은 AutonomousProxy가 되는 것이다.

NetRole을 활용한 중요 함수

AActor::HasAuthority()
 : 서버 측 액터 판별 함수
 : 게임에 중대한 영향을 끼치는 대미지나 스폰 같은 로직은 위 함수로 판별, 서버 액터에서 실행한다.

AController::IsLocalController()
APawn::IsLocallyControlled()

 : 컨트롤러 빙의 액터 판별 함수
 : 입력 관련 로직이나 UI는 Autonomous Proxy에서 수행되어야 한다.
 : 컨트롤러가 있을 때 true를 반환하는 경우는 다음과 같다.
 - NetMode == NM_Standalone이다.
 - NetMode == NM_Client일때, 로컬 롤이 AutonomousProxy이다.
 - 로컬 롤이 Authority, 리모트 롤이 AutonomousProxy가 아니다. (리슨서버 방장 측 액터)

댓글

이 블로그의 인기 게시물

내일배움캠프 사전캠프 - 사전캠프설 연휴 커피 파밍 이벤트 작품 [ EXTREMITY ]

내일배움캠프 29일차 - 커리어데이 2일차 : 클라이언트 프로그래머로서 포트폴리오, 입사준비팁