手動処理について解説

自動同期と手動同期の違い

また同期には自動同期と手動同期が存在し、双方にメリット・デメリットが存在します。

自動同期は作成が簡単ですが、どのタイミングで同期が発生するか分からず、
手動同期は作成が面倒ですが、任意のタイミングで同期を発生させることができます。

あまりにも自動同期する値が多すぎると、同期するタイミングの奪い合いが発生し、ユーザー同士で値がズレている間隔が長くなります。そのため、手動同期の作成が推奨されています。

自動同期は下記記事で解説していますので、本記事では公式の手動同期を作成していきます。

Udonスクリプト作成

サンプルのButtonSyncOwnerをU#に書き直し

Udon Graph

U#

public class ButtonSyncOwnerBySharp : UdonSharpBehaviour
{
    public Text uiText;

    [UdonSynced]
    private int clickCount = 0;

    public void OnClick()
    {
        if (Networking.IsOwner(this.gameObject)) // オブジェクトのオーナーでのみ下記処理を発生させる
        {
            clickCount++; // この値はオブジェクトのオーナー以外が変更してはいけない。
            uiText.text = clickCount.ToString();
            RequestSerialization(); // このメソッドが呼び出された時だけ同期処理が発生する。
        }
    }

    // 同期処理。値の代入などの処理を記述するメソッド
    public override void OnDeserialization()
    {
        uiText.text = clickCount.ToString();
    }
}

どういうわけか、サンプルのUdon GraphではNetworking.IsOwnerの引数はnullだったのですが、U#側で同じようにnullを指定するとうまく動かなかったのでthis.gameObjectにしています。

シーン作成

どこでも良いのでUdon Behaviourコンポーネントを追加して、上記のコードを登録。Synchronization Methodの値をContinuousからManualに変更して、自動同期から手動同期に変更します。

Canvasにボタンを追加してOnClickイベントに先ほど作ったUdonスクリプトのOnClickメソッドを呼び出すようにします。ボタンを追加するとTextオブジェクトも一緒に生成されるので、このテキストに同期した値を表示するようにUdon BehaviourのUi Text値に代入すれば完成。

完成・・・?

これでボタンを押したときにだけ同期処理が発生して、変更が発生した時にだけ同期が発生するので通信リソースを浪費しなくなりました。しかし、値の変更はオブジェクトの所有権を持っている「オーナー」と呼ばれるユーザーでしか許可していません。これはVRChatの仕様上のため、全ユーザーに値の変更をするためには、もう少し手を加えます。

すべてのユーザーに値の変更を可能にするには?

2通りの手段があり、
 オーナーに値の変更を依頼するか
 オーナーに所有権の変更を依頼するか
ので値を変更する必要があります。

オーナーに値の変更を依頼する

下記のコードはオブジェクトの所有者にOnClickメソッドを処理するように依頼するコードです。

SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(OnClick));

このコードを追記した全体のコードはこちら

public class ButtonSyncOwnerBySharp : UdonSharpBehaviour
{
    public Text uiText;

    [UdonSynced]
    private int clickCount = 0;

    public void OnClick()
    {
        if (Networking.IsOwner(this.gameObject))
        {
            clickCount++;
            uiText.text = clickCount.ToString();
            RequestSerialization();
        }
        else
        {
            // オブジェクトのオーナーでなければ、オーナーに変更してもらうようにお願いする
            SendCustomNetworkEvent(NetworkEventTarget.Owner, nameof(OnClick));
        }
    }

    public override void OnDeserialization()
    {
        uiText.text = clickCount.ToString();
    }
}

ちなみに、SendCustomNetworkEvent の第二引数はstring型のメソッド名だが、直接string型で記述するより、nameofを使えばメソッド名のスペルミスをコンパイルエラーが教えてくれるので開発が楽になります。

実装してみた感じではオーナー側の値が変更されてから他のユーザーの値が同期されるので、値の変更を依頼したユーザー視点だと、反応が遅くもっさりしています。

自分がオーナーになる

Networking.SetOwnerメソッドでオブジェクトの所有権を譲ってもらうようにオーナーにお願いします。オーナーは所有権の変更を許可することで権限の受け渡しが完了します。

public class ButtonSyncBecomeOwnerBySharp : UdonSharpBehaviour
{
    public Text uiText;

    [UdonSynced]
    private int clickCount = 0;

    public void OnClick()
    {
        Networking.SetOwner(Networking.LocalPlayer, gameObject); // オブジェクトの所有権を貰えないか尋ねる
        if (Networking.IsOwner(this.gameObject))
        {
            clickCount++;
            uiText.text = clickCount.ToString();
            RequestSerialization();
        }
    }

    public override void OnDeserialization()
    {
        uiText.text = clickCount.ToString();
    }

    // オブジェクトの所有権を譲る許可を返すメソッド trueで許可 falseで拒否
    public override bool OnOwnershipRequest(VRCPlayerApi requestingPlayer, VRCPlayerApi requestedOwner)
    {
        return true;
    }
}
手動同期をオーナーしか値を変更できない方法で作成する

投稿ナビゲーション


コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)