VRC Avatar Parameter Driver を併用した物の出し入れ・左右の持ち替えの実装例と同期の話（後編）

# はじめに
どうも。「バーチャルためにならない改変お姉さん」の水無月せきなです。

記事を書いている間に VRChat が Unity 2019 に移行していました。自分が使っている SDK の古さに驚いていたのですが、Unity も VRChat クライアントのバージョンも古いものとなってしまいました。読まれる方には大変申し訳なく思いますが、移行直前に解決したことのお話なのでお許しを……

さて[前回](https://qiita.com/MinadukiSekina/items/e95bff60c899d1ad59a3 " VRC Avatar Parameter Driver を併用した物の出し入れ・左右の持ち替えの実装例と同期の話（前編）")は、物を出し入れするのに少し凝ったことをやろうとした話をしました。今回はその続きで、実装時に頭を抱えた、同期に関してのお話です。

# 環境
Unity：2018.4.20f1
VRChat：VRChat 2021.3.1（Build 1114）
VRCSDK：VRCSDK3-AVATAR-2021.01.28.19.08_Public

- - -

:::note warn 注意
ここから先は憶測を含みますので、その点ご了承ください。
:::

# 実装時に起きた問題
###「同期するはずなのに同期しない」

Avatars 3.0 の導入当初、「SDK2 のアバターと違い、後から来た人にも同期される」というのを見た覚えがあります。
その高い自由度とともに、「同期される」というのは１つのキーワードだった気がしますが、だからと言って絶対に同期されるわけではありません。

そう、__目の前で見ている人にすら同期されない__ことも起こりえます。
（実例が今回の私です）

どの記事で見たかという記憶は定かではないですが、「ステートマシンではなくパラメータの値が同期されるため、遷移の組み方によっては意図したように相手に見えない（つまり『同期されない』）ことはある」ということで、私もわかっていたつもりでした。

そんな私が当初組んでいた（そして同期しなかった）、オブジェクトの ON ・OFF に関するレイヤーがこちらです。
![スクショ加工.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/312a209a-e9e5-6e0c-7f6a-6080f9923793.png)

条件と処理の流れは以下のような感じです。

１： ON にするパラメータは True 、既に ON になっているオブジェクトは０個
　　 ⇒ 個数のカウントを１、オブジェクトを True に。
２： ON にするパラメータは True 、既に ON になっているオブジェクトは１個
　　 ⇒ 個数のカウントを２、オブジェクトを True に。
３： ON にするパラメータは False 、既に ON になっているオブジェクトは１個
　　 ⇒ 個数を０、オブジェクトを OFF に。
４： ON にするパラメータは False 、既に ON になっているオブジェクトは２個
　　 ⇒ 個数のカウントを１、オブジェクトを OFF に。
（番号を振り忘れましたが、右に流れるルートはキャンセルするルートです）

ON になっているオブジェクトの個数は、Bool のパラメータをビットに見立てた２進数として保持しています。
![パラメータ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843472/d2fe5083-3690-6905-0644-b34b9673bddf.jpeg)
また、途中のステートマシンに付けた VRC Avatar Parameter Driver でこのパラメータの値を変更しています。

以上が概略ですが、このように実装したら、他の人に同期されませんでした。具体的な例を挙げると、「何も持っていない状態からオブジェクトを ON にすると、メニューから OFF にしても他の人からはずっと ON の状態になる」というものです。

原因は、__１．トランジションの条件で参照するパラメータの値を、その遷移先のステートマシンで変更していたこと ２．なおかつそれを考慮した条件設定や遷移の組み方をしていなかったこと__でした。

### 「同期しているから『同期しない』」

わかりにくい表現となってしまったので、「１．トランジションの条件で参照するパラメータの値を、その遷移先のステートマシンで変更していたこと」から行きましょう。

まず「パラメータの値が同期される」ということについて、パラメータの値が変わる度に同期が行われるのだと私は思っていました。つまり、メニューを操作してパラメータの値が変更されると__すぐに__他の人に同期され、それぞれで Animator 上の移動処理が__すぐに__行われると思っていたわけです。
また、途中のステートマシンの前後では通過するように条件を設定しており、ここでパラメータの値を変更しても、既にルートに入っているので大丈夫だと思ったのです。

しかし今回の事象を見る限り、私の認識は間違っていたようです。

トランジションの条件と移動後の私側で、ON になっているオブジェクトの個数を示すパラメータの値をまとめます。
（１・２は OFF ⇒ ON 、３・４は ON ⇒ OFF）

| ルート |   1   |   2   |   3   | 4 |
|:------:|:-----:|:-----:|:-----:|:-:|
| 条件   |   0   |   1   |   1   | 2 |
| 移動後 |   1   |   2   |   0   | 1 |

何もオブジェクトを ON にしていない状態から OFF ⇒ ON ⇒ OFF にした場合、私の側では１・３のルートを通ります。他の方から見てもそうなるように期待したわけですが、ならなかったのは何度も書いている通りです。
「ON になったらずっと ON になっているように見える」ということから１・２のどこかで止まっていることは確実なので、３・４で余分な物である VRC Avatar Parameter Driver をとりあえず無効化してみました。
すると、__同期します。__

「原因はお前か！」

ですが、１・２では有効化したままで同期されているので、VRC Avatar Parameter Driver 自体が原因ではありません。
１・２では有効化したままでも同期され、３・４では有効化した途端に同期されなくなります。何が違うのでしょうか。

改めて表を見ましょう。

| ルート |   1   |   2   |   3   | 4 |
|:------:|:-----:|:-----:|:-----:|:-:|
| 条件   |   0   | __1__ |   1   | 2 |
| 移動後 | __1__ |   2   | __0__ | 1 |

私が１のルートを移動すると個数のカウントは１になり、２のルートの条件を__満たします__。しかし、３のルートを移動すると個数のカウントは０になり、３・４どちらの条件も__満たしません__。
ついでに、３・４で VRC Avatar Parameter Driver を無効化した場合は１・２の移動後の値のままなので、３・４どちらの条件も__満たします__。
仮に、パラメータの同期がメニュー操作後すぐではなく、私の Animator 上の移動が終わってから同期しているなら、今回起きた同期ズレは説明がつきます。

つまり、__パラメータの値の同期はアバター着用者側での Animator 処理終了後に行われる__ため、条件を満たさないように値を変更していれば当然状態がズレるということです。

同期の仕様についてはあくまで状況から導いた仮説であり、未検証のものです。しかし、これを踏まえた上でやり直したのが[前回](https://qiita.com/MinadukiSekina/items/e95bff60c899d1ad59a3 " VRC Avatar Parameter Driver を併用した物の出し入れ・左右の持ち替えの実装例と同期の話（前編）")であり（ON・OFF の部分は別のやり方ですが）、こちらは一応同期も確認できたので、まあまあの確からしさはあるのかなと思っています。

では、「２．なおかつそれを考慮した条件設定や遷移の組み方をしていなかったこと」に移りましょう。

今回のような同期ズレを起こさないためには、トランジションの条件で参照するパラメータの値を(少なくともそのレイヤー内では？)変更しないことが一番でしょう。
ただ、私にはどうしてもそれが出来ない部分がありました。

なので次善の策として、変更しない別のパラメータを用意してトランジションを追加するなり、「途中で変えた値で同期する」ことを考えた設定・遷移の組み方をするしかないのかなと思います。

# おわりに
VRChat のアップデートで Bool のパラメータが解禁された際、同じようなことをしようとして同じように同期しなかった時がありました。
その時は理由がわからなかったのですが、ようやく自分なりに原因を知ることができました。長かった……

「 Avatars 3.0 のアバターでも同期ズレすることはある」というのはこういうことを言われていたのでしょうし、既に誰かが書かれているかもしれません。
自分の浅学さを恥じる次第です。

同期の確認と原因究明にあたっては私のフレンドさん達、特にライルさんに協力していただきました。ありがとうございました。

どなたかのお役に立てば幸いです。それでは。