Property Replication
변수 복제와 조건부 복제 마스터하기
기본 Property 복제
Replicated와 ReplicatedUsing
Property Replication은 서버에서 변경된 변수를 자동으로 클라이언트에 동기화합니다. UPROPERTY 지정자로 복제를 설정합니다.
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
// 기본 복제 속성
UPROPERTY(Replicated)
int32 CurrentScore;
// RepNotify를 사용한 복제 속성
UPROPERTY(ReplicatedUsing = OnRep_Health)
float Health;
// RepNotify 콜백 함수
UFUNCTION()
void OnRep_Health();
// 이전 값을 받는 RepNotify (UE5)
UPROPERTY(ReplicatedUsing = OnRep_Armor)
float Armor;
UFUNCTION()
void OnRep_Armor(float PreviousArmor);
// 필수: 복제 속성 등록
virtual void GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
#include "MyCharacter.h"
#include "Net/UnrealNetwork.h"
AMyCharacter::AMyCharacter()
{
// 복제 활성화
bReplicates = true;
// 이동 복제
SetReplicateMovement(true);
Health = 100.0f;
Armor = 0.0f;
CurrentScore = 0;
}
void AMyCharacter::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// 기본 복제
DOREPLIFETIME(AMyCharacter, CurrentScore);
DOREPLIFETIME(AMyCharacter, Health);
DOREPLIFETIME(AMyCharacter, Armor);
}
void AMyCharacter::OnRep_Health()
{
// 클라이언트에서 Health가 변경될 때 호출
if (Health <= 0.0f)
{
PlayDeathAnimation();
}
UpdateHealthBar();
}
void AMyCharacter::OnRep_Armor(float PreviousArmor)
{
// 이전 값과 현재 값 비교 가능!
float ArmorDelta = Armor - PreviousArmor;
if (ArmorDelta > 0)
{
PlayArmorGainEffect();
}
else if (ArmorDelta < 0)
{
PlayArmorDamageEffect();
}
}
조건부 복제
DOREPLIFETIME_CONDITION
대역폭을 절약하기 위해 특정 조건에서만 복제하도록 설정할 수 있습니다.
| 조건 | 설명 | 사용 예시 |
|---|---|---|
COND_None |
모든 클라이언트에 복제 | 체력, 위치 |
COND_OwnerOnly |
소유자에게만 복제 | 탄약 수, 인벤토리 |
COND_SkipOwner |
소유자 제외 복제 | 외형, 장비 시각화 |
COND_InitialOnly |
초기화 시에만 복제 | 팀 ID, 플레이어 이름 |
COND_Custom |
커스텀 조건 | 같은 팀만 등 |
void AMyCharacter::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// 소유자에게만 복제 (예: 탄약 수)
DOREPLIFETIME_CONDITION(AMyCharacter, CurrentAmmo, COND_OwnerOnly);
// 소유자 제외 복제 (예: 다른 플레이어가 볼 외형)
DOREPLIFETIME_CONDITION(AMyCharacter, CurrentSkin, COND_SkipOwner);
// 초기화 시에만 복제
DOREPLIFETIME_CONDITION(AMyCharacter, TeamID, COND_InitialOnly);
// 커스텀 조건 복제
DOREPLIFETIME_CONDITION(AMyCharacter, SecretData, COND_Custom);
}
커스텀 조건 복제
PreReplication과 ACTIVE_OVERRIDE
// MyCharacter.h
class AMyCharacter : public ACharacter
{
// ...
// PreReplication 오버라이드
virtual void PreReplication(
IRepChangedPropertyTracker& ChangedPropertyTracker) override;
protected:
UPROPERTY(ReplicatedUsing = OnRep_SecretData)
FString SecretData;
// 같은 팀 여부
bool bSameTeam;
};
// MyCharacter.cpp
void AMyCharacter::PreReplication(
IRepChangedPropertyTracker& ChangedPropertyTracker)
{
Super::PreReplication(ChangedPropertyTracker);
// 복제 대상 클라이언트와 팀 비교 로직
// (실제로는 ViewTarget의 PlayerState에서 팀 정보를 가져옴)
// SecretData는 같은 팀에게만 복제
DOREPLIFETIME_ACTIVE_OVERRIDE(
AMyCharacter, SecretData, bSameTeam);
}
DOREPLIFETIME_ACTIVE_OVERRIDE
PreReplication에서 런타임에 복제 여부를 동적으로 결정합니다. 마지막 파라미터가 true일 때만 복제됩니다.
Push Model 복제
성능 최적화를 위한 명시적 더티 마킹
Push Model은 속성이 변경될 때 명시적으로 더티 플래그를 설정하여, 서버가 매 프레임 모든 속성을 비교하지 않아도 되게 합니다.
// MyActor.h
UPROPERTY(Replicated)
int32 ImportantValue;
// MyActor.cpp
void AMyActor::SetImportantValue(int32 NewValue)
{
if (ImportantValue != NewValue)
{
ImportantValue = NewValue;
// Push Model: 명시적으로 더티 마킹
MARK_PROPERTY_DIRTY_FROM_NAME(
AMyActor, ImportantValue, this);
}
}
// GetLifetimeReplicatedProps에서 Push Model 등록
void AMyActor::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// FDoRepLifetimeParams로 Push Model 설정
FDoRepLifetimeParams Params;
Params.bIsPushBased = true;
DOREPLIFETIME_WITH_PARAMS_FAST(
AMyActor, ImportantValue, Params);
}
DefaultEngine.ini에서 전역으로 활성화할 수 있습니다:
[SystemSettings]
net.IsPushModelEnabled=1
핵심 요약
- Replicated — 단순 복제, 값 변경 시 자동 동기화
- ReplicatedUsing — 복제 시 콜백 함수 호출, UI 업데이트 등에 활용
- DOREPLIFETIME_CONDITION — 조건부 복제로 대역폭 절약
- COND_OwnerOnly — 소유자에게만 복제, 개인 정보에 사용
- Push Model — 명시적 더티 마킹으로 성능 최적화
도전 과제
배운 내용을 직접 실습해보세요
UPROPERTY(Replicated)로 Health, CurrentWeapon을 선언하고, GetLifetimeReplicatedProps()에서 DOREPLIFETIME을 추가하세요. 서버에서 값을 변경하고 클라이언트에서 동기화되는 것을 확인하세요.
UPROPERTY(ReplicatedUsing=OnRep_Health)를 구현하여 체력 변경 시 클라이언트에서 UI 업데이트와 피격 이펙트를 재생하세요. OnRep 함수에서 이전 값과 새 값을 비교하세요.
DOREPLIFETIME_CONDITION(COND_OwnerOnly)로 소유자에게만 복제되는 프로퍼티(인벤토리)와 COND_SkipOwner로 다른 플레이어에게만 복제되는 프로퍼티(3인칭 애니메이션)를 분리하세요.