15
8

More than 1 year has passed since last update.

[UE5] Blueprint ・Componentが持つプロパティのデフォルト値をSubobjectDataSubsystemを使って確認・変更する方法について

Last updated at Posted at 2022-08-19

はじめに

開発を進めていると、Blueprint(BP)やComponentが持つ各プロパティのデフォルト値(初期値)をリスト化したり一括で変更したくなります。例えば、Tickが不要に有効になっていないか確認したり、Componentが使用しているアセットを変更したりなどです。(レベル上のActorの話ではなく、その元となるコンテンツブラウザ上のBPアセットの話です)

しかし、コンテンツブラウザ上のBPアセット(UBlueprint実装で使っているBPクラス(AActorなど)別物 なので、実はそこそこ面倒でした…。更にC++またはPythonがほぼ必須になり、BPのみで実現することができませんでした…

が、UE5で追加されたSubobjectDataSubsystem を使うことで、BPからでも簡単にプロパティを確認・変更することができるようになりました!

神!(実はComponentを追加したりもできますが、それはまた別の記事で…)

ということで、今回はSubobjectDataSubsystemの使ってプロパティのデフォルト値を確認・変更する方法についてご紹介します。少し細かい話もありますので、早く使いたい!って方は後半まで飛ばして大丈夫です。

UE4時代の場合

UE4時代、BPクラスの各プロパティのデフォルト値はClass Defauilt Object(CDO)からアクセス可能でした。しかし、下図のとおり縦に長く出てしまいますし、よくよく見ると微妙に足りません…(例えば、TickGroupとか)。
image.png
そして、Setが用意されていないのでプロパティの初期値を変更することができません。そのため、対象のBPやComponentが持つプロパティの初期値をGet/Setしたい場合は、C++またはPythonの利用が必須になっていました。

C++の場合

c++
#include "MyEditorBlueprintFunctionLibrary.h"
#include "Kismet2/CompilerResultsLog.h"
#include "Kismet2/KismetEditorUtilities.h"

void UMyEditorBlueprintFunctionLibrary::EditActorProperty(UBlueprint* Blueprint)
{
	if (!Blueprint)
	{
		return;
	}
	
    // CDOを取得して初期値を変更
	UClass* Class = Blueprint->GeneratedClass;
	AActor* CDO = Class->GetDefaultObject<AActor>();
	CDO->SetTickGroup(TG_DuringPhysics);

	// コンパイルして変更を反映
	FCompilerResultsLog LogResults;
	FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::None, &LogResults);

	// Blueprintに編集されたことを通知
	Blueprint->MarkPackageDirty();
}

image.png

Pythonの場合

python
import unreal

selected_asset_datas = unreal.EditorUtilityLibrary.get_selected_asset_data()
for asset_data in selected_asset_datas:
    asset_class = unreal.load_class(None, str(asset_data.object_path) + "_C")
    cdo = unreal.get_default_object(asset_class)
    cdo.set_tick_group(unreal.TickingGroup.TG_POST_UPDATE_WORK)
    unreal.SystemLibrary.transact_object(cdo)

参考

【UE4】DefaultObjectを使ってアセットの初期値を取得
【UE4】【Python】BlueprintClassのデフォルトの変数値を一括変更する【★★★】
Creating and editing Blueprint from C++

UE5で追加された SubobjectDataSubsystem

この状況を解決するのが、今回ご紹介する SubobjectDataSubsystemです!
最新の機能なので残念ながら情報やドキュメントはほぼ0なのですが、エンジンコード内のコメントを見ると

The Subobject Data Subsystem will produce the reflected subobject data based on a given root object. A root object can be anything, an actor instance clicked on via the level editor, a UBlueprint* by opening an asset, or something piped in from python or other scripting languages.
サブオブジェクト データ サブシステムは、指定されたルート オブジェクトに基づいて反映されたサブオブジェクト データを生成します。 ルート オブジェクトは、レベル エディターを介してクリックされたアクター インスタンス、アセットのオープンによる UBlueprint*、Python やその他のスクリプト言語からパイプされたものなど、何でもかまいません。。 (サクッとGoogle翻訳した結果)

レベル上のActor、今回の議題であるBlueprintなど何でも編集できる凄い機能っぽいのが伝わってきます!しかも、BPにたくさんノードが公開されているのでBPオンリーで色々できそうです!神機能の予感!
image.png

ということで、SubobjectDataSubsystemを使ってプロパティの初期値を取得・変更してみます!といっても、超簡単です!なお、エディタ限定のノードを複数使用するため、Editor Utility BlueprintEditor Utility Widgetで処理を組んでいきます。

SubobjectDataSubsystem を使って、BPが持つプロパティの初期値を『取得』してみる

まずは、SubobjectDataSubsystem が持つ Gather Subobject Data For Blueprintノードを使って、指定のBPアセット(UBlueprint)からBPクラス(AActor)を取得します…え、もう AActorまでたどり着いちゃいました!超かんたん!
image.png

↑のノードの解説

Gather Subobject Data For Blueprint ノードを使うことで、対象のBPアセットが持つSubobject Dataのリストを取得できます。このリストにはそのBPアセットが管理してるBPクラスやそのBPクラスが持つComponentの情報が格納されています。

そして、Get Data ノードとIs Actor ノードでその情報がBPクラスなのかを判別して、もしBPクラスだったらGet Objectで実際のデータを取得し、最後に編集したいクラスにCastしています。

あとはいつもの通り、Getノードや専用の関数から各プロパティの値を取得することができます!超かんたん!!!
image.png

SubobjectDataSubsystem を使って、BPが持つプロパティの初期値を『変更』してみる

BPクラスまでCastできてるので、初期値の変更もその流れで実装できます。かんたんですね!
image.png

Transact Objectノードを使っているのは、アセットに編集中/未保存マーク(Dirty Flag)をつけるためです。これをしておかないとデータが変わったことがエディタに伝わらないので、保存忘れやバージョン管理がうまくいかないなどのトラブルが発生する可能性があります。なので、結構重要だったりします。
ちなみに、Transact Objectノードは Undo/Redoを実装する際に使うもの なのですが、こういった用途でも使えます。便利です。
image.png

SubobjectDataSubsystem を使って、Componentが持つプロパティの初期値を『取得・編集』してみる

次は、BPが持つComponentの初期値を変更してみましょう!
はい、できました。かんたんですね!
image.png
先程はDataの中身がActorか否かで判別してましたが、Componentの場合はIs Componentノードで判別可能です。判別できたら、あとは確認・編集したいComponentにCastすればOKです。

ちなみに、さきほどは割愛したのですが、プロパティの取得・編集は Get Editor Property, Set Editor Propertyノードからも可能です。こちらであれば文字列でプロパティを指定できるので、例えば Excelのデータを使ってプロパティを一括変更したい! ってケースなどで便利です。また、Dirty Flagも自動でつけてくれます。
ただし、直接プロパティを弄りに行くので予期せぬ不具合が発生する可能性もありますので扱いには少し注意が必要です。
image.png

SubobjectDataSubsystem を使って、レベル上のActorを編集してみる

おまけで、SubobjectDataSubsystemを使って選択中のActorに対して編集を行う処理も組んでみました!…といっても、Actorなので直接弄ったほうが速いのでSubobjectDataSubsystemを使う意味は正直ありません!
image.png

しかし、Gather Suboject Data For Instance / Blueprintが返す配列の型は同じなので、プロパティの初期値とレベル上に既に配置したActorが持つプロパティの値を同時に編集したり、比較しながらチェック処理を走らせるといったことをする際は便利かと思います。

さいごに

少し話が長くなった感もありますが、 SubobjectDataSubsystemによりBPだけで様々なプロパティを取得・編集できるようになりました!
ある程度の開発規模になると、大量のアセット・Actorを手作業でチェック・編集するのは非現実的になってきます。そんな時に非常に便利な機能ですので是非ご活用ください!

おしまい

つづき(予告)

SubobjectDataSubsystem を使って、BPアセットに対してComponentを追加する方法について

15
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
8