< [이득우의 언리얼 프로그래밍 Part3 필기] 5. 액터 리플리케이션 기초

언리얼엔진5/[Part3] 이득우의 언리얼 프로그래밍

[이득우의 언리얼 프로그래밍 Part3 필기] 5. 액터 리플리케이션 기초

Rocketbabydolls 2024. 4. 29. 17:47

액터 리플리케이션

  • 특정 플레이어에 속한 액터의 정보를 네트웍 내 다른 플레이어에게 복제하는 작업
  • 클라이언트 - 서버 모델에서는 대부분 서버에서 클라이언트로 전달함.
  • 리플리케이션의 방법에는 크게 두 가지가 있음.
    1. 프로퍼티 리플리케이션
    2. RPC (Remote Procedure Call)

 

도식화

 

 

기본 액터의 로딩

  • 클라이언트가 초기화 될 떄 모든 액터 정보를 서버로부터 받는 것은 비효율적
  • 따라서 기본 배경에 관련된 액터는 맵을 통해 스스로 로딩하도록 설계되어 있음.
  • 고정으로 제공하는 액터와 동적으로 생성하는 액터
    고정으로 제공하는 액터의 예 : 레벨을 구성하는 배경 액터
    동적으로 생성하는 액터의 예 : 플레이어 컨트롤러와 폰
  • 고정 액터에 대해 NetLoadOnClient속성을 체크해야 함 (기본값)

 

 

 

리플리케이션 작업에서 가장 중요한 것은 데이터 전송량을 최소화 하는 것

NetLaodOnClient 레벨에 배치된 액터라면 모두 참으로 설정되어 있는데, 서버와 통신없이 클라이언트 초기화 시  자체적으로 로딩된다.

 

 

액터의 리플리케이션 설정

 

리플리케이션 프로퍼티의 지정

 

  1. 액터의 리플리케이션 속성을 참으로 지정함
    bReplicates 속성을 true로 설정
  2. 네트웍으로 복제할 액터의 속성을 키워드로 지정.
    UPROPERTY에 Replicated 키워드 설정
  3. GetLifeTimeReplicatedProps 함수에 네트웍으로 복제할 속성을 추가.
    #include "Net/UnrealNetwork.h" 헤더 파일 지정
    DOREPLIFETIME 매크로를 사용해 복제할 속성을 명시
Lifetime 은 액터 채널의 Lifetime 을 의미함.
즉 활성화된 액터 채널로 전송할 복제될 속성을 의미함.

 

++)

프로퍼티 리플리케이션이란

네트워크 데이터를 최소화하기 위해선 변경시키는데 사용되는 데이터인 속성 값만 정리해서 보내는 방법 (state ) 

 

리슨 서버 모델에서는

클라이언트와 서버코드 분리해야한다.

 

데디케이티드 서버는 클라이언트 로직을 고려 안하기 때문에 서버 로직만 있으면 된다. (훨씬 편리)

 

매 틱마다 서버로부터 받은 속성을 업데이트 시켜 주면 매 프레임마다 실행되는 틱의 코드가 방대해지고 상대방의 네트워크 전송 주기가 틱보다 느리면 틱이 쌓여서 비효율적으로 동작할 수 있다.(와다다다 업데이트 됄 수 있다.)

 

따라서 더 효율적으로 프로퍼티 리플리케이션을 구성할 방법이 필요하다.

-> 리플리케이션 콜백 함수 호출 

 

 

리플리케이션 콜백 함수 호출

  1. 클라이언트에 속성이 복제될 때 콜백 함수가 호출되도록 구현
    UPROPERTY의 Replicated 키워드를 ReplicatedUsing 키워드로 변경
    ReplicatedUsing에 호출할 콜백 함수를 지정.
    호출될 콜백 함수는 UFUNCTION으로 선언해야 함.
  2. 콜백 함수의 구현
    일반적으로 OnRep_의 접두사를 가지는 이름 규칙을 가짐.
    콜백 함수는 서버가 아닌 클라이언트에서만 호출됨.

 

필요한 타이밍에만 해당 로직을 처리할 수 있어 효율적인 구현이 가능하다.

 

 

 

액터 리플리케이션 -> 액터 채널 사용

액터채널이 열린다음에 리플리케이션이 진행된다.

 

소스 코드

// Called every frame
void AABFountain::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (HasAuthority())
	{
		AddActorLocalRotation(FRotator(0.0f, RotationRate * DeltaTime, 0.0f));
		ServerRotationYaw = RootComponent->GetComponentRotation().Yaw;
	}
	else
	{

	}
}
void AABFountain::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(AABFountain, ServerRotationYaw);
}
void AABFountain::OnRep_ServerRotationYaw()
{
	AB_LOG(LogABNetwork, Log, TEXT("Yaw : %f"), ServerRotationYaw);

	FRotator NewRotator = RootComponent->GetComponentRotation();
	NewRotator.Yaw = ServerRotationYaw;
	RootComponent->SetWorldRotation(NewRotator);
}