Udon Network Updateなど同期関連についての個人的まとめメモ
未検証・不明のとこと判明しているとこを正しく峻別したい
Udon network
大本ドキュメント docs.vrchat.com
- 変数
- イベント
- Owner
を理解しよう
Owner
- GameObjectごとの所有権
Onwer以外の特殊な権限
- IsInstanceOwner
- インスタンスを建てた人
- 同期系では特別扱いされない気がするが、VRChatのUI上部屋の権限(問答無用でkickできるとか)がこの人に紐付いていたりする。
- IsMaster
- インスタンスにはじめて入ってきた人
- 最初に全てのGameObjectのOwnerをつかむ
- 退出した場合次に入ってきた人が順次選ばれる
同期手段
イベント
変数同期より遅いらしい?
- ローカルのみに通知
- SendCustomEvent
- SendCustomEventDelayedSeconds
- SendCustomEventDelayedFreams
- Onwerのみに通知(Onwerが発火した場合Ownerに送られる)
- SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All)
- 全員に通知(送った人を含む)
- SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner)
特にネットワーク系は引数が取れないのでFoo1、Foo2などのイベントを作って対応したりするハックがあったりする。
同期変数
- 同期変数値の変更はOwnerのもののみがネットワーク越しに反映される
- 非ローカルで一時的に変更することは可能
- 変更後Ownerの値に戻るタイミング?(次フレーム前か次の変数同期時か)
- 同期間隔中の補完手段が選択できる
- None: 補完無し
- Linear: 線形補間
- 直前2値の線形補間?
- Smooth: スムース補完
- 直前3値のベジエとか?
- 詳しくは検証していない
- 変数同期の方針として、GameObjectごとに連続同期(Continuous)と手動同期(Manual)を設定できる
- 同じGameObject内のUdonBehavior及びVRCObjectSyncは全てその設定上で最も厳しい(Manualのほうが厳しい)モードになる
- Onwerが切り替わる瞬間がいろいろ怪しい?
連続同期
手動同期
- 変更が少ない変数に適する
- 変数を変更して同期したい場合、RequestSerializationを呼ぶ
- 変数変更してからRequestSerializationを呼んでも、RequestSerializationを呼んでから発火されるOnPreSerialization中で変更しても良い。
- フレーム内や次フレームと言う保証はなく、次のネットワーク同期タイミングになる
- RequestSerializationを高速で呼ぶとレート制限がかかる
- 待機時間の後にOnPreSerialization→送信→OnPostSerializationが実行される
- 更新が遅れるが失われはしない?
- VRCObjectSyncはこの方式では動作できないため、VRCObjectSyncと手動同期UdonBehaviorを同一GameObjectに配置することは出来ない。
OnDeserialization
- 変数が変更されたか否かにかかわらず、同期変数値が到着したら常に発火される。
VRCObjectSync
- positionとrotationを高速に同期する
- localのそれなのか?
- parentを変更しても動作するか?
細かい仕様・動作挙動
参照ツリー
個人用Udon UnU調査メモ
— KOMETARO (@kometaro_vr) 2021年5月7日
・調査環境:UnU Beta-v5
・PlayerAのSendCustomNetworkEvent(Foo)~PlayerBのFoo呼び出しにかかる時間:550ms~650ms(参考値)
・PlayerAのRequestSerialization~PlayerBのOnDeserialization呼び出しにかかる時間:250ms~350ms(参考値)
ネットワーク初期化タイミング
- Startメソッド時点ではネットワークの初期化がすんでいない
- ネットワーク系の記述はしないべき
- IsOwnerがつねにfalseだったり、SendCustomNetworkEventが正しく動作しない
- OnPlayerJoin時点で初期化済み
- 後からjoinしたユーザーにも変数同期済み
- unu以前は入室直後に同期変数の値が更新されていない問題が存在した
Udonアプデで確認したこと:
— リノール (@F_Linoal) 2021年5月18日
Manual変数はLateJoinerに自動で同期される。そのタイミングは、LateJoinerのStartコール時には未同期だが、OnPlayerJoinedのコール時には同期されている。そのため、LateJoinerが初回に変数を同期後にしたい処理(画面に反映させるなど)はOnPlayerJoined内で書くとよい。
エディタ上での特殊な挙動
- シーン再生開始時に非アクティブなGameObjectについたUdonBehaviorにおいてはOnEnable、OnDisable、Startが実行されない。
エディタ上限定でシーン再生時に非アクティブだったUdonBehaviorではその後アクティブにしたり非アクティブに切り替えてもOnEnable、OnDisable、Startが実行されない問題のCanny
— 黒鳥@ケモカフェオーナー (@kurotori4423) 2021年3月2日
投票協力お願いします。#VRChat #Udonhttps://t.co/shCPRXbiry
RequestSerialization / OnDeserialization (Manual)
- RequestSerialization呼び出しはOwnerのみ有効
- RequestSerialization後のOnDeserializationは非Owner(送信先)でしか呼ばれない。 - →送信元でも同期変数の変化に伴う処理をしたい場合は、OnPostSerializationあたりでOnDeserializationと同様の処理をするのが良さそうかも?
SetOwnerの挙動
- OwnerがSetOwnerを呼ぶ
- OnOwnershipRequestやOnOwnershipTransferedは呼ばれない。
- 非OwnerがSetOwnerを呼ぶ
- 同一フレーム内でローカルのOnOwnershipRequest及びOnOwnershipTransferedが呼ばれる
- この時点ではネットワーク上実際にOwnerが移動してはいない
- OwnerのOnOwnershipRequest及びOnOwnershipTransferedも数百ms後に呼ばれる
- 同一フレーム内でローカルのOnOwnershipRequest及びOnOwnershipTransferedが呼ばれる
- Ownerと非Ownerの結果が食い違った場合
- 非OwnerローカルでOnOwnershipRequestがtrueだったがOwner側がfalseを後で返した場合、再び非Owner側にてOnOwnershipTransferedが呼ばれ、IsOwnerの結果もfalseになる。
つまり
- SetOwner呼び出し同一フレーム中のOnOwnershipTransferedはかりそめの状態。
- SetOwner要求後OwnerがOnOwnershipRequestでtrueを返すまでの間、Owner要求者と実際のOwner両方のローカルでIsOwnerがtrueになっている。
- つまりIsOwnerで判定して動く処理が、要求者およびOwnerの両方で動作することに注意。
応答時間
- SendCustomNetworkEvent
- PlayerAのSendCustomNetworkEvent(Foo)~PlayerBのFoo呼び出しにかかる時間:550ms~650ms(参考値)
- RequestSerialization / OnDeserialization (Manual)
- PlayerAのRequestSerialization~PlayerBのOnDeserialization呼び出しにかかる時間:250ms~350ms(参考値)
- 環境差異がある(UnU betaとOpen Betaで違ったり)が、同期変数のほうがイベントより速く伝わる傾向は変わらない
- Continuousの同期間隔
- ?