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에서 동적 복제 조건을 구현하세요. 예를 들어, 은신 상태 캐릭터의 위치를 적 팀에게만 숨기는 시스템을 구현해보세요.