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 기능을 활용하여 네트워크 성능을 극대화하세요.