コンテンツにスキップ

自作ギミックとつなぐ

UdonSharp や Udon Graph で自作ギミックを書く方向けのページです。コードを書かずに使う場合は 設定リファレンス だけで足ります。

外部連携の入口は2つです。

  • スイッチ(StaffTrigger) — SBSメニューから自作ギミックへイベントを送る(SBS → 自作)
  • StaffRegistry — 自作ギミックからスタッフ判定を読む・変化を受け取る(自作 → SBS)

ここに載せているクラス名・メソッド名・フィールド名は、出荷のたびに前バージョンとの互換を機械検査しています。

スイッチの発火は「押した人のクライアントでローカル1回」

ボタンを押すと、押した人のクライアントで発火先の UdonBehaviour に SendCustomEvent が1回呼ばれます。SBS がやるのはここまでです。

  • 引数は渡せません(SendCustomEvent の仕様)
  • 他のクライアントでは実行されません。SBS は発火先の Owner も変更しません
  • 発火の直前にスタッフ判定を再チェックし、連打は 0.7 秒のクールダウンで弾きます
  • 「誰がいつどのスイッチを押したか」の表示だけは SBS 側でグローバル同期し、レイトジョイナーにも見えます
  • グローバルにするかどうかは発火先の実装が決めます
  • 全員のクライアントで実行する発火はありません。同期する受け側と組み合わさると、全員が Owner を取り合って人数分の同期が走るためです
  • ネットワークに乗るのは「押した記録」と「受け手の同期変数」の2つだけ。人数が増えても送信コストは変わりません

図はクリックすると画面いっぱいに出ます。もう一度押すと戻ります。

グローバルにするなら、イベントを配らず状態を書く

受け側は、イベントを配るのではなく [UdonSynced] に状態を書きます。

  • 同期変数の現在値は、レイトジョイナー・入り直しにも届きます(Late Joiners)
  • SendCustomNetworkEvent(All, ...) はその瞬間にいた人にしか届かず、レイトジョイナーには再生されません(Network Events)。状態を持つギミックには不向きです
  • 書き込み前に SetOwner で所有権を取ります。Owner が退室しても所有権は自動で移り(Ownership)、値は保たれます

GameObject の出し入れなら、同梱の StaffObjectToggle(同期する=ON)がこの作りです。自作するときの骨組みは次のとおりです。

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class GateReceiver : UdonSharpBehaviour
{
    public GameObject gate;

    [UdonSynced] private bool _open;

    // スイッチの「イベント名」にはこのメソッド名を書く(押した人のクライアントでだけ呼ばれる)
    public void OpenGate()
    {
        _open = true;
        Apply();

        // 押した人が Owner を取って状態を配る。レイトジョイナーには現在値が自動で届く
        var lp = Networking.LocalPlayer;
        if (!Utilities.IsValid(lp)) return;
        if (!Networking.IsOwner(gameObject)) Networking.SetOwner(lp, gameObject);
        RequestSerialization();
    }

    public override void OnDeserialization()
    {
        Apply();
    }

    private void Apply()
    {
        if (Utilities.IsValid(gate)) gate.SetActive(_open);
    }
}

Owner を取った直後の1回は配られないことがあります

移譲が済む前の RequestSerialization は落ちることがあり、初めて押した人の変化だけ伝わらない形で現れます。同梱の StaffObjectToggle は 0.5 秒後にもう一度呼んで防いでいます。

ローカルのままでよいのは、押した本人にだけ見せるもの(確認用の表示など)です。

効果はスタッフ以外にも届く

スタッフ限定なのは「押せる人」だけです。受け側がグローバルに反映する実装なら、スタッフ以外を含む全員の画面が変わります。入場ゲート・照明・演出の切り替えに使えます。

重要な操作は受け側でも検証する

Udon のイベントはエントリポイントとして公開されるため、スイッチ以外からも呼べます。入退場のロック解除のような重大な操作は、受け側でもスタッフ判定を確認してください。

using MGR.StaffBridgeSystem;

public StaffRegistry registry; // Inspector で割り当てる

public void Unlock()
{
    if (!Utilities.IsValid(registry) || !registry.IsLocalStaff()) return;
    // ここから先が本処理
}

スタッフ判定を読む・変化を受け取る(StaffRegistry)

メンバー 内容
bool IsLocalStaff() 自分がスタッフか
bool IsStaff(VRCPlayerApi player) / bool IsStaffId(int playerId) 指定プレイヤーがスタッフか
int StaffCount() 現在のスタッフ人数
void Register(UdonSharpBehaviour listener) 通知先として登録する。登録直後に一度、以後は変化のたびに _OnStaffStateChanged が届く

その場の判定だけなら IsLocalStaff() で足ります。登録するのは、スタッフの増減に反応したいときだけです。

using MGR.StaffBridgeSystem;
using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class StaffLamp : UdonSharpBehaviour
{
    public StaffRegistry registry; // Inspector で割り当てる
    public GameObject lamp;

    private void Start()
    {
        registry.Register(this); // 登録直後に現在状態が一度通知される
    }

    public void _OnStaffStateChanged()
    {
        lamp.SetActive(registry.IsLocalStaff());
    }
}

登録数の上限は128個です。超えた分は登録されず、Console にエラーが出ます。

制約

項目 内容
スイッチの表示上限 20件。超過分はスイッチタブに出ません
StaffTrigger の数 1シーンに1個。複数あるとメニューの作り直しが中止されます
イベント名 文字列指定のため、間違ってもコンパイルエラーになりません。診断(健全性チェック)が発火先にその名前が実在するかを検査します
作り直しの引き継ぎ メニューの作り直し・再生成で、スイッチの配線は自動で引き継がれます
配線の退避 スイッチページの「設定を書き出し (.asset)」で配線一式を保存できます
発火先の型 VRC.Udon.UdonBehaviour。UdonSharp 製・Udon Graph 製のどちらも指定できます

公式リファレンス

同期の説明は VRChat 公式の次のドキュメントに基づいています。