Arknights EP - [Confront]
Categories
Tags
1258 words
6 minutes
[UE5/System] 언리얼 엔진 데이터 관리 및 시스템 구조
언리얼 엔진의 데이터 저장 방식부터 모듈 시스템까지 묶어서 정리하였다.
1. 직렬화 (Serialization)
언리얼에서 UObject의 데이터를 저장하고 불러들이는 기본 원리이다.
1.1 직렬화와 언리얼의 방식
- 직렬화(Serialization): 메모리 상의 오브젝트를 디스크 저장이나 네트워크 전송이 가능한 바이트 스트림(Byte Stream)으로 변환하는 과정이다. 역직렬화(Deserialization)는 그 반대다.
- 언리얼의 구현: 언리얼은
FArchive클래스와 시프트 연산자(<<)를 재정의하여 사용한다. - 저장과 로딩 모두
Ar << Data하나의 코드로 통일하여 작성한다. (아카이브 내부 상태인IsLoading(),IsSaving()이 방향을 결정함)
1.2 실습: 일반 C++ 구조체 직렬화
가장 기초적인 단계로 일반 구조체를 파일로 입출력하는 방법이다.
struct FStudentData
{
int32 Order = -1;
FString Name = TEXT("기본이름");
// 직렬화를 위한 연산자 오버로딩 (FArchive 통로 약속)
friend FArchive& operator<<(FArchive& Ar, FStudentData& InData)
{
Ar << InData.Order;
Ar << InData.Name;
return Ar;
}
};
// 파일 저장 예시
const FString RawDataAbsolutePath = FPaths::Combine(*SavedDir, TEXT("RawData.bin"));
FStudentData RawDataSrc(16, TEXT("홍길동"));
FArchive* FileWriterAr = IFileManager::Get().CreateFileWriter(*RawDataAbsolutePath);
if (FileWriterAr)
{
*FileWriterAr << RawDataSrc; // 오버로딩된 operator<< 호출
FileWriterAr->Close();
delete FileWriterAr;
}
1.3 실습: UObject 직렬화 (2단계 방식)
UObject는 자체적으로 Serialize 함수를 가진다. 보통 객체를 메모리 버퍼로 먼저 변환한 뒤, 그 버퍼를 파일로 저장하는 2단계 방식을 주로 사용한다.
// 1. 객체를 메모리(Buffer)에 쓰기
TArray<uint8> BufferArray;
FMemoryWriter MemoryWriterAr(BufferArray);
StudentSrc->Serialize(MemoryWriterAr);
// 2. 메모리를 파일에 쓰기 (TUniquePtr 활용으로 자동 메모리 해제)
if (TUniquePtr<FArchive> FileWriterAr = TUniquePtr<FArchive>(IFileManager::Get().CreateFileWriter(*ObjectPath)))
{
*FileWriterAr << BufferArray;
FileWriterAr->Close();
}
JSON 직렬화 팁 JSON 포맷을 사용하려면
Build.cs에 반드시"Json","JsonUtilities"모듈을 추가해야 한다.
흐름:
[UObject] <-> (Converter) <-> [FJsonObject] <-> (Serializer) <-> [String]
2. 패키지(Package)와 에셋(Asset)
직렬화된 데이터를 에디터가 인식할 수 있는 .uasset 형태로 관리하는 구조이다.
2.1 패키지와 에셋의 관계
- 패키지 (
UPackage): 여러 언리얼 오브젝트를 포장하는 최상위 오브젝트이다. - 에셋 (Asset): 패키 내부에 포함된 오브젝트 중 에디터 콘텐츠 브라우저에 노출되는 메인 오브젝트이다.
- 일반적으로 1개의 패키지는 1개의 에셋을 가진다.
2.2 오브젝트 패스와 에셋 로딩 전략
에셋은 메모리 관리를 위해 고유한 경로인 오브젝트 패스 (Object Path)로 관리된다.
- 형식:
패키지명.에셋명(예:/Game/Student.TopStudent)
메모리 부하를 줄이기 위해 필요한 시점에 로딩하는 전략을 사용한다.
- 생성자 로딩 (
ConstructorHelpers): 클래스 생성자에서 미리 로드. (에러 시 크래시 주의) - 동기 로딩 (
LoadObject): 런타임에 즉시 로드. (프레임 드랍 유발 가능) - 비동기 로딩 (
StreamableManager): 백그라운드에서 로딩 후 콜백 실행. (대규모 게임 필수)
// 비동기 로딩 예시
FStreamableManager StreamableManager;
const FString Path = TEXT("/Game/Student.TopStudent");
StreamableManager.RequestAsyncLoad(Path, [&]()
{
// 로딩 완료 후 실행될 람다
});
3. 모듈(Module)과 플러그인(Plugin)
저장된 데이터와 작성된 코드들이 실제로 어떻게 엔진에서 뭉쳐서 돌아가는지에 대한 구조이다.
3.1 C++ 프로젝트와 모듈
언리얼 엔진의 모든 소스 코드는 모듈(Module) 단위로 구성된다.
- 블루프린트 프로젝트는 엔진 기본 모듈만 사용하지만, C++ 프로젝트는 개발자가 직접 작성한 커스텀 C++ 모듈을 엔진에 추가하여 작동하는 원리이다.
- 컴파일 결과물은 에디터용 빌드 시
DLL 동적 라이브러리형태로 생성된다.
3.2 UBT (Unreal Build Tool)
언리얼은 멀티 플랫폼 빌드를 위해 Visual Studio에 종속되지 않고 자체적인 UBT (C# 프로그램)를 사용한다.
이를 위해 두 가지 중요한 C# 설정 파일이 필요하다.
.Target.cs(타겟 설정): 게임/에디터 등 전체 솔루션의 빌드 환경 설정..Build.cs(모듈 설정): 특정 모듈의 의존성(위의 JSON 모듈 추가 등) 설정.
[UE 5.7 기준 Editor 타겟 파일 예시]
using UnrealBuildTool;
using System.Collections.Generic;
public class UnrealBuildSystemEditorTarget : TargetRules
{
public UnrealBuildSystemEditorTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Editor;
DefaultBuildSettings = BuildSettingsVersion.V6;
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_7;
CppStandard = CppStandardVersion.Cpp20; // C++20 지원
bOverrideBuildEnvironment = true;
ExtraModuleNames.AddRange(new string[] { "UnrealBuildSystem" });
}
}
요약 (System Architecture Flow)
- 코드 (Module):
.Build.cs와.Target.cs를 통해 C++ 코드를 UBT가 DLL 모듈로 컴파일한다. - 데이터 생성 (Serialization): 컴파일된 코드가 실행되며
FArchive를 통해 데이터를 직렬화한다. - 포장 및 관리 (Package & Asset): 직렬화된 데이터는
UPackage로 묶여 콘텐츠 브라우저에.uasset으로 노출되며, 오브젝트 패스를 통해 효율적으로 로드된다.

