커스텀 노드 구현
팀 기반 노드, Dormancy 노드 등 게임 특화 노드 개발
커스텀 노드 기초
UReplicationGraphNode 상속
UCLASS()
class UMyCustomReplicationNode : public UReplicationGraphNode
{
GENERATED_BODY()
public:
// Actor 추가 알림
virtual void NotifyAddNetworkActor(
const FNewReplicatedActorInfo& ActorInfo) override;
// Actor 제거 알림
virtual bool NotifyRemoveNetworkActor(
const FNewReplicatedActorInfo& ActorInfo,
bool bWarnIfNotFound) override;
// 연결별 Actor 목록 수집 (핵심!)
virtual void GatherActorListsForConnection(
const FConnectionGatherActorListParameters& Params) override;
protected:
// 노드가 관리하는 Actor 목록
FActorRepListRefView ReplicationActorList;
};
팀 기반 노드 구현
같은 팀에게만 복제하는 노드
UCLASS()
class UReplicationGraphNode_TeamBased : public UReplicationGraphNode
{
GENERATED_BODY()
// 팀별 Actor 목록
TMap<int32, FActorRepListRefView> TeamActorLists;
public:
virtual void NotifyAddNetworkActor(
const FNewReplicatedActorInfo& ActorInfo) override
{
int32 TeamId = GetActorTeamId(ActorInfo.Actor);
TeamActorLists.FindOrAdd(TeamId).Add(ActorInfo.Actor);
}
virtual void GatherActorListsForConnection(
const FConnectionGatherActorListParameters& Params) override
{
// 뷰어의 팀 ID 가져오기
int32 ViewerTeamId = GetViewerTeamId(Params.Viewer);
// 같은 팀의 Actor만 복제 목록에 추가
if (FActorRepListRefView* TeamList = TeamActorLists.Find(ViewerTeamId))
{
Params.OutGatheredReplicationLists.AddReplicationActorList(*TeamList);
}
}
private:
int32 GetActorTeamId(AActor* Actor)
{
if (ITeamInterface* TeamActor = Cast<ITeamInterface>(Actor))
{
return TeamActor->GetTeamId();
}
return -1; // 팀 없음
}
};
팀 전용 마커, 아군 HP 바, 팀 채팅 등 같은 팀에게만 보여야 하는 정보에 유용합니다.
Fortnite 스타일 노드 구성
대규모 Battle Royale 최적화 패턴
class UFortniteReplicationGraph : public UReplicationGraph
{
// 1. 항상 관련있는 Actor (GameState, GameMode 등)
UReplicationGraphNode_AlwaysRelevant* AlwaysRelevantNode;
// 2. 연결별 항상 관련있는 Actor (PlayerState, PlayerController)
UReplicationGraphNode_AlwaysRelevant_ForConnection* ForConnectionNode;
// 3. 공간 분할 (동적 Actor)
UReplicationGraphNode_GridSpatialization2D* GridSpatialization;
// 4. Dormant Actor (상호작용 전까지 휴면)
UReplicationGraphNode_DormancyNode* DormancyNode;
// 5. 팀 기반 노드 (같은 팀만 복제)
UReplicationGraphNode_TeamBased* TeamNode;
};
- AlwaysRelevant - 최우선, 모든 연결에 복제
- ForConnection - 특정 연결에만 항상 복제
- GridSpatialization - 거리 기반 필터링
- Dormancy - 휴면 Actor 효율적 관리
Dormancy 노드 구현
휴면 Actor의 효율적 관리
UCLASS()
class URepGraphNode_DynamicDormancy : public UReplicationGraphNode
{
GENERATED_BODY()
FActorRepListRefView DormantActors;
FActorRepListRefView ActiveActors;
public:
virtual void GatherActorListsForConnection(
const FConnectionGatherActorListParameters& Params) override
{
// 활성 Actor만 복제 목록에 추가
Params.OutGatheredReplicationLists
.AddReplicationActorList(ActiveActors);
// 휴면 Actor는 뷰어 근접 시에만
FVector ViewerLoc = Params.Viewer.ViewLocation;
for (AActor* Actor : DormantActors)
{
float Dist = FVector::Dist(
ViewerLoc, Actor->GetActorLocation());
if (Dist < WakeUpDistance)
{
WakeActor(Actor);
}
}
}
void WakeActor(AActor* Actor)
{
DormantActors.Remove(Actor);
ActiveActors.Add(Actor);
Actor->FlushNetDormancy();
}
};
FlushNetDormancy()는 해당 Actor의 모든 프로퍼티를 다시 비교해야 하므로 비용이 큽니다. 한 프레임에 대량의 Actor를 깨우지 마세요. 프레임당 최대 깨우기 수를 제한하는 로직을 추가하세요.
핵심 요약
- GatherActorListsForConnection - 연결별 복제 Actor 목록 결정의 핵심
- 팀 기반 노드 - 같은 팀에게만 복제, 적 위치 정보 숨김에 유용
- Dormancy 노드 - 상호작용 전 Actor의 효율적 관리
- 노드 조합 - 여러 노드를 조합하여 게임 특화 최적화
도전 과제
배운 내용을 직접 실습해보세요
UReplicationGraphNode를 상속하여 IGenericTeamAgentInterface 기반 팀 필터링 노드를 구현하세요. GatherActorListsForConnection에서 뷰어의 TeamId를 확인하고 같은 팀 Actor만 복제 목록에 추가하세요.
WakeUpDistance를 설정 가능한 Dormancy 노드를 구현하세요. NotifyAddNetworkActor에서 Actor의 초기 Dormancy 상태를 확인하고, GatherActorListsForConnection에서 거리 체크 후 FlushNetDormancy를 호출하는 로직을 구현해보세요.
AlwaysRelevant + GridSpatialization + TeamBased + Dormancy 4개 커스텀 노드를 조합한 완전한 UReplicationGraph을 구현하고, RouteAddNetworkActorToNodes에서 Actor 클래스별로 적절한 노드에 분배하는 전체 시스템을 완성해보세요.