PART 1 - 강의 3/4

Property Replication 심화

FRepLayout, GetLifetimeReplicatedProps, 복제 조건 상세 분석

01

FRepLayout 구조

프로퍼티 복제의 메타데이터

핵심 개념

FRepLayout은 GetLifetimeReplicatedProps가 처음 호출될 때 생성되며, UClass당 한 번만 생성되어 모든 인스턴스가 공유합니다.

C++ void AActor::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 기본 복제 DOREPLIFETIME(AMyActor, Health); // 조건부 복제 DOREPLIFETIME_CONDITION(AMyActor, Ammo, COND_OwnerOnly); // Push Model 사용 FDoRepLifetimeParams Params; Params.bIsPushBased = true; DOREPLIFETIME_WITH_PARAMS_FAST(AMyActor, Score, Params); }
02

복제 조건 (ELifetimeCondition)

프로퍼티 복제 대상 제어

조건 설명
COND_None 0 모든 클라이언트에 항상 복제
COND_InitialOnly 1 초기 Bunch에서만 복제
COND_OwnerOnly 2 소유자 클라이언트에게만 복제
COND_SkipOwner 3 소유자 제외 모든 클라이언트
COND_SimulatedOnly 4 Simulated Proxy에게만
COND_AutonomousOnly 5 Autonomous Proxy에게만
COND_Custom 8 커스텀 조건 사용

커스텀 복제 조건

C++ // PreReplication에서 동적으로 복제 제어 void AMyActor::PreReplication( IRepChangedPropertyTracker& ChangedPropertyTracker) { Super::PreReplication(ChangedPropertyTracker); // bShouldReplicate가 true일 때만 MyProperty 복제 DOREPLIFETIME_ACTIVE_OVERRIDE( AMyActor, MyProperty, bShouldReplicate); }
03

Push Model Replication

성능 최적화를 위한 명시적 변경 알림

성능 향상

Push Model을 사용하면 네트워크 트래픽 및 서버 CPU 사용량을 50% 이상 절감할 수 있습니다.

C++ // 헤더 파일 UCLASS() class AMyActor : public AActor { GENERATED_BODY() UPROPERTY(ReplicatedUsing = OnRep_Health) float Health; UFUNCTION() void OnRep_Health(); void SetHealth(float NewHealth); }; // CPP 파일 void AMyActor::GetLifetimeReplicatedProps( TArray<FLifetimeProperty>& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); FDoRepLifetimeParams Params; Params.bIsPushBased = true; DOREPLIFETIME_WITH_PARAMS_FAST(AMyActor, Health, Params); } void AMyActor::SetHealth(float NewHealth) { if (HasAuthority()) { Health = NewHealth; // 명시적으로 변경 알림! MARK_PROPERTY_DIRTY_FROM_NAME(AMyActor, Health, this); } }
주의사항

Push Model 사용 시 MARK_PROPERTY_DIRTY 호출을 잊으면 프로퍼티가 복제되지 않습니다. Setter 함수를 통해서만 값을 변경하세요.

04

RepNotify 콜백

클라이언트에서 복제 수신 시 호출

C++ // 기본 RepNotify UPROPERTY(ReplicatedUsing = OnRep_Health) float Health; UFUNCTION() void OnRep_Health() { // 클라이언트에서 Health 변경 시 호출 UpdateHealthUI(); } // 이전 값을 받는 RepNotify UFUNCTION() void OnRep_Health(float OldHealth) { float Damage = OldHealth - Health; if (Damage > 0) { PlayDamageEffect(Damage); } }
RepNotify 호출 시점
  • 클라이언트 - 서버로부터 새 값 수신 시 호출
  • 서버 - 기본적으로 호출되지 않음
  • Listen Server 호스트 - REPNOTIFY_Always로 설정 시 호출
SUMMARY

핵심 요약

  • FRepLayout - UClass당 하나, GetLifetimeReplicatedProps 첫 호출 시 생성
  • 조건부 복제 - COND_OwnerOnly, COND_SimulatedOnly 등으로 대상 제한
  • Push Model - MARK_PROPERTY_DIRTY로 명시적 변경 알림, 50%+ 성능 향상
  • RepNotify - 클라이언트에서 복제 수신 시 콜백, 이전 값 전달 가능
  • 커스텀 조건 - DOREPLIFETIME_ACTIVE_OVERRIDE로 런타임 제어
PRACTICE

도전 과제

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

실습 1: 복제 조건 비교

동일한 프로퍼티에 COND_None, COND_OwnerOnly, COND_SkipOwner를 각각 적용하고, 소유자 클라이언트와 다른 클라이언트에서 값이 어떻게 보이는지 비교하세요. PIE 3인 환경에서 테스트하세요.

실습 2: Push Model 적용

기존 DOREPLIFETIME으로 복제하던 프로퍼티를 Push Model로 전환하세요. bIsPushBased = true 설정, Setter 함수에서 MARK_PROPERTY_DIRTY_FROM_NAME 호출, stat net으로 대역폭 변화를 측정하세요.

심화 과제

DOREPLIFETIME_ACTIVE_OVERRIDE를 사용하여 PreReplication에서 동적 복제 조건을 구현하세요. 예를 들어, 은신 상태 캐릭터의 위치를 적 팀에게만 숨기는 시스템을 구현해보세요.