본문으로 건너뛰기
Unreal Engine 멀티플레이LESSON 09

Replicated 변수와 RepNotify

난이도입문 → 초급
예상 시간75분
선수지식8강의 서버 Spawn 복제 Actor

9강. Replicated 변수와 RepNotify

1. 이번 강의에서 해결할 문제​

서버 점령 지점의 진행률은 바뀌지만 클라이언트 UI가 그대로이거나, Multicast 한 번을 놓친 늦은 참가자가 현재 진행률을 모릅니다. 진행률·체력·점수처럼 현재 값이 중요한 상태는 이벤트 한 번이 아니라 서버의 최신 상태를 복제해야 합니다.

2. 학습 목표​

3. 핵심 개념​

Property Replication은 서버 값을 클라이언트가 결국 최신 상태로 수렴하게 합니다. 모든 중간 변경을 반드시 전달하는 이벤트 스트림이 아니므로 “10→20→30”이 한 네트워크 갱신 사이에 일어나면 클라이언트가 30만 볼 수 있습니다. 현재 상태에는 적합하지만 매 사건 자체가 반드시 필요하면 별도 기록 구조를 검토합니다.

ReplicatedUsing=OnRep_CaptureProgress는 클라이언트가 새 값을 수신할 때 후처리 함수를 호출합니다. 일반적인 서버 실행에서는 서버 자신에게 복제가 되지 않으므로 같은 표현이 서버에도 필요하면 서버 변경 함수에서 공통 갱신 함수를 직접 호출합니다.

4. 단계별 실습​

파일 경로: Source/CaptureArena/World/CapturePoint.h

CapturePoint.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CapturePoint.generated.h"

UCLASS()
class CAPTUREARENA_API ACapturePoint : public AActor
{
GENERATED_BODY()

public:
ACapturePoint();

void SetCaptureProgress(float NewProgress, int32 NewTeamId);

virtual void GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const override;

protected:
UPROPERTY(ReplicatedUsing = OnRep_CaptureProgress,
VisibleInstanceOnly, Category = "Capture")
float CaptureProgress = 0.0f;

UPROPERTY(ReplicatedUsing = OnRep_OwningTeam,
VisibleInstanceOnly, Category = "Capture")
int32 OwningTeamId = INDEX_NONE;

UFUNCTION()
void OnRep_CaptureProgress();

UFUNCTION()
void OnRep_OwningTeam();

private:
void RefreshVisuals();
};
CapturePoint.cpp
#include "World/CapturePoint.h"

#include "Net/UnrealNetwork.h"

ACapturePoint::ACapturePoint()
{
PrimaryActorTick.bCanEverTick = false;
bReplicates = true;
}

void ACapturePoint::SetCaptureProgress(float NewProgress, int32 NewTeamId)
{
if (!HasAuthority()) return;

CaptureProgress = FMath::Clamp(NewProgress, 0.0f, 1.0f);
OwningTeamId = NewTeamId;
RefreshVisuals(); // 리슨·데디케이티드 서버의 로컬 상태도 일관되게 갱신
}

void ACapturePoint::OnRep_CaptureProgress()
{
RefreshVisuals();
}

void ACapturePoint::OnRep_OwningTeam()
{
RefreshVisuals();
}

void ACapturePoint::RefreshVisuals()
{
UE_LOG(LogTemp, Display, TEXT("Capture Team=%d Progress=%.2f Role=%s"),
OwningTeamId, CaptureProgress,
*UEnum::GetValueAsString(GetLocalRole()));
}

void ACapturePoint::GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ACapturePoint, CaptureProgress);
DOREPLIFETIME(ACapturePoint, OwningTeamId);
}

두 OnRep의 호출 순서에 게임 규칙을 의존하지 않습니다. 서로 연관된 값이 항상 하나의 원자적 스냅샷이어야 한다면 한 USTRUCT Property로 묶고 단일 RepNotify에서 해석하는 방법을 검토합니다.

5. 코드가 동작하는 이유​

서버만 Setter를 통해 값을 바꾸고 NetDriver가 변경된 Property를 관련 연결로 보냅니다. 클라이언트는 수신 뒤 RepNotify를 실행해 Material, ProgressBar와 사운드 조건을 갱신할 수 있습니다. 늦게 참가한 클라이언트도 Actor가 관련성이 생길 때 최신 Property를 받으므로 현재 진행률을 복구합니다.

6. 자주 하는 실수와 해결법​

7. 직접 실습​

8. 이해 점검 질문 3개​

9. 핵심 요약​

MINI QUIZ

Replicated 변수와 RepNotify 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“Replicated 변수와 RepNotify” 내용을 실제 작업에 적용한 설명으로 가장 알맞은 것은 무엇인가요?
  2. 문제 2“Replicated 변수와 RepNotify”에서 ‘서로 다른 OnRep 순서를 가정’ 문제가 생겼습니다. 가장 알맞은 진단 또는 대응은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

9강. Replicated 변수와 RepNotify 미완료 상태