70.9K Views
June 02, 23
スライド概要
講演アーカイブ:
https://youtu.be/agU9FLvQsIo
講演内容:
Unreal Engine のプラグイン機能を活用して、社内の技術資産を効率的に運用したり、プラグインからエンジン機能を拡張するためのノウハウを、弊社社内プラグインの stellla を題材にお話します。
講演者:
石川 陸(Alche株式会社)
https://twitter.com/strvert
南舘 岳人(Alche株式会社)
https://twitter.com/koituwasugee
Alche株式会社についてはこちら:
https://alche.studio/
UNREAL FEST 2023 TOKYO 公式サイト:
https://unrealengine.jp/unrealfest/2023/
Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/
プラグインによる効率的なエンジン拡張 stelllaで実現するメタバース開発
はじめに プラグインによるエンジン拡張をテーマとして、プラグインの開発ノウハウや、 管理・運用事例などについて話します。
本日の内容 ● ● ● ● ● ● 登壇者・会社紹介 検証環境 UE におけるプラグイン stellla 基本思想 プラグインによる拡張ノウハウ プラグインの管理・運用事例
自己紹介 石川 陸 テックリード ● 高専を経て上京し、C/C++ を用いた組み込みシステムから Web フロントまで幅広い開発に従事。学生の頃から Unreal Engine を学んでおり、趣味が高じて Alche 株式会社に入社。 ● Alche 株式会社ではエンジニアチームのリードのほか、stellla の設計や開発、開発ワークフロー・インフラの整備などを行っ ている。 ● 技術と創作が好き。 Riku Ishikawa strvert strvert https://strv.dev
自己紹介 南舘 岳人 テクニカルアーティスト ● CG会社でゲームエンジンを使った映像作品やゲーム開発を経験。 Unreal Engine を使った開発に魅了され、Alche 株式会社に入社。 ● 現在はテクニカルアーティストとして stellla の開発をしている。 ● 趣味で Unreal Engine のブログを投稿している。 ● インディーゲームと猫が好き。 Gakuto Minamidate koituwasugee ゲーム開発備忘録
Alcheについて Alcheは、メタバースという領域でエンターテイメント性 のあるコンテンツの制作、実装を行なっている。 建築、ランドスケープデザイナーやマジシャン、 シナリオライターなど多様なバックグランドをもった メンバーで構成されている。 コンテンツを通して、勇気や元気を与えられるような 作品を発信する会社。 alche_studio https://alche.studio/
実績(一例) RADWIMPS SHIN SEKAI お台場 バーチャル冒険アイランド えんとつ町のプペルVR Virtual Tokyo Tower OFFICEtainment
メタバース領域の特徴と開発の経緯 ● メタバースという領域は、まだまだ発展途上であり未成熟なところが多い。 ● ゲーム系のコンテンツと比較すると以下のような特徴がある。 ○ 開発プロジェクトとしても納期やリリースまでが短い。 ○ 一方で、要求される機能に共通点も多く、マルチプレイや、 アバターカスタマイズ、コミュニケーション といったものがある。 こうした状況を受けて弊社では、メタバース系コンテンツに頻出の機能を プラグインとして集約した stellla を Unreal Engine を用いて開発している。 ※これらはあくまで私達の考えです。
本講演での stellla の扱い 本講演では、Unreal Engine のプラグインについて説明しつつ、 実装事例として stellla の機能に触れる。 本来、stellla はマルチプレイ機能やバックエンド実装までを含む広範な フレームワークだが、題材の都合上、今回は特に Unreal Engine プラグインとしての stellla に注目した内容。
検証環境 以下の環境を前提として検証を行っています。 ● Unreal Engine 5.1 (Launcher 版) ● C++ 17
Unreal Engine におけるプラグイン
Unreal Engine のプラグインの概要 ● コードとアセット、データなどのコレクション。 ● 携帯性が良く、チームで簡単に共有できる。 ● 簡単に ON / OFF できる。 ● 約500 のビルトインプラグインが含まれているほか、 マーケットプレイスや GitHub などから追加で入手する こともできる。 ● もちろん自分で実装することもできる。
Unreal Engine はモジュールの集合体 UE はモジュールの集合として実装されている。 Unreal Engine モジュールは主にC++の実装からなり、大きく Engine ふたつのグループに分かれている。 Engine Module ● エディタやランタイム機能などからなる、 Unreal Engine そのものを形成する モジュール。 Project Module Module Module Module Module Project Module ● C++ プロジェクトが作成されたときに、新 たに加わる独自のモジュール。 どちらも任意の数のモジュールを持てる。
プラグインはモジュールの運び屋 モジュールの視点で見ると、プラグインは モジュールの運び屋。 プラグインは内部に独自のモジュールを 持つことが可能。 エンジンにもプロジェクトにも追加できる。 エンジンモジュールもプロジェクト モジュールも、可能なことは大きくは 変わらず、どちらのプラグインからでも機能 を拡張していける。 Unreal Engine Engine Project Module Module Module Module Module Plugin A Module Plugin B Module Module プラグインによってモジュールを追加できる。
いつ有効なモジュールか? モジュールがどこにあるかによって、 いつ有効になるものであるかが変わる。 Engine Unreal Engine を利用しているときには常に 有効。(Editor / Runtime の差異はある) Unreal Engine Engine Project Module Module Module Module Module Project そのプロジェクトの中でだけ常に有効。 Plugin (Engine/Project 共通) プラグインが配置、有効化されているときに だけ有効。必要に応じてプロジェクトや エンジンに機能を追加したり、 別プロジェクトに持ち運べる! Plugin A Module 無効化 Plugin B Module Module ロードされるのは有効なプラグインのモジュールだけ。
エンジンプラグインのオーバーライド エンジンのビルトインプラグインは、 エンジンの拡張ポイントとしても機能する。 Unreal Engine Engine エンジン機能には、ビルトインのプラグイン として実現されているものも多い。 エンジン側のプラグインと同名のプラグインが プロジェクト側に存在する場合、プロジェクト のプラグインが優先される。 プラグインとして実装されているエンジン機能 であれば、プロジェクトでカスタマイズ可能! Project Module Module Module Module Module Plugin A プロジェクト Module で上書き Plugin A Module Module エンジンのプラグインはプロジェクトで上書きできる。
プラグインはモジュール以外も持てる エンジンやプロジェクトがコンテンツや設定 などを保持できるのと同様に、プラグインも それらを保持できる。 Content : *.uasset, *.pak 等アセット Config : *.ini 設定ファイル Shaders : *.usf, *.ush シェーダー Unreal Engine (のコンテンツ) Engine Contents Project Contents Content Content Config Config Shaders Plugin A これらリソースも、プラグインに含めた場合は プラグインの有効状態と連動する。 Plugin B Config Content Content Shaders プラグインによってモジュールを追加 ※プラグインとプロジェクトが持てるのはグローバルシェーダだけ
つまり、プラグインは何ができる? ● プロジェクトの実装で可能なことは、プラグインでもほぼすべてできる。 ○ 多くの場合、再利用したいプロジェクト実装を整理してプラグインの モジュールに移動するだけでプラグイン化できる。 ● 再利用できるのは実装だけではなく、アセットや設定なども含まれる。 ● エンジン改造に手を付ける前に、プラグインで取れる手段は多い。 ● エンジンやエンジンプラグインのソースコードが公開されているので透明性が 高く、独自プラグイン実装に大いに参考にできる。
逆に、プラグインは何ができない? ● ● エンジンが直接持つモジュールに書かれたコードに割り込んだり、エンジン モジュールを上書きするのは原則できない。この場合はエンジン改造が必要。 ○ 外から処理を追加できるように、デリゲートなどの拡張ポイントが 公開されていることはある。 ○ 利用するモジュールやクラスをモジュール名指定で設定可能になっている 場合もある。 エンジンおよび、エンジンに導入したプラグインのモジュールが、 プロジェクトや、プロジェクトのプラグインのモジュールに依存することは できない。
そもそも、なぜエンジン改造を避けるのか? ● エンジンへの変更を保守管理できるリソースがあるなら避ける必要はない。 ● それにはどんなリソースが必要? ○ エンジンのコードをまるごとバージョン管理しなければいけなくなる。 ○ コードを変更するために、チーム全体へエンジンの共有を行う必要がある。 ○ ビルド時間の増大。 ○ エンジンに更新があるたびに、変更を Merge する必要がある。 ● 拡張した機能や実装を外部へと共有することが難しくなるという問題もある。 ● 弊社では、必要性が無い限りはプラグインなどで対応するようにしている。 ● エンジン改造を行った場合には、Installed Build などが便利。 ※これらはあくまで私達の考えです。
UEプラグインはフレームワーク基盤として強力 弊社の stellla は、こうした Unreal Engine の特徴を背景に誕生した。 昨今のメタバース領域のサービスには共通した実装が多い。これらの実装を都度再実装 すると、資産になりにくく、プロジェクト独自の実装に割けるリソースも減ってしまう。 しかし、UEのアーキテクチャやプラグインシステムは、エンジンを特定の目的のために 強化することを積極的に可能にしてくれている。 Unreal Engine の強力な機能をベースとしつつ、プラグインとしてフレームワークを実装 することで、機能を再利用したり、独自にエディタを拡張したりすることが可能。 効率的に製品のクオリティを高めることができる。
stellla 基本思想
stellla 基本思想 - 整理された機能と最小限の依存 基本プラグイン マルチプレイ対応 モバイル対応 core multiplay mobile 便利機能 backend utility ︙ 認証&データストア
stellla 基本思想 - 整理された機能と最小限の依存 stellla プラグイン群は core に依存している。 utility core プロジェクト mobile backend multiplay
stellla 基本思想 - 整理された機能と最小限の依存 モバイル向けに 提供する予定はない。 utility core プロジェクト mobile backend multiplay
stellla 基本思想 - 整理された機能と最小限の依存 仕様が変わってマルチプレイに 対応しないといけない。 utility core プロジェクト mobile backend multiplay
stellla 基本思想 - 整理された機能と最小限の依存 パッケージングサイズの 削減に貢献。 utility core プロジェクト mobile backend multiplay
stellla 基本思想 - PnP (Plug and play) プラグインを有効にする。 stellla mobile Settings
stellla 基本思想 - PnP (Plug and play) 自動でセットアップが完了! Settings stellla mobile Complated !!
stellla 基本思想 - ベースクラス stellla 統合のために多くの ベースクラスが存在する。 stellla core stellla により拡張された ベースクラスをプロジェクトで継承する。 ACharacter Engine AStelllaCharacter stellla AProjectCharacter Project AStelllaCharacter UStelllaAnimInstance AStelllaGameplayAbility ︙ ︙ 簡単に stellla の機能を利用できる。
stellla 基本思想 - 実装のアセット・モジュール化 実装をアセットとして分離することで 組み合わせのみでベースが完成。 BP 機能をアセットとして配信も可能。
stellla 基本思想 - IDベースで管理されたアイテム メッシュ ID [ XXXX-YYYY-ZZZZ ] 機能 IDで管理されたアイテムに 必要なアセットが紐づけられている。 設定
stellla 基本思想 - プロジェクト互換性 異なるプロジェクトでもstelllaに則れば、 マルチプレイやアイテムに互換性ができる。 プロジェクトA プロジェクトB マップ マップ BP BP エモート エモート メッシュ メッシュ stellla stellla
stellla 基本思想 - プロジェクト互換性 プロジェクトの垣根を超えたメタバース世界を目指している。 プロジェクトA プロジェクトB stellla
stellla 基本思想 - まとめ ● stellla は、実装のアセット化とモジュラー化や、それらの管理を行う機能をベースに 構築されており、迅速なシステムの構築と拡張が可能。 ● セットアップコストを抑えるとともに、stellla のワークフローを支援する エディタ拡張も搭載している。また、あくまで Unreal Engine のプラグインなので、 Unreal Engine 自体の機能をそのまま活用した自由なコンテンツ制作を提供する。 ● 最終的には、複数の世界を接続するシステムとして機能することを目的としている。 ○ ● 現時点でも、プロジェクト間で実行時にアイテムやブループリント実装を 共有する機能などを実現。 特定のアプリケーションやプラットフォームごとに閉じがちな、既存のメタバース系 サービスとは異なり、 stellla は「共通基盤」や「プロトコル」のようなものを 目指している。
プラグインによる拡張ノウハウ
プラグインによる拡張ノウハウ ● プラグイン開発を通して得られたノウハウや、 利用できる Unreal Engine の機能などを紹介。 ● 特にプラグイン開発で便利な手法をピックアップして、 stellla の事例とともに 逆引き的に紹介 する。 ○ プラグイン以外でも可能なことも含む。 ● stellla での独自機能はタイトルに 「 stellla での拡張 」と記述している。 ● は難易度。
プラグインによる拡張ノウハウ - エディタ編 -
Blueprint クラス選択一覧をカスタマイズしたい プラグインに独自のベースクラス などが増えてくると、独自クラスを 継承して実装を進めてほしくなる。 作成メニューの一覧を独自クラスに 書き換えてしまえば効果的に利用を 促せるし、クラスを検索して探す手 間も省ける。 クラス選択を独自クラスで上書き。 この例では Stellla のクラスが表示されている。
→ Editor.ini で設定を追加 or 上書きする方法 プロジェクトやプラグインの Editor 系設定で、NewAssetDefaultClasses の 項目を変更するだけで書き換えることができる。 下に示したコードの ! から始まる行を消せば、上書きではなく追加もできる。 [/Script/UnrealEd.UnrealEdOptions] !NewAssetDefaultClasses=ClearArray +NewAssetDefaultClasses=(ClassName="/Script/Engine.Actor", AssetClass="/Script/Engine.Blueprint") +NewAssetDefaultClasses=(ClassName="/Script/Engine.Character", AssetClass="/Script/Engine.Blueprint") +NewAssetDefaultClasses=(ClassName="/Script/Engine.AnimInstance", AssetClass="/Script/Engine.Blueprint") ClassName は /Script/[ModuleName].[ClassName] の形式。
→ 専用のデリゲートをバインドして上書きする方法
UUnrealEdOptions::OnGetNewAssetDefaultClasses() に表示したいクラスの
リストを返す処理をバインドしておくことで、動的にクラスリストの内容を制御
できる。
このデリゲートにバインドすると、先ほどの Editor.ini のプロパティは無視される。
const static TArray<FClassPickerDefaults> ClassPickerDefaults
{
{TEXT("/Script/Engine.Actor"), TEXT("/Script/Engine.Blueprint")},
{TEXT("/Script/GameplayAbilities.GameplayEffect"), TEXT("/Script/Engine.Blueprint")},
};
if (UUnrealEdOptions* UnrealEdOptions = GUnrealEd->GetUnrealEdOptions())
{
UnrealEdOptions->OnGetNewAssetDefaultClasses().BindLambda([]() -> const TArray<FClassPickerDefaults>& {
return ClassPickerDefaults;
});
}
※ UnrealEdOptions はエンジン初期化後にしかアクセスできないことに注意。
エディタのツールバーやメニューを拡張したい もとから存在するエディタのツールバーやメニューに 機能を増やしたくなることはよくある。 コンテキストメニューとか ツールバーとか
エディタのツールバーやメニューを拡張したい stellla でも、エディタの各所に stellla での開発に便利な機能を拡張している。
→ ToolMenus で可能 BPでの実装を解説
→ ToolMenus - BPでの実装手順紹介 1. Editor Utility Blueprint を作成し、 EditrUtilityToolMenuEntry を継承。 2. BP の Class Defaults で最低限以下を設定する。 a. b. c. d. Menu: 拡張先のメニュー名。Edit Menuで確認できるもの。 Section: 追加にあたって作成するセクションの名前。 Name: 追加する Entry 自体の名前。 Entry Type: 拡張先のメニューのタイプに合ったものを選択する。 その他、ツールチップを定義したり、StyleSet を指定して アイコンを設定することも可能。
→ ToolMenus - BPでの実装手順紹介 3. “Run” という名前の CustomEvent を作成し、 Register Menu Entry を接続。 4. Context Menu から Run ! EUB は “Run” という関数名で実行をハンドリングしている。 名前を合わせるだけで実行に反応できる。 5. メニューが現れる。
→ ToolMenus - 動作の設定 作成した Blueprint で関数をオーバーライドすることで、クリック時の処理を Blueprint で 書いたり、表示を動的に変更したり、有効無効を切り替えたりできる。意外なほどに簡単。
→ ToolMenus - 拡張先メニュー名の取得 拡張先のメニュー名の取得には、エディタで ToolMenus.Edit 1 コマンドを実行 すると、拡張可能な場所に Edit Menu ボタンが表示されるようになる。 ToolMenus.Edit 1
→ ToolMenus - 拡張先メニュー名の取得 表示されたボタンを押すと、UToolMenus で管理された 拡張可能メニューの詳細情報ウィンドウが表示される。 この情報を元に、好きな場所のメニューを拡張できる。 該当部のメニュー名 エントリのプロパティ 既にセクションにあるエントリ一覧
→ ToolMenus - Appendix
エディタで有効になっているアイコンとして利用可能な Style の一覧を得るには、
以下のようにすることができる。
また、Widget Reflector から開ける Texture Atlas Visualizer でも部分的に確認
可能。( StyleSetNameはわからない )
C++ ですべての Style を表示することで確認可能。
FSlateStyleRegistry::IterateAllStyles([](const ISlateStyle& Style)
{
for (const FName& StyleKey : Style.GetStyleKeys())
{
UE_LOG(LogTemp, Log, TEXT("StyleSet: %s\t\t StyleKey: %s"),
*Style.GetStyleSetName().ToString(), *StyleKey.ToString());
}
return true;
});
すべての Style をログ出力。
Visualizer
→ ToolMenus - C++
もちろん C++ でも同様の仕組みで可能。
C++ なら、Slate (UE の UI システム) の資産をフルに
活用して更に自由にメニューをカスタマイズできる。
機能の複雑度や、使い捨て機能かどうかで使い分ける。
UToolMenu* Menu = UToolMenus::Get()->ExtendMenu("ContentBrowser.AddNewContextMenu");
FToolMenuSection& Section = Menu->FindOrAddSection("ColorPickers");
Section.AddEntry(FToolMenuEntry::InitWidget("ColorPickerMenu", SNew(SColorPicker), FText::GetEmpty()));
これも案外シンプル。
C++ ならアセット作成メニューに
カラーピッカーを!(特に意味はない)
→ stellla での拡張 stellla では、C++ で Editor Utility Blueprint を更に拡張している。 特定ディレクトリの下に配置しておくだけでエディタ起動時に自動登録され、 登録のノードを配置する必要もなくなるなど、ツール開発支援機能も実装している。 プラグインを下支えとして気軽な拡張を可能にすることで、プロジェクト固有の アドホックな拡張などもしやすくなる。拡張ツールを作成する人員の敷居も下げられる。 stellla では stellla 系プラグインか導入プロジェクトの [Content]/Editor/ToolMenus に配置するだけ。
プラグインによる拡張ノウハウ - ランタイム編 -
プロジェクト/エディタ設定でプラグインの設定をしたい Project Settings / Editor Preference を拡張できると、プラグイン機能のもつパラメータ をプロジェクトごとに変更したり、アセットをプラグインに認識させたりできる。
→ DeveloperSettings を使うのがおすすめ
UDeveloperSettings を継承したクラスを含むモジュールがロードされると、
自動でエンジンが認識し、UPROPERTY を設定画面に表示してくれる。
UCLASS(Config=Game, DefaultConfig, DisplayName="Example Project Settings")
class UExampleProjectSettings : public UDeveloperSettings
{
GENERATED_BODY()
public:
UPROPERTY(Config, EditAnywhere, Category="Example")
FString ExampleString;
UPROPERTY(Config, EditAnywhere, Category="Example")
int32 ExampleInt;
UPROPERTY(Config, EditAnywhere, Category="Example")
TSoftObjectPtr<UStaticMesh> ExampleStaticMeshObject;
};
これを定義するだけで実装完了!
→ DeveloperSettings を使うのがおすすめ
設定した値は、作成したクラスに対して自動生成される CDO (Class Default Object) の
値として利用される。以下のようにどこからでもアクセスできる。
const UExampleProjectSettings* Settings = GetDefault<UExampleProjectSettings>();
Settings->ExampleInt;
Settings->ExampleString;
Settings->ExampleStaticMeshObject;
Blueprint から利用する際には、取得を行う UFUNCTION を作成すれば OK。
UFUNCTION(BlueprintCallable, Category="ExampleProjectSettings")
static const FString& GetExampleStringValue()
{
const UExampleProjectSettings* Settings = GetDefault<UExampleProjectSettings>();
return Settings->ExampleString;
}
設定ファイルとカテゴリについて UCLASS(Config= ) の値 (= Config名) を変えることで、保存する設定ファイルや、 エディタ上での設定の表示場所が変わる。 ゲーム機能に関する設定なのか、エディタ機能に関する設定なのか、 個人の環境設定なのか、などによって使い分ける。 主要な Config 名の例 Config名 設定ファイル エディタ表示場所 Game *Game.ini ProjectSettings Engine *Engine.ini ProjectSettings Editor *Editor.ini ProjectSettings EditorPerProjectUserSettings *EditorPerProjectUserSettings.ini EditorPreferences ※「*」 付きなのは、配置場所によってプレフィックスが変動するため。
プラグイン独自の設定ファイルが利用できる
プラグインのモジュール内でのみ、プラグインの名前を冠した Config 名を利用すると、
専用の設定ファイルを読み込める。もしプラグイン名が ExamplePlugin なら、以下のような形。
UCLASS(Config = ExamplePlugin, DefaultConfig,
DisplayName="Plugin Unique Settings")
class UPluginUniqueSettings : public UDeveloperSettings
{
GENERATED_BODY()
// 略
};
プラグインの設定ファイルを分離することで、
設定の所属の明確化を図れたり、設定ファイルの
肥大化を防いだりすることができる。
プロジェクトで値を上書きすることも可能。
ExamplePlugin
Config
BaseExamplePlugin.ini
[Project Folder]
Config
DefaultExamplePlugin.ini
プラグインとプロジェクト、どちらの
Config でも利用できる。
プラグイン有効化で設定を上書きする方法 プラグインのフォルダ内に対応する Config 名の設定ファイルを配置するだけ! プラグイン初期化時に検出され、設定を上書きする。 ただし、EditorPerProjectUserSettings はプラグインで上書きできない Config 名として 処理されており配置しても無意味。 [Plugin Folder] Source Config Game.ini 有効化と同時に行いたい設定を記述可能なため、 プラグイン利用時の設定系セットアップを簡易化できる。 Editor.ini Engine.ini ※「プラグインで上書きできない Config名」 を自分で追加する方法もある。
キャラクターなどの実装を機能別に分離・整理したい Unreal Engine で愚直に実装を始めると、キャラクターなどの基本的なクラス の BP 実装が爆発しがち。
キャラクターなどの実装を機能別に分離・整理したい なぜキャラクタークラスは爆発するのか? ● 入力などのイベントハンドリングをグラフに配置できる。 ● キャラクターにあらゆる関するロジックが配置されやすい。 1つのキャラクタークラス内に、「入力などのハンドリング」と「キャラクターの ロジック」がベタ書きされることで、プロジェクト間はおろか、プロジェクト内 ですら再利用が難しい状態を生み出している事が多い。 → 入力などのハンドリングとキャラクターロジック をキャラクターから分離できれば 解決する。
→ ひとつなぎのキャラクター Character Event Logic キャラクターアセット キャラクターにあらゆる実装を書いている。 こうしたキャラクターはよく爆発している。
→ GameplayAbility や Enhanced Input の活用 Enhanced Input Gameplay Ability ● 入力イベントを抽象化した InputAction。 ● 具体的な入力とアクションを紐付ける InputMappingContext。 ● BP のロジックを、 1 ロジック 1 アセットで扱える Ability。 ● Ability の処理は任意の方法で Activate することで実行可能。 などの機能を利用して入力の定義や ハンドリングを分離できる機能。定義は すべてデータアセットとして管理される。 UE 5.1 から標準の入力システムに。 実行可能なロジックを Ability アセットとして 扱うことが可能。 キャラクターなどに Ability を付与すると、 その上でロジックを実行できる。 Unreal Engine のアセットベースな強力な機能が活用できる
→ GameplayAbility や Enhanced Input の活用 トリガ (Event) Ability (Logic) 入力 アセット ロジック アセット EnhancedInput 付与 実行 Character キャラクター アセット Enhanced Input と Gameplay Ability を連携させる実装と、 Ability を受け取れるキャラクターを実装した場合。
→ GameplayAbility や Enhanced Input の活用 トリガ 付与 実行 アセット単位で再利用性が高まることで、組み合わせ的に実装が可能に。
→ プラグインのコンテンツとしてアセットを持てる Plugin Project A Project B Project C こうした再利用性の高いアセットをプラグインで運搬することで、 プロジェクトの実装を効率化する。
→ stellla での拡張 ● stellla には、予め UE の Enhanced Input や Ability System を拡張し、 組み合わせベースで、コード(ノード)を書かずに連携させる事ができる仕組み が実装されている。 ● それらによって駆動されることを前提とした便利機能を実装した、stellla専用 の Character / Actor などの基本クラスを含めており、プロジェクトでは これらを継承することですぐに、既存資産の利用を開始できる。 → 過去に実装した機能アセットを簡単に組み合わせることができるので、 コンテンツを迅速に構築できる。新たな機能を追加する時も、Ability を実装して、 付与の設定を行うだけ。作った Ability は新たな資産となる。
→ stellla での拡張 - キャラクター機能実装例 Project AProjectCharacter stellla の基本クラス を継承 stellla Plugin AStelllaCharacter アセットと設定による 機能実装 プロジェクト独自 Ability stellla 同梱 Ability stellla が更に再利用性と実装の簡便性を向上
→ stellla での拡張 - Abilityの拡張例 Ability を拡張し、Enhanced Input によって Activate できるように接続しているほか、 Ability 内で InputAction の値や情報にアクセスできる機能なども追加。
→ stellla での拡張 - 機能のランタイムインストール 実装のアセットによる分離のメリットは実機でのランタイムにもある。 アセットになることで、C++実装などと異なり、ランタイムにも機能を 個別のファイルとして扱いやすくなる。 stellla では、このメリットを活かして、単体 Ability のパッケージングと配布や、 クライアントがランタイムに単体の Ability をダウンロードし、その場で キャラクターに新機能を追加することなどを可能にしている。 ※ C++実装をキャラクター機能単位で動的リンクライブラリにして配ったりするのはかなり大変
プラグインの管理・運用事例
バージョン管理 ● バージョン管理には Git を利用 ○ ● バイナリを扱うために Git LFS を活用 ○ ● ブランチを用いたワークフローや、周辺ツールとの連携性の良さ、コストなどが選定理由。 Git でバイナリなどの大きなファイルを効率的に管理するための拡張。 オープンソースのセルフホストGitサービスの Gitea を利用 ○ ○ ○ Git LFS の Lock にも対応している。 オンプレミスで安価に運用可能。 LFSファイルの実体を AWS S3 などのバケットに配置でき、 コストを抑えつつ高速転送 が可能。
プラグイン管理に特有の課題 ● 再利用を目的とした、複数のプロジェクトに導入されるプラグインの開発は どこで行う? どうやってバージョン管理する? ● 特定のプロジェクトに依存しない形でのCI(ビルドチェック)はどうする? プロジェクトに依存せずに、プラグイン単体で品質を管理する必要がある。 などなど……
プラグイン管理に特有の課題 ● 再利用を目的とした、複数のプロジェクトに導入されるプラグインの開発は どこで行う? どうやってバージョン管理する? ● 特定のプロジェクトに依存しない形でのCI(ビルドチェック)はどうする? プロジェクトに依存せずに、プラグイン単体で品質を管理する必要がある。
良くなかった例 ➀ 各プロジェクトのリポジトリ内部に、 直接プラグインのファイルを配置して運用する。 プロジェクトA リポジトリ プロジェクトB リポジトリ プラグインX プラグインX File File File File
良くなかった例 ➀ 直感的だが、プロジェクトの履歴と混在し、 プラグイン自体のバージョン管理ができていない。 また、手動でコピペする以外にプラグインを導入・管理する方法がない。 プロジェクトA リポジトリ プロジェクトB リポジトリ プロジェクトC リポジトリ プラグインX プラグインX プラグインX File File File File ??? File File
良くなかった例 ② プラグイン単独のリポジトリを作成してバージョン管理。 必要なバージョンをプロジェクトにコピー。 プロジェクト リポジトリ プラグインX リポジトリ プラグインX Commit File File 手動で導入 File File ※ Commit とは Git における変更履歴のこと
良くなかった例 ② プラグインの履歴は管理できるが、手動でコピペが必要なのは変わらず。 また、各プロジェクトに現在導入されているプラグインのバージョンなども 人間が管理する必要がある。 プロジェクト リポジトリ プラグインX リポジトリ プラグインX Commit File File File File 今入ってるバージョンはいつのもの? 更新は気付いた時にコピペする? ※ Commit とは Git における変更履歴のこと
→ Git Submoduleを使って解決 Git Submodule を活用し、 各プロジェクトはプラグインリポジトリの 特定コミットへの参照情報を管理している。 プロジェクト リポジトリ プラグインX リポジトリ Commit Submodule プラグインX 特定コミットの参照 File File ※ Commit とは Git における変更履歴のこと
プラグイン管理に特有の課題 ● 再利用を目的とした、複数のプロジェクトに導入されるプラグインの開発は どこで行う? どうやってバージョン管理する? → Git 管理の場合、 Git Submodule がプラグインにぴったり。 きちんと単体でバージョン管理し、手間や運用コストを削減できる。 ● 特定のプロジェクトに依存しない形でのCI(ビルドチェック)はどうする? プロジェクトに依存せずに、プラグイン単体で品質を管理する必要がある。
プラグイン管理に特有の課題 ● 再利用を目的とした、複数のプロジェクトに導入されるプラグインの開発は どこで行う? どうやってバージョン管理する? → Git 管理の場合、 Git Submodule がプラグインにぴったり。 きちんと単体でバージョン管理し、手間や運用コストを削減できる。 ● 特定のプロジェクトに依存しない形でのCI(ビルドチェック)はどうする? プロジェクトに依存せずに、プラグイン単体で品質を管理する必要がある。
プラグインのビルドチェック ● UE には、プラグインの単体パッケージング機能がある。 これは UAT (Unreal Automation Tool) を通じて CLI で実行できる。 ● 複数のビルド対象プラットフォームと、エディタプラットフォームを指定できる。 RunUAT.bat BuildPlugin -Plugin="[プラグインのパス ]/StelllaCore.uplugin" -Package="[パッケージ済み出力ディレクトリ ]" -EngineDir="[ビルドに利用するエンジンのインストールディレクトリ ]" -TargetPlatforms="[Win64+Android+IOS のようにターゲットのプラットフォームを +で接続して指定 ]"
ビルドに含めるパスを設定する パッケージング時、成果物として、 プラグインフォルダから追加でファイルを コピーしたい場合がある。 [FilterPlugin] この場合、 FilterPlugin.ini を配置すれば、 BuildPlugin コマンドが自動でコピーを行う。 /README.txt /Extras/... /Binaries/ThirdParty/*.dll [Plugin]/Config/FilterPlugin.ini ドキュメントや動的ロードするライブラリを含 める作業を自動化できる。 再帰やワイルドカードも利用できる。
Gitea Actions による CI CIを設定した プラグインリポジトリ PR merge ビルド実行イベント ステータスをチェック ビルドマシン Windows Mac 弊社では、Gitea Actions という CI 機能を利用して自動で マルチプラットフォームに単体パッケージを行っている。 Linux main
プラグイン管理に特有の課題 ● 再利用を目的とした、複数のプロジェクトに導入されるプラグインの開発は どこで行う? どうやってバージョン管理する? → Git 管理の場合、 Git Submodule がプラグインにぴったり。 きちんと単体でバージョン管理し、手間や運用コストを削減できる。 ● 特定のプロジェクトに依存しない形でのCI(ビルドチェック)はどうする? プロジェクトに依存せずに、プラグイン単体で品質を管理する必要がある。 → UAT で単体パッケージング。CLI ツールであるため、CIシステムと 連携して自動化することも可能。
おわりに
おわりに ● Unreal Engine は拡張性を意識した設計で構築されている。 拡張用のツールキットや拡張ポイントもエンジンに多数用意されているため、 プラグインからランタイム機能もエディタ機能も拡張していける。 ● stellla は、Unreal Engine のプラグインとして弊社が開発しているメタバース系 サービス構築に特化したフレームワーク。 Unreal Engine の拡張性と豊富な機能、オープンなソースコードに支えられて、 stellla のようなプラグインの開発も進めやすく、エンジンを存分に活用すること ができる。 ● また、ワークフローの上でも、UAT などのユーティリティを利用することで、 プラグインの開発や運用の堅牢性を高めていくことができる。
ご清聴ありがとうございました