ネットワーク
変化を教えてくれる同期値と、誰でも送れる型付きメッセージ。シーンに用意するものはありません。
ワールドの中の 2 台のクライアントが同じ内容を共有する方法は 2 つあり、選び方を間違えると静かに壊れます。
同期変数は「全員が持っている事実」です。 スコア、扉の開閉、次に誰の番か。あとから入ってきた人にも、誰も送り直さずに現在の値が届きます。
メッセージは「一度だけ起きたこと」です。 攻撃が当たった、ラウンドが始まった、ボタンが押された。これを変数で送ると、何も起きていないように見える形で壊れます。同じ値を 2 回入れても変化は 1 回なので、同じ攻撃 2 回は 1 回になります。遅れて入った人には、見ていない戦闘の最後の一撃が今起きたかのように届きます。書けるのはオーナーだけなので、2 人が同じ対象を攻撃すると変数を奪い合い、片方の攻撃は何も言われずに消えます。
このパッケージはその両方で、うまくいかない部分は引き受けます。
public class Door : UdoniteBehaviour
{
private Synced<bool> open = new Synced<bool>();
public override void Start()
{
open.Subscribe(OnOpenChanged);
Room.Subscribe<Knocked>(OnKnocked);
}
public override void Interact()
{
open.Value = !open.Value; // 複製され、各クライアントのハンドラーが動く
Room.Send(new Knocked()); // 送信者も含め、全員が一度だけ受け取る
}
private void OnOpenChanged(bool value) => panel.SetActive(value);
private void OnKnocked(Knocked message) => sound.Play();
}
Room.Send の行き先はルーム全体で、誰でも送れます。特定のオブジェクトについてのメッセージはそのオブジェクトの上を流れ、オブジェクトそのものであるビヘイビアに this.Send と書きます。そちらはそのオブジェクトの所有が要ります。どちらもメッセージにあります。
open.Value = ... は変数を書いて複製を依頼します。忘れがちな RequestSerialization はありません。Subscribe は値が届いたときに各クライアントでハンドラーを呼びます。更新の途中ではなく、全部が届いてからです。
何を誰が所有している必要があるか
所有権はこのパッケージのものではなく VRChat のものです。replicate されるのは所有者の書き込みだけで、違うのは所有者でないときに何が起きるかです。
| すること | 所有が要るもの | 所有していないと |
|---|---|---|
Synced<T> に書く |
そのフィールドを持つオブジェクト | 書き込みは自分のクライアントに留まり、次に届いた値で上書きされます |
このオブジェクトのチャンネルへの this.Send |
このオブジェクト | 何も積まれず何も配られません。コンソールに一度だけ出ます |
NetworkBus への channel.Send |
そのバスのオブジェクト | 同じです |
Room.Send |
不要 | 各クライアントが自分のプレイヤーオブジェクトのバスに書くので、取り合うものがありません |
NetworkTransform を動かす |
そのオブジェクト | 所有者が送り、ほかは全員そこへ補間します |
所有者が要らないのはルームのメッセージだけで、どのクライアントも動いてよいときにこれを選ぶ主な理由です。オブジェクトのチャンネルも同期フィールドも、結局は書き手が 1 人です。誰でも動いてよいワールドは先に所有を取ります。
if (!Ownership.IsMine(gameObject))
Ownership.Claim(gameObject);
ピックアップや Interact なら、たいていすでに取れています。MasterOwned は逆で、これを継承すると調停役のクライアントしか所有できません。ほかの誰にも書かせたくない状態のためのものです。
ここにあるもの
Synced<T> |
全クライアントが持つ変数。変化を教えてくれます |
Room |
型付きメッセージの送信と購読。誰がいるか、誰が調停役か |
NetworkEvent |
バイト列ではなく、フィールドを持つメッセージ |
NetworkBus |
オブジェクト自身のチャンネル。そのオブジェクトについての話に |
NetworkTransform |
位置・回転・スケール。補間とテレポート検出つき |
Ownership |
誰が持っているか、取る、渡す |
MasterOwned |
調停役だけが持てるオブジェクトの基底クラス |
用意しなくてよいもの
ルームのメッセージは、シーンの中の 1 つのオブジェクトに書かれます。書き込み先はクライアントが所有している必要があり、ワールド実行中に作ることはできないからです。このパッケージが自動で追加し、その理由をコンソールに一度だけ出します。送信しないワールドには何も追加されません。
自分で置きたい場合は、VRCPlayerObject を持つオブジェクトに NetworkBus を付けてください。名前ではなくコンポーネントで探すので、そちらが使われます。
Udonite → Open Window → Settings → Net にこれを切るトグルがあります。オフにすると、ワールドが何を送っていようとパッケージはシーンに一切触れません。バスを置くのは完全にあなた次第になります。デフォルトはオンです。この設定は ProjectSettings/ にあり、除外リストと同じくコミットされます。これは開発者一人の好みではなく、シーンを誰が持つかという、プロジェクト自体の話だからです。