콘텐츠로 이동

UE5 네트워크 직렬화와 Fast TArray

void AMyActor::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const {
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AMyActor, Health);
// 조건부 복제
DOREPLIFETIME_CONDITION(AMyActor, TeamColor, COND_InitialOnly);
DOREPLIFETIME_CONDITION(AMyActor, bIsVisible, COND_SkipOwner);
}

기본 직렬화보다 적은 비트를 사용해 대역폭을 줄입니다.

USTRUCT()
struct FCompressedVector {
GENERATED_BODY()
FVector Value;
bool NetSerialize(FArchive& Ar, UPackageMap* Map, bool& bOutSuccess) {
// 16비트 고정 소수점으로 압축 (기본 96비트 → 48비트)
if (Ar.IsSaving()) {
int16 X = FMath::RoundToInt(Value.X * 10.f);
int16 Y = FMath::RoundToInt(Value.Y * 10.f);
int16 Z = FMath::RoundToInt(Value.Z * 10.f);
Ar << X << Y << Z;
} else {
int16 X, Y, Z;
Ar << X << Y << Z;
Value = FVector(X * 0.1f, Y * 0.1f, Z * 0.1f);
}
bOutSuccess = true;
return true;
}
};
template<>
struct TStructOpsTypeTraits<FCompressedVector> : TStructOpsTypeTraitsBase2<FCompressedVector> {
enum { WithNetSerializer = true };
};

일반 TArray 복제는 배열 전체를 비교합니다. FFastArraySerializer는 변경된 항목만 전송합니다.

USTRUCT()
struct FInventoryItem : public FFastArraySerializerItem {
GENERATED_BODY()
UPROPERTY() int32 ItemId = 0;
UPROPERTY() int32 Quantity = 0;
UPROPERTY() float Durability = 1.f;
// 클라이언트에서 항목 변경 시 호출
void PostReplicatedChange(const struct FInventoryList& InArraySerializer);
void PostReplicatedAdd(const struct FInventoryList& InArraySerializer);
void PreReplicatedRemove(const struct FInventoryList& InArraySerializer);
};
USTRUCT()
struct FInventoryList : public FFastArraySerializer {
GENERATED_BODY()
UPROPERTY() TArray<FInventoryItem> Items;
bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms) {
return FFastArraySerializer::FastArrayDeltaSerialize<FInventoryItem, FInventoryList>(
Items, DeltaParms, *this);
}
};
template<>
struct TStructOpsTypeTraits<FInventoryList> : TStructOpsTypeTraitsBase2<FInventoryList> {
enum { WithNetDeltaSerializer = true };
};

컴포넌트에서 사용:

UCLASS()
class UInventoryComponent : public UActorComponent {
GENERATED_BODY()
UPROPERTY(Replicated)
FInventoryList Inventory;
void AddItem(int32 ItemId, int32 Qty) {
FInventoryItem& NewItem = Inventory.Items.AddDefaulted_GetRef();
NewItem.ItemId = ItemId;
NewItem.Quantity = Qty;
Inventory.MarkItemDirty(NewItem); // 변경 표시
}
void RemoveItem(int32 Index) {
Inventory.Items.RemoveAt(Index);
Inventory.MarkArrayDirty();
}
};
조건설명
COND_None항상 복제
COND_InitialOnly첫 복제 시만
COND_OwnerOnly소유 클라이언트만
COND_SkipOwner소유 클라이언트 제외
COND_SimulatedOnly시뮬레이션 프록시만
COND_Dynamic런타임에 조건 변경
// 1. 작은 변화는 복제 안 함
UPROPERTY(ReplicatedUsing = OnRep_Health)
float Health;
void AMyCharacter::SetHealth(float NewHealth) {
if (FMath::Abs(NewHealth - Health) < 0.01f) return; // 작은 변화 무시
Health = NewHealth;
}
// 2. 네트워크 업데이트 빈도 조절
NetUpdateFrequency = 10.f; // 초당 10회 (기본 100)
MinNetUpdateFrequency = 2.f; // 최소 초당 2회
  • NetSerialize로 구조체를 비트 단위로 압축해 대역폭 절약
  • FFastArraySerializer로 대형 배열 변경 시 델타 전송
  • MarkItemDirty / MarkArrayDirty로 변경된 항목만 표시
  • DOREPLIFETIME_CONDITION으로 불필요한 클라이언트에 복제 차단
  • NetUpdateFrequency 낮춰 업데이트 빈도 조절