서버 스트리밍
Dedicated Server와 Listen Server에서의 World Partition
서버 스트리밍 배경
왜 서버에서 스트리밍이 필요한가
역사적으로 Dedicated Server는 전체 맵을 메모리에 로드해야 했습니다. 충돌 데이터와 액터 상태를 검증하기 위해서입니다. 하지만 대규모 오픈월드에서는 이것이 불가능합니다.
기존 방식
서버가 전체 월드 로드. 메모리 집약적이고, 대규모 월드에서는 불가능합니다.
서버 스트리밍 (UE 5.1+)
서버도 플레이어 위치 기반으로 셀을 스트리밍. 대규모 월드 지원 가능합니다.
서버 스트리밍 활성화
CVar 및 프로젝트 설정
// Console Command로 활성화
wp.Runtime.EnableServerStreaming 1
// 또는 DefaultEngine.ini에 추가
[/Script/Engine.WorldPartitionRuntimeSpatialHash]
bEnableServerStreaming=true
GameMode에서 설정
UCLASS()
class MYGAME_API AMyGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
virtual void InitGame(const FString& MapName,
const FString& Options,
FString& ErrorMessage) override
{
Super::InitGame(MapName, Options, ErrorMessage);
// 서버 스트리밍 설정
ConfigureServerStreaming();
}
protected:
void ConfigureServerStreaming()
{
// Dedicated Server인 경우
if (IsRunningDedicatedServer())
{
// 서버 스트리밍 CVar 설정
static IConsoleVariable* CVarEnableServerStreaming =
IConsoleManager::Get().FindConsoleVariable(
TEXT("wp.Runtime.EnableServerStreaming"));
if (CVarEnableServerStreaming)
{
CVarEnableServerStreaming->Set(1);
UE_LOG(LogTemp, Log, TEXT("Server streaming enabled"));
}
}
}
};
Listen Server 고려사항
호스트 + 플레이어 동시 처리
Listen Server에서는 호스트 플레이어가 스트리밍 소스로 작동합니다. 다른 원격 플레이어들도 각자의 스트리밍 소스로 등록해야 합니다.
UCLASS()
class MYGAME_API AMyPlayerController : public APlayerController
{
GENERATED_BODY()
public:
virtual void BeginPlay() override
{
Super::BeginPlay();
// 모든 플레이어 컨트롤러를 스트리밍 소스로 등록
// PlayerController는 기본적으로 IWorldPartitionStreamingSourceProvider 구현
// 별도 등록 없이 자동으로 스트리밍 소스로 동작
if (UWorld* World = GetWorld())
{
if (UWorldPartitionSubsystem* WPSubsystem =
World->GetSubsystem<UWorldPartitionSubsystem>())
{
UE_LOG(LogTemp, Log, TEXT("PlayerController registered as streaming source"));
}
}
}
};
APlayerController는 IWorldPartitionStreamingSourceProvider 인터페이스를 기본 구현하므로, 별도 코드 없이도 각 플레이어가 스트리밍 소스로 작동합니다.
네트워크 리플리케이션과 스트리밍
동적 생성 액터의 네트워크 처리
// Procedural Actor 리플리케이션 시 주의사항
UCLASS()
class MYGAME_API AMyProceduralActor : public AActor
{
GENERATED_BODY()
public:
AMyProceduralActor()
{
bReplicates = true;
// bNetStartup을 true로 설정하면 레벨에서 로드된 것처럼 처리
// 클라이언트가 FNetworkGUID를 acknowledge할 수 있다고 가정
bNetStartup = true;
}
virtual bool IsNetRelevantFor(const AActor* RealViewer,
const AActor* ViewTarget,
const FVector& SrcLocation) const override
{
// 스트리밍 시나리오에서는 클라이언트가 아직 스폰하지 않았을 수 있음
// 클라이언트 측 생성이 완료될 때까지 Relevant하지 않게 설정
if (!bClientSideGenerated)
{
return false;
}
return Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);
}
private:
bool bClientSideGenerated = false;
};
서버에서 셀이 로드되었지만 클라이언트에서는 아직 로드되지 않은 경우, 해당 셀의 액터 리플리케이션이 실패할 수 있습니다. Net Relevancy를 적절히 설정해야 합니다.
서버 스트리밍 아키텍처
서버와 클라이언트의 스트리밍 독립성
┌─────────────────────────────────────────────────────────────┐
│ SERVER (Dedicated/Listen) │
├─────────────────────────────────────────────────────────────┤
│ Streaming Sources: │
│ - 모든 연결된 플레이어의 위치 │
│ - 서버 전용 AI/시스템 스트리밍 소스 │
│ │
│ 로드된 셀: 모든 플레이어 주변 셀의 합집합 │
└─────────────────────────────────────────────────────────────┘
↓ Replication ↓
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ CLIENT 1 │ │ CLIENT 2 │ │ CLIENT 3 │
├──────────────────┤ ├──────────────────┤ ├──────────────────┤
│ Streaming Source:│ │ Streaming Source:│ │ Streaming Source:│
│ - 로컬 플레이어 │ │ - 로컬 플레이어 │ │ - 로컬 플레이어 │
│ │ │ │ │ │
│ 로드된 셀: │ │ 로드된 셀: │ │ 로드된 셀: │
│ 자신 주변만 │ │ 자신 주변만 │ │ 자신 주변만 │
└──────────────────┘ └──────────────────┘ └──────────────────┘
- 서버는 모든 플레이어 주변 셀의 합집합을 로드
- 각 클라이언트는 자신의 플레이어 주변 셀만 로드
- 리플리케이션은 서버-클라이언트 간 셀 로드 상태에 따라 조절
핵심 요약
- wp.Runtime.EnableServerStreaming으로 서버 스트리밍 활성화 (UE 5.1+)
- Dedicated Server도 플레이어 위치 기반 스트리밍으로 메모리 절약
- Listen Server에서 모든 플레이어가 자동으로 스트리밍 소스
- Net Relevancy 설정으로 동기화 문제 방지
- 서버는 모든 플레이어 주변 셀의 합집합을 로드
도전 과제
배운 내용을 직접 실습해보세요
프로젝트 설정에서 서버 스트리밍을 활성화하고, bUseServerStreamingForDedicatedServer 옵션을 설정하세요. 데디케이트 서버에서 서버 기반 스트리밍 그리드가 사용되는 것을 확인합니다.
ListenServer 환경에서 서버와 클라이언트 각각의 스트리밍 소스가 독립적으로 작동하는 것을 확인하세요. 클라이언트가 서버와 다른 위치에 있을 때 각각의 셀 로딩 상태를 디버그 표시합니다.
64인 이상의 대규모 멀티플레이어에서 서버 스트리밍 성능을 최적화하세요. ServerStreamingCellSize 조절, 플레이어 밀집도 기반 동적 셀 관리, 서버 메모리 예산 모니터링 시스템을 구현합니다.