[UE4] 独自のアセットを実装する方法(6) 独自のシリアライズを実装する

02.02

[UE4] 独自のアセットを実装する方法(6) 独自のシリアライズを実装する はコメントを受け付けていません。

cb
今回は、アセット実装の連続記事の最終回です。

独自のシリアライズを実装することで、UPROPERTYに対応していない型のデータをセーブ/ロードする方法をご紹介したいと思います。

 

第1回の記事でご紹介したように、UObject派生クラスでUPROPERTYにしたメンバ変数は、自動的にセーブ/ロードに対応されます。

しかし、時にはUPROPERTYに対応していない型のデータや、外部ライブラリで定義されたデータ型でUSTRUCT化出来ないものを保存したいケースも出てくると思います。

そういった場合には、UObject::Serialize()関数をオーバーライドすることで対応することが出来ます。

 

1.準備

UPROPERTY化出来ない型に、、、と言っておいてイキナリですが、UPROPERTY化しないとエディタ上で値を確認するのが難しくなります・・・

なので、今回はサンプルと割りきって、シリアライズ対象外に指定したUPROPERTYを自前でシリアライズする、という、現実的には非常に無意味なコードを書いてみたいと思います。

MyAsset.h
UCLASS()
class UMyAsset : public UObject
{
//~中略~
    UPROPERTY(EditAnywhere, Transient)
    int32 ValueX;
//~中略~
};

UMyAssetクラスにメンバを追加します。

UPRPPERTYのオプションに「Transient」と追加することで、このメンバはシリアライズ対象外となります。

この状態で実行し、エディタ上でValueXの値を書き換えてセーブし、エディタを再起動すると、ValueXの値が保存されずに0に戻っていることを確認してみて下さい。

 

今回は、このValueXを自前のコードでセーブ/ロードに対応していきます。

 

2.Serialize関数のオーバーライド

 まずは、UMyAssetクラスでSerialize()関数をオーバーライドして、ValueXのセーブ/ロードを実装してみます。

MyAsset.h
UCLASS()
class UMyAsset : public UObject
{
//~中略~
    virtual void Serialize(FArchive& Ar) override;
//~中略~
};
MyAsset.cpp
void UMyAsset::Serialize(FArchive& Ar)
{
    Super::Serialize(Ar);
    if(Ar.IsSaving() || Ar.IsLoading())
    {
        Ar << ValueX;
    }
}

 

Serialize()関数は、セーブ/ロード以外にも呼び出される場合があります。

セーブ/ロードのために呼び出されたかどうかは、引数で渡されたFArchiveから取得出来ます。

 

また、ちょっと分かりにくいのですが、セーブ/ロードの際の手順は同じで、FArchiveに対する<<演算子で実装されています。

構造体など、直接<<演算子が対応されていない型を保存したい場合は、対応したデータ型にバラして順次<<を呼び出していきます。

 

で、このままのコードで実行すると、新規にインポートしたアセットは正常にセーブ/ロード出来るのですが、ValueXのシリアライズを実装する以前にセーブしていたアセットをロードしようとすると、エディタがクラッシュしてしまいます。

これは、以前セーブされた際にはアセット内にValueXが保存されていないため、存在しないデータを読み出そうとしてしまうからです。

 

次は、アセットにバージョン情報を埋め込んで、古いバージョンのデータからは、ValueXの読み出しを行わないための対応を実装します。

 

3.アセットにバージョン情報を追加する

まずはソースコードです。UMyAsset::Serialize()関数を、以下のように書き換えます。

MyAsset.cpp
void UMyAsset::Serialize(FArchive& Ar)
{
    Super::Serialize(Ar);
 
    static const int32 MyVersion = 1;
    static const FGuid MyGUID(111, 222, 333, 444);
    static FCustomVersionRegistration 
        RegisterMyAssetCustomVersion(MyGUID, MyVersion, TEXT("MyAssetVersion"));

    Ar.UsingCustomVersion(MyGUID);
    if(Ar.IsSaving() || (Ar.IsLoading() && (MyVersion <= Ar.CustomVer(MyGUID))))
    {
        Ar << ValueX;
    }
}

3つのstatic変数は、必要に応じてクラスのstaticメンバにするなり、グローバル変数にするなりして下さい。

 

MyVersionが、自分で定義するアセットのバージョン番号です。

アセットのデータ形式が変わった場合は、この値を書き換えていきます。

 

MyGUIDには、他と被らない適当な値を入れておき、予めGUIDとバージョン番号を組み合わせて登録しておきます。

シリアライズを行う際には、UsingCustomVersion()で、GUIDに紐付けられたバージョン番号を使用することを宣言します。

これで、セーブ時にはアセットにバージョン情報が追加されるようになります。

ロード時には、CustomVer()を使って保存されたバージョン情報を取得し、現在のバージョンより古ければValueXのシリアライズを行わない、という処理を追加しました。

 

これで、古いアセットをロードしてもValueXはデフォルト値の状態で正常に処理され、改めてセーブすることで最新バージョンに更新される、という形を実装出来ました。

 

 

プロジェクトの規模によっては、旧バージョンのデータの保守を続けるのは大変になりますが、最低でも1つ前のバージョンをサポートするようにして、バージョンが変わった際にはコンソールコマンドで一括変換、というようなワークフローが構築出来ればよいのではないでしょうか。

(もちろん、標準のシリアライズだけで対応出来れば一番簡単なのですが・・・)

 

 

今回はサンプルコードが長くなってしまいましたので、この記事で使用したソースコードを公開したいと思います。

こちらからダウンロードして解凍して下さい。対応バージョンは UE4.6.1 になります。

 

全6回に渡って、独自のアセットを実装する方法をご紹介してきましたが、以上で本連続記事は終了になります。

最後まで読んで頂き、ありがとうございました。

 

[UE4] 独自のアセットを実装する方法(1) アセットクラスの実装
[UE4] 独自のアセットを実装する方法(2) インポートの実装
[UE4] 独自のアセットを実装する方法(3) 再インポートの実装
[UE4] 独自のアセットを実装する方法(4) アセットにアクションを追加する
[UE4] 独自のアセットを実装する方法(5) アセットエディタを実装する
[UE4] 独自のアセットを実装する方法(6) 独自のシリアライズを実装する

 

  • このエントリーをはてなブックマークに追加

関連記事

コメントは利用できません。

カテゴリー

ページ上部へ戻る