PART 6 · 강의 5/8

네트워크 최적화

Relevancy, Priority, Dormancy로 대역폭 관리

01

Actor Relevancy

필요한 클라이언트에게만 복제

Relevancy(관련성)는 어떤 클라이언트에게 어떤 액터를 복제할지 결정합니다. 멀리 있는 액터를 모든 클라이언트에게 복제하면 대역폭 낭비입니다.

OptimizedActor.h UCLASS() class MYGAME_API AOptimizedActor : public AActor { GENERATED_BODY() public: AOptimizedActor(); // Relevancy 오버라이드 virtual bool IsNetRelevantFor( const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation ) const override; protected: // 커스텀 관련성 거리 UPROPERTY(EditDefaultsOnly) float CustomNetCullDistanceSquared; UPROPERTY(Replicated) int32 OwningTeamID; };
OptimizedActor.cpp AOptimizedActor::AOptimizedActor() { bReplicates = true; // 기본 컬링 거리 (약 12km) NetCullDistanceSquared = 150000000.0f; // 커스텀 컬링 거리 (약 3km) CustomNetCullDistanceSquared = 10000000.0f; } bool AOptimizedActor::IsNetRelevantFor( const AActor* RealViewer, const AActor* ViewTarget, const FVector& SrcLocation) const { // 1. 기본 관련성 체크 if (!Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation)) { return false; } // 2. 거리 기반 체크 float DistSq = (GetActorLocation() - SrcLocation).SizeSquared(); if (DistSq > CustomNetCullDistanceSquared) { return false; } // 3. 팀 기반 체크 (예: 적 기지는 해당 팀에게만) if (const APawn* ViewerPawn = Cast<APawn>(ViewTarget)) { if (const AMyPlayerState* PS = ViewerPawn->GetPlayerState<AMyPlayerState>()) { if (OwningTeamID != INDEX_NONE && PS->TeamID != OwningTeamID) { return false; // 다른 팀은 볼 수 없음 } } } return true; }
02

Actor Priority

중요한 액터 우선 복제

대역폭이 제한되면 우선순위가 높은 액터부터 복제됩니다.

PriorityActor.cpp float APriorityActor::GetNetPriority( const FVector& ViewPos, const FVector& ViewDir, AActor* Viewer, AActor* ViewTarget, UActorChannel* InChannel, float Time, bool bLowBandwidth) const { // 기본 우선순위 float Priority = NetPriority; // 마지막 복제 이후 시간에 따라 증가 (기아 방지) Priority *= (Time + 2.0f); // 뷰어와의 거리에 따라 조정 float DistSq = (GetActorLocation() - ViewPos).SizeSquared(); if (DistSq < 1000000.0f) // 10m 이내 { Priority *= 4.0f; // 매우 높은 우선순위 } else if (DistSq < 10000000.0f) // 100m 이내 { Priority *= 2.0f; } // 시야 내에 있으면 우선순위 증가 FVector ToActor = (GetActorLocation() - ViewPos).GetSafeNormal(); float DotProduct = FVector::DotProduct(ViewDir, ToActor); if (DotProduct > 0.5f) // 시야 내 { Priority *= 1.5f; } return Priority; }
03

Network Dormancy

변경되지 않는 액터 휴면 처리

Dormancy(휴면)는 변경되지 않는 액터의 복제를 일시 중지하여 서버 CPU를 절약합니다.

DormantActor.cpp ADormantActor::ADormantActor() { bReplicates = true; // 레벨에 배치된 액터: DORM_Initial // 동적 스폰 액터: DORM_DormantAll NetDormancy = DORM_Initial; bIsOpen = false; } void ADormantActor::WakeForInteraction() { // 중요: 속성 변경 전에 깨워야 함! FlushNetDormancy(); // 이제 속성 변경 가능 bIsOpen = !bIsOpen; // 서버에서 직접 OnRep 호출 (서버는 OnRep 자동 호출 안됨) if (HasAuthority()) { OnRep_IsOpen(); } } void ADormantActor::ReturnToDormancy() { // 상호작용 완료 후 다시 휴면 SetNetDormancy(DORM_DormantAll); } void ADormantActor::OnRep_IsOpen() { if (bIsOpen) { PlayOpenAnimation(); } else { PlayCloseAnimation(); } }
FlushNetDormancy 순서

FlushNetDormancy()는 반드시 속성을 변경하기 전에 호출해야 합니다. 순서가 바뀌면 변경사항이 복제되지 않습니다.

Dormancy 유형
  • DORM_Never — 절대 휴면하지 않음
  • DORM_Awake — 현재 깨어있음
  • DORM_DormantAll — 모든 연결에 대해 휴면
  • DORM_DormantPartial — 일부 연결에 휴면
  • DORM_Initial — 초기 복제 후 휴면
04

복제 빈도 조절

NetUpdateFrequency 설정

복제 빈도 설정 AMyActor::AMyActor() { bReplicates = true; // 초당 최대 복제 횟수 (기본값: 100) NetUpdateFrequency = 10.0f; // 초당 10회로 제한 // 최소 복제 간격 MinNetUpdateFrequency = 2.0f; // 최소 초당 2회 } // 동적으로 빈도 조절 void AMyActor::AdjustUpdateFrequency(bool bInCombat) { if (bInCombat) { // 전투 중: 높은 빈도 NetUpdateFrequency = 30.0f; } else { // 평화로운 상태: 낮은 빈도 NetUpdateFrequency = 5.0f; } }
적절한 빈도 설정

플레이어 캐릭터: 30-60Hz
NPC: 10-20Hz
정적 오브젝트: 1-5Hz
환경 요소: Dormancy 사용 권장

SUMMARY

핵심 요약

  • Relevancy — IsNetRelevantFor 오버라이드로 복제 대상 클라이언트 결정
  • Priority — GetNetPriority로 대역폭 부족 시 중요한 액터 우선
  • Dormancy — 변경 없는 액터를 휴면 처리하여 서버 CPU 절약
  • NetUpdateFrequency — 초당 복제 횟수 제한
  • FlushNetDormancy — 휴면 액터 속성 변경 전 필수 호출
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: Relevancy 설정

AActor::IsNetRelevantFor()를 오버라이드하여, 먼 거리의 NPC는 복제하지 않도록 구현하세요. NetCullDistanceSquared를 설정하여 관련성 범위를 조절하세요.

실습 2: NetUpdateFrequency 조정

중요도에 따라 Actor의 NetUpdateFrequency를 조정하세요. 플레이어(100Hz), 보스 몬스터(30Hz), 일반 NPC(10Hz), 환경 오브젝트(1Hz)로 차등 설정하고 대역폭 감소를 측정하세요.

심화 과제: 네트워크 대역폭 프로파일링

stat Net, Net Saturation Warning을 모니터링하고, Unreal Insights의 네트워크 채널 뷰를 사용하여 어떤 Actor/Property가 대역폭을 많이 사용하는지 분석하세요. Dormancy와 Push Model 복제를 적용하여 최적화하세요.