タイトルの通り、私達のプロジェクトではサーバーが `UWorld::ServerTravel` を呼び出してクライアントが Level を遷移した後、
稀に一部のクライアントで遷移前のWorldが破棄されない問題が発生することがあります。
Worldが破棄されない、というのは以下状況から推測しています。
- 遷移前Worldに配置していたUIが消えないこと
- 問題を起こしたクライアントの遷移後のActorから `GEngine->GetWorldFromContextObject` で取得できるWorldが遷移前のものであると見受けられる
これは以下のようなクライアントに発生しやすいようです。
- 処理能力の低いクライアント
- SeamlessTravel時に大きなヒッチが発生しているクライアント
これらの問題に対し、どのような対策を行うことができるかアドバイスが欲しいです。
再現手順
本番環境で発生が確認されていますが、再現は取れていません。
SeamlessTravel時に大きなヒッチが発生しているクライアントがいると、そのクライアント上で発生することがあるようです。
実際にレベル遷移が起こった際にDevelopmentやDebugビルドであれば、シームレストラベル中のGC後に古いレベルが確実に破棄されているかのチェックが入るはずです。
ご確認いただいたのはTestやShippingビルドでだけで、Developmentビルドでは再現しない状態でしょうか?
もしログは取得可能な状況であればサーバーおよび各クライアントのログを確認してレベル遷移の前後の状況を正常系と比較して見ることで問題の特定につなげられる可能性が高いです。
そのログも共有可能でしたら是非アップロードをお願いします。
レベル遷移時の大きなヒッチによってサーバー側のアクター破棄などのイベントがクライアント側に伝わっていない可能性があります。
例えば不適切に残ってしまっているクライアントでのUIなどの破棄に関して、ネットワーク通信に関係しているか通信に依存せずローカルだけで処理されているかなどの確認してみることも状況を限定することにつながりそうです。他にもレベル遷移前に絶対にクライアント側で処理しなければならない通知などがあれば、通知が無くともレベル遷移に反応して正しくクリーンナップできるように動作を確認したり、サーバー側で処理が確認ができるまで待つような対処が必要になるかもしれません。
また大きなヒッチが起こる事自体もあまり望ましくはありません。ヒッチの原因が特定できていればご共有ください。対処について調査することができると思います。
古いレベルと共に残ってしまっているアクターはSeamlessTravelActorなどで処理された特別なアクターでしょうか?
それともPlayerStateなどの一般的にシームレストラベルで移行するアクターでしょうか?
クライアント上ではシームレストラベル後にサーバーとの通信によって新しいレベルに則したPlayerControllerおよびPlayerStateがセットアップされるはずですが、
ヒッチなどでこれらの通信が適切なタイミングで受信できなかった場合に問題が発生しているのかもしれません。
現時点の情報では明確になにが起こっているのか判断がつかないので、もし再現が可能でログを取得できる可能性があるならLogNetTrafficやLogNetPackageMapのログを有効化できれば具体的な問題をみつけることができるはずです。
GEngine->GetWorldFromContextObjectで得られる値はワールドへのアドレスはアクターのOwnerを辿っているので、不適切なワールドを返すものが検出できるのであればそれは古いワールドに紐づいたアクターなのでクライアント側で無視するような応急処置を行いつつレプリケートを待つことができると思いますが、もし後述のリンクにあるようにNetGUIDの同期のミスのような現象が起こっているとするのであれば、時間が経過しても通信用のチャンネルの生成が行えないので net.ResetAckStatePostSeamlessTravel 周辺のコードを取り込むなどの対処が必要になるかもしれません。
シームレストラベル後のPlayerStateの同期に関してEpicProSupport内に以下の様なトピックがございました。
[Content removed]
[Content removed]
[Content removed]
著しいヒッチはロード処理の待ち時間などで発生する可能性があるため同期的に読み込んでいるアセットなどが無いかなどを今一度ご確認いただくことも良いかと思います。
ご確認よろしくお願いします。このケースはクローズせずに置いておこうと思いますが、時間経過によって最終的にはクローズされます。
なにか進捗がございましたら追記いただけますと幸いです。
回答をいただいた後 [Runtime-spawned actor randomly not replicating after seamless [Content removed] とUE5.5のエンジンコードを元に net.ResetAckStatePostSeamlessTrave を取り込みました。
現時点までで社内のQAチームではアクタが不適切なワールドに残る現象や、この取り込みによる別の不具合は発生していません。
この後も経過を観察しつつ、ユーザー環境へ反映予定です。
もともと社内では発生しづらいため、まだユーザー環境にて再発の可能性は捨てきれないという状況です。
ユーザー環境へ反映後、十分に経過を見ることができたら再度書き込み予定です。
経過観察を行う件、承知いたしました。
ちなみにレベル遷移前のヒッチについては再現や問題の特定などの進展はございましたか?
承知しました。適切なプリロードで極端なヒッチを回避できたことによって問題が改善された可能性がある旨承知いたしました。それでは本件はクローズさせていただきます。
ご回答ありがとうございます!
> ご確認いただいたのはTestやShippingビルドでだけで、Developmentビルドでは再現しない状態でしょうか?
今のところShippingビルドでだけで発生し、Developmentでは発生したことがありません。
現状確認している中ではShippingビルドでの発生のみとなっています。
Testに関しては施行回数が少なく、確証が得られません。
____
> もしログは取得可能な状況であればサーバーおよび各クライアントのログを確認してレベル遷移の前後の状況を正常系と比較して見ることで問題の特定につなげられる可能性が高いです。
> そのログも共有可能でしたら是非アップロードをお願いします。
現状Shippingでの低確率の再現しか取れておらず、ログが取れていません…
____
> また大きなヒッチが起こる事自体もあまり望ましくはありません。ヒッチの原因が特定できていればご共有ください。対処について調査することができると思います。
ヒッチに関しては現在原因がわかっておらず、現在調査中です。
必ず起きるわけではなく、稀に起こるようです。
____
> 例えば不適切に残ってしまっているクライアントでのUIなどの破棄に関して、ネットワーク通信に関係しているか通信に依存せずローカルだけで処理されているかなどの確認してみることも状況を限定することにつながりそうです。
こちらに関しては教えていただいた通りの対処で解決できそうです!
ありがとうございます。
UIの方はそちらで対応できそうなのですが、
- 問題を起こしたクライアントの遷移後のActorから `GEngine->GetWorldFromContextObject` で取得できるWorldが遷移前のものであると見受けられる
上記の問題の解決方法が現在わからず、現在対応方法を模索していますが良い方法がわかっていません。
`GEngine->GetWorldFromContextObject` で遷移前のWorldが返ってきてしまうため、
本来存在しているはずのWorldのGameStateが取得できずに該当Actorがゲームの状況を取得できない状況になっています。
こちら何か解決方法は無いでしょうか。
よろしくお願いいたします。
> 古いレベルと共に残ってしまっているアクターはSeamlessTravelActorなどで処理された特別なアクターでしょうか?
> それともPlayerStateなどの一般的にシームレストラベルで移行するアクターでしょうか?
問題が発生するのはPlayerStateなどの一般的にシームレストラベルで移行するアクターです。
一応ですが、 `AGameMode::GetSeamlessTravelActor` ではオブザーバー(観戦用のSpectatorな PlayerState)を追加しています。
回答、関連のトピックの共有ありがとうございます!
ひとまずは不適切なワールドに居ないかの検知からはじめ、
net.ResetAckStatePostSeamlessTraveや関連トピックで情報を得てみます。
返信が遅くなりすみません。
> レベル遷移前のヒッチについては再現や問題の特定などの進展はございましたか?
こちらに関しては現在は再現しないようになっており、特定できておりません。
遷移先Levelの事前ロードを実装してから発生しなくなったため、これに関連する問題だった可能性があります。