EditorValidatorSubsystemを使ってみた

この記事は、サブシステムの勉強も兼ねて、サブシステムの一つであるEditorValidatorSubsystemを調査した記事です。
EditorValidatorSubsystemについて、実用的な使い方は[おかずさんが紹介](https://pafuhana1213.hatenablog.com/entry/2019/12/31/233628)されている為、この記事に記載されていない内容で気になった事を検証しています。


# 調査環境

UnrealEngine 5.1.1

# EditorValidatorSubsystemとは

簡単に説明すると、UEで扱うアセットのバリデーション処理が行われる際に、割り込み処理を入れられます。

例えば、StaticMeshがUEにインポートされた際に、特定の命名規則になっていない場合に警告を出したり、
StaticMesh保存した際にマテリアルインスタンスが無かった場合は、専用のマテリアルインスタンスも生成してしまう事も出来ます。

アセットのバリデーション処理についかで割り込み処理を入れられるだけなので、レベル内にあるアクターに変更を加えたりはありませんが、間違ったデータがプロジェクト内に混在する事を監視する事が出来る為、人的ミスの防止に繋がるかと思います。



# EditorValidatorSubsystemを使う

EditorValidatorSubsystemを使うには、EditorValidatorBaseを継承したウジェットブループリントを作成する必要があります。
チェック用の関数には、『**CanValidate**』『**CanValidateAsset**』『**ValidateLoadedAsset**』があり、オーバーライドして実装する必要があります。
三つ全て実装する必要はなく、また、一つも実装していなくてもコンパイルは通ります。
しかし、CanValidateAssetは、実装を省略すると結果としてfalseを返しているみたいので、**ValidateLoadedAssetまで実行されません**。
また、CanValidate → CanValidateAsset → ValidateLoadedAsset の順で実行されています。

使い方の詳細については、最初に上げた、[おかずさんの記事](https://pafuhana1213.hatenablog.com/entry/2019/12/31/233628)と[公式のドキュメント](https://docs.unrealengine.com/5.1/ja/running-blueprints-at-unreal-editor-startup/)が参考になります。

# EditorValidatorSubsystemが実行されるタイミング

トリガーの種類の詳細は、次の項目で説明しています。
普段使う際に、EditorValidatorSubsystemのバリデーションが走るタイミングとしては、以下の場合があり得るかと考えられます。

* アセットアクション → アセットの検証 を実行した時
* アセットの保存操作を行った時

また、コマンドラインからの実行でパッケージングした際にも走るようです。詳しくは[こちら](https://docs.unrealengine.com/4.27/ja/ProgrammingAndScripting/ProgrammingWithCPP/Assets/DataValidation/#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)



# CanValidate関数

![CanValidateノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/c5c90e5c-2eeb-2109-f7ef-47ec7650c13a.png)

オーバーライドできる関数の一つです。
データの(操作の)トリガー方法をチェック出来る関数になります。
引数のEDataValidationUsecase型で、どの操作でのチェックが走っているのかを調べられます。
**実装を省略した場合は、結果がtrueを返しているみたいなので、常に合格判断**がされます。


|値|パラメータ|説明                                                                                       |
|--|----------|-------------------------------------------------------------------------------------------|
|0 |None      |デフォルト                                                                                 |
|1 |Manual    |アセットアクション → アセットの検証の操作で呼び出される                                   |
|2 |Commandlet|コマンドラインからの呼び出し。パッケージ作成処理の過程検証で呼び出されると思われる(未検証)|
|3 |Save      |アセットを保存をした時に呼び出される                                                      |
|4 |PreSubmit |一時ファイルのチェックに実行される？(未検証)                                              |
|5 |Script    |実装されていないっぽい                                                                    |

『Script』については、説明をみる限り、ブループリントやC++で『IsValid』を実行した際にコールされるのかと考えていたのですが、
実装されていないのではないかと予想しています。
EDataValidationUsecaseでは、『Script』というパラメータが用意されていますが、
**.poファイル(コメントやツールチップの説明文の言語情報が記載されたファイル)以外で、エンジンコード中で使用されている形跡がありません**。
コールされるタイミングを知っている方が居たら、教えてください。



# CanValidateAsset関数

![CanValidateAssetノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/b694958d-c726-efc4-2ed7-3a20bbb68e54.png)

オーバーライドできる関数の一つです。
データのチェックを出来る関数になりますが、最終的には、ValidateLoadedAssetで有効なデータか返す必要があります。
**実装を省略した場合は、結果がfalseを返してしまうみたいなので、常に不合格判断**がされ、ValidateLoadedAssetまで呼び出されません。


CanValidateAssetは、UObjectを引数にもらえる為、CastやGetClass等で、クラスを調べる事が出来ます。
また、**AssetFailsをCanValidateAssetで呼び出そうとすると以下のエラーでコンパイルエラーになります**。

```ruby:qiita.rb
関数  Asset Fails  はステート変更はできますが、このコンテキスト内で読み取り専用のターゲットであるため「自身」に呼び出すことはできません。
```

**※ AssetFailsについては後述します**

# ValidateLoadedAsset関数

![ValidateLoadedAssetノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/bbb8e4fd-af09-bd43-35d0-eea4160506a2.png)

オーバーライドできる関数の一つです。
ロード済のデータのチェックする関数になります。
**実装を省略した場合は、結果はエラーメッセージが発生しない為、ValidかNotValidatedを返している**ようです。
ここで、データに問題があったかどうか結果を返します。
ValidateLoadedAssetの第一引数は、UObjectを引数にもらえる為、Cast等を行い、オブジェクトをチェックしていく事になります。
第二引数のValidationErrorsは、ValidateLoadedAssetに来るまでのエラーメッセージが入っています。

リターンする際は、EDataValidationResult型を返します。

**EDataValidationResult型のパラメータ**

|パラメータ  |意味                                        |
|------------|--------------------------------------------|
|Invalid     |バリデーションに失敗(メッセージログに表示) |
|Valid       |バリデーションに合格                       |
|NotValidated|バリデーションを未チェック                 |

# その他のノード紹介

こちらで紹介するノードは、ValidateLoadedAsset関数で使用するノードです。

**AssetPassesノード**
![AssetPassesノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/ad738cac-7870-87ca-f146-2344a5c81528.png)

チェックデータに問題無い場合に呼ぶノードです。
リターンもValidを返す事になるでしょう。


**AssetWarningノード**
![AssetWarningノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/bd5e6e7c-2466-caff-9b46-0abbce715c27.png)

チェックデータに警告があった際に呼び出すノードです。
このノードを呼び出すと、メッセージログに下画像のような警告アイコンのメッセージが表示されます。
![AssetWarningの警告メッセージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/e138c34d-9436-b5bf-4433-343593984889.png)


**AssetFailsノード**
![AssetFailsノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/bb0d4a8c-af50-6c22-f1ce-227b210e42a5.png)

チェックデータに問題があった際に呼び出すノードです。
リターンもInvalidを返す事になるでしょう。
このノードを呼び出すと、メッセージログに下画像のようなエラーアイコンのメッセージが表示されます。
![AssetFailsのエラーメッセージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/1d98ca83-ebf9-e564-3905-5bc894e2e12f.png)

また、右下に、いつものエラーのフィードも表示されます。

![AssetFailsのエラーメッセージ_フィード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/76f3b0c5-14e3-20cc-5ed2-7f3d2e8de81b.png)


ちなみに、AssetWarningとAssetFailsを同時に実行出来る為(その場合、警告とエラーの両方メッセージが表示)、依存関係等はないみたいです。


# おまけ

最後に実験してみたい事があったので、やってみました。
実験内容は、CanValidateAssetとValidateLoadedAssetでアセットのプロパティの変更が可能か調査しました。
CanValidateAssetで、チェックデータがStaticMeshである場合は、マテリアルを変更するような事を行ってみます。

:::note info
バリデーション中に、バリデーションしているデータに変更を加えられるのかを検証します。
:::

**ブループリント実行前の状態**
![SMのマテリアルの変更前_Cone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/5e6879d2-9221-92ce-ad2b-796078b205e7.png)

**使用したブループリント**
![SMのマテリアルの変更用のブループリント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/21d8e7f3-45a2-33a1-12b3-616d4984c6e7.png)

**ブループリント実行後の結果**
![SMのマテリアルの変更後_Cone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/7cb98cc0-2fa0-466c-c576-891cde2524f2.png)

こちらは、マテリアルが変更される事を確認しました。
マテリアルが変更されており、Dirtyフラグも付いています。
注意しなければならないのは、このObject型はアセットである為、**Actor系のキャストは失敗する**点です。