忙しさにかまけて放置してしまっていたが、久々に更新。
デコレーターでクックエラー
突然だが、UE4 のビヘイビアツリーには、デコレーター(Decorator)というものがある。
このデコレーターのアセットを作った上で、パッケージングをするためにクックを走らせると、
以下のようなエラーが出て止まるということがあった。
LogOutputDevice: Error: === Handled ensure: ===
LogOutputDevice: Error: Ensure condition failed: ObservedKeyNames.Num() > 0
[File:D:\Build\++UE4+Release-4.19+Compile\Sync\Engine\Source\Runtime\AIModule\Private\BehaviorTree\Decorators\BTDecorator_BlueprintBase.cpp] [Line: 67]
UE4 の ensure アサーションに捕まっている。
とりあえず、上記に書かれているソースコードを読んで見る。
void UBTDecorator_BlueprintBase::PostLoad()
{
Super::PostLoad();
if (GetFlowAbortMode() != EBTFlowAbortMode::None && bIsObservingBB)
{
ObservedKeyNames.Reset();
UClass* StopAtClass = UBTDecorator_BlueprintBase::StaticClass();
BlueprintNodeHelpers::CollectBlackboardSelectors(this, StopAtClass, ObservedKeyNames);
ensure(ObservedKeyNames.Num() > 0);
}
}
BTDecorator_BlueprintBase
はブループリントでデコレーターを作る際には必ず継承する必要があるクラス。
このクラスの PostLoad
つまりロード直後のイベント内でアサートしている。
具体的には、GetFlowAbortMode() != EBTFlowAbortMode::None
かつ bIsObservingBB
のとき、
自分のクラスに、 FBlackboardKeySelector
のメンバ変数があるかどうか探して、なければアサーション。
(BlueprintNodeHelpers::CollectBlackboardSelectors
は FBlackboardKeySelector
のプロパティを検索してその名前をリスト化して返す)
EBTFlowAbortMode
はデコレーターが元々持っているもので、ビヘイビアツリーの中断発生時の振る舞いを決めるものだけど、
一般的に考えて EBTFlowAbortMode::None
にする運用はあまりないといっていい。
なので、bIsObservingBB
が true になっていることが問題?と一瞬思うのだが、
void UBTDecorator_BlueprintBase::InitializeProperties()
{
if (HasAnyFlags(RF_ClassDefaultObject))
{
UClass* StopAtClass = UBTDecorator_BlueprintBase::StaticClass();
BlueprintNodeHelpers::CollectPropertyData(this, StopAtClass, PropertyData);
bIsObservingBB = BlueprintNodeHelpers::HasAnyBlackboardSelectors(this, StopAtClass);
}
}
void UBTDecorator_BlueprintBase::PostInitProperties()
{
Super::PostInitProperties();
InitializeProperties();
if (PerformConditionCheckImplementations || bIsObservingBB)
{
bNotifyBecomeRelevant = true;
bNotifyCeaseRelevant = true;
}
}
とあるように、PostInitProperties
時に、
BlueprintNodeHelpers::HasAnyBlackboardSelectors
で ‘FBlackboardKeySelector’ を事前検索しているだけだった。
どういうことなの・・・
もうわからんので、ぐぐってみる。
AnserHub にもとりあげられていた。ああ、まさにこれこれ。
ここにもあるけど、結局のところ結論から言えば、
アセットを作り直せ。
である。ええ・・・。
どうも、デコレーター編集をしている際、一時的に BlackboardKeySelector
を使用していて、
その後、削除するような操作をしたとき、起きる場合があるのだと思われる(検証はしてないが)
作り直すのはいいんだけどさ
ここで1つ問題がある。
そもそも、どのデコレーターアセットのエラーなのかわからない
ということ。
エラーログを見る限り、全くわからない状態。
いやー、困ったね。
どのアセットが問題か探す
探し方として、以下のような方法がとれる。
1. デコレーターアセットを別プロジェクトに Migrate して該当するアセットが含まれているか確認
今制作しているプロジェクトへ影響を与えず、かつ、問題の箇所を明確にするため、デコレーターアセットを Migrate して別プロジェクトにインポートして、エラーが起きるか確認する。
アセット自体を分けてしまうことで、問題の切り分けもはっきりするし、1回のクック時間も短く済む。
2. 各デコレーターアセットの Observer Abouts を1つずつ None にしてクックエラーが出ないか確認
上のソースコード読めばわかるように、
GetFlowAbortMode() != EBTFlowAbortMode::None
でなければ、そもそも、このエラーにはならない。
1つずつ None しながら、クックエラーが起きないかチェックすることで、どのデコレーターアセットで問題が起きているか、
特定することができる。
該当アセットの修正
該当アセットを削除して作り直す・・・わけだが、ある程度作った後だった場合は、ちょっと大変な作業になる。
回避策としては、今のところ、早めにクックをして、問題が発生していないか確認しておくぐらいしかなさそうだ。
なお、「BlackboardKeySelector のプロパティを1つ持たせておく」ことで通すことができないか検証したが、それだけではうまく行かなかった。
また Duplicate してもエラーは解決しない。
きちんとまっさらなものから作り直す必要がある。
コメント