プロトコルについて¶
UdonRabbit Interop では、以下の方法にそって実装することによって、なつねこらぼらとりーで配布している、 Udon 関連コンポーネントおよびこのプロトコルを実装している他者作成パッケージとの相互運用性を確保することが可能になります。
このプロジェクトはできる限り型安全に、かつユーザーフレンドリーに扱えることを目指しており、そのための機能も提供しています。
Info
以下において、すべての項目にて UdonSharp (U#) にて解説しています。
Udon Graph でも同様のことが可能ですが、現時点で夏猫が Udon Graph を理解しきっていないため、サポートはしておりません。
また、 Type Validator の実装には UdonSharp (U#) での実装が必須となります。
Warning
下記のサンプルコードすべてにおいて、例外処理を省いています。
必要に応じて null チェックなどの例外処理を行って下さい。
メリット¶
UdonRabbit Interop のプロトコルを採用するメリットとしては、以下の通りです。
- (開発者) 型のある状態で U# プログラミングを行うことが出来る
- (開発者) パラメータの受け渡しを行うことが出来る
- (利用者) SDK2 の時のように、主にドラッグアンドドロップで操作が完結する
- (利用者) 対応しない組み合わせを行った場合、警告が表示されるのでデバッグが簡易に出来る
デメリット¶
ただし、 UdonRabbit Interop には、開発者・利用者ともに以下のデメリットが発生します。
- UdonRabbit.Interop パッケージを導入する必要がある
MOCHIZUKI_INTEROP プリプロセッサ¶
UdonRabbit Interop が導入されている環境では、 MOCHIZUKI_INTEROP プリプロセッサが有効になります。
このプリプロセッサを使用することで、 UdonRabbit Interop が導入されていない環境では、動作を行わないことが可能になります。
以下に MOCHIZUKI_INTEROP プリプロセッサが有効になっているときのみ、 UdonSharp でのコンパイルを有効にする例を示します。
#if MOCHIZUKI_INTEROP
using Mochizuki.VRChat.Interop;
namespace Mochizuki.VRChat.Examples
{
public class ExampleButton : UdonSharpBehaviour
{
// ...
// ここにコードを書く
// ...
}
}
#endif
EventListener UdonSharp コンポーネント¶
UdonRabbit Interop における、共通実装すべきコンポーネントです。
イベントの送信側および受信側の両方でこのコンポーネントに依存することで、型安全に設定およびイベントの送受信が行えるようになります。
DefaultExecutionOrder について¶
UdonRabbit Interop では、イベント送信側の DefaultExecutionOrder を 0 ~ 10000 番台、イベント受信側の DefaultExecutionOrder を 20000 ~ 30000 番台に推奨しています。
これは、イベントの発生を Update() で受け取るのを前提としている部分があるからです。
イベントの発生順を指定しなかった場合、 Unity ランタイムによって不定な順番で呼ばれ、想定通りの動作を行わない可能性があります。
イベントの送信¶
UdonRabbit Interop では、基本的にはイベントを発生させる側の Prefab に EventListener コンポーネントを含めることを推奨しています。
これは、 EventListener コンポーネントにおいて、どのイベントを受け渡すかの設定が可能であり、またこれらの設定は利用者側ではなく、開発者側が設定すべきであると考えているためです。
以下に、 Interact イベントの送信の為のコードを示します。
using Mochizuki.VRChat.Interop;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
namespace Mochizuki.VRChat.Example
{
public class ExampleButton : UdonSharpBehaviour
{
[SerializeField]
private EventListener listener;
public override void Interact()
{
listener.EmitInteract();
}
}
}
何らかのパラメーターを渡したい場合は、 SetArgument(object) を使用します。
listener.SetArgument(true);
基本的には、すべてのイベントにおいて、 EmitVrcEventName の形でイベントの送信が利用できます。
また、イベントにパラメータが渡されている場合は、以下のようにして送受信が可能です。
using Mochizuki.VRChat.Interop;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
namespace Mochizuki.VRChat.Example
{
public class ExampleButton : UdonSharpBehaviour
{
[SerializeField]
private EventListener listener;
public override void OnPlayerJoined(VrcPlayer player)
{
// イベントの送信
listener.EmitPlayerJoined(player);
}
private void Update()
{
// イベントの受信
if (listener.IsPlayerJoined())
{
// パラメータの受け取り
var player = listener.GetPlayerArg();
}
}
}
}
詳しくは、Event Listener についてを参照してください
イベントの受信¶
イベントの受信を行いたいコンポーネントでは、下記のコードにて任意のイベントの受信が行えます。
using Mochizuki.VRChat.Interop;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
namespace Mochizuki.VRChat.Example
{
public class ExampleButton : UdonSharpBehaviour
{
[SerializeField]
private EventListener listener;
private void Update()
{
if (listener.IsInteract())
{
// Interacted Event is fired
}
}
}
}
IsVrcEventName() では一度のイベント発生に付き、同じフレームの間のみ有効な値 (True) を返します。
パラメータを受信したい場合は、以下のように行うことで、設定されたパラメータが取得できます。
var arg = listener.GetArgument(); // 欲しい型へキャストしてください
Validator¶
UdonRabbit Interop では、コンポーネント間の相互運用性のチェックのために、いくつかのバリデーターを提供しています。
これらはフィールドアノテーションとして実装され、 UdonSharp の動作上、アノテーションはコンパイル段階で削除されるため、 VRChat 上での動作は変化ありません。
ただし、 UdonSharp でのコンパイルチェックはアノテーションでも有効になっているため、いくつかの制約が加えられています。
また、バリデーターを使うには、 Mochizuki.VRChat.Interop.Validator へのアセンブリ参照を AsmDef で行う必要があります。
Type Validator¶
上記の形式では、 SetArgument および GetArgument で送受信されるパラメータの型については保証されておらず、ユーザーの側で設定するときに不備が発生する可能性があります。
そこで、受信側にて以下のフィールドアノテーションを付与することで、 Inspector 上で型チェックを行うことが可能になります。
[SerializeField]
[RequestArgumentType(typeof(bool))] // 追加
private EventListener listener;
送信側および受信側にて渡している型と送信している型が異なる場合は、以下のように警告が表示されます。
Sync Validator¶
受信側にて同期状態を保持している場合、送信側で同期状態を保持したくない場合があります。
そのような場合は Sync Validator を使うことで、簡易的なチェックを行うことが可能です。
Info
これには負荷の都合上、送信側の実装も必要になります。
送信側がうまく対応していない場合はバリデーターが正しく動かない可能性もありますので、ご了承ください。
Sync Validator には、以下の 2 種類が存在します。
なお、フィールドアノテーションを付けない場合は、すべての状態が許容されます。
| Validator | Description |
|---|---|
RequestSyncedEvent |
送信側 (Sender) で同期された (グローバル) イベントを発生させることをリクエストします |
RequestNoSyncedEvent |
送信側 (Sender) で同期されていない (ローカル) イベントを発生させることをリクエストします |
例えば、送信側にて全プレイヤーに同期されたイベントを発して欲しい場合は、以下のようにします。
[SerializeField]
[RequestSyncedEvent]
private EventListener listener;
また、送信側にて、同期された・同期されていないイベントであることを明示する場合は、以下のようにします。
アノテーションを付けなかった場合は、同期されているイベントであると見なします。
// 同期されているイベント
[SerializeField]
[RequestSyncedEvent]
private EventListener listener;
// 同期されているイベント
[SerializeField]
private EventListener listener;
// 同期されていないイベント
[SerializeField]
[RequestNoSyncedEvent]
private EventListener listener;
ここでいう同期されたイベントとは、以下を示します。
- 全ユーザーに、同じタイミングで発生されるイベント
例えば、 SendCustomNetworkEvent(NetworkEventTarget.All, "YourMethod") で呼ばれたメソッドの内部で発生したイベントは、同期したイベントと見なせます。
送信側および受信側にて、期待している同期状態と、実際の同期状態が異なる場合は、以下のように警告が表示されます。
Event Validator¶
受信側にて、特定のイベントを要求する場合、 RequestValidateEvent フィールドアノテーションを付けることで、特定のイベントが送信されているかを確認することが可能になります。
たとえば、受信側が以下のような UdonSharp のコード側を持つとき:
using Mochizuki.VRChat.Interop;
using Mochizuki.VRChat.Interop.Validator.Attributes;
using UdonSharp;
using UnityEngine;
namespace Mochizuki.VRChat.Example
{
public class ExampleReceiver : UdonSharpBehaviour
{
[SerializeField]
[RequestValidateEvent]
private EventListener listener;
private void Update()
{
if (listener.IsInteract())
{
SomeStuff();
}
}
// other code
}
}
送信側で対応するメソッドが呼ばれているか (この場合は EmitInteract()) をチェックすることが可能になります。
なお、受信側にこのフィールドアノテーションがあったとしても、 IsSomeEventIsEmitted() のみを要求している場合は、バリデーションはパスされます。
送信側および受信側にて、期待しているイベントコールと、実際のイベントコールが異なる場合は、以下のように警告が表示されます。