TIL - 파츠 테스트

Kyu_·2026년 6월 11일

29주차

목록 보기
3/4

파츠

복제문제

  • 서버에서 장착한 파츠가 클라에서 안보임

  • 반대는 가능

첫번째 예상

비주얼 컴포넌트로 따로 분리를해서 비주얼 컴포넌트쪽을 의심했지만 OnPartChanged 콜백을 받아서 메시를 불러와서 띄워주는 역할을 하기때문에 파츠 컴포넌트쪽 레플리케이션 조건을 바꿔보았다. 기존에는 COND_OwnerOnly로 소유한 클라에게만 복제되게끔 되어있는데 이를 모든 접속자에게 복제하도록 변경해보았다.

void UNSPartEquipComponent::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    // 이전 코드
	// DOREPLIFETIME_CONDITION(UNSPartEquipComponent, EquippedParts, COND_OwnerOnly); 
    // 새 코드
    DOREPLIFETIME(UNSPartEquipComponent, EquippedParts);
}
  • 결과

바로 정상적으로 복제되었다.

  • 이유
  1. 호스트가 장착 -> 호스트 PlayerState의 EquipParts가 원격 클라에 복제 안됨(onwer가 아니므로) -> 클라에서 OnRep 안일어남 -> 클라에서 안보임
  2. 클라가 장착 -> 서버는 항상 authority라 데이터를 가지고 있음, EquipPart()가 직접 OnPartChanged.Broadcast 호출 -> 호스트에서 보임

파츠는 모든 플레이어에게 보여야 하므로 증강처럼 owner 전용 복제가 잘못된 조건

증강

복제문제

서버에서는 정상적으로 증강이 출력되는데 클라이언트에서 O키(디버그용키)를 눌렀을때 증강이 제대로 출력되지 않던 문제
데이터 서브시스템에서 데이터가 모두 존재하면 EnterRun()함수를 호출해서 데이터가 로드되었다는 것을 Enum으로 설정하고 이를 IsRunReady라는 함수로 확인할 수가 있다. 증강쪽 코드에는 IsRunReady()를 확인해서 데이터가 있는지 확인하고 증강을 띄워준다.
허나 아직 데이터 서브시스템을 달아놓지 않았기 때문에 둘다 동작을 안하거나 둘다 동작해야 맞는데 계속 서버만 동작하게끔 되어있었다. 그래서 디버깅을 계속하다가 문제를 찾게 되었다.
문제는 플레이어 컨트롤러에서 인런으로 넘겨주는 Server_RequestStartRun함수였다.

if (!HasAuthority())
{
	return;
}

AGameModeBase* CurrentGameMode = GetWorld()->GetAuthGameMode();
if (CurrentGameMode && CurrentGameMode->Implements<UNSOutGameInterface>())
{
	INSOutGameInterface::Execute_RequestStartRun(CurrentGameMode);
}

//서버 인런 데이터 로드
if (UNSDataSubsystem* Data = UNSDataSubsystem::Get(this))
{
	Data->EnterRun();
}

Client_NotifyRunStarted();

이 함수는 서버에서만 동작하고 Client_NotifyRunStarted를 호출한다. 해당 함수에서는

if (UNSDataSubsystem* Data = UNSDataSubsystem::Get(this))
{
	Data->EnterRun();
}

이렇게 데이터서브시스템이 있으면 EnterRun을 해서 임시로 런으로 넘겨주는 부분이 있는데 이때문에 서버에서는 EnterRun으로 넘어가고 클라에서는 Server_RequestStartRun의 !HasAuthority()를 넘기지 못하고 return되고 있었던 것

  • 해결
for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
{
	if (ANSPlayerController* PC = Cast<ANSPlayerController>(It->Get()))
	{
		PC->Client_NotifyRunStarted();
	}
}
  • GetPlayerControllerIterator()를 통해서 모든 플레이어컨트롤러를 가져와서 Client_NotifyRunStarted()함수를 호출해서 해결하였다.

0개의 댓글