こんにちは。
クラウド事業本部コンサルティング&テクノロジー部の酒井です。
今回はUnityのUNETで同期するアプリケーションを作ったけど、うまく同期されない、というときに確認するポイントをまとめてみました。
実際にHoloLensアプリ開発中に引っかかったポイントなのですが、それ以外の環境でも使える内容です。
この記事はネクストスケープ クラウド事業本部 Advent Calendar 2017の6日目となります。
※UNETについて知りたいという方はAdvent Calendar 2017の3日目の記事もどうぞ。
対象環境
Unityのバージョンは2017.1.2p2で検証しています。
また、ローカルネットワーク上で接続するパターンを想定しています。
サンプルアプリについて
サンプルとして、ボタンをクリックすると値を1プラスして同期するアプリケーションを作成しました。
正常な場合はこのような動作を行います。
プロジェクトの中はこのようになっています。
NetworkItems配下に値を同期するスクリプトが追加されているオブジェクトがあり、NetworkObjectsAのObject1はボタンのA-1に、NetworkObjectsBのObject3がB-3といったようにUIと接続されています。
本記事ではこのアプリケーションを使って説明します。
チェックポイント
UNETで同期するアプリケーションを作成している際にスクリプト上は問題なさそうなのに、
- Editor上では正常なのにデプロイすると動かない
- 何もしていない(はず)、なのに動かない
といった現象が発生しました。
その時、原因として多かった、かつ、ひっかかりやすかった、
- そもそも端末間がつながっているか?
- アプリケーション間に差異がないか?
- Prefabの子オブジェクトにNetworkIdentityが存在しないか?
の3点について説明します。
端末間がつながっているか?
接続に失敗している場合は当然同期されません。
Logを確認して、接続までの処理が正常に完了しているかを確認しましょう。
処理が正常であれば、Host端末とClient端末間が通信可能かどうかのチェックをします。
こちらもLogを確認できるようにしておくとやりやすいかと思います。
PC上であればファイヤーウォール、UWP(HoloLens)アプリであればPlayerSettingsのCapabilityも確認ポイントです。
アプリケーション間に差異がないか?
下記はClient側のみNetworkObjectAをDisableにしてみた例です。
Disableにしたオブジェクト以外も同期が変になっていることが確認できるかと思います。
これは同期対象のオブジェクトを識別するNetIdが有効なオブジェクトのInstanceID順になっていることが原因です。
このため、オブジェクトを無効にするなどして、同期対象のオブジェクトの数が変わるとNetIdがズレてしまいます。
先ほどのプロジェクトで問題が起きているオブジェクトを確認すると同じオブジェクトにもかかわらず、NetIdが違うことがわかります。
バージョンアップなどの都合で、差異が発生する場合でもNetworkIdentityが存在するオブジェクトには差異が発生しないように気をつけましょう。
Prefabの子オブジェクトにNetworkIdentityが存在しないか?
下記のようにPrefabの子オブジェクトにNetworkIdentityを追加するのは推奨されていません。
このような状態の場合、正常に値が同期されないことがあります。
下記はHost側だけ、一度Buildを走らせた状態でEditor実行した例です。
ちなみに、Buildする前は正常に動作します。
正常に動作したり、しなかったりという現象になりがちですので、注意が必要です。
なぜ、こうなるのか?
シーン上のオブジェクトごとに付与されるInstanceIDが、Prefabの子オブジェクトと通常のオブジェクトとで異なる振られ方がされるのが原因のようです。
InstanceIDはシーンを開いた段階で存在するオブジェクトには、決まった順序で正の値が割り当てられますが、新規に追加したオブジェクトやPrefabの子オブジェクトは負の値が割り当てられます。
しかし、Build後にシーンが再度開かれた際には、どちらも正の値に振りなおされます。
このため、
Build前のInstanceIDの順序
- Prefabの子オブジェクト(InstanceIDがマイナス)
- その他のオブジェクト1(InstanceIDがプラス)
- その他のオブジェクト2(InstanceIDがプラス)
だったのが、
Build後のInstanceIDの順序
- その他のオブジェクト1(InstanceIDがプラス)
- Prefabの子オブジェクト(InstanceIDがプラス)
- その他のオブジェクト2(InstanceIDがプラス)
※新たに割り当て値によっては順番が変わらない場合もあります
といったようにInstanceIDの順序が変わり、結果としてNetIdの順序も変わってしまい、このような現象が発生するようです。
全部チェックしたけど解消しない場合
UNET自体の実装に起因している問題かもしれません。
UNET(Unity.Networking名前空間)のソースはBitBucketで公開されていますので、そこから追いかけることもできます。