언리얼 멀티 플레이 코드 설계

Woogle·2023년 5월 1일
0

언리얼 엔진 5

목록 보기
43/60

📄 서버-클라이언트 구조

  • 언리얼 엔진은 멀티플레이어 기능을 지원하기 위해 서버-클라이언트 아키텍처를 사용해 내장 네트워크 프레임워크를 제공한다.

  • 이를 잘 사용하기 위해서는 코드를 다음과 같이 분리해서 설계해야한다.

    • 서버에서만 동작하는 코드
    • 클라이언트에서만 동작하는 코드
    • 서버와 클라이언트 모두에서 동작하는 코드

🧠 서버 (Server)

대부분의 작업을 처리하고 중요한 결정을 담당한다.

1. 월드 생성 및 관리

  • 게임 모드에서 게임의 자체 인스턴스를 실행하여 연결된 모든 클라이언트 간에 공유되는 월드 역할을 담당한다.
  • 레벨은 언제든 변경 가능하며, 연결된 모든 클라이언트를 모두 자동으로 다른 레벨로 이동시킬 수도 있다. (Server Travel)

2. 클라이언트 참가 및 퇴장 처리

  • 클라이언트는 직접 IP 연결 또는 OSS(Online Subsystem)을 통해 서버에 참가 요청을 보낸다.
  • 서버가 요청을 수락하면 플레이어 컨트롤러를 클라이언트에 할당하고 GameMode의 PostLogin 함수가 호출되어 다른 클라이언트와 상호작용할 수 있게 된다.
  • 연결이 끊어지면 모든 클라이언트에게 알림을 요청하고 GameMode의 Logout 함수가 호출된다.

3. 모든 클라이언트가 알아야 하는 액터의 생성

  • 클라이언트에게 액터의 인스턴스를 생성(Spawn)하도록 지시할 수 있는 권한은 서버에만 있다.
  • 따라서 모든 클라이언트가 알아야하는 액터를 생성할 때는 서버에서 처리하는 것이 일반적이다.

4. 중요한 게임플레이 로직

  • 승패를 결정하거나, 클라이언트의 체력을 깎는 등의 중요한 로직은 서버에서 처리한다.

5. 변수 리플리케이션 처리

  • 리플리케이션이 필요한 변수는 서버에서 변경하여 모든 클라이언트의 값을 자동으로 업데이트한다. 부정행위를 방지하고, 모든 클라이언트가 동기화되도록 서버의 최신값으로 대체한다.

6. 클라이언트에서 RPC 처리

  • 서버는 클라이언트에서 보낸 RPC을 처리해야한다.


👥 클라이언트 (Client)

대부분의 액터에 대한 권한은 서버가 갖기 때문에, 작업은 서버에서 수행되고 클라이언트는 서버의 명령을 따른다.

1. 서버로부터 변수 리플리케이션 적용

  • 리플레케이션 된 변수의 값이 서버에서 변경되면, 클라이언트도 변경된 값을 적용한다.

2. 서버에서 RPC 처리

  • 클라이언트는 서버에서 전송한 RPC를 처리해야한다.

3. 시뮬레이션 시 움직임 예측

  • 클라이언트가 액터를 시뮬레이션할 때 액터의 속도를 기반으로 로컬에서 예측해야한다.

4. 클라이언트만 알아야 하는 액터 생성

  • 멀티 플레이 생존 게임의 크래프팅 시 미리보기용 액터 등

📄 동기화

  • 동기화의 주인공은 Actor이다.
  • Actor Replication을 활성화시키려면 BP의 디테일 탭에서 Replicates를 체크하거나 C++에서 AActor::SetReplicates(true)를 사용한다.

👯 리플리케이션 (Replication)

  • 변수를 Replication(복제)해서 업데이트를 전송해 서버와 클라이언트를 동기화하는 방법
  • 설정해놓으면 변수 값이 변경될 때마다 자동으로 Replicate 및 동기화된다.

✏️ Replicated

  • 변수를 단순히 Replicate(복제)만 하고 싶은 경우 사용하는 지정자
UPROPERTY(Replicated)
float Health = 100.f;

✏️ RepNotify

  • 변수가 업데이트될 때마다 함수를 호출하고 싶은 경우 사용하는 지정자
  • ReplicatingUsing 지정자에서 사용되는 함수는 UFUNCTION()으로 선언해야한다.
// 해당 변수를 업데이트할 때마다 On_Rep_Health 함수 호출
UPROPERTY(ReplicatedUsing=On_Rep_Health)	
float Health = 100.f;
void OnRep_Health()
{
   UpdateHUD();
}

⚡ RPC (Remote Procedure Call)

  • 로컬에서 호출하지만 (호출하는 장치와 다른) 원격 장치에서 실행되는 함수.
  • 서버가 클라이언트의 함수를 실행하거나, 클라이언트가 서버의 함수를 실행해 동기화한다.
  • 함수 구현 시 일반 함수와 다르게 _Implementation 버전만 구현해야한다.

✏️ Server RPC

  • 중요한 로직을 서버에서 실행하도록 만들어 보안을 강화하고 동기화시킬 때 사용
  • Server RPC를 실행하려면 액터 인스턴스를 가진 클라이언트에서 호출해야 한다.
UFUNCTION(Server, Relable, WithValidation)
void ServerRPCFunction(int32 InterParame, float FloatParam, AActor* ActorParam);
void ARPCTes::ServerRPCTest_Implementation(int32 IntegerParam, float FloatParam, AActor* ActorParm)
{
}

✏️ Multicast RPC

  • 모든 클라이언트에서 함수를 호출하도록 지시할 때 사용
  • 총알을 발사하는 캐릭터의 발사 애니메이션 재생 등
  • Multicast RPC를 실행하려면 Multicast RPC를 정의한 액터 인스턴스의 서버에서 호출해야 한다.
UFUNCTION(NetMulticast)
void MulticastRPCFunction(int32 InterParam, float FloatParam, AActor* ActorParam);
void ARPCTest: :MulticastRPCTest_Implementation(int32 Integer Param, float FloatParam, AActor* ActorParam)
{
}

✏️ Client RPC

  • RPC를 정의한 액터를 소유한 클라이언트에서만 함수를 실행 시 사용
  • 발사체를 맞았을 때 해당 클라이언트에서만 들리는 피격 사운드 등
  • Client RPC를 실행하려면 Client RPC를 정의한 액터 인스턴스의 서버에서 호출해야 한다.
UFUNCTION(NetMulticast)
void ClientRPCFunction(int32 Integer Param float FloatParam, AActor* ActorParam);
void ARPCTest::ClientRPCTest_Implementation(int32 IntegerParam, float FloatParam, AActor* ActorParam)

✏️ WithValidation

  • RPC를 정의할 때, RPC를 호출하기 전 입력이 잘못된 경우 RPC를 호출하지 않도록 하기 위한 추가 보안 옵션으로 사용할 수 있다.
  • WithValication 지정자를 사용하면 RPC 실행 여부를 나타내는 bool을 반환하는 함수의 _Validate 버전을 구현해야한다.
UFUNCTION(Server, WithValidation)
void ServerSetHealth(float NewHealth);
bool ARPCTest::ServerSetHealth_Validate(float NewHealth)
{
	return NewHealth <= MaxHealth;
}

✏️ Reliable

  • 원격 장치가 수신을 확일할 때까지 요청을 반복해 RPC가 실행됐는지를 확인하는 추가 옵션 지정자.
  • 중요한 게임 플레이 로직을 실행하는 등의 매우 중요한 RPC에만 사용해야한다.
UFUNCTION(Server, Reliable)
void ServerReliableRPCFunction(int32 IntegerParameter);

📄 참고 자료

profile
노력하는 게임 개발자

0개의 댓글