4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【引数対応!】新・SendCustomNetworkEventの使い方

Last updated at Posted at 2025-05-25

はじめに
ようやくUdonSharpのSendCustomNetworkEventに引数の受け渡し機能が追加されましたね!!
このアップデートによってSendCustomNetworkEventの使い方が少し変わったので、新しくまとめてみました

もくじ

  1. 新しいSDKにするには

  2. 新しいSDKでできるようになったこと

  3. SendCustomEventとSendCustomNetworkEventの違い

  4. SendCustomNetworkEventの簡単な使い方

  5. 新しいSDKで追加された便利なもの

0. 新しいSDKにするには

新しいSendCustomNetworkEventを使うにはVRChatSDK 3.8.1以上が必要です

まだアップデートしていない人はVCCからアップデートしておきましょう!

20250525081716imagepng

(VRChatSDK - Worldsと- Baseの2種類がありますが、両方ともアップデートしておけば良いと思います)

1. 新しいSDKでできるようになったこと

新しいSDKでは

  • SendCustomNetworkEventに引数の受け渡し機能の追加

  • NetworkEventTarget.OthersNetworkEventTarget.Selfの追加

  • NetworkEventを呼び出したプレイヤーの取得

  • VRC.Udon.Common.Interfaces.NetworkEventTarget.~~~を短く記述

ができるようになりました!

これ以外にも追加されたものはありますが、ここでは紹介しません...(難しく私にはわかりませんでした)

詳しくは公式サイトの説明をごらんください

2. SendCustomEventとSendCustomNetworkEventの違い

今回ここで主に取り扱うSendCustomNetworkEventと似たものとしてSendCustomEventというものがあります

両者の違いはネットワーク同期するかどうかです
SendCustomNetworkEventはネットワーク同期しますが、SendCustomEventはネットワーク同期しません

SendCustomNetworkEventを使うと自分以外のプレイヤーにもその動作を行わせることができますが、SendCustomEventだと自分にしかその動作を行わせることができません

(その代わりにSendCustomEventにはSendCustomEventDelayedSecondsというn秒後にその動作を行わせることができる、というメソッドがあったりします)

また、新しいSDKではSendCustomNetworkEventで引数が使えるようになりましたが、SendCustomEventでは引数は使えません!!!

そのSendCustomEventで引数が使えないという制限の回避策として今回のアップデートでNetworkEventTarget.Selfが追加されたようです。そのことについては5で解説します

C#での呼び出しとの比較↓

C#での呼び出しとの比較

SendCustomEventは同期の機能がないもの、と説明しましたが同期が必要でない部分であればわざわざこれを使わなくても良かったりします

じゃあどうやるのといえば大したことではないのですが、C#のメソッドの呼び出しと同じように記述することでUdonSharpでも同じようにメソッドを呼び出すことができます

SendCustomEventを使用した例
public class WhiteCube : UdonSharpBehaviour
{
    void Start()
    {
        SendCustomEvent("Greet");
    }

    public void Greet()
    {
        Debug.Log("こんにちは!");
    }
}
出力結果
  こんにちは

上記の例はSendCustomEventを使った例ですが、これは以下のように書くこともできます

SendCustomEventを使用しない例
public class WhiteCube : UdonSharpBehaviour
{
    void Start()
    {
        Greet();
    }

    public void Greet()
    {
        Debug.Log("こんにちは!");
    }
}
出力結果
  こんにちは

このようにどちらで書いても出力結果は変わりません
しかし両者には明確な差があります。

SendCustomEventを使用した場合、そのメソッドの返り値を受け取ることができません!!
2つ目の例のやり方ではそのメソッドの返り値を受け取ることが可能です

なのでぶっちゃけあんまりSendCustomEventを使う場所はない気がするのですが、SendCustomEventDelayedSecondsにはしっかりと使う場面があります

その場面とは、
n秒後に指定の動作をさせたいというときです。

今まででUnityを触ったことのある人はコルーチン使えばいいやん、と思ったかもしれませんがUdonSharpではコルーチンは使用不可能です

具体的なコードについてはハツェさんの一定間隔で処理をするやつの正攻法と裏技 - ハツェの真時代傾向璋をごらんください

SendCustomNetworkEventの簡単な使い方

新しくなった機能を利用するにはVRC.SDK3をインポートするのが(おそらく)必須です!!

引数について

SendCustomNetworkEventの引数は

第1引数 :メッセージを送る対象
第2引数 :実際に実行させるメソッドの名前(String)
第3引数~:メソッドに渡す引数(任意)

となっています。

  • 第1引数

    メッセージを送る対象をここで指定します
    選ぶことのできるものは以下のとおりです

    指定できる種類 意味
    NetworkEventTarget.All そのワールドにログインしている全員に送信する
    NetworkEventTarget.Owner そのオブジェクトのオーナにのみ送信する
    NetworkEventTarget.Others 自分以外の全員に送信する
    NetworkEventTarget.Self 自分のみに送信する

    アップデートではOthersSelfが追加されたようです
    また、従来のやり方ではVRC.Udon.Common.Interfaces.NetworkEventTarget.~~~と、呪文レベルで長かった文章がNetworkEventTarget.~~~で良くなっています

    (短縮した書き方を使用する場合にはusing VRC.Udon.Common.Interfaces;を追加しておきましょう)


  • 第2引数

    実行するメソッドの名前を指定します
    名前はStringで与える必要があります。直接"hogehoge"と指定しても良いですし、nameof(hogehoge)として与えても良いです

    (公式的にはnameofを使用する方法を推奨している気がしますが、UdonSharpの記事では前者の直接文字列で指定する方法をよく見る気もします。まあどっちでもいいと思います)


  • 第3引数以降

    メソッドに渡す引数を設定することができます
    ここで設定できる引数の上限数は8個までで、同期変数として使用できる型ならおそらく全て利用可能です

    よく使いそうな型としてはbool、int、long、float、Vector2、Vector3、char、String、VRCUrlなどがサポートされています

    現在サポートされているすべての型を見るには公式サイトをごらんください

簡単な例

まず簡単な例をここで紹介します

WhiteCube.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.SDK3;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;
using VRC.SDK3.UdonNetworkCalling;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class WhiteCube : UdonSharpBehaviour
{
    void Start()
    {
        SendCustomNetworkEvent(NetworkEventTarget.All, "Greet", "hogehoge");
    }

    [NetworkCallable]
    public void Greet(string name)
    {
        Debug.Log(name + "さん、こんにちは!");
    }
}
出力
hogehogeさんこんにちは

まず、使い始めるときにはusing VRC.SDK3;とusingの部分に追加するようにしましょう!
これを追加することによって新しく追加されたものを簡単に利用できるようになります

そして呼び出したいメソッドは、必ずpublicで宣言するようにして、[NetworkCallable]属性を付与するようにしましょう!
(引数を付けた呼び出しをする際にはこれが必須になります。引数を必要としないものの呼び出しではこの属性付与はおそらく必要ありませんが、公式ではつけるようにおすすめされているので引数が必要でない場合でもつけるようにしておきましょう)

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]について

この部分では共有変数の同期方法について設定しています
BehaviourSyncMode.Manualを任意のものに変更することで同期方法を変更することができます

設定可能な値は以下のとおりです

モード 意味
None 同期を行わない
NoVariableSync 動作に共有変数が強制されない...らしいです(よくわかりません)
Continuous 一定周期ごとに自動的に変数の同期を行う
Manual 手動で変数の同期を行う

Continuousは自動的に変数の同期を行うが、Manualだと手動で設定したタイミングでしか同期が行われないので、ネットワーク的にManualを使うことがおすすめ、とされています(多分)
しかし、Manualモードの弊害として、VRC ObjectSyncコンポーネントが使用できなくなります。

ちなみにNoneにすると全く同期が行われないらしく、この状態ではSendCustomNetworkEventは使用できなくなります。
NoVariableSyncについては同期を行わないという点ではNoneと共通していますが、唯一違う点として、SendCustomNetworkEventが使用可能です

同期をオフにしたいけれどSendCustomNetworkEventを使いたい!というときにはNoVariableSyncを使いましょう

ちなみに[UdonBehaviourSyncMode(BehaviourSyncMode.~~~)]のようなものを書かない場合、このようにインスペクターから同期方法を設定することができます

imagepng

しかし、[UdonBehaviourSyncMode(BehaviourSyncMode.~~~)]を書くと
このように設定項目がグレースケールになり、インスペクター上から変更ができなくなります
(ちなみに下の例はManualモードで固定しています)

imagepng

コード側から指定したほうが安全性も増すと思うのでできるだけ[UdonBehaviourSyncMode(BehaviourSyncMode.~~~)]という書き方を使ったほうが良いと思います

もっと詳しくこの同期方法について知りたい方はシン・U# 入門 ② - ハツェの真時代傾向璋を見ることをおすすめします!

別のクラスのメソッドを呼び出すには

SendCustomNetworkEventでは別のクラスのメソッドを呼び出すことができます!
(これができるようになると、「特定の物にインタラクトしたときに、別の物の位置を変える」というようなことができるようになります。)

以下はWhiteCubeにインタラクトしたときに、RedCubeの位置を少し上にするというサンプルです
WhiteCubeにはWhiteCube.csが、RedCubeにはRedCube.csがそれぞれアタッチされています
(見やすくなるようにサンプルコードではusingが省略されていますが、RedCube.csではちゃんとusing VRC.SDK3;を追加しましょう!)

WhiteCube.cs
/*
    呼び出す側のUdonです
*/
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class WhiteCube : UdonSharpBehaviour
{
    [SerializeField]
    private UdonBehaviour redCubeUdon;// RedCubeのUdonBehaviourをここでセット

    public override void Interact()
    {
        redCubeUdon.SendCustomNetworkEvent(NetworkEventTarget.All, "MoveUp", 1);
    }
}
RedCube.cs
/*
    呼び出される側のUdonです
*/
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class RedCube : UdonSharpBehaviour
{
    [NetworkCallable]
    public void MoveUp(int value)
    {
        transform.position += new Vector3(0, value, 0);
    }
}

別のクラスのメソッドを呼び出すには、そのクラスのインスタンス(UdonBehaviour)を取得することがまず必要です
この例では[SerializeField]属性を付与しているのでredCubeUdonはインスペクター上で指定できます
下の写真で青く囲まれている部分にRedCubeを指定しましょう

imagepng

これで、WhiteCubeに対してインタラクトするとRedCubeが、SendCustomNetworkEventで指定した数値だけ上昇するようになりました!
(SendCustomNetworkEventでインスタンス内のプレイヤー全員にこのメッセージを送信しているため他のプレイヤーからも同じように見えるようになっています)

Recording 2025-05-27 063709.gif

このようにすることで他のクラスのメソッドについてもSendCustomNetworkEventで呼び出せます

特定のプレイヤーにのみSendCustomNetworkEventを実行させる

SendCustomNetworkEventには残念ながら特定のプレイヤーにのみ送信する、といったものは用意されていません
しかし、引数にプレイヤーIDを与え、それをもとに「特定のプレイヤー」かどうか判定するといった手法を取ることでそれを回避することができます

WhiteCube.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.SDK3;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;
using VRC.SDK3.UdonNetworkCalling;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class WhiteCube : UdonSharpBehaviour
{
    public override void Interact()
    {
        VRCPlayerApi localPlayer = Networking.LocalPlayer;
        Debug.Log("あなたのプレイヤーID: " + localPlayer.playerId);
        SendCustomNetworkEvent(NetworkEventTarget.All, "Greet", "hoge", 2);
    }


    [NetworkCallable]
    public void Greet(string name, int playerId)
    {
        VRCPlayerApi localPlayer = Networking.LocalPlayer;
        if (localPlayer.playerId == playerId)
        {
            Debug.Log("こんにちは " + name + "さん! (Player ID: " + playerId + ")");
        }
        else
        {
            Debug.Log("プレイヤーIDが一致しません。");
        }
    }
}

上の例ではSendCustomNetworkEventの引数として 2 を指定しています
実際に使うときはこの部分を、その実行させたいプレイヤーのIDに変更すれば良いと思います
Greetメソッドではif文を使って、与えられたプレイヤーIDと自分のプレイヤーIDが同じかどうか判定しています

このとき注意してほしいことが一つあって、呼び出される側のメソッドを宣言するときにはデフォルト引数を使用することができません!

WhiteCube.cs
[NetworkCallable]
public void Greet(string name, int playerId = -1)
{
    //何らかの処理
}

このようにint playerId = -1として宣言することはできません
(ちなみにこれはコンパイル時にエラーになります)

4. 新しいSDKで追加された便利なもの

新しいSDKではSendCustomNetworkEventを呼び出したプレイヤーのVRCPlayerApiを取得できるようになりました!

具体的にはNetworkCalling.CallingPlayerプロパティを使用します
このプロパティの値としてはネットワーク呼び出しが行われた場合には、その呼び出しを行ったプレイヤーのApiを、ネットワーク呼び出し出ない場合にはNoneを取得できます

以下はCallingPlayerプロパティを使用してSendCustomNetworkEventを呼び出したプレイヤーのプレイヤーIDを取得する例です

WhiteCube.cs
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.SDK3;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;
using VRC.SDK3.UdonNetworkCalling;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class WhiteCube : UdonSharpBehaviour
{
    void Start()
    {
        SendCustomNetworkEvent(NetworkEventTarget.All, "Greet", "hogehoge");
    }

    [NetworkCallable]
    public void Greet(string name)
    {
        VRCPlayerApi caller = NetworkCalling.CallingPlayer;
        Debug.Log(name + "さん、こんにちは!" + "プレイヤーIDは " + caller.playerId + " です。");
    }
}
出力
hogehogeさんこんにちはプレイヤーIDは1です

もうちょっと細かい仕様説明

一部今までで説明した内容と被る部分もありますが、SendCustomNetworkEventを使うときにいくつか注意しないといけないことがあります

  • 引数を使った呼び出しを使う際は[NetworkCallable]の付与が必須
    • 以前までの互換性を保つために引数を使わない場合には付与しなくても良くなっている
  • 呼び出し先のメソッドではオーバーロードが使用不可
  • アクセス修飾子publicの付与が必須
  • 呼び出し先のメソッドではデフォルト引数の設定ができない
動かない例
public void Greet(string name, int playerId = -1)
  • 一度に送れるデータの上限値は16KBまで
    • 1KBを超えるデータは複数に分割されて送信される
  • 同期モードをNoneにした場合はNetworkEventTarget.Selfにしても動作させることはできない
動かない例
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]//←同期モードがNoneになっている!
public class WhiteCube : UdonSharpBehaviour
{
    public override void Interact()
    {
        SendCustomNetworkEvent(NetworkEventTarget.Self, "Greet");
    }

    [NetworkCallable]
    public void Greet()
    {
        Debug.Log("Hello from WhiteCube!");
    }
}
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?