お世話になっております。
NiagaraDataChannelを使用してParticleを発生させているのですが、パッケージビルド版でNiagara内のNiagaraDataChannelReaderのReadに失敗する現象が発生しております。
プレイヤーや敵キャラクターのFootstepのようなものを発生させたいためゲームのシステム的なレイヤーで管理したく、
UTickableWorldSubsystemを継承したSubsystemからNDCへの書き込みを行っております。
NDCへの書き込みは正常に行えているようなのですが、ログには下記のように表示されており、NDCアセットかランタイムクラスの初期化が行えていないのではと思っております。
---
[2026.09.11-07.38.43:436][ 1]LogNiagara: Warning: Niagara Data Channel Reader Interface is trying to read parameters that do not exist in this channel.
It's likely that the Data Channel Definition has been changed and this system needs to be updated.
Data Channel: NiagaraDataChannel_Global_0
System: /Game/VFX/NS_NDCParticle.NS_NDCParticle
Component:/Game/Maps/L_NewMap.L_NewMap:PersistentLevel.WorldSettings_1.NiagaraComponent_2147482457
Missing Parameters:
NiagaraPosition PositionWS
---
エンジンのカスタマイズが出来る環境にあるため、UNiagaraDataChannelの中に下記のような関数を作成してLayoutInfoを無理やり再作成させる機能を作り、Subsystemの初期化時に呼び出すことでNiagara側でNDCのReadが正しく行えるのは確認しています。
void UNiagaraDataChannel::RebuildLayoutInfo() const
{
LayoutInfo = MakeShared<FNiagaraDataChannelLayoutInfo>(this);
}
C++のSubsystemからNDCへの書き込みを行う際の正しい方法があるのかどうか、もし不具合の場合今回のワークアラウンドで問題ないかどうかを確認させて頂きたいです。
以上、よろしくお願いいたします。
[Attachment Removed]
お世話になっております。
サンプルプロジェクトとエンジンコード(5.7)を確認しました。
結論から申し上げますと、Subsystem からの書き込み方法自体には問題ありません。今回の現象は、パッケージ版における初期化順序に起因するエンジン側の不具合で、HelperClassを Config(TSubclassOf)で指定していることが引き金になっています。
パッケージ版(モノリシックビルド)では、全クラスのCDO生成が INiagaraModule::StartupModule()より前に行われます。UNDCWriteSystemのCDO生成時にLoadConfig()がBP_WriteSystemHelperを同期ロードし、そこからハード参照されている NDC のPostLoad()がこの時点で走ります。PostLoad()はGetLayoutInfo()でレイアウトを構築してキャッシュしますが、このとき FNiagaraTypeDefinition::GetPositionStruct()がまだ初期化されておらずnullptrを返すため、PositionWSが無効な型として登録されてしまいます。ランタイムにはこのレイアウトを再構築する経路がなく、Reader DIは名前と型の両方で変数を照合するため、Read に失敗します。エディタではゲームモジュールがNiagaraモジュールの起動後にロードされるため、この順序の問題は起きません。
エンジンを改造せずに対応する方法として、HelperClassをTSoftClassPtrに変更し、Initialize()でロードしていただくのが確実です。これでNDCのロードがワールド初期化時(全モジュール起動後)になり、レイアウトは正しく構築されます。DefaultGame.iniの記述はそのままで問題ありません。
UPROPERTY(Config, noclear)
TSoftClassPtr<UNDCWriteSystemHelper> HelperClass;
if (UClass* LoadedHelperClass = HelperClass.LoadSynchronous())
{
Helper = NewObject<UNDCWriteSystemHelper>(this, LoadedHelperClass);
}
一点ご注意いただきたいのは、この変更で起動時のハード参照がなくなるため、BPやNDC、Niagara Systemがクック対象から漏れる可能性があることです。DirectoriesToAlwaysCookに/Game/BlueprintsとGame/VFXを追加するなどして、クックに含まれることをご確認ください。
現在お使いのRebuildLayoutInfo()によるワークアラウンドについては、Initialize()の時点ではNiagaraモジュールの起動が完了しており、かつNDCへの最初のアクセス前であるため動作しています。一時的な回避策としては問題ないと考えますが、エンジン改造なしで解消できる上記の方法を推奨します。
お手数ですが、よろしくお願いします。
[Attachment Removed]
お世話になっております。確認が遅れまして申し訳ありません。
提示して頂いた通り、TSubclassOfをTSoftClassPtrにし、Subsystem内のInitializeで読み込むことで解決出来ました。
スレッドはクローズして頂いて問題ありません。
ありがとうございました。
[Attachment Removed]