アセットとパッケージのバージョンを管理する

カスタマイズされたシリアル化コードとバージョン管理を使用して、アセットとパッケージからオブジェクトを読み込む方法を制御します

Unreal Engine (UE) には、エンジンとエンジンが消費するコードおよびデータとの間の互換性を定義、保証する複数のバージョン管理システムがあります。 バージョン管理は、互換性のないコードやデータを検出するだけでなく、カスタムのシリアル化とデータ変換の管理にも使用可能です。 UE のバージョン管理は、 エンジン バージョンシリアル化 バージョンビルド ID の 3 つの主要システムに分けられています。

エンジン バージョン

エンジンのバージョン は、UE 内で最もレベルが高く、最も作業することの多いバージョン管理のフォームです。エンジンにあるバージョン管理システムのこの部分は、後方互換性を確保し、アセットの保存と読み込みを制御することでデータ損失を防ぎます。 エンジン バージョンは、エディタ内にあるヘルプメニューの [About Unreal Editor (Unreal Editor について)] セクションに表示されています。

The About Unreal Editor dialogue box displays the current version of the Unreal Editor as well as the current 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

個々の数値コンポーネントは、高次の値が増加した場合を除いて、時間の経過とともに値が減少することはありません。 つまり、2 つのエンジン バージョンをコンポーネントごとに比較して、それらが同一であるかどうか、またはどちらが新しいかを判断できます。 さらに、メジャー バージョン、マイナー バージョン、パッチ バージョンの値がすべて一致していれば、ライセンシーが作成したチェンジリストは常に Epic のチェンジリストよりも新しいリストと見なされます。 ブランチ名は互換性チェックには使用されず、主に表示目的で存在しています。

互換性のないエンジン バージョンの使用は、エンジンがアセットを読み込めない原因となります。 場合によっては、互換性のないエンジン バージョンの使用によって操作があからさまに失敗することがありますが、新しいバージョンのエンジンで保存されたアセットは単にコンテンツ ブラウザに表示されず、それらアセットへの参照は「null」として扱われます。 そのような参照を持つアセットの保存は危険な場合があります。現在「null」になっている参照はプロセスに保存され、ユーザーに通知せずにその情報が事実上失われるためです。

アセットとパッケージ

アセットには、それらを保存するために使用されたエディタのエンジン バージョンが含まれています。 ロード時にこの値をチェックすることによって、エンジンはコード変更によってシリアル化が行われたデータに追加された値や、値から削除されたプロパティを適切に処理できます。 逆シリアル化中 (アセットのロード中など) に削除されたフィールドは認識されずに無視される一方で、新しく追加されたフィールドはシリアル化されたデータから失われますがデフォルト値は保持されます。 アセットのデータをディスクに保存するためにシリアル化すると、削除されたフィールドのデータは破棄されて新しく追加されたフィールドのデータが現れ、他のすべてのプロパティと共にシリアル化されます。 この結果、データ構造が時間の経過とともに変更されると、それらの構造のシリアル化表現は、新しいフィールドを追加しながら、古いフィールドをスムーズに破棄していきます。 このため、エンジンの特定のバージョンからシリアル化されたデータは、同じバージョンまたは新しいバージョンに対してのみ読み込み可能になります。 このルールにより、古いバージョンのエンジンが新しいプロパティを破棄してからデータをディスク上の形式にシリアル化し直すことによって発生するデータ損失エラーを防ぐことができます。

チェンジリスト 0 のエンジン バージョンは、他のすべてのエンジン バージョンと互換性があると見なされます。 これにより、エンジニアはエンジン開発が容易になりますが、このリストをアセットをディスクに保存するためには使用しないでください。 代わりに、コンテンツ作成者は分散されたエディタのバイナリ ビルドを使用してください。そうすることで、正確なエンジン バージョン データを伝え、提供されたデータの損失を防ぐことができるアセットで作業できます。

エンジン バージョンでのコーディング

FEngineVersion クラスは、プロジェクト内のエンジン バージョン情報へのアクセスを提供します。 エンジンのバージョンを表示したり、互換性を確認したりする必要があるときにこれらの関数を呼び出すことをお勧めします。

関数名

スタティック/インスタンス

効果

Current

スタティック

ビルドのエンジン バージョンを取得します。 通常、実際の互換性チェックではなく表示目的で使用します。

CompatibleWith

スタティック

現在のビルドに互換性のある、最も古い (最も低い) エンジン バージョンを取得します。 アセット、モジュール、ネットワークデータなどの互換性チェックを目的としています。

IsCompatibleWith

インスタンス

現在のエンジン バージョンが、指定した FEngineVersionBase 入力パラメータと互換性があるかどうかを示します。

互換性があるのは、現在のエンジン バージョンがチェック対象のエンジン バージョンと同じかそれより新しい場合です。 例えば、4.19 のエディタのビルドは 4.18 のアセットと互換性がありますが、4.18 のエディタのビルドは 4.19 のビルドで保存されたアセットとは互換性がありません。 これに対する例外は、どちらかが 0 のチェンジリスト コンポーネントを持つ場合です。その際は、2 つのエンジン バージョンは常に互換性があると見なされます。これは、Unreal Game Sync を介して同期されなかったコード ベースのエンジン ビルドはチェンジリスト 0 としてマークされ、バージョン チェックに関してより寛容な環境を作成するため、これは実際の開発環境をサポートするために行われます。 ただし、ビルドをクックするときにこれらのアセットから警告が発せられます。そのため、「チェンジリスト 0 」アセットの使用はお勧めしません。

「チェンジリスト 0」アセットでビルドをクック中に表示される警告を無効にするには、プロジェクトの「DefaultEngine.ini」ファイルの [Core.System] セクションに ZeroEngineVersionWarning=0 を追加します。

エンジン バージョンを更新する

ビルドのエンジン バージョンは、エンジンの「/Build/Build.version」ファイル内で定義された値によって制御されます。 このファイルは手動で編集するか、「UpdateLocalVersion」コマンドレットを実行するか、Unreal Game Sync を介して同期することで更新できます。 以下のフィールドは「/Build/Build.version」ファイルから読み込まれます。

フィールド名

注記

MajorVersion

エンジンのメジャー バージョンを制御します。

MinorVersion

エンジンのマイナー バージョンを制御します。

PatchVersion

エンジンのパッチ バージョンを制御します。

Changelist

手動で定義します。 手動で更新することも AutomationTool コマンドの UpdateLocalVersion を使用してシステムをビルドすることによって更新することもできます。 これはビルドのデポのパス名を使用し、スラッシュをプラスに置き換えます。

CompatibleChangelist

これは、このエンジン バージョンと互換性があるとみなされるチェンジリストの最も低い (または最も早い) 値です。 エンジンのローカル ビルドの場合のように、この値はしばしばゼロとなりますが、Epic から公式リリースされたバイナリ ビルド、または内部的に配布されたバイナリ ビルドはゼロ以外の値を持ち、ローカルでコンパイルされたバージョンと互換性がありません。

IsLicenseeVersion

ソース管理から同期されたローカルでコンパイルされたビルドの場合は「0」となっていますが、AutomationTool コマンドの UpdateLocalVersion を使用するとビルドシステムによって「1」に設定されます。 この値の設定が「1」だと昇格ビルドに適しており、厳密なバージョンチェックが可能になりますが、ホットリロードは無効になります。

IsPromotedBuild

これが昇格ビルドであることを示します。 デフォルト値は「1」です。

BranchName

ビルドのコンパイル元のブランチを説明するために使用される文字列です。 表示目的、またはビルドを一意に識別するために使用します。 互換性チェックには影響しません。

BuildId

コンパイル時には、エンジンとモジュールはすべてこの値でタグ付けされています。 この値がないモジュールは、エンジンから互換性がないと見なされます。 この値を空白のままにしておくことをお勧めします。これにより、コンパイルごとに新しい一意の値が生成されます。 詳細については、以下の「ビルド 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

整数 (0)

Build.version」の「Changelist」フィールドを制御します。

CompatibleCL

整数 (0)

Build.version」の「CompatibleChangelist」フィールドを制御します。

Build

文字列 (empty)

ソースコード内の BUILD_VERSION マクロを更新することによって、エンジン内のビルド バージョン文字列を置き換えます。

SkipHeader

ブール (false)

存在する場合、エンジンのヘッダ ファイルは更新されません。

Licensee

ブール (false)

Build.version」の「IsLicensee」フィールドを制御します。 このパラメータが存在する場合は、「true」として扱われます。

Promoted

ブール (false)

Build.version」の「IsPromotedBuild」フィールドを制御します。 このパラメータが「0」以外の整数値の場合、「true」と見なされフィールドに「1」が書き込まれます。

Branch

文字列 (empty)

Build.version」の「BranchName」フィールドを制御します。

オブジェクト バージョン

UObject の派生クラスは、エンジン バージョンに基づいた互換性チェックの対象となりますが、それらには、エンジン レベル バージョンと任意の数のカスタム オブジェクト レベル オブジェクト バージョンの両方を備えた、2 つのパートに分かれたバージョン管理システム、**オブジェクト バージョン**もあります。 オブジェクトのシリアル化は、パフォーマンスの向上 (大量のバルク データを含むアセットなど) 、データ形式変更 (単位変換の実行など) の実装、容量の節約 (オブジェクト データの圧縮フォーマットでのディスク書き込みなど) のため、カスタマイズされることがよくあります。 カスタムなシリアル化を実装するには、`UObject` 関数のオーバーライド、`Serialize`、プロジェクトのニーズに応じたデータ形式の変更、新しいコードのオブジェクト バージョンに基づいたチェックを含めることが必要となります。これを行うことで、エンジン バージョンと同じ方法で、データの損失を防ぎながら、シリアル化の変更による後方互換性を維持できます。

エンジン レベルのシリアル化とバージョン管理

エンジン レベルでは、グローバル列挙型である EUnrealEngineObjectUEVersion が、カスタム シリアライザ関数のバージョン管理に使用されます。 カスタム シリアライザが変更されるたびに、新しいエントリが EUnrealEngineObjectUEVersion に追加されます。 この列挙型は Unreal Engine 4 公式リリースで Epic によって変更されました。そのため、ライセンシーが独自のエンジン レベルのバージョン管理を追加するためのパラレル グローバル列挙型である EUnrealEngineObjectLicenseeUEVersion があります。 今後保存されるすべてのパッケージは、両方の列挙型の増分値をパッケージに保存し、シリアル化 (および逆シリアル化) コードはこれらの値でロジックを実行してデータの読み書き方法を決定できます。

エンジンは自動的にこれらバージョンの値をエンジン自身に対してチェックし、エンジンよりも高いバージョン番号を持つパッケージのロードは失敗となります。

複数のチームでエンジンのさまざまな分野に取り組んでいる場合、この方法が最適とは言えません。 バージョンの列挙を複数の場所で更新することは不可能で、マージ時に定数を並べ替えると、それらのバージョン番号で保存されたアセットが破損または無効になります。 カスタム シリアル化コードを書く複数のチームで作業している場合、オブジェクト レベルのシリアル化をお勧めします。

オブジェクト レベルのシリアル化とバージョン管理

並列開発をサポートするために (特に異なるブランチを使用する場合) 、エンジンは FGuid ベースのカスタム バージョンによるオブジェクト レベルのバージョン管理を提供しています。 FGuid 構造体には整数のバージョン番号が含まれています。これは、他のバージョン番号と同様に、時間をかけて増やすことができます (通常はカスタム列挙型として実装されます)。しかし、この構造にはグローバルな一意の識別子 (GUID) も含まれているため、チームのニーズに応じて、さまざまな並列カスタム バージョンを作成できます。 システムまたはブランチごとに個別のカスタム バージョンを保持すると、他のブランチからのコードをマージするときに競合が発生することなく、1 つのブランチでカスタム バージョンを簡単に更新できます。

新規で FGuid を登録するには、GUID と現在のバージョン番号を使用して FCustomVersionRegistration 型のグローバル オブジェクトを作成します。 例えば、次のコード行は Engine/Source/Runtime/AnimGraphRuntime/Private/AnimationCustomVersion.cppAnimGraphVer FGuid を作成します。

    const FGuid FAnimationCustomVersion::GUID(0x2EB5FDBD, 0x01AC4D10, 0x8136F38F, 0x3393A5DA);
    // Register the custom version with core
    FCustomVersionRegistration GRegisterAnimationCustomVersion(FAnimationCustomVersion::GUID, FAnimationCustomVersion::LatestVersion, TEXT("AnimGraphVer"));

オブジェクト レベルでは、各 UObject 派生クラスは、FArchive 関数、UsingCustomVersion を呼び出すことによって、その Serialize 内の 1 つ以上の FGuid 構造体を直列化することを選択できます。 カスタム コードは、登録されている FGuid のバージョン番号に基づいてロジックを実行し、読み書きするデータを決定できます。 この方法で登録された FGuid のバージョンに関連付けられているバージョン番号は決して減少しないため、エンジンに新しいバージョンのアセットがロードされないようにして、エンジン バージョンと同じ方法で後方互換性を維持しながらデータの損失を保護します。

カスタムシリアル化関数

オブジェクトは、Serialize と呼ばれる UObject 関数をオーバーライドして、ディスク上の正確なデータ表現を制御できます。 この FArchive 関数はクラスを使用してデータを読み書きします。つまり、データ形式を 1 回レイアウトするだけで済みます。 次の FArchive 関数は、シリアル化コードでバージョン ベースのロジックを書くときに役立ちます。

関数名

使用方法

UEVer

(Epic) エンジン レベルのバージョン番号を返します。 この値は EUnrealEngineObjectUEVersion のエントリまで一致します。

LicenseeUEVer

(ライセンシー) エンジン レベルのバージョン番号を返します。 この値は EUnrealEngineObjectLicenseeUEVersion のエントリまで一致します。

CustomVer

提供された FGuid に基づいて、現在のオブジェクトのオブジェクト レベルのカスタム バージョン番号を返します。 オブジェクトが保存されたときに、この FGuidUsingCustomVersion (下記参照) が呼び出されなかった場合、この関数は「-1」を返します。

UsingCustomVersion

FGuid をオブジェクトに登録して、そのカスタム バージョン番号を追跡します。

オブジェクト バージョン コードの例

PhysXVehicles プラグイン (エンジンに同梱) にあるホイール付きの車 (Wheeled vehicle) は、物理コードへの特定の変更の前にビルドされたアセットとの後方互換性を維持するためにエンジン オブジェクト バージョンとカスタム バージョンの両方を使用します。

ここでは、カスタム バージョンを使用して、車のサスペンションを表す物理スプリング オブジェクトへのオフセットの計算方法を変更する変数を設定します。 使用される特定のカスタム バージョン値は、物理コードを管理するチームが作成した列挙型から取得されます。

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

次の例では、単位変換は、角速度を毎秒あたりのラジアンではなく毎秒あたりの回転数で測定する物理的な変化に応じて実行されます。 これらの角速度は浮動小数点値 (単位なし) として格納されていたため、古いアセットではロード時変換が必要になりました。 この場合では、アセットをロードするときに角速度変数のみを変更します。このタイプの保存するアセットはすでに毎秒あたりの回転数で角速度を持っており、現在のエンジンのバージョン番号と共に保存されるので、次にアセットがロードされるときに変換コードを実行する必要はありません。

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

UEVer 関数呼び出しを LicenseeUEVer に変更すると、正式な Epic のバージョン番号ではなく、ライセンシーのバージョン番号を使用するようにコードが変更されます。 この方法は、独自のバージョンの Unreal Engine 4 を管理している非 Epic ユーザーにお勧めです。

バイナリのバージョン管理

詳細は「バイナリのバージョン管理」リファレンスを参照してください。

Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
キャンセル