언리얼 네트워크에 관련된 다양한 속성들

김혁·2025년 8월 27일

Property Replication

NetLoadOnClient 속성

  • UPROPERTY 혹은 UCLASS에서 지정할 수 있는 속성으로, 클라이언트에서 자동으로 로드해야 하는지 여부를 결정
  • 레벨 디자인을 통해 레벨에 고정적으로 배치되는 액터는 NetLoadOnClient 속성을 true로 지정해서 모든 클라이언트가 스스로 스폰

  • ADXBox를 만들어서 실습해본 결과, 복제되는 것이 아닌 서버, 클라이언트 각자 로드가 되는 것을 확인

Replication Notify

  • 해당 변수 값이 서버에서 클라이언트로 동기화될 때 호출되는 함수
  • UPROPERTY(ReplicatedUsing = OnRep_FunctionName) 키워드를 통해 정의
  • 콜백함수는 OnRep_ 접두사가 꼭 붙어야 하고, UFUNCTION() 키워드가 붙어야 함
  • 특징
    • 서버에서 실행되지 않고, 클라이언트에서만 실행됨
    • 서버에서도 해당 로직이 실행되어야 한다면, 명시적으로 호출해야 함
    • 주로 UI 갱신, 이펙트 재생, 상태 변화 알림에 사용
  • Blueprint RepNotify 함수와 비교
C++ OnRep_함수Blueprint RepNotify 함수
클라이언트에서만 호출서버와 클라이언트 모두에서 호출
명시적 호출 가능명시적 호출 불가능
속성 값이 변경될 때만 호출서버는 항시 호출되고, 클라이언트는 속성 값 변경될 때만 호출

NetUpdateFrequency

개념

  • 액터 레플리케이션 빈도의 최대치
  • 1초당 몇 번 레플리케이션을 시도할지 지정한 값
  • 서버의 성능이 NetUpdateFrequency보다 낮은 경우, 서버의 성능에 맞춰서 복제됨

주요 액터의 기본값

  • Actor : 100
  • Pawn : 100
  • PlayerController : 100
  • GameState : 10
  • PlayerState : 1

네트워크 부하 줄이기

  • 액터의 서버의 위치와 클라이언트의 위치는 동기화한다고 가정
  • 동기화하는 방법
    1. 매 틱마다 서버에서 액터의 위치를 클라이언트 측으로 복제해서 동기화
    2. 서버에서 액터의 처음 위치와 속도 값을 안다면, 이를 이용해서 예측해서 동기화
  • 클라이언트에서 보간
    • NetUpdateFrequency 속성 값을 줄이고, 클라이언트 자체에서 속도 기반으로 보간
  // DXBox.cpp
  
ADXBox::ADXBox()
{
	SetNetUpdateFrequency(1.f);
    NetUpdatePeriod = 1 / GetNetUpdateFrequency();
}
  
void ADXBox::Tick(float DeltaSeconds)
{
  	if (HasAuthority())
    {
    	...
    }
    else
    {
    	AccDeltaSecondSinceReplicated += DeltaSeconds;
		const float LerpRatio = FMath::Clamp(AccDeltaSecondSinceReplicated / NetUpdatePeriod, 0.f, 1.f);

		const float NextServerRotationYaw = ServerRotationYaw + RotationSpeed * NetUpdatePeriod;
		
		const float EstimatedClientRotationYaw = FMath::Lerp(ServerRotationYaw, NextServerRotationYaw, LerpRatio);
		SetActorRotation(FRotator(0.f, EstimatedClientRotationYaw, 0.f));
    }
}
  
void ADXBox::OnRep_ServerRotationYaw()
{
	SetActorRotation(FRotator(0.f, ServerRotationYaw, 0.f));

	AccDeltaSecondSinceReplicated = 0.f;
}

Relevancy

  • 레벨에 있는 모든 액터의 정보를 모든 클라이언트에게 실시간으로 전송하기에는 너무 큰 부하가 걸림
  • 따라서 연관성이 있는지 없는지를 판단하는 여러 기준을 토대로 판단하여 서버 측에서 해당 클라이언트와 관련성이 있는 액터만 복제해줌

액터 클래스의 연관성을 판단하는 기준

  • Owner
    • 해당 액터를 소유하고 있는 액터
    • 해당 액터와 Owner는 연관성이 있다고 판단
  • Instigator
    • 해당 액터에게 영향을 끼친 액터
    • 해당 액터와 Instigator는 연관성이 있다고 판단
    • ex) 데미지를 가한 폰
  • AlwaysRelevant
    • 해당 액터가 모든 클라이언트에게 항상 연관성이 있게끔 설정
  • NetUseOwnerRelevancy
    • 오너 액터의 연관성으로 해당 액터의 연관성을 대신할 때 사용
    • ex) 캐릭터가 소유하고 있는 무기 액터. 캐릭터가 보여야만 무기가 보여야 함
  • OnlyRelevantToOwner
    • 오너 액터에게만 연관성을 가짐
    • 다른 액터와는 연관성이 없음
  • NetCullDistance
    • 뷰어와의 거리에 따라 연관성 여부를 결정함
    • ex) 가까운 액터는 보이고, 멀면 안 보이게끔 함

폰 클래스의 연관성을 판단하는 기준

  • Viewer
    • 클라이언트 커넥션이 소유하고 있는 플레이어 컨트롤러
  • ViewTarget
    • 플레이어 컨트롤러가 빙의한 폰
    • Viewer에 빙의된 ViewTarget이 레벨을 돌아다니면서 어떤 액터와 연관성이 있는지 확인

NetPriority

  • 클라이언트에 보낼 수 있는 대역폭은 한정되어 있기 때문에, NetPriority 값이 높은 액터의 데이터를 우선 전달하게 됨
  • NetPriority 값은 순서를 정하는 데만 사용되는 것이지, 만약 대역폭이 널널하다면 모두 다 같은 빈도로 전달하게 됨
  • 이 값을 계산하는데 NetCullDistance 같은 연관성 관련 속성들이 반영됨
  • 또한 직전 패킷을 보낸 후 경과 시간과 가중치, 이전 NetPriority 값 등을 곱해서 계산함

가중치

  • 해당 액터가 ViewTarget이거나 영향을 받은 경우 -> 가장 높은 가중치
  • ViewTarget이 바라보는 방향 및 거리에 따라 가중치를 부여

포화 상태

  • 액터 관련 데이터가 너무 커서 대역폭을 넘어선 경우
  • 현재 NetPriority 값이 낮은 액터는 다음 서버 틱에서 레플리케이션됨



NetDormancy

  • 액터가 복제되었지만, 자주 수정되지 않을 때 사용하는 것으로 액터를 휴면 상태로 전환할 수 있음
  • 휴면(NetDormancy) 상태인 액터는 프로퍼티 레플리케이션이나 RPC가 동작하지 않음
  • 자주 수정되는 액터를 휴면 상태로 두면 오히려 오버헤드가 발생함

여러 가지 네트워크 휴면 상태

  • DORM_Never : 절대 휴면되지 않음
  • DORM_Awake : 휴면 상태가 아니고, 레플리케이션이 됨
  • DORM_Initial : 휴면 상태로 시작하고, 필요하면 깨울 수 있는 상태
  • DORM_DormantAll : 모든 커넥션에게 휴면 상태

휴면 상태 설정

  • AActor::SetNetDormancy() : 함수를 호출하여 휴면 상태를 변경하여 액터를 깨울 수 있음
  • AActor::FlushNetDormancy() : 함수를 호출하여 휴면 상태 액터의 변경사항을 복제할 수 있음
    -> 액터의 휴면 상태 스테이트를 변경하지 않고, 하나 이상의 업데이트를 강제로 리플리케이트함
    -> 예외로, DORM_Initial로 설정된 액터에서 해당 함수가 호출되면 DORM_DormantAll 상태로 변경됨


출처 : 팀스파르타 내일배움캠프, 언리얼엔진 공식문서
profile
게임 개발자를 향해..

0개의 댓글