자기개발/UE5

[UE5] 3. RPC를 공부하며..

KGW2027 2023. 2. 24. 22:15
728x90
반응형

 - 저는 UE를 공부중인 학생이며, 복습의 목적으로 작성한 글이므로 틀린 내용이 있을 수 있습니다. 틀린 내용이 있을 시 댓글로 작성해주시면 찾아보고 반영하겠습니다.


 RPC는 Remote Procedure Control의 약자로 Client-Server 모델에서 통신을 위해 사용되는 기술?이다.

멀티플레이어 게임을 만들면 보통 CSM을 이용하게 되는데,

이 경우 서버(Dedicated Server, Listen Server)와 클라이언트(User)간의 데이터 검증이 중요하게 작용한다.

서버에 대해 부연 설명을 하자면, 마인크래프트를 예시로 들었을 때,
Bukkit등을 이용해 CLI같은 곳에서 콘솔만 주구장창 뜨는 화면이 서버 역할을 하면 Dedicated
LAN 서버 열기하면 플레이어가 호스트가 되서, 그 사람이 나가면 종료되는 그런게 Listen이다.

 

 데이터 검증의 예시를 들기 위해 문을 여는 상황을 가정해보자.

 

 

 문은 닫혀있고, Client 1과 Client 2는 문을 바라보고 있다. 이 상황에서 Client 1이 이 문을 열었다고 해보자.

만약 데이터 복제 및 검증이 없다면 상황은 이렇게 될 것이다.

 

 

Client 1은 문을 열었기 때문에 안으로 들어갔지만,

Client 2는 문을 열지 않은 것으로 보고 있기 때문에 지나가지 못하고,

Server도 Client 1과 문이 겹쳐진 상태라고 생각할 것이다.

 

 만약 RPG게임을 하는데 다른 유저가 열리지도 않은 문을 뚫고 지나가고 있다면,

보통 비-정상적인 플레이를 하고 있다고 의심하게 될 것이다. (사실은 그저 통신이 안되고 있을 뿐임에도)

그래서 이런 부분을 없애고 Server와 Client들이 모두 최대한 동일한 환경에서 플레이하게 만들려면 데이터 통신, 검증이 필요하고, 이 기능을 개발자에게 좀더 편하게 사용할 수 있게 해주는 것이 RPC다.

※ 잡설1. 핑차이가 있기 때문에, '완벽하게' 동일한 환경은 만들기 어렵다.

※ 잡설2. RPC는 게임환경에서만 사용되는게 아니라, Local-Remote 통신에서 많이 쓰이는 것으로 알고있다.

 


UE에서는 이러한 데이터 검증을 위해 Actor에 Replicate라는 속성을 이용해 자동으로 클라이언트에게 서버의 상태를 복제해주는 기능이 존재한다.

일반적으로 위의 상황에서 Client 1이 문을 연 것을 모두가 공유하려면 다음과 같은 과정을 거친다.

 '(Client 1)문 열기 요청 -> (Server) 유효성 검증 -> (Server) 문 열기 Multicast -> (Clients) 문 열기 함수 작동'

만약, 이 문의 Replicate 속성이 켜져있다면, Multicast부분을 직접 만들 필요 없이, 엔진에서 서버의 값을 클라이언트들에게 복제해준다.

여기서 주의해야할 점은, Client와 Server가 동일한 오브젝트를 가지고 있어야 Replicate가 실행된다는 점이다.

일반적으로 이런 상태를 복제할 때에는 문제가 발생하지 않지만, 변수등을 복제할 때 실수로 문제가 발생할 수 있다.

 

 

 변수의 복제에 대해 알기 위해 다시 위의 문 그림을 가져와서 살펴보자.

문이 열리고 닫히는 것을 클라이언트와 서버가 공유하기 위해 문의 Replicate Movement 속성을 켜놨다.

그러면 Client 1이 문을 열때 Client 2도 문이 열리는 것을 볼 수 있고, 그 반대도 볼 수 있다.

그렇다면 만약 Client 1이 문을 열고, Client 2가 문을 닫으려고 한다면 어떻게 해야 할까?

Client 1과 Client 2가 공유하는 문의 상태를 나타내는 변수가 있어야 할 것이고, 이 변수를 복제해야 할 것이다.

복제하지 않으면 어떻게 될까?
 
 Client 1이 문을 열면 게임의 상태는 이렇다.
 [Client 1] 문 : 열린 상태, IsOpen : true
 [Client 2] 문 : 열린 상태, IsOpen : false
 
 이 상태에서 Client 2가 문을 닫으려 하면
 IsOpen이 false->true가 되면서 문이 다시 열리게 되고,
 한 번 더 눌러야 문이 닫히게 된다.

 

 변수를 복제하게 만드는 방법은 정말 간단하다.

블루프린트라면 변수의 속성에서 Replication을 None->Replicated로 변경하면 되고,

C++라면 UPROPERTY 안에 Replicated를 넣으면 된다.

그리고 주의할 점은 하위 속성을 복제하기 위해서는 상위 속성도 반드시 복제를 수행해야한다는 부분인데,

변수에 Replicated를 설정해놓아도, 그 변수를 가진 액터가 Replicated 되어있지 않다면, 복제가 일어나지 않는다.

 


 변수를 복제하는 방법을 알았으니 이제 문을 열고 닫는 시스템을 멀티 플레이어 게임에 추가할 수 있겠다!

라고 생각했다면 아쉽지만 거지같은 부분이 하나 남았다.

바로 복제는 Server->Client로만 발생한다는 점이다. 즉, 특정 Client->Server->전체 Client로 복제하기 위해서는 Client->Server 로 RPC하는 코드를 구현해야한다는 것이다.

이 부분만 있다면 그나마 괜찮았겠지만 여기에 더 귀찮은 점이 하나가 더 있는데,

바로 Actor Ownership에 따른 RPC의 작동방식이다.

 

 

 자 우리가 봐야할 점은, 아래의 RPC invoked from a client에서 Server 부분이다.

만약 문과 같이 Owner가 없거나(Unowned actor), 다른 클라이언트 혹은 서버가 소유한 액터에서

Server RPC를 실행하면 Drop해버린다.

이로 인해, 그냥 액터에서 Server RPC를 바로 실행해버렸다면 이런 에러를 만나게 된다.

UNetDriver::ProcessRemoteFunction: No owning connection for actor [Actor Name]. Function [ServerRPC] will not be processed.

 

 그래서 Actor에서 SetOwner를 실행해 클라이언트가 해당 Actor를 소유하게 하고 실행하면 작동할까? 라는 생각을 했지만, 잘 작동하지도 않았을 뿐더러 Owner를 설정하고 해제하는 것에도 오버헤드가 발생하므로 별로 좋지 않아보였다.

그렇게 사용하게 된 방법은 PlayerController 내지 Player를 Router로 사용하는 것이다.

예시를 들자면

 

' (Client 1) 문 열기 요청 -> (Client 1 Player) [ServerRPC] 문 열기 함수 실행 -> (Server Player(C1)) 문 열기 -> (Server) 문 열림 -> (Multicast) 문이 열리는 상태가 복제됨'

이런 방식으로, 문 열기를 요청한 플레이어에 다시 문 변수를 보내 ServerRPC를 실행하는 방식이다.

(이외에 더 좋은 방법이 있다면 알고싶다...)

 


그렇게 문을 여는 코드를 만들었다면 이렇게 작동한다.

이렇게 클라이언트에 복제되는 모든 액터 동작은 서버에서 복제되므로,

최대한 월드에 변화를 주는(모든 클라이언트에게 무결성이 보장되어야하는) 것들은 Server에서 처리하게 하는 것이 좋다.

 

 싱글플레이어 게임만 염두에 두고 있다면 이런 과정을 거칠 필요 없이 Client단에서만 실행되게하면 되고, 그게 편하지만.

그렇게 짠 게임을 나중에 멀티플레이어로 만들고 싶어진다면, 모든 코드를 이런 방식으로 뜯어고쳐야하므로...

싱글 플레이 게임도 Listen Server에서 1명의 Player(= Server)가 플레이한다고 생각하고 만드는게 좋은 것 같다.

 


 RPC는 할때마다 Actor Ownership 때문에 어디서 RPC가 드롭되버린다거나,

어디 Replicated설정이 안되어있어서 변수가 복제가 안되고 있다던가 하는

사소한 이슈들때문에 할때마다 머리가 아파져서 아는 내용을 정리해보자는 생각으로 작성한 것인데

이 Actor->Player->ServerPlayer->ServerActor->Actor의 구조가 너무 길어서

Actor->ServerActor->Actor로 줄이고 싶다는 생각이 마구마구 든다..

하지만 방법을 모르겠

 

728x90
반응형

'자기개발 > UE5' 카테고리의 다른 글

[UE5.1] 위젯과 ChatGPT  (0) 2023.02.22
[UE5] 2. Mesh Outline  (0) 2023.02.07
[UE5] 1. 돌 캐기  (0) 2023.01.12