에셋 및 패키지 버전 관리

커스터마이징된 시리얼라이제이션 코드 및 버전 관리를 사용하여 에셋과 패키지에서 오브젝트를 로드하는 방법을 제어합니다.

Choose your operating system:

Windows

macOS

Linux

언리얼 엔진(UE) 에는 엔진과 엔진에서 사용하는 코드 및 데이터 사이의 호환성을 정의하거나 보증하는 다양한 버전 관리 시스템이 존재합니다. 버전 관리를 사용하면 호환이 불가능한 코드 또는 데이터를 감지할 뿐만 아니라, 커스텀 시리얼라이제이션 및 데이터 변환을 관리할 수도 있습니다. 이 페이지에서 UE의 버전 관리 시스템을 엔진 버전(Engine Version), 시리얼라이제이션 버전(Serialization Version), 빌드 ID(Build ID), 이 3가지로 설명해 보겠습니다.

엔진 버전

엔진 버전 은 UE에서 수준이 가장 높고 사용자 가시성이 제일 뛰어난 버전 관리 형태입니다. 엔진의 버전 관리 시스템에서 엔진 버전을 사용하면 하위 호환성을 확보하고, 에셋의 저장 및 로드를 제어하여 데이터 손실을 방지할 수 있습니다. 엔진 버전은 에디터 내 도움말(Help) 메뉴의 언리얼 에디터에 대하여(About Unreal Editor) 섹션에 있습니다.

The About Unreal Editor dialogue box displays the current version of the Unreal Editor as well as the current changelist.

에디터에 표시되는 엔진 버전

실제 엔진 버전은 주 버전(Major version), 부 버전(Minor Version), 패치 버전(Patch Version)에 이어 체인지리스트(Changelist), 빌드된 브랜치 이름까지 5개의 컴포넌트로 이루어져 있습니다. 코드에서는 이 5개 컴포넌트를 FEngineVersion 클래스와 그 부모 클래스인 FEngineVersionBase 에서 확인할 수 있습니다.

컴포넌트

타입

예시 값(위의 스크린샷 참조)

주 버전(Major Version)

uint16

5

부 버전(Minor Version)

uint16

0

패치 버전(Patch Version)

uint16

3

체인지리스트 수(Changelist Number)

uint32

20979098

브랜치 이름(Branch Name)

FString

+++UE5+Release-5.0

엔진 버전을 이루는 각 숫자 컴포넌트는 상위의 값이 증가하는 경우를 제외하면 값이 감소하지 않습니다. 다시 말해 두 엔진 버전을 컴포넌트별로 비교하여 두 버전이 동일한지, 아니면 어느 버전이 최근 버전인지 파악할 수 있습니다. 그리고 주 버전, 부 버전, 패치 버전의 값이 모두 일치하는 경우, 에픽의 체인지리스트보다 라이선스 이용자가 생성한 체인지리스트를 항상 최근 버전으로 간주합니다. 브랜치 이름은 호환성 검사에 사용하지 않으며, 주로 외부에 표시하는 용도입니다.

엔진 버전이 호환되지 않으면 엔진에서 에셋을 로드할 수 없습니다. 엔진 버전으로 인한 작업의 실패인 것이 명백한 경우가 있지만, 최근 버전의 엔진에서 저장된 에셋은 콘텐츠 브라우저에 나타나지 않으며, 이 에셋에 대한 레퍼런스는 null로 취급됩니다. 이런 레퍼런스가 있는 에셋은 저장하지 않는 게 좋습니다. 레퍼런스가 null로 취급된 상태로 프로세스에 저장되면서 사용자가 모르는 채로 정보가 없어질 수 있기 때문입니다.

에셋 및 패키지

에셋에는 에셋 저장에 사용한 에디터의 엔진 버전 정보가 포함됩니다. 엔진에서는 로드 시 이 값을 확인하여, 코드 변경을 통해 시리얼라이즈된 데이터에 추가되거나 제거된 프로퍼티를 적절히 처리할 수 있습니다. 시리얼라이즈를 해제하는 중(예: 에셋을 로드하는 중)에 제거된 필드는 인식되지 않고 무시되는 반면, 새로 추가된 필드는 시리얼라이즈된 데이터에서 없어지지만 기본값을 유지합니다. 에셋의 데이터를 디스크에 저장하기 위해 시리얼라이즈하는 경우, 삭제된 필드의 데이터는 바로 폐기되고, 새로 추가된 필드의 데이터는 유지되어 다른 프로퍼티와 함께 시리얼라이즈됩니다. 그 결과, 데이터 구조는 서서히 변경되며, 해당 데이터 구조의 시리얼라이즈된 표현은 새 필드를 추가하는 동안 필요 없는 필드는 자연스럽게 폐기됩니다. 따라서 시리얼라이즈된 데이터는 엔진 버전에 상관없이 동일 버전이나 최근 버전에서만 인식할 수 있습니다. 이 규칙을 통해 최근 버전의 프로퍼티를 폐기하고 데이터를 다시 디스크상에 시리얼라이즈하면서 생기는 이전 버전 엔진의 데이터 손실 오류를 방지할 수 있습니다.

체인지리스트 0(Changelist 0)이 포함된 엔진 버전은 다른 모든 엔진 버전과 호환되는 것으로 간주합니다. 덕분에 엔지니어들의 엔진 개발이 간편해졌지만, 에셋을 디스크에 저장하는 데에는 적합하지 않습니다. 대신 콘텐츠 크리에이터는 배포된 에디터의 바이너리 빌드를 사용해야 하는 데, 그래야 정확한 엔진 버전 데이터를 지닌 에셋으로 작업하고, 에셋으로 인한 데이터 손실을 방지할 수 있기 때문입니다.

엔진 버전에 따른 코딩

FEngineVersion 클래스를 통해 프로젝트의 엔진 버전 정보에 액세스할 수 있습니다. 엔진 버전을 표시하거나 호환성을 검사할 때 해당 함수를 호출하는 것이 좋습니다.

함수 이름

스태틱/인스턴스

결과

Current

스태틱

빌드의 엔진 버전을 가져옵니다. 일반적으로 실제 호환성 검사보다는 표시용으로 사용합니다.

CompatibleWith

스태틱

현재 빌드와 호환되는 것 중 가장 초기의(가장 낮은) 엔진 버전을 가져옵니다. 에셋, 모듈, 네트워크 데이터 등의 호환성을 검사하는 용도로 사용합니다.

IsCompatibleWith

인스턴스

여러분이 지원하는 FEngineVersionBase 입력 파라미터에 현재 엔진 버전이 호환되는지를 표시합니다.

현재 엔진 버전이 검사 중인 엔진 버전과 같거나 최근 버전이면 호환됩니다. 예를 들어 4.19 에디터 빌드는 모든 4.18 버전 빌드의 에셋과 호환되지만, 4.18 에디터 빌드는 4.19 빌드에서 저장된 에셋과 호환되지 않습니다. 단, 체인지리스트 컴포넌트가 0인 경우 두 엔진 버전은 항상 호환 가능한 상태로 간주합니다. 이 기능을 통해 라이브 개발 환경을 지원할 수 있습니다. 언리얼 게임 동기화(Unreal Game Sync)를 통해 동기화되지 않은 엔진의 코드 기반 빌드가 있는 경우, 이 빌드의 체인지리스트를 0으로 표시하면 버전 검사와 관련해 훨씬 유연한 환경을 만들 수 있기 때문입니다. 하지만 빌드를 쿠킹할 땐 해당 에셋에서 경고가 발생하므로, 이때는 'Changelist 0' 에셋을 사용하지 않는 것이 좋습니다.

"Changelist 0" 에셋을 넣은 채 빌드를 쿠킹하는 동안 발생하는 경고를 비활성화하려면, 프로젝트 내 'DefaultEngine.ini' 파일의 [Core.System]ZeroEngineVersionWarning=0 을 추가하세요.

엔진 버전 업데이트

빌드의 엔진 버전은 엔진 내 /Build/Build.version 파일에서 정의한 값으로 제어할 수 있습니다. 이 파일은 직접 수정한 뒤 UpdateLocalVersion 커맨드릿으로 실행하거나 언리얼 게임 동기화로 동기화하면 업데이트할 수 있습니다. 다음 필드는 /Build/Build.version 파일에서 확인할 수 있습니다.

필드 이름

참고

MajorVersion

엔진의 주 버전을 제어합니다.

MinorVersion

엔진의 부 버전을 제어합니다.

PatchVersion

엔진의 패치 버전을 제어합니다.

Changelist

수동으로 정의합니다. 수동으로 업데이트하거나, UpdateLocalVersion AutomationTool 명령을 사용한 빌드 시스템으로 업데이트할 수 있습니다. 업데이트 시 디포 경로 이름을 사용하고 슬래시(/)를 더하기 기호(+)로 교체합니다.

CompatibleChangelist

해당 엔진 버전과 호환 가능한 것으로 간주할 수 있는 가장 낮은, 즉 제일 처음 만들어진 체인지리스트의 값입니다. 엔진의 로컬 빌드에 사용할 때처럼 0으로 설정될 때도 있지만, 정식 출시된 에픽의 바이너리 빌드 또는 내부적으로 배포된 바이너리 빌드는 0이 아닌 값을 가지므로 로컬 컴파일된 버전과 호환되지 않습니다.

IsLicenseeVersion

소스 컨트롤에서 동기화된 로컬 컴파일된 빌드에 사용할 경우 0으로, UpdateLocalVersion AutomationTool 커맨드릿을 통해 시스템을 빌드할 경우 1로 설정해야 합니다. 승격된 빌드에 사용할 경우 1로 설정하는 게 적절합니다. 버전 검사가 더 까다로워지는 대신 핫 리로드(Hot Reload)가 비활성화됩니다.

IsPromotedBuild

해당 빌드가 승격된 빌드인지 나타냅니다. 디폴트 값은 '1' 입니다.

BranchName

빌드가 컴파일된 브랜치를 설명하는 스트링입니다. 빌드를 표시하거나 식별하기 위해 사용합니다. 호환성 검사에는 영향을 미치지 않습니다.

BuildId

컴파일할 때 엔진 및 모듈에 전부 이 값을 태그합니다. 엔진에서는 이 값이 없는 모든 모듈을 호환 불가능한 대상으로 간주합니다. 이 값은 공백으로 두는 편이 좋습니다. 공백으로 두면 컴파일할 때마다 고유한 새 값이 생성됩니다. 추가 정보는 다음 빌드 ID(Build ID) 섹션을 참조하세요.

UpdateLocalVersion 커맨드릿

UpdateLocalVersion 커맨드릿은 전용 빌드 머신에서 컴파일할 때처럼 Build/Build.version 파일을 수동으로 편집할 필요가 없는 경우에 유용합니다. /Build/BatchFiles/RunUAT.bat 파일로 UpdateLocalVersion 커맨드릿을 다음과 같이 실행할 수 있습니다.

RunUAT.bat UpdateLocalVersion [-CL=INT] [-CompatibleCL=INT] [-Build=STRING] [-SkipHeader] [-Licensee] [-Promoted=BOOL] [-Branch=STRING]

이 파라미터들은 다음 표에 적힌 대로 해석됩니다.

파라미터

타입(디폴트 값)

해석

CL

Integer (0)

Build.versionChangelist 필드를 제어합니다.

CompatibleCL

Integer (0)

Build.versionCompatibleChangelist 필드를 제어합니다.

Build

String (empty)

소스 코드에 있는 BUILD_VERSION 매크로를 업데이트해 엔진의 빌드 버전 스트링을 변경합니다.

SkipHeader

Bool (false)

이 파라미터가 있으면 엔진의 헤더 파일이 업데이트되지 않습니다.

Licensee

Bool (false)

Build.versionIsLicensee 필드를 제어합니다. 이 파라미터가 있으면 true로 취급됩니다.

Promoted

Bool (false)

Build.versionIsPromotedBuild 필드를 제어합니다. 이 파라미터에 0 이외의 정수를 입력하면 true 로 간주하고 필드에 1 을 입력합니다.

Branch

String (empty)

Build.versionBranchName 필드를 제어합니다.

오브젝트 버전

UObject 파생 클래스는 엔진 버전에 기반한 호환성 검사에 영향을 받지만, 두 부분으로 구성된 오브젝트 버전(Object Version) 버전 관리 시스템을 별개로 두고 있습니다. 이 시스템은 엔진 레벨 버전과 커스텀 설정된 번호인 오브젝트 레벨의 버전에 모두 적용됩니다. 오브젝트 시리얼라이제이션은 대량의 벌크 데이터를 포함한 에셋의 퍼포먼스를 개선하거나, 단위 변환 시 데이터 포맷 변경을 구현하거나, 오브젝트 데이터를 압축된 포맷의 디스크에 저장할 때 공간 절약을 위해 커스터마이징되어 사용됩니다. 커스텀 시리얼라이제이션을 구현하려면 UObjectSerialize 함수를 오버라이드하여 프로젝트의 필요에 따라 데이터 포맷을 변경하고, 신규 코드의 오브젝트 버전에 기반한 검사를 포함해야 합니다. 구현을 통해 시리얼라이제이션이 변경되어도 하위 호환성을 그대로 보존하면서 엔진 버전과 같은 방식으로 데이터 손실을 방지할 수 있습니다.

엔진 레벨 시리얼라이제이션 및 버전 관리

엔진 레벨에서는 글로벌 열거형 타입인 EUnrealEngineObjectUE5Version 을 사용해 커스텀 시리얼라이저 함수의 버전 관리에 사용합니다. 커스텀 시리얼라이저가 변경될 때마다 새 항목이 EUnrealEngineObjectUE4Version 에 추가됩니다. 에픽게임즈가 공식 언리얼 엔진 출시 버전에서 이 열거형 타입을 수정함에 따라, 병렬 글로벌 열거형 타입인 EUnrealEngineObjectLicenseeUE4Version 은 언리얼 엔진 사용자가 자체적인 엔진 레벨 버전 관리를 추가할 수 있습니다. 이후 나중에 패키지를 저장하면 두 열거형 값이 증가한 채 패키지에 저장되며, 시리얼라이즈 및 디시리얼라이즈 코드가 해당 값으로 로직을 수행해 데이터 읽기/쓰기 방식을 결정합니다.

엔진에서는 자동으로 이 버전의 값을 자동으로 자체 검사하는데, 엔진보다 높은 버전이 있을 경우 패키지를 로드할 수 없습니다.

이 메서드는 엔진의 여러 분야를 각자 맡아 작업하는 여러 팀을 둔 개발자들에게 적합하지 않습니다. 다수의 버전에서 버전 열거형을 업데이트할 수는 없으며, 병합 시 상수를 다시 정렬하는 동안 해당 버전 숫자로 저장한 에셋이 손상되거나 무효화됩니다. 다양한 팀과 커스텀 시리얼라이제이션 코드를 작성하는 개발자에게는 오브젝트 레벨의 시리얼라이제이션이 좋습니다.

오브젝트 레벨 시리얼라이제이션 및 버전 관리

각자 다른 브랜치를 사용해 개발하는 경우, 동시 개발을 지원하려면, 엔진이 FGuid 기반 커스텀 버전을 통해 오브젝트 레벨 버전 관리를 제공해야 합니다. FGuid 구조에는 다른 버전처럼 서서히 증가하는 정수형 버전 번호(주로 커스텀 열거형 타입의 형태로 구현)뿐만 아니라, 팀의 요구에 따라 동시에 다양한 커스텀 버전을 보유할 수 있는 글로벌 고유 식별자(Global Unique Identifier, GUID)도 존재합니다. 시스템 또는 브랜치 별로 커스텀 버전을 유지하면 다른 브랜치의 코드를 병합할 때 충돌이 없으므로, 한 브랜치에서 커스텀 버전을 간편하게 업데이트할 수 있습니다.

신규 FGuid 를 등록하려면 GUID 및 새 버전 숫자를 이용해 FCustomVersionRegistration 타입의 글로벌 오브젝트를 생성하십시오. 예를 들어 다음 행처럼 코드를 입력하면 'Engine/Source/Runtime/AnimGraphRuntime/Private/AnimationCustomVersion.cpp'에 'AnimGraphVer' FGuid 가 생성됩니다.

const FGuid FAnimationCustomVersion::GUID(0x2EB5FDBD, 0x01AC4D10, 0x8136F38F, 0x3393A5DA);
// 코어로 커스텀 버전 등록
FCustomVersionRegistration GRegisterAnimationCustomVersion(FAnimationCustomVersion::GUID, FAnimationCustomVersion::LatestVersion, TEXT("AnimGraphVer"));

오브젝트 레벨에서는 UObject 파생 클래스에서 FArchive 함수, UsingCustomVersion 호출을 통해 Serialize 에 속한 FGuid 구조 중 하나 이상을 선택해 시리얼라이즈할 수 있습니다. 커스텀 코드에서는 등록된 모든 FGuid 에 있는 버전 번호를 고려한 로직을 수행해 데이터 읽기/쓰기 방식을 결정합니다. 이런 식으로 등록한 모든 `FGuid`와 연결된 버전 번호는 절대 감소하지 않으며, 엔진이 신규 버전의 에셋을 로드하지 않도록 할 수도 있습니다. 이렇게 하면 엔진 버전과 같은 방법을 사용하며 하위 호환성도 보장하고 데이터 손실도 방지할 수 있습니다.

커스텀 시리얼라이제이션 함수

오브젝트는 Serialize 라 부르는 UObject 함수를 오버라이드해 디스크에 있는 정밀 데이터 표현을 제어할 수 있습니다. 이 함수는 FArchive 클래스를 사용해 데이터 읽기 및 쓰기 기능을 모두 수행하므로, 데이터 포맷을 한 번만 배치하면 됩니다. 다음 FArchive 함수는 시리얼라이제이션 코드에서 버전 기반의 로직을 작성할 때 유용합니다.

함수 이름

용도

UEVer

에픽의 엔진 레벨 버전 번호를 반환합니다. 이 값은 EUnrealEngineObjectUEVersion 에 있는 한 항목의 값과 일치하도록 설정됩니다.

LicenseeUEVer

라이선시의 엔진 레벨 버전 번호를 반환합니다. 이 값은 EUnrealEngineObjectLicenseeUE4Version 에 있는 한 항목의 값과 일치하도록 설정됩니다.

CustomVer

제공된 FGuid 에 기반하여 현재 오브젝트의 오브젝트 레벨 커스텀 버전 번호를 반환합니다. 오브젝트가 저장되었을 때 이 FGuid 로 아래의 UsingCustomVersion 함수를 호출하지 않는 경우 -1을 반환합니다.

UsingCustomVersion

FGuid 를 오브젝트에 등록해 커스텀 버전 번호를 추적합니다.

오브젝트 버전 코드 예시

(엔진에도 포함된) PhysXVehicles 플러그인의 휠 달린 차량은 엔진 오브젝트 버전 및 커스텀 버전을 모두 사용하여, 실제 코드를 변경하기 전 만들어진 에셋과도 하위 호환성을 유지하고 있습니다.

여기서 커스텀 버전은 휠 서스펜션을 표현하는 피직스 스프링 오브젝트에 대한 오프셋의 차후 계산 방식을 변경하는 변수를 세팅할 때 사용됩니다. 사용된 특정 커스텀 버전 값은 피직스 코드를 관리하는 팀에서 제작한 열거형 타입에서 가져온 것입니다.

void UWheeledVehicleMovementComponent::Serialize(FArchive& Ar)
{
    Super::Serialize(Ar);
    Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID);
    if (Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::WheelOffsetIsFromWheel)
    {
        bDeprecatedSpringOffsetMode = true;
    }
}

다음 예시에서는 각 속도(Angular Velocity)가 초당 라디안 대신(RPS) 분당 회전(RPM)으로 발생하는 물리적 변화에 대응해 단위 전환을 수행하고 있습니다. 이 각 속도는 단위가 없는 부동 소수점 값으로 저장되므로, 낮은 버전의 에셋 사용 시 로드 시간 변환이 필요합니다. 이 경우에는 에셋을 로드할 때 각 속도 변수만 수정하면 됩니다. 이 타입으로 저장되는 모든 에셋은 이미 각 속도를 분당 회전(RPM) 단위로 저장하며, 다음에 로드할 때 코드를 변환할 필요가 없도록 현재 엔진 버전 번호로 저장합니다.

void FConstraintInstance::PostSerialize(const FArchive& Ar)
{
#if WITH_EDITORONLY_DATA
    // ...
    if (Ar.IsLoading() && Ar.UE4er() < VER_UE_FIXUP_MOTOR_UNITS)
    {
        AngularVelocityTarget *= 1.f / (2.f * PI);
    }
    // …
#endif
}

LicenseeUEVer 에 대한 UEVer 함수 호출을 변경할 경우, 에픽의 공식 버전 번호가 아니라 언리얼 엔진 사용자의 버전 번호를 사용하도록 코드가 변경됩니다. 자체 버전의 언리얼 엔진 4를 따로 관리하는 에픽 외 사용자에게 권장합니다.

바이너리 버전 관리

자세한 내용은 바이너리 버전 관리 레퍼런스 페이지를 참조하세요.