同期値
全クライアントが持つ変数。入れられる型と、変化を明示的に伝える必要がある 2 つの場合。
宣言する
同期値はビヘイビアのフィールド、または自動プロパティです。
private Synced<int> score = new Synced<int>();
public Synced<string> Message { get; } = new Synced<string>();
どちらも、書いたとおりの名前の複製変数 1 つになります。独自のアクセサーを持つプロパティは動かないので拒否されます。Udon が複製するのは名前のついた変数であり、アクセサーは各クライアントで実行されるコードだからです。
ビヘイビアの上になければいけません。ビヘイビアが使うただのクラスに置いた同期値はコンパイルは通っても複製されないので、これもフィールド名を挙げて拒否されます。
入れられる型
C# の基本型すべて、string、Vector2、Vector3、Vector4、Quaternion、Color、Color32、VRCUrl、およびそれらの配列です。これは VRChat の一覧であって、このパッケージの都合ではありません。それ以外は、実行時に落とされるのではなくコンパイル時に拒否されます。
初期値はコンストラクターに渡します。
private Synced<int> lives = new Synced<int>(3);
読み書き
score.Value = score.Value + 1;
書けば複製されます。対にすべきシリアライズ呼び出しはありません。「代入したのに呼び出しを忘れて、同期が静かに止まる」という失敗がなくなります。1 フレームに何度書いても送信は 1 回です。VRChat がまとめてくれます。
書けるのはオーナーだけです。 ほかのクライアントでの代入はローカルに留まります。このパッケージが隠さない唯一の Udon の規則です。Ownership.Claim(gameObject) で先に取るか、はじめから適切なクライアントが所有しているオブジェクトに置いてください。
変化を受け取る
score.Subscribe(OnScoreChanged);
値が届いたとき、書いたクライアントも含めて全員のハンドラーが動きます。同じハンドラーを 2 回購読しても増えず、Unsubscribe で外せます。
変わる前の値も欲しいハンドラーは、両方を受け取ります。
score.Subscribe(OnScoreChanged);
private void OnScoreChanged(int previous, int current)
{
scoreboard.Show(current, current - previous);
}
最初の変化より前は、前の値がありませんから、その型の既定値になります。同じ値に両方の形を購読でき、どちらも動きます。
ハンドラーは更新がすべて届いてから動きます。 VRChat は 1 つずつ適用するので、届いた順に呼ぶと、ハンドラーが読んだ別の値がまだ前の値ということが起こります。実際に 2 クライアントで確認しました。カウンターが届いた横で、文字列がまだ空でした。今は、同じ更新で届いた値を読めます。
配列
配列は値ごと複製されるので、入れ替えは期待どおりに動きます。
private Synced<int[]> scores = new Synced<int[]>(new int[8]);
scores.Value = fresh;
要素 1 つの書き換えは、代入だけからはコンパイラに見えません。明示してください。
scores.Value[2] = 7;
scores.MarkChanged();
MarkChanged は、配列ごと代入したときと同じように複製し、このクライアントの購読者にも伝えます。これがないと、変更は書いたクライアントに静かに留まります。
オーナーシップ
Ownership.IsMine(gameObject) |
このクライアントが同期値を書けるか |
Ownership.Claim(gameObject) |
拒否されなければ取得する |
Ownership.GiveTo(player, gameObject) |
誰かに渡す |
Ownership.Of(gameObject) |
誰が持っているか |
OnOwnershipRequest を override して false を返せば移譲を拒否できます。MasterOwned はその override を書いたものです。継承すれば調停役だけがそのオブジェクトを持てます。ほかの誰にも書かせたくない値の置き場所です。
ClientSim はオーナーシップ要求を発生させません。これはアップロードしたワールドで確かめる必要があります。