[UE4] UE4 Network Compendium Pt.1
Network in Unreal
언리얼엔진4는 기본적으로 Server-Client 구조를 사용한다.
이 것이 무엇을 의미하냐면, Server는 관리자이며 모든 데이터는 Client에서 Server로 전송되어야 하며
서버는 코드에 따라서 데이터와 반응을 입증한다.
예를 들어 Miltiplayer Match에서 Player가 Client에서 Character를 이동시키고자 할 때, 실제로 Player가 Character를 이동시키는 것이 아니라 Server에게 이동하고 싶다고 전달을 한 뒤 서버는 캐릭터의 Location을 Update 시켜주는 것이다.
추가로 Local Client의 lag을 방지하기 위해선 Coder들은 종종 Player가 직접 Character를 Local에서 이동시키게 해준다.
만약 Client가 Cheating을 시도하더라도 Server는 Character의 Location을 덮어쓸 수 있다.
이는 Client 끼리는 절대 직접적으로 통신하지 않는다는 것을 의미한다.
마지막으로 절대로 Client 를 신뢰해선 안되며, Client 작업을 실행하기 전 테스트 하지 않는 것은 Cheat를 유발할 수 있다.
예를 들면 Client상에서 Ammo가 충분하여 발사한다고 할 때 바로 Shoot을 허용하지 않고 Server를 통해 Shoot이 가능한 상태인지 확인하여 확실하게 검사를 해봐야 한다.
Framework & Network
앞서 설명한 UE4의 Server-Client 구조를 4개로 분리할 수 있다.
- Server Only : Objects들이 서버에만 존재.
- Server & Client : Object들이 서버와 모든 클라이언트에 존재.
- Server & Owning Client : Object들이 서버와 자신의(Local) Client에 존재.
- Owning Client Only : 오직 Client에만 존재.
여기서 Owning Client란 Actor를 지니고있는 Player Client를 말하며, Ownership은 후의 "RPCs" 부분에서 중요한 키워드가 된다.
위 그림은 Network Freamwrok 내에 Dedicated Server와 2개의 클라이언트 사이
Class Object들이 어떻게 분배되어 있는지를 나타내는 예시도이다.
Client1과 Client2 사이에는 그 어떤 교차 Object가 없다는 걸 볼 수 있다.
이는 실제로 개별의 Client가 자신만 알고있는 object들에 대해 Client끼리 공유하지 않고있기 때문이다.
Game Mode
UE 4.14 버전부터 GameMode Class는 GameModeBase와 GameMode 두개로 나뉘었다.
몇몇 게임들은 기존의 GameMode가 지니고있는 모든 feature가 다 필요하지는 않기 때문에 GameModeBase는 지니고있는 feature가 적다.
- AGameMode Class
게임의 Rule을 정의할때 사용.
Apawn, PlayerController, AplayerState 등의 class를 include 하고있다.
Server에서만 사용 가능하며, Client들은 GameMode Object가 존재하지 않고 접근을 시도하면 nullptr을 받게된다.
Deathmatch, Capture the Flag 등 Mode를 구성하기 위한 요소로 잘 알려져있다.
- BluePrint
- 게임에 알맞는 세부적인 Rule을 정하여 수행할 수 있도록 하는 Override Function이 존재한다.
이는 GameMode가 DefaultPawn을 Spawn하는 방식을 수정하거나, 어느 조건에 게임을 시작할 것인지를 정하기 위한 Ready to Start Function 등이 있다. - 또 Match 도중 발생하는 특수한 상황들에 대해 반응하기 위해 사용할 수 있는 Event 기능이 존재한다.
대표적인 예로는 Event OnPostLogin이 있는데 이는 Player가 Game에 입장할 때마다 매번 호출되는 함수로, 이 Event는 접속한 Player에게 자신의 PlayerController를 건네주는 역할을 수행한다. - 이러한 함수들을 override 하여 사용함으로써 GameMode를 통해 Match Flow를 관리가 가능하며
함수들은 대부분 'Ready to..' 함수의 반환값이 TRUE일 때 자동적으로 call되지만, 수동적인 사용도 가능하다. - 이런 부분들을 GameState Class가 관리하지 않는 이유는 사실 GameMode의 function들은 GameState와 밀접하게 연관되어 작동하고 있으며 GameMode는 서버에만 존재하기 때문에 Client와 떨어져있는 State를 관리하기 위한 Point를 주기 위함이다
- 모든 BluePrint는 C++를 통해서도 수행이 가능하다.
- 게임에 알맞는 세부적인 Rule을 정하여 수행할 수 있도록 하는 Override Function이 존재한다.
Game State
UE 4.14 버전부터 GameState Class는 AGameStateBase와 AGameState 두개로 나뉘었으며,
GameMode와 같은 이유로 GameStateBase는 적은 feature를 지니고 있다.
- AGameState
Server와 Client 사이 정보 공유를 위한 가장 중요한 class.
GameState는 PlayerStates를 포함한 Game의 Current State를 추적하기 위해 사용되며 멀티플레이어의 경우 연결된 Player List (APlayerState)를 포함한다. (예를 들면 팀 승리를 위한 Total Kill이 있을 때, 각 Player의 Kill 수를 추적한다.)
GameState는 모든 Client에 복제되어 모두가 접근할 수 있으며, 이는 GameState를 멀티플레이어 게임을 위한 가장 중심적인 클래스 중 하나로 만든다.
GameMode는 GameState의 Match State 함수가 호출되고 GameState가 클라이언트에서도 사용될 수 있는지를 확인한다.
GameMode와 비교하여 GameState는 많은 작업을 제공하지 않지만, 여전히 Client에게 정보를 전파할 수 있도록 하는 Logic을 생성할 수 있게 해준다.
위의 사진은 기본 GaseState Class의 변수들이다.
PlayerArray, MatchState, ElapsedTime은 복제되어 Client들이 접근이 가능하지만, AuthorityGameMode는 그렇지 않다.
이유는 GameMode가 Server에만 존재하기 때문에 Server만이 접근 가능하기 때문이다.
*PlayerArray는 직접적으로 복사되진 않지만, 모든 PlayerState는 스스로 PlayerArrayon 구성에 추가되고 GameState는 생성되었을 때(PostInitializeComponents) 그것을 한 번 수집해준다.
Player State
APlayerState Class = 특정 Player에게 가장 중요한 class
Player에 관한 현재 정보를 지니고 있다.
각 Player는 PlayerState를 지니고 있으며, PlayerState 또한 모두에게 복제되어 다른 Client의 정보를 가져오거나, 출력할 때 사용된다.
모든 PlayerState에게 접근할 수 있는 가장 쉬운 방법은 GameState Class 내부에 있는 PlayerArray를 통하는 것이다.
사용처
Multiplayer 게임에서 PlayerState는 접속된 Player의 State를 지니고 있다.
이는 Name, Score, Ping 등 다양한 사용자 변수를 포함하고 있으며 Player State가 복제되었기 때문에 Client에서 다른 Client의 정보를 쉽게 얻을 수 있게 된다.
또한 PlayerState는 데이터가 Level Change나 예상치 못한 Connection Issue가 발생해도 꾸준히 존재할 수 있도록 만들어준다.
PlayerState는 재접속 Player나 새로운 맵으로 이동한 Player를 위한 두개의 함수가 존재한다.
(CopeyProperties, OverrideWith)
CopeyProperties = 현재 Player State를 새로운 PlayerState에 복사. traveling에 사용.
OverrideWith = 이전 PlayerState를 현재 PlayerState에 덮어씌움. 재접속 시에 사용.
Pawn
APawn Class = Player가 실제로 조종하는 Actor.
Player는 한번에 한 Pawn만 소유할 수 있지만, 손쉽게 소유해제나 재소유 등이 가능하다.
Pawn은 대부분 모든 Client에 복제된다.
Pawn의 Child Class인 ACharacter는 Player Character의 Position, Rotation 등을 관리하는 MovementComponent가 존재하여 주로 사용된다.
사용처
Multiplayer에서 대부분 Character를 출력하고 다른것들과 정보를 공유하기 위해 Pawn의 Replication을 사용한다.
대표적인 예로 Character의 Health와 같은 부분인데, 단지 출력을 위해 Replicate 하는 것이 아닌 서버에서도 권한을 갖고 Client의 Cheat를 방지하기 위해서 Replicate 해주게 된다.
Pawn은 소유 및 비소유에 관한 두가지 함수가 존재하며 (Unpossessed, Possessed), Unpossessed의 사용 예로는 소유가 해제되었을 때 Pawn을 숨기기 위해서 사용되기도 한다.
이런 Possessing과 같은 것들은 Server에서 일어나기 때문에, 이러한 이벤트들 또한 Server에서만 호출된다.
두번째 예로는 계정의 Health를 활용하는 예이다.
위 사진은 'EventAnyDamage"와 Replicate된 'Health'를 사용하여 Player의 health를 낮추는 사진이다.
이는 Client가 아닌 Server에서 발생한다.
Pawn이 Replicate 되었기 때문에 'DestroyActor'를 Server가 호출하게 된다면 Client Version의 Actor는 파괴 될 것이고,
Client는 HUD나 HealthBar를 위해 Replicated Health를 활용할 수 있을 것이다.
(Pawn의 Reference인 HUD나 HealthBar는 Progressbar와 같은 Widget을 통해 만들 수 있다.)