위젯 생성 경고

실행 종료 후 출력된 경고

 

  • Server는 사운드,비주얼과 같은 렌더링 작업을 하지 않는다. (UI, VFX, Camera ...)
  • 독립형이 아닌 Listen,Dedicated 서버의 경우 서버 컨트롤러 + 복제된 로컬 컨트롤러 생성
  • IsLocalController()를 사용하여 로컬 내 복제된 컨트롤러인지 확인 후 위젯 생성 리팩토링

 

동일한 채팅이 두번 출력되는 경우

  • 각 클라이언트는 서버와 연결된 컨트롤러 / 복제된 로컬 컨트롤러 존재
  • HasAuthority() 또는 IsLocalController()를 사용한 특정 클라이언트만 해당 함수 호출할 수 있도록 변경
    • HasAuthority() : 서버에서만 동작해야 하는 로직
    • IsLocalController() : 본인 로컬에서만 실행하거나, 입력,UI등을 처리해야 하는 경우
    • 리슨서버의 경우 호스트 구분을 위해서는 두개 다 확인해야한다.

 

HasAuthority를 사용하여 권한이 있는 경우에 함수를 실행하는 이유

  1. Listen서버에서 중복 실행되는것을 방지하기 위한 보안성
  2. 서버에 존재하는 컨트롤러는 모든 클라이언트의 정보를 보유하며, 직접 값을 변경 할 수 있음.
    클라이언트에 존재하는 컨트롤러(복제된)것을 통해 서버 컨트롤러의 내 존재하는 데이터를 수정하기 위해

 

 

난수 생성시 RPC Server / Client의 난수 값이 일치하지않아 생긴 문제

Replicated 적용 전

void AChatPlayerController::Client_ReceiveMessage_Implementation(const FString& Message, const FString& TargetRandValue)
{
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, Sender + TEXT("(Input Value) : ") + Message);	// 유저가 입력한 Value
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, Sender + TEXT("(Local): ") + RandValue);		// 서버에서 복제한 컨트롤러(Not Replicated) RandValue
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, Sender + TEXT("(Server) : ") + TargetRandValue); // RPC Server에서 전송한(Not Replicated) RandValue

	if (AChatPlayerState* PS = GetPlayerState<AChatPlayerState>())
	{
		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, Sender + TEXT("(PlayerState) : ") + PS->RandValue);	// 동기화를 위한 Replicated된 PlayerState의 RandValue
	}
}
  • PlayerController BeginPlay내에서 난수를 생성하는 경우, Server, Local의 난수값이 서로 다르다.
  • RPC (Client)에서 InputValue가 Server와 비교하고 싶은 경우
    • RPC(Server)에서 Client 호출시 해당 정보를 같이 전송해야한다.
    • 현재 구조는 FString 하나의 데이터만을 전송하지만, FCharacterMoveData와 같은 구조체 전송의 경우 불필요한 대역폭 소모
  • RPC (Client)에서 InputValue Client와 비교하는 경우
    • Client (!HasAuthority())의 경우 값을 수정할 수 없음
    • 데이터 변경의 경우 서버에서만 실행된다.
    • 데이터를 변경해야 하는 경우 복제된 컨트롤러 내 값을 사용하면 일관성이 유지되지 않는다.
      • 해당 문제들은 데이터 변경시 RPC(Server) 이벤트 호출하여 실행 할 수 있다.
        하지만, 난수값과 같은 경우 Set이 아니라면 일관성을 유지하지 않는다.

 

Replicated를 사용한 리팩토링

 

Replicated를 사용한 데이터만으로 난수 비교 가능

	UPROPERTY(ReplicatedUsing = OnRep_PlayerNumbers)
	FString RandValue;

AChatPlayerState::AChatPlayerState()
{
  // PlayerState 클래스의 경우 기본적으로 RPC와같은 네트워크 지원
	bReplicates = true;
}

void AChatPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
  // Replicated한 데이터를 네트워크 복제하라는 명령 매크로
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(AChatPlayerState, RandValue);
}

 

'Unreal Engine > Debugging' 카테고리의 다른 글

[UE NET] GameState vs GameStateBase  (0) 2025.04.11
[UE5] UObject 클래스 내 GetWorld Null 반환  (0) 2025.02.26
[UE5] - 유효성 검사  (0) 2025.01.27

+ Recent posts