발생한 문제

프로젝트 및 월드 세팅을 언리얼 엔진에서 제공하는 GameState 클래스의 경우 컨트롤러에 빙의한 캐릭터 내
Movement Component가 자동으로 동기화가 됨.

 

게임 내 공통적으로 필요한 기능들을 구현하기 위해 GameStateBase 기반의 커스텀 GS를 생성, 게임모드 생성자에서

GameStateClass = MyGS::StatcClass() 적용, 프로젝트 및 월드세팅 확인 후 결과

다른 컴포넌트들은 정상적으로 동기화가 되었으나, 언리얼에서 제공하는 Movement Component는 동기화가 안됨.

 

해결 과정

AMyGameMode.cpp

AMyGameState::AMyGameState()
{
	bReplicates = true;
	bAlwaysRelevant = true;
	bNetLoadOnClient = true;
}

 

리플리케이티드 및 네트워크 동기화를 위한 변수 true 적용해보기

언리얼에서 제공하는 기본 게임 스테이트 클래스에서는 적용이 되어있었으나,

커스텀 게임 스테이트 클래스에서는 명시적으로 처리해야 하는 것.

  • bReplicates : 클라이언트에 해당 GameState 복제에 대한 여부
  • bAlwaysRelevant : 모든 클라이언트가 항상 리플리케이션 되도록 설정
  • bNetLoadOnClient : 클라이언트가 레벨 로드시 GameState를 생성하도록 설정

 

BP_MyCharacter

 

무브먼트 컴포넌트 내 리플리케이트 설정

  • C++ : GetMovementComponent()->SetIsReplicated(true);

 

두가지의 적용 결과 언리얼에서 제공하는 기본적인 기능들이 리플리케이션이 적용되지 않았습니다.

- Weapon관련 RPC, Health관련 RPC의 경우는 정상적으로 동작됨을 확인

 

 

AGameStateBase -> AGameState 클래스 상속 변경

 

기반 상속구조 변경 후 정상적으로 동기화가 됨.

 

 

멀티플레이 내 GameState VS GameStateBase

  • override 하지 않은 함수들의 경우, 기본적으로 GameStateBase에서 동일한 로직을 구현할 것이라 생각.
  • 생성자 관련 부분 먼저 확인해보기

GameStateBase.cpp - Constructor
GameState.cpp - Constructor

 

  • 생성자 관련 부분에서 State에서는 추가적인 멀티플레이 로직이 없는것을 확인 할 수 있었음.
  • 즉, 생성자 외 오버라이드된 함수 내에서 추가기능을 통해 Possess 관련 동기화과 있을것이라 생각.

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/game-mode-and-game-state-in-unreal-engine

 

공식문서 설명을 보면, 해당 함수 및 변수들이 멀티플레이 관련 역할을 한다고 알 수 있다.

 

// AGameStateBase.cpp
void AGameStateBase::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	UWorld* World = GetWorld();
	World->SetGameState(this);

	FTimerManager& TimerManager = GetWorldTimerManager();
	if (World->IsGameWorld() && GetLocalRole() == ROLE_Authority)
	{
		UpdateServerTimeSeconds();
		if (ServerWorldTimeSecondsUpdateFrequency > 0.f)
		{
			TimerManager.SetTimer(TimerHandle_UpdateServerTimeSeconds, this, &AGameStateBase::UpdateServerTimeSeconds, ServerWorldTimeSecondsUpdateFrequency, true);
		}
	}

	for (TActorIterator<APlayerState> It(World); It; ++It)
	{
		AddPlayerState(*It);
	}
}

// AGameState.cpp
void AGameState::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	FTimerManager& TimerManager = GetWorldTimerManager();
	TimerManager.SetTimer(TimerHandle_DefaultTimer, this, &AGameState::DefaultTimer, GetWorldSettings()->GetEffectiveTimeDilation() / GetWorldSettings()->DemoPlayTimeDilation, true);
}

 

  • 주요 문제는 StateBase 상속 시 Component가 동기화 되지않음
  • 즉, Component 관련 설정이 문제다. -> PlayerArray에 추가하는 로직이 오버라이드 되어있다.
  • 언리얼은 서버 동기화시 실시간성을 동시 지원하기위해 예측 및 Reconciliation 방법을 사용.
  • 동기화시 서버 월드와 클라이언트의 월드는 서로 다르기때문에 월드 서버를 기준으로 동작해야된다.
    • TimeManager를 통해 서버의 월드를 Simulate해서 클라이언트의 월드를 복제, 시간값 관련 동기화

 

 

 

 

+ Recent posts