🐡

UE4プラグイン作成のポイント

2020/09/26に公開

先日、技術書典9にてUnrealEngine4 Introduction to RHIという本を頒布しました。この本は、Live2D Cubism plugin for UE4を開発するにあたり得たRHIに関する知見をまとめた本です(よかったら買ってね)。

プラグイン開発の知見もあわせて溜まったので、UE4のプラグイン開発をするにはこの点に気をつけてね、というポイントを書いてみます。

プラグインの初期実装はマルチモジュールからはじめると楽

プラグイン開発のプロジェクトは、プラグインの新規作成から始める人も多いことでしょう。私も最初はそうでした。

UE4に限らず何かしらのアプリケーションに対応した機能拡張・プラグイン開発の経験がある人だと分かると思いますが、プラグイン開発では通常のアプリケーション(ビルドしたあとに、実行ファイルになるアプリケーション)開発とは違うめんどくさい手続きが要求される場面が多々あります。

例えばアプリケーション上でプラグインの動作チェックのため毎回手動でプラグインを読み込まないといけない、とか。

このようなめんどくさいことは、最初からプラグインとして開発を進めているがために発生しているのです。

そこでプラグイン開発の初期段階は、プロジェクトを2つのモジュール(マルチモジュール)で構成する ことをオススメしてます。1つをゲーム本体プロジェクト、もう1つをプラグイン化を前提としたモジュールを用意して開発を進めることをオススメします。

次のコードは、マルチモジュールで設定したuprojectファイルです。

{
  "FileVersion": 3,
  "EngineAssociation": "4.24",
  "Category": "",
  "Description": "",
  "Modules": [
    {
      "Name": "L2DGameApp", ←ゲーム本体のモジュール
      "Type": "Runtime",
      "LoadingPhase": "Default",
      "AdditionalDependencies": [
        "CoreUObject"
      ]
    },
    {
      "Name": "Live2dcubism", ←プラグイン化前提のモジュール
      "Type": "Runtime",
      "LoadingPhase": "PostConfigInit",
      "AdditionalDependencies": [
        "CoreUObject",
        "Engine"
      ]
    }
  ]
}

これによりプラグイン特有の面倒くさい手続きがなくなり、通常のC++による開発と同じ流れでプラグインの開発ができます。

開発初期は動作は安定せず、コードの編集、ビルド、実行を頻繁に行うことでしょう。そんな時期は開発のサイクルを少しでも短くする方法を検討した方がよいです。で、その手段の一つがマルチモジュール化なのです。

プラグイン化するタイミング

最初はマルチモジュールで開発していますが最終的にはプラグインとして実装しないといけません。では、どのタイミングでプラグイン化するとよいのでしょうか?

それは、マルチモジュールで必要な実装がほぼ完了し、残すはプラグインに関連する実装のみ、というタイミングが良いでしょう。このタイミングではじめてプラグインのプロジェクトを作成し、マルチモジュールにあるソースコードをプラグインのプロジェクトへ移し替えます。

これにプラグイン化した後の開発もスムーズにいくことでしょう。

扱うデータはuassetファイルへ変換しなくてはいけない

UE4ではアセットとしてpngやjsonはそのまま扱えません。.uassetファイルへ変換してようやく扱えます。当たり前の話なのですが忘れがちなので紹介しています。

今回作成したプラグインの元となっているLive2D Cubismでの事例を元に解説します。

変換前のデータ群

Live2D Cubismではモデルを表示・アニメーションする場合、元データとしてmoc3ファイル(モデルデータ)、pngファイル(テクスチャ)、jsonファイル(モーションデータ等)といった複数のファイルを使用します。

Live2DCubismにて書き出したファイル

しかし、UE4ではmoc3ファイルやjsonファイルは、パッケージ化された際にアセットとして直接読み込むことはできません。

変換後のアセット

先のデータ群をUE4向けに変換しました。

次のスクリーンショットはuasset化した後のファイル群です。

先の変換前のデータ群では、jsonファイルは複数存在しており、それぞれモーションデータなど用途別にデータが格納されていました。uasset化した段階で、それらjsonファイルはすべて1つにまとめL2DCubismAssetというアセットに格納しています。

一般的に流通しているファイルフォーマット(例えばpngファイルなど)は既にUnrealEditor側で対応済みです。しかし、Live2D Cubism固有のmoc3ファイルはUE4ではサポートしている訳がないので、このmoc3ファイルをuassetファイルへ変換する処理をプラグインに実装しなければなりません。

ランタイムとエディタの分離を意識して開発しないと地獄みる

プラグインにUnrealEditorでの編集機能(エディタ)と、アプリケーションでの実行機能(ランタイム)の2つの役割をもったものを開発することもあるでしょう。

編集機能とは、例えば以下のような機能です。

編集機能(エディタ)とは、UnrealEditor上でデータ編集するためのUIだったり、元データをインポートするためのPC上で編集するためのあれこれの機能をさします。実行機能(ランタイム)とは、文字通りゲームでプラグインの機能を実行するためのものです。パッケージ化したアプリケーションには、実行機能(ランタイム)が組み込まれます。

ここからが重要なのですが、このような2つの役割をもったプラグインは、 必ず編集機能(エディタ)と実行機能(ランタイム)の2つのモジュールに分けて開発 しなければなりません。

これを1つのモジュールで作るとどうなるか(私が実際にやらかしたのですが)。結果から言うとパッケージ化できません。言い換えると、UnrealEditor上では使えるが、実際のアプリには適用できないプラグインとなります。今回のようなアプリケーションに組み込んでなんぼのプラグインであれば、これは致命的となります。

なんで1つのモジュールでパッケージ化できないのか? これはUnrealEdというモジュールが大きく影響しています。

UnrealEdモジュールとは

UnrealEdモジュールは、UE4エディタ上で編集機能(エディタ)をプラグインで実装するためには必須のモジュールです。

このモジュールの特徴は次の2つがあります。

  • UnrealEditorで編集機能(エディタ)を実装するために必須のモジュールである
  • UnrealEdはパッケージに含めることができない(エラーとなる)

これら2つの要件を満たすために、冒頭にも書いた通り、モジュールを役割別に分離して開発しないといけないのです。

私の体験談

最初は、この2つのモジュールで開発しないといけない重要性を理解してませんでした。そのため、編集機能(エディタ)も実行機能(ランタイム)もあわせて1つのモジュールにして開発していました。

それで確かに動作するのですよ、UnrealEditor上では。

そして気まぐれに「さて、試しにパッケージ化してみるかー」と思って、パッケージ化してみました。すると、UnrealEdを含んだ状態でモジュール化できない、というエラーメッセージとともにパッケージ化に失敗するわけです。

「あー、やっちまったー」

UnrealEdモジュールは、アプリケーションの実行時には不要なのは分かってましたが「バイナリサイズが大きくなる程度は、まぁいいか。動けばOK。」というノリで開発を進めていたので、UnrealEdを含んだ状態でパッケージ化できないことが分かった瞬間、とても焦りました。

それと同時に「なぜ他のプラグインは編集機能(エディタ)と実行機能(ランタイム)の2つのモジュールに分けて実装しているか」も理解できたのです。

ということで、最初からこのように2つのモジュールに分けて実行することを念頭において開発しておけば、こんなにあせらずに済むのです。覚えて起きましょう。

Discussion