目次
※この記事で使用しているUnrealのVersionは05.1.0です。
※この記事のサンプルプロジェクトは以下URLにアップされています。
サンプルプロジェクト
DataLayerConvert用サンプルプロジェクト
※この記事はUnreal Engine (UE) Advent Calendar 2022の17日目の記事になります。
昨日はnokonoko_08の[UE5]Niagara Fluidsを触ってみるでした!Niagara Fluidsめちゃめちゃ興味があったので時間あるときにじっくり読みたいです!!
前置き
挨拶
みなさんUE5はいかがですか?
キンアジちゃんは、目まぐるしく変わりゆくUnrealを、必死に追い回す餌時のアジの如く頑張ってついていこうとしていますが、何もわからん状態らしいです🐟<ナンモワカランヨ~
今回は、何もわからないなりに、UE5からの新しいLevel Streaming手法「World Partition」という機能で使える「Data Layer」という機能について、色々紹介していこうかなと思います。
※なるべく万人にわかりやすいようにするために若干本来の意味と異なる説明をしている部分があったりします。もしくは単に説明を間違えている場合がございます。どうか温かい目で御覧ください。
ご質問やご意見ご連絡等はTwitterのDMやメールなどにいただければと思います。
WorldPartitionって?
まずはWorld Partitionについての説明を簡単にしたいと思います。
World Partitionとは、”オープンワールド用に作られた距離をベースにしたグリッド単位でオブジェクトのストリーミング管理を行う機能“です。
→UE4からある「Level」をベースにした「World Composition」と呼ばれる機能の進化版(?)といったところでしょうか。
World Partitionを有効にした場合、通常のレベル管理と比較すると以下のような比較ができるかなと思います。
比較表 | World Partition | 従来のLevel |
---|---|---|
Editor上でのレベル・アクターの管理 | ・World Partition + Data Layer World Partition WindowでGUIによるセル単位の表示・非表示管理 + Data Layerによる任意のグループ単位での表示・非表示管理 | ・Persistent LevelおよびStreaming Level(Sub Level) Levels Windowにより、レベル単位での表示・非表示管理 ※WorldCompositionはGUI+Layer+Level |
プレイ中のストリーミング | グリッド単位(自動でストリーミングレベル生成) | レベル単位 |
編集するファイルの単位 | ・アクター単位(One File Per Actor) World Partitionが有効なレベルでは、1つのアクターに対して1つのファイルが作成され、より分割された単位でのファイルの編集が可能 | ・レベル単位 Persistent Levelと各サブレベルごとに1つのファイルになっており、作業者はレベル単位でファイルを編集。 |
同じレベルを複数配置可能 | ・レベルのインスタンス化レベルをアクターとして配置が可能なので、同じレベルを複数配置することが可能 | 同じレベルをサブレベルとして複数配置が出来ない |
Levelの入れ子の関係を作成可能 | レベルのインスタンス化レベルをアクターとして配置が可能なので、入れ子の関係をいくつも作ることが可能 | サブレベルがもつサブレベルはパーシスタントレベルには表示されない |
UE4の場合、広大なマップを作成する場合は、Persistent LevelにいくつかのStreaming Level(Sub Level)をぶら下げ、それをLevel Streaming Volumeを使用したり、BlueprintやC++から直接Streaming管理を行ったりしてレベルのロードを制御してきました。
その際Actorは、必ずどこかしらのレベルに所属させる必要がありました。
上記の手法では、大規模な開発ではよく起こりがちな問題が発生します。
それは、同じレベルを編集したい複数の人がいる場合に、編集の競合が発生し易いということです。
UE4における大規模レベル実装ワークフローとブループリント活用事例
→上記リンクのP.90にある「レベル構成とサブレベルの切り分け」にもこの問題を解決するためにサブレベルを増やして解決しているようでした。
World Partitionを使う場合の大きなメリットのうちの一つが、「One File Per Actor」という機能で、アクター単位で一つのファイルになるため、ファイル編集時の競合が起きにくくなりました。
また、アクターを明示的に任意のサブレベルに所属させる必要がなくなるので、アクターの座標を変えたりすることで発生する所属レベルの変更作業等も行う必要がありません。
さらに、アクターのサイズが大きくなると、複数のグリッドをまたがなければならなくなったりした場合に専用のレベルを作成したりする必要もありません。
ストリーミングレベルは自動でグリッド単位で生成され、配置したアクターは自動でいずれかのグリッドに所属するようになります。
アクターのバウンスが複数のグリッドに所属する場合は、そのいずれかのグリッドが読み込まれる際に該当のアクターがロードされます。
さて、そんなWorldPartitionですが、その中でも今回は「DataLayer」にフォーカスしてあれこれ説明していきたいと思います!
(まんべんなく記事にすると、めちゃくちゃ膨大になるのと、5.1でかなり変わっていて把握しきれていない部分があるため、本当にまだまだ書きたいことたくさんあったのですが、また別の機会に他のWorldPartitionの説明させてください)
事前準備
DataLayerはWorldPartitionを有効にしたレベルでしか使えないため、まずはWorldPartitionのレベルを作成します。
UE5.1のプロジェクトで、エディター左上のFile
からNew Level
を選択します。
その後に、Open World
のテンプレートを選択してCreateを押すだけです!
作成すると、↓のようなマップが表示されると思います。
ここまでできましたら、エディター左上の方にある保存のアイコン(フロッピー)を押して、レベルを保存しておきます。
これで準備ができましたので、ここからDataLayerの説明をしていきます。
DataLayerについての基本的な説明
その1ーDataLayerとは?
UE4におけるLayer機能のUE5版にバージョンアップした機能で、World Partitionとセットで使うことを想定した機能になります。
WorldPartitionを使っているマップでは、デフォルト状態だとプレイヤーカメラ(PlayerController)からの距離によって自動ストリーミングされてしまい、今までUE4で使っていたSubLevelのLevelStreamingによる任意のタイミングでのストリーミングを行うことができません。
※LevelInstanceを用いたストリーミングは可能です。
DataLayerは、そんな任意のタイミングのストリーミングを行える機能としてWorldPartitionの機能をサポートしてくれるようです。
また、ランタイムとしての機能だけではなく、Editor作業用のDataLayerというものも存在し、作業する上で不要なアクターなどを破棄したりすることも行え、従来のサブレベルのときよりも柔軟にアクターの管理を行うことができます。
さらに、Level管理の時はできなかった使い方として、レベル管理時はアクターは必ず一つのレベルに所属していましたが、DataLayerの場合は所属しなかったり、逆に複数所属をすることもできるようになっていま。
わかりやすく言うと、「ストリーミングを行うためのタグ」のようなものだと考えていただければと思います。
今までは、アクター側は所属しているレベルの情報を明示的に持ってはいませんでしたが、アクターの詳細にDataLayerという項目が追加され、DataLayerの所属情報をアクター側が持つようになっています。
DataLayerの構成やマップで使用するDataLayerの管理は、Data Layers Outliner
ウィンドウにて行うことができます。(この情報は、WorldPartitionのマップを作成すると自動で生成されるWorldDataLayers
というアクターが行っています)
ウィンドウはEditor左上にあるData Layers Outliner
Window
→WorldPartition
→
を選択することで表示できます。Data Layers Outliner
開くとこのようなウィンドウが表示されると思います。
※WorldPartitionが有効なマップでなければDataLayerは使えないため、DataLayersOutlinerはWorldPartitionが無効なマップでは一切機能しません。
その2ーDataLayerを作成してみる
さて、まずはDataLayerを一つ作ってみましょう。
DataLayersOutlinerの上半分の空いているところで右クリックし、Create New DataLayer
を選択します。
すると、新しいDataLayerのインスタンスがUnKnown
という文字で作成されます。
その後、作成したDataLayerインスタンスを選択し、下にある詳細ウィンドウから、Data Layer Asset
の部分のプルダウンを選択し、新しくDataLayerを作成します。
これで、DataLayerを新しく作成することができました。
作成したDataLayerアセットは、5.1現在ではDataLayerType
というプロパティを持っており、ここがEditor
かRuntime
かによって、DataLayerの用途が変わってきます。
DataLayerType=Editor
→Editor上でのアクターの管理のためのみに使われるDataLayer。基本的には、WorldPartitionは大きなマップになることが想定されているのと、サブレベルが使えないことにより、不要なアクターが多ければ多いほど作業の邪魔になるため、アクターの種類などでDataLayerを設定しておき、DataLayersOutlinerにて任意の作業タイミングでDataLayerをエディター上でストリーミングしてアクターの管理をする。
DataLayerType=Runtime
→↑のEditorでできることができる+プレイ中にDataLayerを使って、アクターを任意のタイミングでストリーミングする事ができる。
では、作成したDataLayerをアクターに割り当ててみましょう。
アクターへの割当の方法はいくつかあります。
一番簡単なのは、所属させたいアクターと所属させるDataLayerを選択状態にして、右上の+マークのアイコンを押す、です。
アクターをDataLayerへ所属させるということは、アクターのプロパティを変更するということなので、当然アクターの詳細ウィンドウからもDataLayerの追加などは行うことができます。
ただし、DataLayersOutlinerでDataLayerInstanceと紐づけしていないDataLayerAssetを設定しようとすると、DataLayerの設定はうまくいかずに空っぽになってしまいます。
また、紐づけているDataLayerAssetが存在しなくなった場合は、アクターを再保存するタイミングでDataLayerAssetの参照が外れて配列の要素から削除されます。
ちなみに他には、
・Outlinerウィンドウからアクターをドラッグ&ドロップで所属ができる
・CurrentDataLayerにしておくことで、新しくレベルに配置したアクターを自動でCurrentDataLayerに所属させる
・UDataLayerEditorSubsystem
のAddActorToDataLayer
などの関数を用いてEditorUtilityBlueprintから追加をする
などの方法で追加ができます。
では、DataLayersOutlinerに戻って、このウィンドウを細かく見てみます。
↑の8と9のエディター上のDataLayerの初期状態は、DataLayersOutlinerで表示やロード状態を変更した場合は、Savedフォルダ内のコンフィグにその情報が保存され、次回レベルを開いたときも同じ状態が引き継がれます。
基本的にこの設定は複数人開発のときに、Editor上のDataLayerの設定を推奨の状態にするためのものだと考えていただければと思います。
続いてDataLayerを右クリックした際のメニューです。
大体はメニュー名から動作がわかると思います。
ActorEditorContext内のMake Current Data Layer(s)
(現在のデータレイヤーを作成
)などの「CurrentDataLayer」というのは、レベルのときにもあったCurrentLevelと同じで、CurrentDataLayerにしておくと、新しくアクターを配置したときに自動でそのDataLayerに所属させてくれる機能になります(5.1から入ったかなり便利機能になります)
次は右上の歯車マークアイコンから表示できるフィルターなどのメニューについての説明です。
こちらも基本的には日本語の説明を見ればだいたいの内容はわかるかなと思います。
自分はDataLayersOutlinerで、どのアクターがどのDataLayerに所属しているかをわかりやすくしたいので、Hide Actors
のプロパティはよくチェックを外しています。
5.1からフィルターの項目が増えてたり、編集の許可やリセットができるようになってたりするので、5.0のときよりだいぶ使いやすくなっています。
その3ーDataLayerの構成について
ここで少しDataLayerの構成についての説明をいたしましょう。
DataLayerは、2つの要素からなりたっています。
1,レベル上で、各DataLayerのストリーミングを管理するためのインスタンスである
DataLayerInstance
2,DataLayerの名前やDataLayerTypeなどを管理するDataLayerAsset
DataLayersOutlinerでは、DataLayerInstanceとDataLayerAssetを紐づけて、そのレベル内でどのDataLayerを扱うかや、DataLayerの親子関係を構築したりします。
そしてDataLayerAssetは、配置しているアクターに設定することでDataLayerInstanceでストリーミングした際にアクターがどのDataLayerに所属しているかがアセットを通じて判別できるようになっています。
↓簡単な図解
その4-DataLayerによるストリーミングをやってみる
では、DataLayerにアクターを所属させられるようになったところで、実際にDataLayerを使ってストリーミングを行いたいと思います。
プレイ中にストリーミングを行いたい場合は、DataLayerAssetのDataLayerTypeの設定をRuntimeにしましょう。
すると、DataLayersOutlinerウィンドウの、Typeを設定したDataLayerの詳細を見てみると、下の方にAdvancedという項目の中にRuntime
→Initial Runtime State
という項目が増えていると思います。
ここに設定されているのは、プレイが始まった時(マップに遷移した時)のDataLayerの初期ストリーミング状態です。デフォルトではUnloadedになっています。
このRuntimeStateというプロパティは3種類の状態があり、以下がそれぞれの説明になります。
Unloaded:所属しているアクターは常にアンロード状態になる
Loaded:所属しているアクターはWorldPartitionのストリーミングによってロード範囲内になった場合はロード状態になる。ただし表示は常にされない。
Activated:所属しているアクターはWorldPartitionのストリーミングによってロード範囲内になった場合はロード状態になる。WorldPartitionのストリーミングによって表示範囲内になった場合は、表示される。
ちなみに、LoadedとActivatedの違いは、LevelStreamingのUnloadとLoadの違いと同じく、Loadedの場合だとメモリには乗っているがアクターとしては使えなかったり、BeginPlay
が走ってなかったり、GetAllActorsOfClass
などで取得もできない状態です。
この部分をプレイ中に変更するには、少しBlueprintを書く必要があります。
今回はActorクラスを継承したBlueprintを作成し、入力を受け付けるようにした設定のBlueprintに以下のようにノードを記載しました。
そして、Blueprintで設定したDataLayerに任意のアクターを所属させてから実行してみます。
しっかりDataLayerのストリーミングによってアクターをロード・アンロードできてそうな挙動をしています、やった!
ここからは、もう少しDataLayerについて掘り下げた解説をしていきます。
DataLayerについての豆知識
その1ーDataLayerによるストリーミングを待つ
一番シンプルなDataLayerの構造だと、RuntimeStateを切り替えた場合はそのままアクターに適応されます。
レベルのストリーミングだと、LoadStreamingLevel
関数を使ったりしますが、あれは完了するまで待ってくれるLatent関数なので完了を待つことはできますが、DataLayerのActivateなどを設定した場合にそのDataLayerのActivatedが完了するのを待つには少しテクニックが必要になります。
先程DataLayerのUnloadedとActivatedを切り替えるBlueprintを作成しましたが、そこにActivatedの完了を待つ処理を追加してみようと思います。
これを先程のようにDataLayerのRuntimeStateのテストと合わせて実行してみます。
分かりづらいですが、DataLayerのActivatedが完了するまでIsStreamingCompleted
がFalseになっていて、完了するとTrueになっています。
このBlueprintだと複数DataLayerに対応できてないのでそのままは使えないですが、色々使えそうな感じがしますね。
※以下のツイートを参考にしました。いつもありがとうです。
その2ーDataLayerの親子関係と、複数DataLayerに所属している場合について
DataLayerは親子関係を作ることもできます。
では、DataLayerが親子関係になっていた場合RuntimeStateの扱いはどうなるのでしょうか?
結論から言うと、DataLayerが親子になっている場合は
1,優先されるStateがありUnloaded>Loaded>Activateの順番となっている
2,親の状態が引き継がれる
となる。
例:DL_Test_01
の子供にDL_Test_01_A
がぶら下がっている場合
・
DL_Test_01
がUnloadedであれば、DL_Test_01_A
は絶対にUnloaded
・DL_Test_01
がLoadedであれば、DL_Test_01_A
はUnloadedであればUnloaded,LoadedかActivateであればLoaded
・DL_Test_01
がActivatedであれば、DL_Test_01_A
は自身のRuntimeStateになる
とこのような感じになります。
では、1つのアクターに複数のDataLayerを所属させた場合はどうでしょうか?
これも結論から言うと、複数のDataLayerに所属している場合は
・所属しているすべてのDataLayerのステータスを鑑みて、Activate>Unloaded>Loadedの順番でRuntimeStateが優先される
となります。
例:DL_Test_01
とDL_Test_02
の2つのDataLayerに所属しているアクターの場合
・
DL_Test_01
かがActivatedであればActivated
DL_Test_02
・DL_Test_01
とがどちらもActivatedではなくどちらかがLoadedであればLoaded
DL_Test_02
・DL_Test_01
とDL_Test_02
どちらもUnloadedならUnloaded
とこのような感じになります。
親子関係と複数所属だと、RuntimeStateの優先順位がまるっきり逆になるのが面白いですね。
その3ーDataLayerに所属しているアクターが他の異なるDataLayerに所属しているアクターを参照をしている場合の扱いについて
DataLayerが設定されているアクターが他のアクターの参照を持っている場合、すこし扱いが特殊になります。
何が特殊かというと、参照されているアクターと参照しているアクターは同じRuntimeのDataLayerに所属していないといけないというところです(TypeがEditorのDataLayerは特に関係ありません)
まずはテスト用の簡単なサンプルBlueprintを作ってみます。
このBlueprintをWorldPartitionのマップに2つ配置します。
片方のアクターの作成したActor型の変数にもう片方のアクターを入れてあげます。
そして、2つのアクターにそれぞれ別のRuntimeのDataLayerを設定してみます。
最後にアクターをセーブし、同じマップを開き直すとおそらく以下のようなMapCheckErrorが表示されるかと思います。
Actor BP_ReferenceActorTest(/Game/WorldPartition/PL_WorldPartition_Test) references an actor in a different set of runtime data layers BP_ReferenceActorTest2
日本語
アクタBP_ReferenceActorTest(/Game/WorldPartition/PL_WorldPartition_Test) ランタイム データ レイヤー の別のセットにあるアクタを参照しています BP_ReferenceActorTest2
なぜこのようなエラーが起きるかというと、WorldPartitionの仕様として参照しているアクターとされているアクターは、ストリーミングされる際にアクター参照を辿って一緒にロードを行うようになっているからです。
↓参照をしていない状態でのプレイ
↓参照をしている状態でのプレイ
通常のアクターの参照をしている場合は、設計としてアクターがある前提になるようになっています。
これは、サブレベルのときにもある、異なるサブレベルにあるアクターの参照を持てないのと同じ原理になります。
そして、DataLayerもストリーミングとしての機能があるため、異なるDataLayerの設定を持つアクター同士が参照を持つことを推奨しないということです。
ちなみに、通常の参照の場合は互いが互いをある前提で同時にストリーミングされますが、これがSoftReferenceであれば異なるDataLayerを持つアクター同士の参照を持つことができます。
↓SoftReferenceでの参照するための変数の型
SoftReferenceの場合は、変数を使うときにアクターがロードされているかを確認するためにBlueprintなどにチェック処理をいれてから使うのが推奨されます。
その4ーLevelInstanceにおけるDataLayerの扱いについて
UE5.1から、LevelInstanceActor内にあるアクターにもDataLayerを設定できるようになりました。
※埋め込みモードでのみ有効
そもそもLevelInstanceって?に関しては公式ドキュメントを参照してください。
または、LevelInstanceのとても良い解説記事がありましたのでこちらも参考にしてください
LevelInstanceActorのLevelStreamingモードと動的レベルインスタンス生成
ここでは、LevelInstanceのアクターにDataLayerを設定して、実際にStreamingするところまでやってみます。
適当にアクターを配置して、配置したアクターを右クリックしてからLevel
→CreateLevelInstance...
を選択します。
その後出てきた設定は何も変更せず(変更しても影響はない)OKを押します。
そして、保存するレベルの名前と保存先を決定します。
これで選択していたアクターをLevelInstanceにすることができました。
UE5.1では、この方法でLevelInstanceを作ると、LevelInstance側のレベルもWorldPartitionのマップとして扱われ、WorldDataLayersアクターなどのアクターが自動で入っています。
LevelInstance内のアクターにDataLayerを設定するには、まずLevelInstanceを編集状態にします。
LevelInstanceActorを右クリック→Level
→Edit...
を選択します。
すると、LevelInstance内のアクター以外が白黒の背景になるかと思います。
※わかりやすいように配置したCubeのマテリアルの色を変更してあります。
※尚、LevelInstanceを編集中に、周りの背景を白黒にしたくない場合は、Viewport上部のShow
→Visualize
→VisualizeLevelInstanceEditing
のチェックを外すことで、見た目を元に戻すことができます。
LevelInstanceを編集状態にしたら、あとは通常通りDataLayerにアクターを所属させるだけです。
所属させると、DataLayersOutliner
にLevelInstanceにあるWorldDataLayerのDataLayerがツリーとして表示されるようになります。
この状態でセーブして、LevelInstanceのレベルをパーシスタントレベルとして開いてみると、所属させたDataLayerのツリーがそのままコピーされて、DataLayerInstanceが作成されています。
もちろん、DataLayerに所属したアクターは通常通りDataLayerのRuntimeStateによってストリーミングが可能になります。
ここまでできると、大規模開発などにおいては特にDataLayerとLevelInstanceの設計が重要なことがわかってくるかなと思います。
(今回は開発フロー的な面の記載はしませんが、気が向いたらWorldPartitionを用いた理想の開発フローとデータ設計みたいなものもかけたら書こうかなと思います)
その5ーUE5.0から5.1で大きな変更のあったDataLayer
ここまでもいくつかUE5.1から更新されたDataLayerに関連する機能を紹介しましたが、UE5.0から5.1へのアップデートでWorldPartitionの様々な機能がかなり大胆にに変更が加わっています。
(Experimentalかな?ってぐらい)
個人的にはWorldPartitionを導入するのは、もう2,3バージョンぐらい待ってから使うほうが、安定してそうな予感がしています。ですが、やはりWorldPartitionは昨今のオープンワールドゲームを作るには便利な機能が多いので使いたくなると思います。その際はバージョンアップの際の保守コストが多いのは覚悟したほうが良いと思っています。
DataLayerに関しては、5.0ではアセットにはなっておらず、AWorldDataLayers
アクターに直接DataLayerの情報が保存されています。
DataLayerアセットになったことによって、
1,複数のWorldPartitionのパーシスタントレベルで、同じDataLayerの設定を共有できるようになった。
2,多人数開発において、UE5でOneFilePerActorになったのに、このDataLayerの情報が1アクターに保存されていたので編集の競合が起きていたが、それが”多少”改善された。
→多少と言うのは、マップ内のアクターに新しくDataLayerを作成して設定する際に、WorldDataLayerアクターを編集することなく設定できるようになったが、新しくDataLayerを作成した場合は結局WorldDataLayerを編集する必要があるので、そこの競合は相変わらず起きる可能性があるということです。ただし、次に書くLevelInstanceでもDataLayerが使えるようになったことにより、WorldDataLayerを実質的に分割できるようになったため、ある程度編集するファイルを分割することが可能になった。
3,UE5.0では、LevelInstanceアクターを使った際に、DataLayerがセットできなかった(パーシスタントレベルのDataLayerと共有できなかったため、LevelInstanceアクターは、そのアクター自体のDataLayerの所属情報と同じ情報が設定しているLevelに伝達していた)が、LevelInstanceとして使うレベル内のアクターにも、それぞれ独自のDataLayer設定を設けられるようになった。
と言った、細かく見るとものすごく多くのアップデートがなされています。
で、肝心のバージョンアップ時に互換性があるのかというと、UE5.0で作成したDataLayerをそのまま5.1に持っていっても、一応使えているが非推奨となってしまい、必然的に変換が必要になっていしまっています。
具体的には、DataLayersOutliner内に5.0で作成したDataLayerがあると、↓のような文言が表示されてしまいます。
Some data within DataLayers is deprecated. Run DataLayerToAssetCommandlet to create DataLayerInstances and DataLayer Assets for this level.
日本語DataLayers 内の一部のデータは非推奨です。DataLayerToAssetCommandlet を実行して、DataLayerInstances と DataLayer アセットをこのレベルに作成してください
というわけで、DataLayerToAssetCommandlet
というコマンドを使って、DataLayerアセットを作成する必要があります。
今回は汎用的にDataLayerを変換できるバッチファイルを作成してみました。
ConvertDataLayerToAsset.bat
@echo off
setlocal
echo DataLayerの変換を始めます
rem 必要な情報の変数作成
SET ProjectName=MyProject4
SET DLAssetPath=/Game/DataLayers
SET ConvertMap=/Game/Maps/PL_WPTest_01
rem UE5.1のUnrealEditor.exeがあるパスへ移動
pushd C:\Program Files\Epic Games\UE_5.1\Engine\Binaries\Win64
rem DataLayerの変換実行
UnrealEditor.exe %~dp0\%ProjectName%.uproject -run=DataLayerToAssetCommandlet -DestinationFolder=%DLAssetPath% %ConvertMap% -IgnoreActorLoadingErrors
popd
echo DataLayerの変換を終わります
endlocal
pause
変数作成
の部分の設定を変更することで、どのプロジェクトでも変更できると思います。
※カレントディレクトリを変えている部分で、エンジンをインストールしている場所がデフォルトの設定ではなかったりカスタムエンジンだったりする場合はpushd
コマンドのパスを変えてください。
実行すると、こんな感じになります。
ちゃんと変換されてそうですね!
ただここで一つ重要な注意点があります。
どうやらUE5.1のDataLayerの設計思想的に、同じDataLayerの名前なら同じDataLayerアセットを使えという感じになっているようで、変換で新しく作成されたDataLayerと同じDataLayerの名前があると、勝手に元々あったDataLayerを消していきます。
すると、元々あったDataLayerを参照していたアクターは、何もないアセットを参照仕様としてエラーを起こしてしまいます。
これは非常に危険で、参照があったすべてのアクターは空のアセットを参照してしまい、再セーブするとリンク情報がすべて消えてしまいます。
自動ですでにあるDataLayerアセットにリンクしてくれたりとかはしないので、消されたDataLayerを後で復元することで元に戻してから、同じDataLayerの名前のものをリンクし直すなどをする必要があります。
自動で対応をするには、WorldPartitionDataLayerToAssetCommandlet.cpp
の中身をコピって独自のコマンドを作成して変換時に自動リンクをするようにするか、変換後にEditorUtilityなどで同じDataLayer名のものを置き換えるようなツールを作るあたりかなと思います。
このコマンドレットは5.1で登場したばかりなので、5.2以降で実行内容がさらに変更になったりする可能性もあります。ご使用の際は最新のバージョンを確認してから注意してお試しください。
ちなみに、コマンドに-NoSave
をつけることで、セーブをしないでお試しでコマンドを実行する方法もありますので、ログを外部ファイルなどに出力するようにしてまずは影響が出ないように試すのをおすすめします。
このDataLayerコンバートのサンプルは、別プロジェクトでアップしてありますので、よければ御覧ください。
DataLayerConvert用サンプルプロジェクト
その他コマンドレットで既存のレベルをWorldPartitionに変換する系に関しては、公式ドキュメントとかアジのお友達が書いた【UE5】既存レベルを World Partition 化する手順やトラブルシューティングあたりを参考にすると良いかなと思います。
その他ーDataLayerの便利機能まとめ
その他DataLayerについての便利な機能の紹介です。
・DataLayerに関するデバッグコマンド
wp.Runtime.ToggleDrawDataLayers
→DataLayerのRuntimeStateの状態をビューポート上に表示する
wp.Runtime.SetDataLayerRuntimeState [Unloaded,Loaded,Activated] [DataLayerLabel]
→任意のDataLayerのRuntimeStateを任意のものに設定する
・DataLayerに関する便利なBP関数たち(主に、DataLayerEditorSubsystemの関数)
※EditorUtilityBlueprintなどで使用できます。
・DataLayerにアクターを追加する
・DataLayerからアクターを削除する
・DataLayerInstanceを作成
・DataLayerInstanceを削除
・Editor上のDataLayerの表示・ロード状態を操作する
他にも↓のようにたくさんのサポート関数がDataLayerEditorSubsystemにあるので、興味がある方は是非御覧ください(サンプルプロジェクトにこのノードは配置してあります)
・C++側の便利機能
AWorldDataLayers::OverwriteDataLayerRuntimeStates
DataLayerInstanceに設定されているInitialRuntimeStateを、変更することなく初期状態を強制的にRuntimeStateを任意の状態から開始する。
→既存の設定を変えずに初期状態を変えられるので、WorldDataLayerアクターを編集することなく任意のRuntimeStateの状態にできます。これはプロファイルのときや特定の状態を作り出したいときにとても役に立ちます。ちなみに、ActivatedをUnloadedなどにした場合しっかり最適化されてて一瞬もロードされないので、不要なDataLayerを読み込まないようにしてプレイインを早くすることができます。
実行するタイミングはFWorldDelegates::OnPreWorldInitialization
あたりのタイミングでAWorldDataLayers::OverwriteDataLayerRuntimeStates
を実行することで設定上書くことができると思います。(検証動画をはろうと思いましたが、若干面倒だったのでまたTwitterとかでアップします)
まとめ
最近様々なプロジェクトで使おうとしているWorldPartitionですが、まだまだ登場したばかりでこれからどんどん新しい機能が入ってきそうな予感がしており、使う側がついていくのが難しいのが現状なのですが、適度に便利な機能を使用することで今ま作るのが難しかったゲームを比較的コストを抑えて作成することができるようになったかなと思います。
が、使う側もそれに合わせた使い方を確立していかなければならないため、今後様々なプロジェクトでのWorldPartition活用事例が出てくることを祈っております。
最近は数多くのプロジェクトにキンアジちゃんがアサインされているので、ブログを書く時間が取れないようですが、折をみていつものEditorUtility系やWorldPartitionを始めとしたUE5の機能だったりを書けたら良いな…と思っておりますので、来年も陰ながら見守ってくれていると嬉しいです!
いつもながら雑な記事になってしまい恐縮ですが、以上となります。
明日はトクナガさんの「EditorUtilityWidgetを触る事が増えてきたのでこの辺り書きます。」です!
EditorUtilityなアジとしては気になるところです!
それでは少し早いですが良いお年をお過ごしください!
最後まで読んでいただきありがとうでした!
※この記事のサンプルプロジェクトは以下URLにアップされています。
サンプルプロジェクト
DataLayerConvert用サンプルプロジェクト