PART 11 · 강의 6/7
Iris Replication System
UE5의 차세대 네트워크 복제 시스템
01
Iris Replication System 개요
기존 대비 31% 성능 향상
Iris Replication System은 UE5에서 새롭게 도입된 실험적 네트워크 복제 시스템입니다. 기존 Generic Replication과 Replication Graph를 대체하며, 대규모 멀티플레이어 게임에서 더 나은 성능과 확장성을 제공합니다.
성능 향상
31%
테스트 플레이어 수
100+
복제 액터 수
50K+
Iris의 핵심 특징
- 모듈식 설계: 복제 로직을 독립적인 모듈로 분리
- 가상 호출 오버헤드 감소: UReplicationBridge 베이스 클래스 제거
- Seamless Travel 지원: 레벨 전환 시 연결 유지
- 향상된 디버깅 도구: 복제 상태 시각화
02
Iris 설정 및 활성화
프로젝트에서 Iris 사용하기
DefaultEngine.ini
; Iris Replication System 활성화
[/Script/Engine.NetworkSettings]
net.IrisEnabled=1
; Iris 특화 설정
[/Script/IrisCore.IrisSettings]
; 최대 복제 액터 수 (기본: 50000)
MaxReplicatedActors=50000
; 복제 빈도 (Hz)
ReplicationFrequency=30
; 우선순위 업데이트 간격
PriorityUpdateInterval=0.1
; 관련성 계산 캐시 시간
RelevancyCacheTime=0.25
UE 5.7 API 변경사항
UReplicationBridge베이스 클래스 제거 (가상 호출 오버헤드 감소)BeginReplication콜백이OnBeginReplication으로 이름 변경StartActorReplication: 새로운 비가상 진입점- Seamless Travel 지원 추가
C++
// IrisReplicationManager.h
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/WorldSubsystem.h"
#include "Net/IrisNetDriver.h"
#include "IrisReplicationManager.generated.h"
/**
* Iris Replication 관리 서브시스템
* 대규모 멀티플레이어 네트워킹 최적화
*/
UCLASS()
class MYGAME_API UIrisReplicationManager : public UWorldSubsystem
{
GENERATED_BODY()
public:
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
// Iris 활성화 여부 확인
UFUNCTION(BlueprintPure, Category = "Iris")
bool IsIrisEnabled() const;
// 복제 통계 가져오기
UFUNCTION(BlueprintPure, Category = "Iris")
FIrisReplicationStats GetReplicationStats() const;
// 액터 복제 우선순위 설정
UFUNCTION(BlueprintCallable, Category = "Iris")
void SetActorReplicationPriority(AActor* Actor, float Priority);
// 관련성 그룹 설정
UFUNCTION(BlueprintCallable, Category = "Iris")
void SetActorRelevancyGroup(AActor* Actor, FName GroupName);
// 복제 일시 중지/재개
UFUNCTION(BlueprintCallable, Category = "Iris")
void PauseReplicationForActor(AActor* Actor, bool bPause);
protected:
// Iris 네트워크 드라이버 참조
UPROPERTY()
TObjectPtr<UIrisNetDriver> IrisDriver;
// 관련성 그룹 맵
TMap<FName, TArray<TWeakObjectPtr<AActor>>> RelevancyGroups;
};
C++
// IrisReplicationManager.cpp
#include "IrisReplicationManager.h"
#include "Engine/NetDriver.h"
void UIrisReplicationManager::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// Iris 드라이버 확인
UWorld* World = GetWorld();
if (World && World->GetNetDriver())
{
IrisDriver = Cast<UIrisNetDriver>(World->GetNetDriver());
if (IrisDriver)
{
UE_LOG(LogIris, Log, TEXT("Iris Replication System 활성화됨"));
}
}
}
bool UIrisReplicationManager::IsIrisEnabled() const
{
return IrisDriver != nullptr;
}
FIrisReplicationStats UIrisReplicationManager::GetReplicationStats() const
{
FIrisReplicationStats Stats;
if (IrisDriver)
{
Stats.ReplicatedActorCount = IrisDriver->GetReplicatedActorCount();
Stats.PendingReplicationCount = IrisDriver->GetPendingReplicationCount();
Stats.BandwidthUsedKBps = IrisDriver->GetBandwidthUsage() / 1024.0f;
Stats.AverageLatencyMs = IrisDriver->GetAverageLatency() * 1000.0f;
}
return Stats;
}
void UIrisReplicationManager::SetActorReplicationPriority(
AActor* Actor,
float Priority)
{
if (!Actor || !IrisDriver) return;
// Iris의 우선순위 시스템에 등록
IrisDriver->SetActorPriority(Actor, Priority);
}
void UIrisReplicationManager::SetActorRelevancyGroup(
AActor* Actor,
FName GroupName)
{
if (!Actor) return;
// 기존 그룹에서 제거
for (auto& Pair : RelevancyGroups)
{
Pair.Value.Remove(Actor);
}
// 새 그룹에 추가
RelevancyGroups.FindOrAdd(GroupName).Add(Actor);
// Iris에 그룹 정보 전달
if (IrisDriver)
{
IrisDriver->AssignActorToRelevancyGroup(Actor, GroupName);
}
}
void UIrisReplicationManager::PauseReplicationForActor(
AActor* Actor,
bool bPause)
{
if (!Actor || !IrisDriver) return;
if (bPause)
{
IrisDriver->PauseActorReplication(Actor);
}
else
{
IrisDriver->ResumeActorReplication(Actor);
}
}
03
Iris 커스텀 복제 로직
게임에 맞는 복제 전략 구현
C++
// IrisReplicatedActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Net/IrisReplicationInterface.h"
#include "IrisReplicatedActor.generated.h"
/**
* Iris 최적화된 복제 액터
* OnBeginReplication 콜백 사용 (UE 5.7+)
*/
UCLASS()
class MYGAME_API AIrisReplicatedActor : public AActor, public IIrisReplicationInterface
{
GENERATED_BODY()
public:
AIrisReplicatedActor();
//~ Begin IIrisReplicationInterface
// UE 5.7에서 BeginReplication -> OnBeginReplication으로 변경
virtual void OnBeginReplication() override;
virtual void OnEndReplication() override;
virtual float GetIrisReplicationPriority(const FVector& ViewerLocation) const override;
virtual bool IsIrisRelevantFor(const AActor* Viewer) const override;
//~ End IIrisReplicationInterface
protected:
// 복제 속성
UPROPERTY(Replicated)
int32 ReplicatedValue;
UPROPERTY(ReplicatedUsing = OnRep_State)
FActorState CurrentState;
UFUNCTION()
void OnRep_State();
// 관련성 설정
UPROPERTY(EditDefaultsOnly, Category = "Replication")
float RelevancyRadius = 10000.0f;
UPROPERTY(EditDefaultsOnly, Category = "Replication")
float BasePriority = 1.0f;
virtual void GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
C++
// IrisReplicatedActor.cpp
#include "IrisReplicatedActor.h"
#include "Net/UnrealNetwork.h"
AIrisReplicatedActor::AIrisReplicatedActor()
{
bReplicates = true;
// Iris에서는 NetUpdateFrequency가 힌트로만 사용됨
// 실제 빈도는 Iris 스케줄러가 결정
NetUpdateFrequency = 30.0f;
MinNetUpdateFrequency = 2.0f;
}
void AIrisReplicatedActor::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AIrisReplicatedActor, ReplicatedValue);
DOREPLIFETIME(AIrisReplicatedActor, CurrentState);
}
void AIrisReplicatedActor::OnBeginReplication()
{
// UE 5.7에서 변경된 콜백명
// 복제가 시작될 때 호출
UE_LOG(LogIris, Verbose,
TEXT("[Iris] %s 복제 시작"), *GetName());
// 초기 상태 동기화 요청
ForceNetUpdate();
}
void AIrisReplicatedActor::OnEndReplication()
{
UE_LOG(LogIris, Verbose,
TEXT("[Iris] %s 복제 종료"), *GetName());
}
float AIrisReplicatedActor::GetIrisReplicationPriority(
const FVector& ViewerLocation) const
{
// 거리 기반 우선순위
float Distance = FVector::Dist(GetActorLocation(), ViewerLocation);
// 가까울수록 높은 우선순위
float DistanceFactor = FMath::Clamp(
1.0f - (Distance / RelevancyRadius),
0.1f,
1.0f
);
return BasePriority * DistanceFactor;
}
bool AIrisReplicatedActor::IsIrisRelevantFor(const AActor* Viewer) const
{
if (!Viewer) return false;
// 거리 체크
float Distance = FVector::Dist(GetActorLocation(), Viewer->GetActorLocation());
if (Distance > RelevancyRadius)
{
return false;
}
// 팀 기반 관련성 (예시)
if (const APawn* ViewerPawn = Cast<APawn>(Viewer))
{
// 적팀은 특정 조건에서만 관련
// 게임 로직에 따라 구현
}
return true;
}
void AIrisReplicatedActor::OnRep_State()
{
// 상태 변경 시 클라이언트에서 호출
OnStateChanged(CurrentState);
}
04
Seamless Travel 지원
UE 5.7에서 추가된 레벨 전환 기능
C++
// IrisSeamlessTravel.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "IrisSeamlessTravel.generated.h"
/**
* Iris Seamless Travel을 지원하는 게임 모드
* 레벨 전환 시 네트워크 연결 유지
*/
UCLASS()
class MYGAME_API AIrisSeamlessTravelGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AIrisSeamlessTravelGameMode();
// Seamless Travel로 레벨 전환
UFUNCTION(BlueprintCallable, Category = "Travel")
void TravelToLevel(const FString& LevelName);
// 전환 중 유지할 액터 지정
virtual void GetSeamlessTravelActorList(
bool bToTransition,
TArray<AActor*>& ActorList) override;
// 전환 완료 후 호출
virtual void PostSeamlessTravel() override;
protected:
// Seamless Travel 활성화
UPROPERTY(EditDefaultsOnly, Category = "Travel")
bool bUseSeamlessTravel = true;
// 전환 시 유지할 액터 클래스
UPROPERTY(EditDefaultsOnly, Category = "Travel")
TArray<TSubclassOf<AActor>> PersistentActorClasses;
};
// IrisSeamlessTravel.cpp
AIrisSeamlessTravelGameMode::AIrisSeamlessTravelGameMode()
{
bUseSeamlessTravel = true;
}
void AIrisSeamlessTravelGameMode::TravelToLevel(const FString& LevelName)
{
if (!bUseSeamlessTravel)
{
// 일반 레벨 전환
GetWorld()->ServerTravel(LevelName);
return;
}
// Seamless Travel 시작
UE_LOG(LogIris, Log,
TEXT("Seamless Travel 시작: %s"), *LevelName);
// Iris 드라이버에 전환 알림
if (UIrisNetDriver* IrisDriver =
Cast<UIrisNetDriver>(GetWorld()->GetNetDriver()))
{
IrisDriver->PrepareForSeamlessTravel();
}
// Seamless Travel 실행
GetWorld()->ServerTravel(LevelName + "?SeamlessTravel", true);
}
void AIrisSeamlessTravelGameMode::GetSeamlessTravelActorList(
bool bToTransition,
TArray<AActor*>& ActorList)
{
Super::GetSeamlessTravelActorList(bToTransition, ActorList);
// 유지할 액터 추가
for (TActorIterator<AActor> It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
for (TSubclassOf<AActor> PersistentClass : PersistentActorClasses)
{
if (Actor->IsA(PersistentClass))
{
ActorList.AddUnique(Actor);
break;
}
}
}
UE_LOG(LogIris, Log,
TEXT("Seamless Travel: %d 액터 유지"), ActorList.Num());
}
void AIrisSeamlessTravelGameMode::PostSeamlessTravel()
{
Super::PostSeamlessTravel();
UE_LOG(LogIris, Log, TEXT("Seamless Travel 완료"));
// Iris 복제 재개
if (UIrisNetDriver* IrisDriver =
Cast<UIrisNetDriver>(GetWorld()->GetNetDriver()))
{
IrisDriver->ResumeAfterSeamlessTravel();
}
}
SUMMARY
핵심 요약
- Iris Replication System은 UE5의 차세대 네트워크 복제 시스템
- 기존 대비 31% 성능 향상, 100+ 플레이어, 50K+ 액터 지원
- UE 5.7 변경: UReplicationBridge 제거, BeginReplication -> OnBeginReplication
- Seamless Travel 지원으로 레벨 전환 시 연결 유지
- 모듈식 설계로 커스텀 복제 전략 구현 용이
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: Iris Replication 기본 설정
UE5의 새로운 Iris 네트워크 복제 시스템을 프로젝트에 활성화하세요. DefaultEngine.ini에서 관련 설정을 구성하고, 기존 복제 시스템과의 호환성을 확인하세요.
실습 2: Iris 복제 성능 비교
동일한 RPG 씬(다수의 NPC, 플레이어)에서 기존 복제와 Iris 복제의 네트워크 대역폭, CPU 사용량을 비교하세요. Unreal Insights의 네트워크 채널로 프로파일링하세요.
심화 과제: 대규모 멀티플레이어 Iris 최적화
수십 명의 플레이어와 수백 명의 NPC가 있는 대규모 RPG 월드에서 Iris의 Spatial Relevancy, Push Model 복제, Object Splitting 기능을 활용하여 네트워크 성능을 극대화하세요.