Unreal Engine - 데디케이티드 서버 3 (Property Replication)

2025. 4. 6. 17:53·Unreal Engine

아래 글에서 이어지는 내용 

https://gbleem.tistory.com/148#4.%20Replication-1-3

 

Unreal Engine - 데디케이티드 서버 2

1. 로그를 통한 흐름 분석1 - 1. 로그인 흐름 분석GameModeBase와 PlayerController에서 로그를 찍어보면 아래와 같이 정리해볼 수 있다.맨 처음 네모는 서버에서만 생성되는 GameMode 로직이다.아래 네모는 C

gbleem.tistory.com

  • Replication
    • Frequency
    • Relevancy
    • NetPriority
    • NetDormancy

1. Relevancy (연관성)


1 - 1. 개념

레벨에 있는 모든 액터의 정보를 모든 클라에게 실시간으로 전송하는 것은 부하가 매우 클 것이다.

  • 이 부하를 줄이기 위해서 "클라이언트의 커넥션" 에 "소유된 액터" 인지를 체크하는 방식을 사용한다.
  • 클라이언트 커넥션에 소유되었다면, 직접적으로 관련된 액터이므로 리플리케이션 해주는 방식

연관성을 판단하는 기준

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/actor-owner-and-owning-connection-in-unreal-engine

  • Pawn
    • Viewer: 클라이언트 커넥션이 소유하고 있는 플레이어 컨트롤러
    • ViewTarget: 플레이어 컨트롤러가 빙의한 폰
    • 어떤 액터가 Viewer, ViewTarget과 연관성이 있는지를 체크해본다.
  • Actor
    • Owner
      • 해당 액터를 소유하고 있는 액터. (Relevancy 있음)
      • 무기를 소유하는 캐릭터
    • Instigator
      • 해당 액터에게 영향을 끼친 폰. (Relevancy 있음)
      • 데미지를 가한 폰
    • AlwaysRelevant
      • 해당 액터가 모든 클라이언트에게 항상 관련이 있게끔 설정
      • 보스몬스터 액터를 레벨 내의 모든 플레이어에게 리플리케이션 할 때
    • NetUseOwnerRelevancy
      • 해당 액터의 연관성을 오너 액터의 연관성으로 대신할 때
      • 무기 액터의 경우, 캐릭터의 오너로 대체 가능하다 (캐릭터가 안보이는데 무기만 보일수는 없음)
    • OnlyRelevantToOwner
      • 오너 액터에게만 연관성을 가진다. 다른 액터와는 연관성 없음
      • 길라잡이 액터, 내가 갈 길을 알려주는 액터는 나에게만 보이면 된다.
    • NetCullDistance
      • 뷰어와의 거리에 따라 연관성 여부를 체크
      • 일정 거리 안으로 들어오면 리플리케이션해주고, 멀면 하지않음

1 - 2. 실습

코드

더보기

cube.h

virtual bool IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const override;
float NetCullDistance;

 

cube.cpp

ADXCube::ADXCube()
	:ServerRotationYaw(0.f)
	,RotationSpeed(30.f)
	,AccDeltaSecondSinceReplicated(0.f)
	,NetCullDistance(1000.f)
{ 
	...
    
	//net cull distance
	SetNetCullDistanceSquared(NetCullDistance * NetCullDistance);
}

void ADXCube::Tick(float Deltaseconds)
{
	Super::Tick(Deltaseconds);

	...
	DrawDebugSphere(GetWorld(), GetActorLocation(), NetCullDistance / 2.f, 16, FColor::Green, false, -1.f);
}

bool ADXCube::IsNetRelevantFor(const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const
{
	bool bIsNetRelevant = Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);

	if (!bIsNetRelevant)
	{
		DX_LOG_NET(LogDXNet, Log, TEXT("%s is not relevant for(%s %s)"), *GetName(), *RealViewer->GetName(), *ViewTarget->GetName());
	}
	return bIsNetRelevant;
}

결과

  • 캐릭터 1이 포함되지 않은 경우 아래와 같은 모습

 

  • 두 캐릭터 모두 포함되지 않은 경우

 

 

2. NetPriority


클라이언트에서 보낼 수 있는 대역폭은 한정되어있다.

그렇기 때문에, NetPriority(우선순위)에 따라 "우선순위가 높은 액터의 데이터를 우선 전달" 하도록 설계되어 있다.

  • PlayerController : 3
  • Pawn : 2
  • Actor : 1

NetPriority는 AActor::GetNetPriority() 함수를 통해서 계산된다.

  • NetCullDistance와 같은 연관성 관련 속성을 반영하여 계산
  • "포화상태가 아니라면" NetPriority 값을 기준으로 정렬된 순서대로 리플리케이션 한다.
  • 만약 "포화상태가 된 경우" NetPriority가 가장 낮은 액터는 다음 서버틱에서 리플리케이션된다.
float AActor::GetNetPriority(const FVector& ViewPos, const FVector& ViewDir, AActor* Viewer, AActor* ViewTarget, UActorChannel* InChannel, float Time, bool bLowBandwidth)
{
	if (bNetUseOwnerRelevancy && Owner)
	{
		// If we should use our owner's priority, pass it through
		return Owner->GetNetPriority(ViewPos, ViewDir, Viewer, ViewTarget, InChannel, Time, bLowBandwidth);
	}

	if (ViewTarget && (this == ViewTarget || GetInstigator() == ViewTarget))
	{
		// If we're the view target or owned by the view target, use a high priority
		Time *= 4.f;
	}
	else if (!IsHidden() && GetRootComponent() != NULL)
	{
		// If this actor has a location, adjust priority based on location
		FVector Dir = GetActorLocation() - ViewPos;
		float DistSq = Dir.SizeSquared();

		// Adjust priority based on distance and whether actor is in front of viewer
		if ((ViewDir | Dir) < 0.f)
		{
			if (DistSq > NEARSIGHTTHRESHOLDSQUARED)
			{
				Time *= 0.2f;
			}
			else if (DistSq > CLOSEPROXIMITYSQUARED)
			{
				Time *= 0.4f;
			}
		}
		else if ((DistSq < FARSIGHTTHRESHOLDSQUARED) && (FMath::Square(ViewDir | Dir) > 0.5f * DistSq))
		{
			// Compute the amount of distance along the ViewDir vector. Dir is not normalized
			// Increase priority if we're being looked directly at
			Time *= 2.f;
		}
		else if (DistSq > MEDSIGHTTHRESHOLDSQUARED)
		{
			Time *= 0.4f;
		}
	}

	return NetPriority * Time;
}

 

 

3. NetDormancy


https://dev.epicgames.com/documentation/ko-kr/unreal-engine/actor-network-dormancy-in-unreal-engine

3 - 1. 개념

NetDormancy(휴면) 상태는 프로퍼티 리플리케이션이나 RPC가 동작하지 않는 상태이다.

서버의 최적화를 위해 사용한다. 

특히, 액터가 리플리케이션 되었지만 자주 수정되지는 않을 때 활용할 수 있다.

단, 캐릭터처럼 자주 수정되는 액터를 NetDormancy로 두면 오히려 오버헤드가 발생할 수 있다.

 

NetDormancy 상태

  • DORM_Never : 절대 휴면하지 않음
  • DORM_Awake : 휴면상태가 아니지만, 휴면상태가 될 수는 있는 상태
  • DORM_DormantPartial : 일부 커넥션에 대해서만 휴면 상태
  • DORM_Initial : 휴면 상태로 시작하고, 필요할 때 깨울 수 있는 상태
  • DORM_DormantAll : 모든 커넥션에게 휴면 상태

 

3 - 2. 실습

아래 코드를 적용하면 point light가 cube에 생기기는 하지만, 색이 변하는 것을 볼 수가 없다. 

그 이유는 cube 액터를 DORM_Init 상태로 두었기 때문이다.

더보기

cube.h

public:
	virtual void BeginPlay() override;

	UFUNCTION()
	void OnRep_ServerLightColor();

protected:
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	TObjectPtr<UPointLightComponent> PointLight;

	UPROPERTY(ReplicatedUsing = OnRep_ServerLightColor)
	FLinearColor ServerLightColor;

 

cube.cpp

ADXCube::ADXCube()
	:ServerRotationYaw(0.f)
	,RotationSpeed(30.f)
	,AccDeltaSecondSinceReplicated(0.f)
	,NetCullDistance(1000.f)
{ 
	...
    
	//net dormancy
	PointLight = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight"));
	PointLight->SetupAttachment(SceneRoot);

	SetNetDormancy(DORM_Initial);
}

void ADXCube::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	...
	DOREPLIFETIME(ThisClass, ServerLightColor);
}

void ADXCube::BeginPlay()
{
	Super::BeginPlay();

	if (HasAuthority())
	{
		FTimerHandle TimerHandle01;
		GetWorld()->GetTimerManager().SetTimer(TimerHandle01, FTimerDelegate::CreateLambda
		([&]() -> void
			{
				float RandomR = FMath::RandRange(0.f, 1.f);
				float RandomG = FMath::RandRange(0.f, 1.f);
				float RandomB = FMath::RandRange(0.f, 1.f);
				ServerLightColor = FLinearColor(RandomR, RandomG, RandomB, 1.f);
				OnRep_ServerLightColor();
			}
		), 1.f, true);
	}
}

void ADXCube::OnRep_ServerLightColor()
{
	if (HasAuthority())
	{
		DX_LOG_NET(LogDXNet, Log, TEXT("OnRep_ServerLightColor(): %s"), *ServerLightColor.ToString());
	}
	PointLight->SetLightColor(ServerLightColor);
}

 

위의 코드 작성 후, point light의 색을 변하게 하려면 아래와 같이 깨우는 설정이 필요하다.

  • 휴면 상태를 깨우는 방법으로는 NetDormancy 프로퍼티를 설정하거나 FlushNetDormancy() 함수를 사용하는 방식이 존재한다.
  • 이번 실습에서는 FlushNetDormancy() 함수를 통해 깨우도록 코드를 작성하였다.
  • 주의점) 
    • NetDormancy가 DORM_Initial인 상태에서
    • FlushNetDormancy() 함수를 호출하면,
    • 해당 액터의 NetDormancy가 DORM_DormantAll 로 변경된다.
더보기
void ADXCube::BeginPlay()
{
	Super::BeginPlay();

	if (HasAuthority())
	{
		...
        
		FTimerHandle TimerHandle02;
		GetWorld()->GetTimerManager().SetTimer(TimerHandle02, FTimerDelegate::CreateLambda
		([&]() ->void
			{
				FlushNetDormancy();
			}
		), 5.f, false);
	}
}

 

추가) DOREPLIFETIME_CONDITION()

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/conditional-property-replication?application_version=4.27

  • DOREPLIFETIME 으로 등록하면, 다시 해제가 불가능하다.
  • 그렇기 때문에 추가적인 조건을 더하여, 세밀하게 조정하기 위해서는 DOREPLIFETIME_CONDITION()을 사용해야 한다.
  • 그러나 이 방식의 경우, 조건식이 너무 자주 바뀌면 오버헤드가 발생할 수 있다.
  • 예시
DOREPLIFETIME_CONDITION(ThisClass, ServerLightColor, COND_InitialOnly);

 

 

4. Actor Replication Flow


https://dev.epicgames.com/documentation/en-us/unreal-engine/detailed-actor-replication-flow-in-unreal-engine?application_version=5.4

 

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

Unreal Engine - 데디케이티드 서버 5 (RPC, Replication)  (0) 2025.04.10
Unreal Engine - 데디케이티드 서버 4 (RPC)  (0) 2025.04.07
Unreal Engine - 데디케이티드 서버 2  (1) 2025.04.03
Unreal Engine - Save Game  (0) 2025.04.02
Unreal Engine - 야구게임(데디케이티드 서버)  (0) 2025.03.29
'Unreal Engine' 카테고리의 다른 글
  • Unreal Engine - 데디케이티드 서버 5 (RPC, Replication)
  • Unreal Engine - 데디케이티드 서버 4 (RPC)
  • Unreal Engine - 데디케이티드 서버 2
  • Unreal Engine - Save Game
gbleem
gbleem
gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (184)
      • Unreal Engine (73)
      • C++ (19)
      • 알고리즘(코딩테스트) (27)
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    싱글턴
    addonscreendebugmessage
    템플릿
    map을 vector로 복사
    매크로 지정자
    상속
    C++
    gamestate
    additive animation
    DP
    const
    blend pose
    enhanced input system
    applydamage
    character animation
    cin함수
    BFS
    Vector
    actor 클래스
    motion matching
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
Unreal Engine - 데디케이티드 서버 3 (Property Replication)
상단으로

티스토리툴바