숫자야구 게임 만드는 과제가 있었다. 그 중에 필수는 다 해서 지금껏 배운 핵심 내용을 정리하려고 한다.
만들기 전에 RPC, Replication, 언리얼 엔진의 각 프레임워크가
멀티 플레이 게임에서는 각 Class가 어떤 인스턴스에 존재하는 지를 알고 만들면 좋다.
그래서 언리얼 온라인 강의에 그런 내용을 공부 후에 만들었다.
마주친 문제들이 많았는데 그 중 기억에 남는 것을 정리했다.
RepNotify, ActorReplication, RPCs를 알고 있다는 가정하에 글을 썼다.
참고로 리슨 서버로 빌드를 하였으며 총 플레이어 수는 2명으로 만들었다.
원래는 OnLoginWithId 이벤트 하나에서 UserId 설정과 그 설정한 UserId를 UI에 텍스트 박스 안에 텍스트로 넣으려고 On User Login이라는 디스패쳐에 연결을 했었다.
그러다 UserId가 Guest 클라이언트에서는 UI에 설정되지 않는 문제가 있었다.
생각해보니 로그인 시 각자 UI에 띄워지는 UserId는 달라야 하니까
서버에서 1번만 실행되는 게 아니라 각자 클라이언트의 UI에 UserId가 띄워져야 했다.
그래서 On User Login 부분과 UserId를 설정하는 부분을 나누었다.
On Login With Id
는 클라이언트 RPC로 만들어 플레이어 컨트롤러 블루프린트에서 연결.
Set UserId
는 서버 RPC로 만들어 플레이어 컨트롤러 블루프린트에서 연결했다.
로그인 후 실행되는 노드들을 보면 플레이어 스테이트에서 UserId를 가져와서
On User Login 이라는 이벤트 디스패쳐를 호출할때 그 값을 인자로 넘겨준다.
일단 RepNotify보다 ActorReplication 방식을 사용하였다.
왜냐하면 구현을 더 빠르게 할 수 있을거라 생각해서 그 방식을 사용했고
RepNotify를 쓴다면 정확한 시점에 클라이언트에 서버값이 리플리케이트 된 후
이후에 원하는 이벤트를 동작하게끔 할 수 있다. 그래서, 나중에는 RepNotify로 바꿀 것이다.
정리하면, ActorReplication은 값만 보내는 것, RepNotify는 값 보내고
뭔가 후처리할 일이 있을 때 쓴다!
UPROPERTY(Replicated, EditAnywhere, BlueprintReadWrite, Category = "Game")
FString UserId; // 각 플레이어 별 아이디
위는 PlayerState의 UserId 변수를 설정한 부분이다.
UserId는 플레이어 별로 각각 가지고 있어야 되는 정보라 생각해 게임 스테이트나 게임 모드보다는 플레이어 스테이트 클래스에 넣어주었다. 아래 사진을 보면 더 이해가 잘 될 것이다.
Replication이란 서버에서 그 객체를 가지고 있는 클라이언트에 동기화해주는 것을 말한다.
그러니까 서버와 클라이언트가 모두 있는 플레이어 스테이트가 플레이어 별로 다른 정보(이름 같은 거)를 저장하기에 가장 적합한 프레임워크라 생각했다.
앞서 말한 리플리케이션은 서버로부터 값을 받아 클라이언트에 동기화해주는 것이기 때문에
플레이어 컨트롤러의 OnUserLoginWithId
가 호출되는 시점에 플레이어 스테이트의 UserId값이 서버와 동기화가 안될 수 있다. 왜냐하면 리플리케이션을 할 때는 약간의 지연시간이 있기 때문이다.
OnUserLoginWithId
는 소유중인 클라이언트에서만 실행되는 클라이언트 RPC다.
그렇기에 그 뒤 노드에서 플레이어 스테이트의 UserId를 가져와 쓰는 부분이 있는데
거기서 리플리케이션에 지연이 걸리면 클라이언트에서 UserId가 동기화되기도 전에
가져와 버려서 없는값을 마지막 노드로 넘겨버리게 되는 것이다.
그래서!! Replication이 되는 시간을 기다리기 위해 딜레이 노드를 넣은 것이다!
그리고 이런 딜레이 노드를 쓰지 않기 위해서 나중에 꼭 RepNotify 방식으로 바꿀 것이다.
리플리케이션이란 개념을 숫자야구 게임을 만들어보며 실제로 적용해보며 어떤 개념인지 좀 더 파악할 수 있었고 리플리케이션을 할 변수가 있다면 언리얼 프레임워크 중 어떤 클래스에 넣는게 좋을지 생각해보는게 중요하다는 것도 깨달았다. 예를 들어, 모든 플레이어가 동시에 알아야 될 정보 같은 경우(채팅, 데미지 등)는 서버에 게임 스테이트 인스턴스 하나에서
그 게임 스테이트를 가지고 있는 모든 클라이언트에게 멀티캐스트나 리플리케이션으로
그 정보를 퍼뜨리는 것이다!