2026-06-15(월) FilterByPredicate(), PlayerState, bReplicates = true, UPROPERTY(Replicated), GetLifetimeReplicatedProps()

조범근·2026년 6월 15일

TIL

목록 보기
70/81

C++ Week 16

Study

멀티플레이 개발



Today I Learned


Unreal Multiplay

1. FilterByPredicate()

Numbers = Numbers.FilterByPredicate(
    [](int32 Num)
    {
        return Num > 0;
    }
);

FilterByPredicate(...)는 Numbers의 각 원소를 람다 함수에 넣고, true가 나온 원소만 모아서 새로운 TArray를 반환해주는 함수이다.

std::vector에서 반복문과 if를 사용하여 거르던 작업을 FilterByPredicate()에서 대신 해주는 것과 같다.

단순히 Numbers.FilterByPredicate(...); 한다고 Numbers가 바뀌는게 아니라 새 배열을 반환하므로 받아줘야한다.

Numbers = Numbers.FilterByPredicate(...);



2. FChar::IsDigit(C)

FChar::IsDigit(TEXT('3')); // true
FChar::IsDigit(TEXT('8')); // true
FChar::IsDigit(TEXT('A')); // false
FChar::IsDigit(TEXT('#')); // false

IsDigit()은 현재 문자 C숫자 모양의 문자인지 확인한다.

for (TCHAR C : InNumberString)  
{  
	if (FChar::IsDigit(C) == false || C == TEXT('0'))  
	{  
		return false;  
	}  
}

이런 식으로 사용가능




3. PlayerState

PlayerState플레이어 한 명의 공개 상태를 저장하는 Actor이다.
예를 들어 플레이어 이름, 점수, 킬 수, 팀, 시도 횟수 같은 데이터를 둔다.

플레이어가 A,B 두 명이라면 서버에는 원본 PlayerState가 각각 존재한다.

Server
├─ PlayerState_A 원본
└─ PlayerState_B 원본

그리고 각 클라이언트에는 모든 플레이어의 PlayerState복제본이 생성된다.

Client A
├─ PlayerState_A 복제본
└─ PlayerState_B 복제본

Client B
├─ PlayerState_A 복제본
└─ PlayerState_B 복제본

PlayerState가 하나의 객체를 모든 컴퓨터가 공유하는 것은 아니다.
서버의 PlayerStateClientPlayerState는 서로 다른 인스턴스이며, 서버 원본의 값이 클라이언트 복제본으로 동기화되는 구조이다.

만약 서버에서 Client A의 변수를 변경하면, 각 클라이언트에 존재하는 A의 PlayerState복제본도 같은 값으로 갱신된다. 반대로 클라이언트가 자신의 PlayerState 복제본 값을 직접 변경해도 서버에는 전달되지 않습니다.

따라서 클라이언트는 Server RPC로 행동을 요청하고, 서버가 PlayerState원본을 수정해야 한다.
또 각 클라이언트는 자기 PlayerController만 가지지만, PlayerState는 다른 플레이어의 것도 가집니다.

즉, PlayerState는 서버에 플레이어별 원본이 존재하고, 각 원본에 대응하는 복제본이 모든 클라이언트에 생성된다. 서버에서 원본 값을 변경하면 각 클라이언트의 복제본으로 동기화된다.




4. Actor와 변수 복제

4-1. bReplicates = true

bReplicates = true;

이건 " 이 Actor 자체를 네트워크 복제 대상으로 지정한다. " 라는 뜻이다.
Actor 자체가 복제되지 않으면, 그 안의 변수를 복제할 대상도 클라이언트에 존재하지 않는다.

다만 APlayerState는 원래 서버에서 플레이어마다 생성되고 모든 클라이언트에 복제되도록 설계된 클래스이다. 따라서 직접 만든 일반 Actor와 달리, PlayerState에서는 보통 bReplicates = true를 다시 적지 않아도 된다.

일반 Actor라면 보통 생성자에서 설정


4-2 UPROPERTY(Replicated)

UPROPERTY(Replicated)
int32 CurrentGuessCount;

이건 " 이 Actor 안에 있는 CurrentGuessCount를 복제 변수로 사용한다. " 라는 선언이다.

서버에서 값이 바뀌면 클라이언트에 존재하는 해당 Actor 복제본의 값도 갱신된다. 복제 프로퍼티는 기본적으로 서버가 변경한 값을 연결된 클라이언트의 로컬 Actor 복제본에 전달하는 구조이다.

하지만 UPROPERTY(Replicated)만 붙인다고 끝나지는 않는다.


4-3 GetLifetimeReplicatedProps()

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

이 함수는 " 이 클래스에서 실제로 어떤 변수들을 네트워크 복제 목록에 등록할 것인가? " 를 엔진에 알려주는 함수이다.

복제 프로퍼티를 가진 Actor 클래스는 이 함수를 오버라이드해서 해당 프로퍼티를 등록해야 한다.

#include "Net/UnrealNetwork.h"

void AMyPlayerState::GetLifetimeReplicatedProps(
    TArray<FLifetimeProperty>& OutLifetimeProps
) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    DOREPLIFETIME(AMyPlayerState, PlayerNameString);
    DOREPLIFETIME(AMyPlayerState, CurrentGuessCount);
    DOREPLIFETIME(AMyPlayerState, MaxGuessCount);
}

DOREPLIFETIME()AmyPlayerState클래스의 CurrentGuessCount 변수를 복제 목록에 등록한다는 뜻이다.

여기서 Lifetime은 변수 값이 영구 저장된다는 뜻이 아니다. 해당 Actor가 네트워크에 존재하는 동안 이 프로퍼티를 복제 대상으로 관리한다. 라는 뜻이다.

기본형은 다음과 같다.
DOREPLIFETIME(클래스 이름, 변수 이름);


4-4 세 요소의 관계

bReplicates = true
→ Actor 자체를 클라이언트에 복제할 수 있게 함

UPROPERTY(Replicated)
→ 해당 변수를 복제 변수라고 표시함

GetLifetimeReplicatedProps()
+ DOREPLIFETIME()
→ 해당 변수를 실제 복제 목록에 등록함

일반 Acotr에서는 세요소를 한 세트로 볼 수 있지만, PlayerState에서는 Actor 자체가 원래 복제되므로 보통 bReplicates = true를 제외한 두 단계가 핵심이다.

0개의 댓글