https://dev.epicgames.com/documentation/ko-kr/unreal-engine/replication-graph-in-unreal-engine?application_version=5.3

https://www.unrealengine.com/ko/tech-blog/replication-graph-overview-and-proper-replication-methods

 

  • 일반적으로 Replicate되는 Actor들은 매 Tick마다 해당 Actor가 Replicate될지 말지 판단을 한다.
    • 게임이 클수록, 동시접속자가 많을수록 CPU 병목현상이 발생하기 쉬워짐
  • Replication Graph는 Actor 단위의 Replicate 판단 여부를 Node 단위로 묶어서 비용을 감소시킨다.

동작 방식

  • 기본적인 동작 방식은 이전의 Actor Replicate와 크게 다르지 않다.
    • 특정 공간 안의 Actor를 별도로 관리(Spatial Partitioning)
    • 대상 클라이언트로부터 먼 거리의 Actor를 제외 (Relevancy Culling)
    • Replicate 빈도 관리 (Frequency Control)

ReplicationGraphNode

  • 동일한 조건으로 Replicate 되어야 할 Actor를 하나로 묶어주는 단위
  • BaseClass인 UReplicationGraphNode는 Pure Virtual Function이 있어서 반드시 이를 상속 받은 Class를 써야 한다.
    • 최소 아래 함수들은 반드시 Implement 되어야 한다.
/** Override this function to initialize the per-class data for replication */
//Initialize UReplicationGraph::GlobalActorReplicationInfoMap.
virtual void InitGlobalActorClassSettings();

/** Override this function to init/configure your project's Global Graph */
//Instantiate new UGraphNodes via ::CreateNewNode. Use ::AddGlobalGraphNode if they are global (for all connections).
virtual void InitGlobalGraphNodes();

//Route actor spawning/despawning to the right node. (Or your nodes can gather the actors themselves)
virtual void RouteAddNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo);
virtual void RouteRemoveNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo);

/** Override this function to init/configure graph for a specific connection. Note they do not all have to be unique: connections can share nodes (e.g, 2 nodes for 2 teams) */
//Initialize per-connection nodes (or associate shared nodes with them via ::AddConnectionGraphNode)
virtual void InitConnectionGraphNodes(UNetReplicationGraphConnection* ConnectionManager);
  • Node 안에 별도의 Child Node를 가질 수 있다.

ReplicationGraphNode_ActorList

  • 간단한 Actor 목록을 관리
  • 복잡한 Frequency나 Relevancy 로직 없이 관리 된다.
  • 소규모 목록에서 사용할 때 유용

ReplicationGraphNode_ActorListFrequencyBuckets

  • Replicate 빈도에 따라 Actor들을 Bucket 단위로 관리
  • 다양한 간격으로 업데이트가 필요한 Actor를 관리할 때 유용

ReplicationGraphNode_AlwaysRelevant

  • 위치, 상태와 관계 없이 모든 Client에게 항상 Replicate 되어야 하는 경우
  • GameMode, Controller, GameState와 같은 GamePlay에 주요한 Actor에게 적합

ReplicationGraphNode_AlwaysRelevant_ForConnection

  • AlwaysRelevant와 유사하지만 그 대상을 특정 Client에게만 제한할 수 있다.
  • 특정 Player에게 필수적인 Actor를 Replicate할 때 적합

ReplicationGraphNode_ConnectionDormancyNode

  • 비활성화 될 여지가 있는 Actor들에 적합
  • 또는 배경의 Actor와 같이 업데이트를 제한하여 자원을 최적화 하는데 적합

ReplicationGraphNode_DormancyNode

  • Actor가 활성화 될 때 모든 Client에 Replicate되어야 하는 경우
  • 간헐적으로 활성화 되는 Actor들에게 유용

ReplicationGraphNode_DynamicSpatialFrequency

  • 공간적 조건에 따라 Replicate 빈도를 동적으로 조절
  • Player의 이동이나 게임 내 Event로 인해 Relevancy가 자주 변경되는 환경에 이상적

ReplicationGraphNode_GridSpatialization2D

  • World를 Grid로 나누고, Grid 위치에 따라 Replicate를 관리
  • 넓은 오픈월드 게임에서 플레이어 주변 Actor만 업데이트하여 네트워크 트래픽 최적화

ReplicationGraphNode_TearOff_ForConnnection

  • Tear Off(서버에서 어느정도 분리된 상태)된 Actor들을 관리
  • 해당 Actor들을 새로운 Client에 적절하게 Replicate 되도록 보장
  • Actor가 급격하게 변경되는 빠른 페이스의 액션이나 파괴 시나리오에서 사용됨.

ReplicationGraph

  • Replication Driver의 기능을 확장한 Class
  • 다수의 ReplicationGraphNode를 관리한다.

작업 방식

Node 추가

  • 기존에 만들었던 ReplicationGraphNode를 InitGlobalGraphNodes에서 생성, 추가한다.
void UBasicReplicationGraph::InitGlobalGraphNodes()
{
	// -----------------------------------------------
	//	Spatial Actors
	// -----------------------------------------------

	GridNode = CreateNewNode<UReplicationGraphNode_GridSpatialization2D>();
	GridNode->CellSize = 10000.f;
	GridNode->SpatialBias = FVector2D(-UE_OLD_WORLD_MAX, -UE_OLD_WORLD_MAX);

	AddGlobalGraphNode(GridNode);

	// -----------------------------------------------
	//	Always Relevant (to everyone) Actors
	// -----------------------------------------------
	AlwaysRelevantNode = CreateNewNode<UReplicationGraphNode_ActorList>();
	AddGlobalGraphNode(AlwaysRelevantNode);
}

Actor 추가

  • AddNetworkActor에서 RouteAddNetworkActorToNodes를 호출
  • RouteAddNetworkActorToNodes에서 등록된 Node를 통해 NotifyAddNetworkActor로 Actor 등록
void UReplicationGraph::AddNetworkActor(AActor* Actor)
{
	LLM_SCOPE_BYTAG(NetRepGraph);
	QUICK_SCOPE_CYCLE_COUNTER(UReplicationGraph_AddNetworkActor);

	if (IsActorValidForReplicationGather(Actor) == false)
	{
		return;
	}

	if (NetDriver && !NetDriver->ShouldReplicateActor(Actor))
	{
		return;
	}

	bool bWasAlreadyThere = false;
	ActiveNetworkActors.Add(Actor, &bWasAlreadyThere);
	if (bWasAlreadyThere)
	{
		// Guarding against double adds
		return;
	}

	ensureMsgf(!Actor->bNetTemporary, TEXT("ReplicationGraph does not support bNetTemporary. Actor: %s has bNetTemporary set."), *Actor->GetPathName());

	// Create global rep info	
	FGlobalActorReplicationInfo& GlobalInfo = GlobalActorReplicationInfoMap.Get(Actor);
	GlobalInfo.bWantsToBeDormant = Actor->NetDormancy > DORM_Awake;

	RouteAddNetworkActorToNodes(FNewReplicatedActorInfo(Actor), GlobalInfo);
}

 

void UReplicationGraph::RouteAddNetworkActorToNodes(const FNewReplicatedActorInfo& ActorInfo, FGlobalActorReplicationInfo& GlobalInfo)
{
	// The base implementation just routes to every global node. Subclasses will want a more direct routing function where possible.
	for (UReplicationGraphNode* Node : GlobalGraphNodes)
	{
		Node->NotifyAddNetworkActor(ActorInfo);
	}
}

Node 탐색

  • 매 Tick마다 ServerReplicateActors를 호출
  • 함수 내부에서 조건에 맞는 Node를  FNewReplicatedActorInfo로 검색
/** This is the struct we use to push new replication actors into the graph. "New" doesn't mean "newly spawned" it means "new to the graph". FIXME: Please suggest a better name! */
struct FNewReplicatedActorInfo
{
	explicit FNewReplicatedActorInfo(const FActorRepListType& InActor) : Actor(InActor), Class(InActor->GetClass())
	{
		StreamingLevelName = GetStreamingLevelNameOfActor(Actor);
	}

	explicit FNewReplicatedActorInfo(const FActorRepListType& InActor, FName OverrideLevelName)
		: Actor(InActor)
		, StreamingLevelName(OverrideLevelName)
		, Class(InActor->GetClass())
	{
	}

	AActor* GetActor() const { return Actor; }

	REPLICATIONGRAPH_API static FName GetStreamingLevelNameOfActor(const AActor* Actor);

	FActorRepListType Actor;
	FName StreamingLevelName;
	UClass* Class;
};

설정 방법

ini 파일 설정

  • Project의 Default.ini에서 아래와 같이 ReplicationDriverClassName 추가
[/Script/OnlineSubsystemUtils.IpNetDriver]
ReplicationDriverClassName="/Script/ProjectName.ClassName"

Instance 반환 함수 Bind

UReplicationDriver::CreateReplicationDriverDelegate().BindLambda([](UNetDriver* ForNetDriver, const FURL& URL, UWorld* World) -> UReplicationDriver*
{
	return NewObject<UMyReplicationDriverClass>(GetTransientPackage());
});

NetReplicationGraphConnection

  • 각 Client 연결에 대한 Replicate Data를 관리
    • ReplicationGraph가 ReplicationDriver를 상속받아 NetDriver의 역할을 한다면, 
      NetReplicationGraphConnection은 ReplicationConnectionDriver를 상속받아 NetConnection의 역할을 한다.
  • ReplcationGraph에서 Replication이 결정 된다면,
    NetReplcationgraphConnection은 해당 Client에게 최적화 된 데이터를 전달해준다.

일반적인 사용 기준

  • Actor의 위치에 따라 Group을 나눈다.
  • 비활성화된 Actor를 식별하여 별도의 목록으로 관리한다.
  • Character가 주워서 들고 다닐 수 있다면, 소유자와 같이 업데이트 한다.
  • 모든 Client가 Replicate 받는 특수 목록을 만든다.
  • 특정 Client에 Relevancy를 갖는 특수 목록을 만든다.

'UE5 > Network' 카테고리의 다른 글

[Network] Property Replication  (1) 2024.06.28
[Network] Network Property  (0) 2024.06.25
[Network] Network Driver  (0) 2024.06.18
[Network] DemoNetDriver 및 Streamer  (0) 2024.06.17
[Network] Beacon  (0) 2024.06.17

+ Recent posts