ぼっちプログラマのメモ

UE4とかUE5とかについて書いたり書かなかったり。

【UE5】Collision Presetの設定状況をReference Viewerで確認可能にする方法について(MarkSearchableName)

本記事はUnreal Engine (UE)のカレンダー | Advent Calendar 2023 - Qiita シリーズ 5の 3日目の記事です

はじめに


ホグワーツレガシーの開発者による講演「Collision Data in UE5: Practical Tips for Managing Collision Settings & Queries(Unreal Engine 5での衝突データ: 衝突設定とクエリの管理に関する実用的なアドバイス)」にて、「Collision Presetの設定状況をReference Viewerから確認できるようにするといいぞ」という内容がありましたが、具体的にどうすればいいのかは説明がなかったので…調べて記事にしました!

動いてる様子

なぜこの対応を入れると良いのか?など講演の内容に関しては下記記事でまとめてるのでどうぞ!
(Collision Preset設定に関する設定ミス・不具合を調査する上で便利、などが理由です)
pafuhana1213.hatenablog.com

対応方法について

PrimitiveComponent(BP, レベル上のActor)への対応

void UPrimitiveComponent::Serialize(FArchive& Ar)
{
...
// add
#if WITH_EDITOR
	if (Ar.IsSaving())
	{
		// This marks the saved name for later searching
		Ar.MarkSearchableName(FBodyInstance::StaticStruct(), BodyInstance.GetCollisionProfileName());
	}
#endif
//
}

StaticMeshアセットへの対応

void UStaticMesh::Serialize(FArchive& Ar)
{
…
// add
#if WITH_EDITOR
	if (Ar.IsSaving() && GetBodySetup())
	{
		// This marks the saved name for later searching
		Ar.MarkSearchableName(FBodyInstance::StaticStruct(), GetBodySetup()->DefaultInstance.GetCollisionProfileName());
	}
#endif
//
}

上記対応を入れた後にアセットを再保存することでReference Viewer上でCollisionPresetの設定状況が確認可能になります。コンテンツブラウザ上でのResaveか、下記記事にある方法で一括Resaveするのが良いと思います!
qiita.com

MarkSearchableNameについて

上記の対応で使っているMarkSearchableNameはアセットのデータ(FArchive)に対してName型の文字列情報をReferenceとして仕込む関数で、エンジン標準ではDataTable・CurveTableの行情報(FDataTableRowHandle, FCurveTableRowHandle)とGameplayTagで使われています。

void FDataTableRowHandle::PostSerialize(const FArchive& Ar)
{
	if (Ar.IsSaving() && !IsNull() && DataTable)
	{
		// Note which row we are pointing to for later searching
		Ar.MarkSearchableName(DataTable, RowName);
	}
}

void FGameplayTag::PostSerialize(const FArchive& Ar)
{
	// This only happens for tags that are not nested inside a container, containers handle redirectors themselves
	// Only do redirects for real loads, not for duplicates or recompiles
	if (Ar.IsLoading() && Ar.IsPersistent() && !(Ar.GetPortFlags() & PPF_Duplicate) && !(Ar.GetPortFlags() & PPF_DuplicateForPIE))
	{
		// Rename any tags that may have changed by the ini file.
		UGameplayTagsManager::Get().SingleGameplayTagLoaded(*this, Ar.GetSerializedProperty());
	}

	if (Ar.IsSaving() && IsValid())
	{
		// This marks the saved name for later searching
		Ar.MarkSearchableName(FGameplayTag::StaticStruct(), TagName);
	}
}

なお、MarkSearchableNameの第1引数にはUEnumかUStructが設定されることが想定されています。

この仕組みを使ってPrimitiveComponentとStaticMeshアセットにBodyInstanceが持つCollisionPreset名を紐付けることで、ReferenceViewer上でCollisionPresetの設定状況を確認可能にしています。

現状確認している不具合


非WorldPartitionレベルの場合、レベル上のActorにおけるCollisionPreset設定をLevelアセットのReferenceから確認できます。しかし、WorldPartitionレベルの場合はBlockAllしかReferenceに追加されません。たぶんOneFilePerActorが理由かなと思ってます。うまく解決できたら追記します!

さいごに

MarkSearchableNameは今回紹介した用途以外でも自由に使えるので、プロジェクト固有のデータとか仕込んでおくと設定管理・不具合調査時に役に立つかもしれません!

おしまい