【UE5】マルチプレイでOnRep(RepNotify)が突然呼ばれなくなる罠と解決法(Manager系アクターの同期切れ)
はじめに
Unreal Engineのマルチプレイ(ネットワーク)対応ゲームを作っている際、ゲームの進行やシステムを管理する「マネージャー系アクター」を作成することはよくあると思います。
しかし、**「ゲーム開始直後は変数の同期(OnRep)が正常に呼ばれるのに、プレイヤーが移動したりワープした後に突然OnRepが呼ばれなくなる」**という謎の現象に遭遇しました。
この記事では、この問題の原因である「ネットワークカリング」の仕様と、その解決法について解説します。
対象環境
- Unreal Engine 5 (UE4でも同様の仕様です)
- C++ / Blueprint 両対応
発生した問題
今回遭遇した不具合の状況は以下の通りです。
- C++(またはBlueprint)で
AActorを継承した、システム管理用のマネージャーアクター(例:AWarpManager)を作成した。 - サーバー側で変数を更新し、クライアント側で
OnRep_XXX(RepNotify)を実行させる仕組みを実装した。 - 初期化時(1回目)はクライアントでOnRepが呼ばれるのに、ゲーム中盤(プレイヤーが遠くへ移動した後)はサーバーで変数を変えてもクライアントでOnRepが呼ばれない。
原因:アクターとプレイヤーの「距離」によるネットワークカリング
結論から言うと、原因はUnreal Engineの通信最適化機能である**「ネットワークカリング(Net Relevancy)」**にありました。
UEのネットワークシステムは、通信量を極限まで減らすために**「プレイヤー(カメラ)から一定距離以上離れたアクターは、クライアントへのデータ送信を停止(カリング)する」**という仕様になっています。
このデフォルトの同期距離(NetCullDistanceSquared)は 15,000ユニット(150メートル) に設定されています。
マネージャー系アクターが陥りやすい罠
メッシュやコリジョンを持たない(RootComponentが設定されていない)純粋なロジック管理用のアクターは、レベル上のどこに配置しても内部的な座標が (0, 0, 0) として扱われるという仕様があります。
そのため、プレイヤーが原点(0,0,0)から150m以上移動したり、遠くのエリアへワープしたりすると、UE側が「このマネージャーアクターはプレイヤーから遠すぎるから、同期しなくていいや」と判断してしまいます。
結果として、サーバーで変数を変更してもそのデータがクライアントに届かなくなっていたのです。
解決策:bAlwaysRelevant を有効にする
システム全体を管理するアクターは、プレイヤーとの距離に関係なく、常に状態を同期し続ける必要があります。
これを解決するには、アクターの bAlwaysRelevant(常にネットワーク関連性を持つ)フラグを true に設定します。
C++の場合
アクターのコンストラクタ内で bAlwaysRelevant = true; を追加します。
AWarpManager::AWarpManager()
{
// アクター自身のレプリケーションを有効化
bReplicates = true;
// 【重要】距離に関係なく、常に全クライアントへ同期を維持する
bAlwaysRelevant = true;
// おまけ:マネージャー自体は移動しないため、移動同期を切って通信量を節約
AActor::SetReplicateMovement(false);
}