위젯 생성 경고
- Server는 사운드,비주얼과 같은 렌더링 작업을 하지 않는다. (UI, VFX, Camera ...)
- 독립형이 아닌 Listen,Dedicated 서버의 경우 서버 컨트롤러 + 복제된 로컬 컨트롤러 생성
- IsLocalController()를 사용하여 로컬 내 복제된 컨트롤러인지 확인 후 위젯 생성 리팩토링
동일한 채팅이 두번 출력되는 경우
- 각 클라이언트는 서버와 연결된 컨트롤러 / 복제된 로컬 컨트롤러 존재
- HasAuthority() 또는 IsLocalController()를 사용한 특정 클라이언트만 해당 함수 호출할 수 있도록 변경
- HasAuthority() : 서버에서만 동작해야 하는 로직
- IsLocalController() : 본인 로컬에서만 실행하거나, 입력,UI등을 처리해야 하는 경우
- 리슨서버의 경우 호스트 구분을 위해서는 두개 다 확인해야한다.
HasAuthority를 사용하여 권한이 있는 경우에 함수를 실행하는 이유
- Listen서버에서 중복 실행되는것을 방지하기 위한 보안성
- 서버에 존재하는 컨트롤러는 모든 클라이언트의 정보를 보유하며, 직접 값을 변경 할 수 있음.
클라이언트에 존재하는 컨트롤러(복제된)것을 통해 서버 컨트롤러의 내 존재하는 데이터를 수정하기 위해
난수 생성시 RPC Server / Client의 난수 값이 일치하지않아 생긴 문제
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이 아니라면 일관성을 유지하지 않는다.
- 해당 문제들은 데이터 변경시 RPC(Server) 이벤트 호출하여 실행 할 수 있다.
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 |