unity-vrc-udon-sharp について
VRChat ワールドで UdonSharp コードを書くための開発スキルです。ランタイムの制約、同期状態の所有権、途中参加者への対応を説明し、コンパイル失敗や気づきにくいネットワーク上の問題を避けるのに役立ちます。
主な機能
- 01Udon ランタイム制約のガイド
- 02同期変数の所有権ルール
- 03途中参加者向け状態設計
- 04シリアライズとデシリアライズのパターン
- 05エディター評価フィールド初期化子の指針
活用シーン
- 01ネットワーク状態の所有者を設計
- 02途中参加プレイヤーの状態を処理
- 03Udon ランタイムで非対応の C# 構文を回避
- 04フィールド初期化子で値をベイク
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ niaka3dayo/ agent-skills-vrc-udon --skill unity-vrc-udon-sharpインストール後、Claude Code で/unity-vrc-udon-sharpを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CHEATSHEET.mdLICENSE.txtassets/templates/ArrayUtils.csBasicInteraction.csBatchedSync.csCloggedRetrySync.csContactReceiver.csCustomInspector.csDataPersistence.csDualCopySync.csEventBus.csMasterManagedPlayerPool.csPackedStateSync.csPlayerSettings.csRateLimitedSync.csStateMachine.csSyncedObject.csUdonSharpProgramAssetAutoGenerator.csUndoableGameManager.cshooks/validate-udonsharp.ps1validate-udonsharp.shreferences/api.mdassembly-definitions.mdconstraints.mdcontext-preservation.mddynamics.mdeditor-scripting.mdevents.mdimage-loading-vram.mdnetworking-antipatterns.md詳細
UdonSharp スキル
このスキルが重要な理由
UdonSharp は通常の Unity C# スクリプトのように見えますが、隠れた制約に直面するまではそうです。標準的な C# 機能(List<T>、async/await、try/catch、LINQ、ジェネリクス)の多くは、Udon ランタイムで実行されるコードではエラーなく動作しなかったり、コンパイルを拒否されたりします。エディターで評価されるフィールド初期化子は別のコンテキストであり、Udon が保持できる最終的な値を生成するために、通常の C# 機能の一部を使用できます。ネットワーク機能はさらに厄介です。所有権がない状態で同期変数を変更してもエラーは発生せず、何も起こりません。RequestSerialization を忘れると、状態の変更は自分のマシンから送信されません。標準的なシングルプレイヤーのローカルテストではプレイヤーが一人しかいないため、こうしたネットワーク関連のバグをまったく検出できません。
このスキルにあるすべてのルールは、UdonSharp がデフォルトでエラーを通知せずに失敗することを踏まえたものです。コードを生成する前に「ルール」を読んでください。
ネットワークコードを書く前に
同期モードを選んだり、同期変数を書いたりする前に決めておく必要がある、4 つのアーキテクチャ上の判断事項です。実装の途中で変更すると、通常は全面的な書き直しが必要になります。
- この状態の所有者は誰ですか? 書き込めるのは所有者だけで、それ以外は読み取りのみです。複数のプレイヤーが書き込める場合(共有トグルなど)は、所有権の移譲プロトコルが必要です。所有権のない状態での書き込みは通知なく破棄されます。
- いつ所有権を移譲しますか? つかんだときですか? インタラクトしたときですか? ゲームイベントのときですか?
OnPlayerLeftのときですか?Networking.SetOwnerは呼び出したクライアント上で即座に反映されます。呼び出し後は同期的にNetworking.IsOwner(gameObject)がtrueになるため、IsOwnerによるガードのもとで、その直後に[UdonSynced]フィールドへ書き込み、RequestSerialization()を呼び出しても安全です。複数のクライアントから同時にSetOwnerが呼び出された場合は、ネットワークへの到着順で解決されます。クライアント側での調停はないため、後から所有権を失ったクライアントの書き込みは上書きされるものとして扱ってください。 - 後から参加したプレイヤーには何が見えますか? 一度きりのイベント(
SendCustomNetworkEvent)だけで設定された状態は、後から参加したプレイヤーには見えません。後から参加したプレイヤーにも見える状態は[UdonSynced]変数に保存する必要があり、その値はOnDeserializationを通じて自動的に届きます。参加時に手動でRequestSerialization()を呼び出す必要はありません。 - セッション中に所有者が退出したらどうなりますか? VRChat は残っているプレイヤーに自動的に所有権を移譲します(選択ルールは公開されていません)。また、すべてのクライアントで
OnOwnershipTransferredが呼び出されます。同期変数は維持されるため、状態が固定されて動かなくなることはありません。現在の値を維持するのか、既知のデフォルト値にリセットするのか、OnOwnershipTransferredで派生状態を再適用または再ブロードキャストするのかを、あらかじめ決めておいてください。
コンテキストの保持
複雑な同期システム、所有権に関わるリファクタリング、またはコンテキストの圧縮や引き継ぎ後に作業を再開する場合は、references/context-preservation.md の読み込みを検討してください。
このファイルには、情報源、通信手段、同期モード、ストレージ、所有権、後から参加したプレイヤーの挙動、検証の根拠を記録するための、軽量なタスクコンテキストメモがあります。
これは複雑な作業向けの任意のガイダンスであり、小規模で機械的な編集で必要となる手順ではありません。
メモに個人データやトランスクリプトの生データを含めないでください。
VRChat SDK Build Panel の検証アラート、赤・黄・白の警告、または UdonSharp コンパイラーの制約ではなくワールドのシーン設定に関わる Auto Fix の副作用には、unity-vrc-world-sdk-3 を使用し、references/build-validation.md を読んでください。
基本原則
- 制約を最優先 — Udon ランタイムコードでは、検証が済むまで標準的な C# 機能は使用できないものとします。エディターで評価されるフィールド初期化子は別扱いとし、最終的に Udon でサポートされる値になることを確認してください。API を使用する前に
udonsharp-constraints.mdを確認してください。 - 変更前に所有権を確認 — オブジェクトの同期変数を変更できるのは、そのオブジェクトのオーナーだけです。必ず
SetOwner→ 変更 →RequestSerializationの順に実行してください。 - 途中参加者への対応 — イベント発生後に参加したプレイヤーに対しても、状態が正しくなる必要があります。リアルタイムの更新だけでなく、再シリアライズも考慮して設計してください。
- 同期を最小限にする — 同期変数はそれぞれ帯域幅を消費します(
udonsharp-sync-selection.mdのデータ予算を参照)。ローカルで導出できるものは導出し、真実のソースだけを同期してください。 - ポーリングではなくイベント駆動 —
Update()で状態を確認する代わりに、状態変化への反応にはOnDeserialization、[FieldChangeCallback]、SendCustomEventを使用してください。ホットパスや定期的な処理については、イベントディスパッチと Behaviour 間の呼び出しコスト層を参照してください。
同期配列は必ず OnDeserialization() から適用してください。配列要素の変更では、FieldChangeCallback による通知は保証されません。同じ長さの配列の変更、配列の再割り当て、配列長の変更にも同じ指針が適用されます。オーナーは変更直後に同じ冪等な適用メソッドを呼び出し、その後、Manual シリアライズを一度だけリクエストしてください。リビジョンガードで過去の一度きりの副作用を保護している場合、途中参加者の最初の OnDeserialization() には現在のリビジョンが渡されるため、その副作用が再実行される可能性があります。最初に受信したリビジョンは副作用なしで基準値として設定しますが、基準値の確認前に永続的な ApplyValues() を実行してください。一度きりの処理を実行するのは、それ以降のリビジョンだけにしてください。リビジョンは順序制御や古いパケットの保護にはなりません。
SDK 3.10.4 のイベントレシーバー引数
この Skill で現在の検証対象となっているのは SDK 3.10.5 です。
SDK 3.10.4 では、UdonSharpBehaviour は IUdonEventReceiver を直接実装しています。
そのため、レシーバーを必要とする API には this を直接渡せます。
VRCStringDownloader.LoadUrl(dataUrl, this);
レシーバー引数は引き続き必要です。現在の SDK では、明示的な (IUdonEventReceiver) キャストだけが不要です。3.10.4 より前のキャストは、過去の移行リファレンスにのみ残してください。これは公式 SDK 3.10.4 リリースノートおよび SDK のソース宣言に基づいています。
Public フィールド:インスペクターでの表示と永続化の方針は別です
[HideInInspector] はインスペクターで public フィールドを非表示にするだけで、Unity は引き続きシリアライズします。エディター時の DI、ベイク、オートワイヤリングで値を Scene/Prefab に永続化する必要がある場合は、[HideInInspector] public を使用してください。他の UdonBehaviour が直接アクセスするか SetProgramVariable を介してアクセスする、ランタイム専用の値には [System.NonSerialized] public を使用してください。[HideInInspector] を意図的に使用する場合は、その値を永続化する必要がある理由をコメントで説明してください。
エディターで評価されるフィールド初期化子
フィールド初期化子は、コンパイル済みの Udon プログラムに初期データを設定するため、Unity/エディター側で通常の C# として評価されます。初期化子内の式は Udon ランタイムでは実行されません。初期化子内の Random.Range 呼び出しはエディターで評価され、ランタイムの乱数ではなく、ベイクされたデフォルト値として保存されます。そのため、LINQ、ラムダ式、または List<T> を使用する同じビヘイビアー内の静的ヘルパーを使って配列初期化子を生成できますが、同じコードを Start()、Interact()、または別の Udon ランタイムメソッドから使用することはできません。最終的なフィールドの型と値は、Udon がサポートしている必要があります。生成処理はシーン、プレイヤー、ランタイムの状態に依存しないようにし、フィールド初期化子やコンストラクターは読み込みスレッドで実行されることがあるため、メインスレッド専用の Unity API は呼び出さないでください。サポートされる形式とその制限については、references/constraints.md を参照してください。
ローカルまたはクライアントごとの乱数には、Start() または遅延初期化ガードのみを使用してください。オブジェクトまたはセッションで共有するシードや状態は、オーナーが生成して [UdonSynced] フィールドに保存します。Manual 同期の場合は、書き込む前に所有権を確立してから RequestSerialization() を呼び出してください。必要に応じて、受信側は OnDeserialization() で派生状態を適用できますが、このコールバックはフィールド同期そのものには不要であり、後から参加したユーザーには現在の同期状態が送信されます。
よくある間違い(絶対に避ける項目)
次の Udon ランタイムおよび Unity シリアル化の制約は、コンパイル時エラーまたは気付かないデータエラーの原因になります。UdonSharp コードやシリアル化される初期値を書く前に、この一覧を確認してください。
| # | 絶対にしてはいけないこと | 問題が表面化せずに失敗する理由 | 代わりに使用するもの |
|---|---|---|---|
| 1 | Udon のランタイムコードで List<T>、Dictionary<T,K>、その他のジェネリックコレクションを使用する | コンパイルエラー — Udon コンパイラーによってブロックされます | T[] 配列、DataList、DataDictionary(DataDictionary.EnsureCapacity/カスタム容量には SDK 3.10.4 以降が必要です)。Editor で評価されるフィールド生成は、上記の限定的な例外です |
| 2 | async/await、System.Threading、コルーチンを使用する | Udon はシングルスレッドで、これらの機能は存在しません | SendCustomEventDelayedSeconds() |
| 3 | オブジェクトの所有者ではないのに [UdonSynced] フィールドを変更する | 変更はローカルに反映されますが、次回のデシリアライズ時に通知なく元に戻されます | 変更前に Networking.SetOwner() を呼び出し、その後 RequestSerialization() を呼び出します |
| 4 | 同期フィールドを変更した後、RequestSerialization() を呼び出し忘れる(Manual 同期) | 状態の変更はローカルクライアントから送信されません。エラーも警告もありません | [UdonSynced] フィールドを変更した後は、必ず RequestSerialization() を呼び出します |
| 5 | try/catch/finally/throw を使用する | コンパイルエラー — 例外処理はブロックされています | 防御的な null チェックと早期リターン |
| 6 | フィールド初期化子で Networking.LocalPlayer にアクセスする | Editor 側の初期値生成では、プレイヤーも Udon のランタイム状態も利用できません | Start() で初期化するか、遅延初期化ガードを使用します |
| 7 | インスタンスごとの状態に static フィールドを使用する | static フィールドは同じクライアント上のすべてのインスタンスで共有され、同期されません | 同期が必要な場合は、[UdonSynced] を付けたインスタンスフィールドを使用します |
| 8 | Manual 同期で毎フレーム RequestSerialization() を呼び出す | 約 11 KB/s のネットワーク帯域予算を使い果たし、ワールド全体に輻輳を引き起こします | 変更検出を行いながら 1~10 Hz に制限し、Networking.IsClogged を確認します |
| 9 | Udon のランタイムコードで LINQ(.Where、.Select など)やラムダ式を使用する | コンパイルエラー — Udon コンパイラーではサポートされていません | 名前付きメソッドを使った手動の for ループを使用します。Editor で評価されるフィールド生成は、上記の限定的な例外です |
| 10 | Button.onClick.AddListener() を呼び出す | Udon では利用できません。ランタイムのデリゲートはサポートされていません | Inspector の OnClick で SendCustomEvent を設定します |
| 11 | 1 つのビヘイビアーで Continuous 同期と Manual 同期の処理を混在させる | 帯域を無駄にする(Continuous で離散値を扱う)か、制御できなくなります(Continuous で RequestSerialization を重複して呼び出す) | ビヘイビアーを分けます。位置/回転には Continuous、離散状態には Manual を使用します |
| 12 | IsOwner ガードなしで [UdonSynced] フィールドに書き込む | 所有者以外による書き込みはローカルでのみ有効で、実際の所有者からの次回のデシリアライズ時に通知なく元に戻されます | 必要に応じて先に Networking.SetOwner を呼び出し(ローカルでは即時反映)、その後 IsOwner の条件下で書き込んで RequestSerialization() を呼び出します |
| 13 | SDK 3.8.1 未満の未対応 SDK で [NetworkCallable] を使用する(過去の移行のみ) | コンパイルエラー — 属性とパラメーター付きネットワークイベント API は利用できません | 現行の SDK ターゲットである 3.10.5 を使用します。過去の移行に関するメモでは、同期変数を使用し、ネットワークイベントと組み合わせずに OnDeserialization/FieldChangeCallback で反応します |
| 14 | SDK 3.10.0 未満の未対応 SDK で PhysBones/Contacts API(OnPhysBoneGrabbed、OnContactEnter など)を使用する(過去の移行のみ) | コンパイルは通りますが、ランタイムでは通知なく無視されます。3.10.0 より前はワールド側の Dynamics が存在しないため、コールバックは一度も呼び出されません | 現行の SDK ターゲットである 3.10.5 を使用します。過去の移行では、プロジェクトが少なくとも SDK 3.10.0 を使用していることを確認します |
| 15 | SDK 3.7.4 未満の未対応 SDK で PlayerData 永続化 API を使用する(過去の移行のみ) | コンパイルエラー — シンボルがありません。PlayerData、PlayerObject、OnPlayerRestored は 3.7.4 で追加されたもので、それ以前の Udon ホワイトリストには含まれていません | 現行の SDK ターゲットである 3.10.5 を使用します。過去の移行では、プロジェクトが少なくとも SDK 3.7.4 を使用していることを確認します |
| 16 | 対応する U# Assembly Definition なしで UdonSharpBehaviour の周囲に Unity の .asmdef を配置する | Unity は C# アセンブリをコンパイルしますが、UdonSharp はそのスクリプトが U# アセンブリに属していないと報告します | シンプルなワールドスクリプトでは asmdef を避けます。パッケージ/asmdef のワークフローでは、対応する U# Assembly Definition を作成し、Source Assembly に Unity の .asmdef を設定します(references/assembly-definitions.md を参照) |
| 17 | 対応する .asset ファイルなしで .cs スクリプトを作成する | スクリプトが UdonBehaviour として認識されず、「関連付けられたスクリプトを読み込めません」というエラーが発生し、Udon のコンパイルも行われません | .cs を作成するたびに、Assets/Editor/UdonSharpProgramAssetAutoGenerator.cs が存在することを確認します。存在しない場合は references/editor-scripting.md に従ってインストールし、ユーザーに通知します(rules/udonsharp-constraints.md のルール 8 を参照) |
| 18 | Update()、PostLateUpdate()、その他の毎フレーム発生するイベント内で Debug.Log() を呼び出す | VRChat のクライアント側ログレートリミッターが超過分のログを通知なく破棄します。さらに、毎フレーム暗黙的に文字列が割り当てられ、継続的な GC 負荷によってフレームレートが大きく低下します。ClientSim と Unity Editor では、どちらの問題も表面化しません | if (debugMode && Time.frameCount % 60 == 0) でガードするか、すべてのログ出力をイベント駆動型のコールバックに移します |
| 19 | GameObject、Transform、UdonBehaviour、その他のコンポーネント参照に [UdonSynced] を使用する | 同期可能なのはプリミティブ型、値型(Vector3、Quaternion、Color など)、string、VRCUrl、およびこれらの単純な配列のみです。コンポーネント参照は SDK のバージョンに応じて、コンパイル時に失敗するか、通知なくシリアライズされません | プレイヤー ID(int)またはシーンオブジェクトのインデックス(int)を同期し、各クライアントで実際の参照をローカルに解決します |
| 20 | 独立した初期値が必要な UdonSharp の VRCUrl フィールドを VRCUrl.Empty で初期化する | VRCUrl.Empty は共有インスタンスであるため、同じ UdonSharp プログラムを使用するフィールド、配列要素、GameObject 間で Inspector のデータが漏れることがあります | [SerializeField]、[UdonSynced]、通常の private フィールド、および各配列要素には、それぞれ個別の new VRCUrl("") を指定します。VRCUrl.Empty はランタイムのセンチネル用途に限って使用します |
同期モードのクイック判断
Changing every frame (position, rotation)? -> Continuous sync
Changing on user action (toggle, score)? -> Manual sync + RequestSerialization()
No sync needed (local UI, effects)? -> NoVariableSync
Need reliable one-shot calls with params? -> [NetworkCallable] (introduced in SDK 3.8.1; active target 3.10.5)
Temporary effect for all players, no state? -> SendCustomNetworkEvent (no synced vars)
詳細な判断ツリー、データ予算、最小化の原則については、
rules/udonsharp-sync-selection.mdを参照してください。
3.8.1より前のSDKでは、NetworkCallable属性やパラメーター付きネットワークイベントAPIが定義されていないため、これらを使用するコードは通常コンパイルに失敗します。
[NetworkCallable]メソッドの戻り値はvoidである必要があります。
同期のデバッグに関するクイック判断
同期が「ローカルでは正しく見えるのに、他のユーザーでは動作しない」場合:
Remote players don't see my state change?
├── Did I call RequestSerialization() after writing? (Manual sync) → Add it
├── Does the local player own the object? → Networking.SetOwner() first
└── Using Continuous sync for button/toggle state? → Switch to Manual + RequestSerialization()
RequestSerialization() called but still not syncing?
├── Is Networking.IsClogged == true? → Throttle; retry after delay
└── Non-owner writing the field? → Acquire ownership first — a non-owner RequestSerialization() is a silent no-op (see NEVER #12)
Late joiners don't see current state?
├── State set only on event (e.g., player trigger)? → Verify the state lives in a [UdonSynced] field — synced values are delivered to late joiners automatically; SendCustomNetworkEvent calls before join are never replayed
└── Using SendCustomNetworkEvent for persistent state? → Use [UdonSynced] variables instead
OnOwnershipTransferred not firing on a remote client?
└── On the caller, the callback fires synchronously inside SetOwner — confirm the calling client called Networking.SetOwner(LocalPlayer, gameObject), and that remote clients resolve the same gameObject reference (scene path or prefab GUID)
参照ファイルの読み込みガイド
必要なものだけを読み込みます。読み込みすぎるとトークンを無駄にし、読み込みが足りないと重大なミスにつながります。
| タスク | 必須で読むファイル | 任意 | 読み込まないファイル |
|---|---|---|---|
| ネットワーク/同期コードの作成 | networking.md、networking-antipatterns.md | networking-bandwidth.md、sync-examples.md | dynamics.md、web-loading.md、image-loading-vram.md |
| UI/メニューの構築 | patterns-ui.md、events.md | patterns-core.md、api.md | networking-bandwidth.md、dynamics.md、web-loading.md |
| 永続化(保存/読み込み)の実装 | persistence.md | patterns-networking.md、events.md | dynamics.md、web-loading.md、image-loading-vram.md |
| Webから文字列/画像をダウンロード | web-loading.md | web-loading-advanced.md、image-loading-vram.md | dynamics.md、persistence.md、networking-bandwidth.md |
| VRCTween、キャンセル可能な遅延呼び出し、またはTweenのクリーンアップの使用 | vrctween.md | patterns-utilities.md、api.md | dynamics.md、web-loading.md、persistence.md |
PhysBones/Contacts/Constraints、Box Contacts、Global Avatar PhysBone Colliders、またはワールドのVRCPhysBoneCollider Udonアクセスの使用 | dynamics.md、events.md | patterns-networking.md、api.md | web-loading.md、image-loading-vram.md、persistence.md |
| 実行時のVRCQualitySettingsの読み取り/書き込み | api.md | events.md;シーンのデフォルト設定:unity-vrc-world-sdk-3 | networking.md、dynamics.md、web-loading.md |
DataList/DataDictionaryの容量調整、またはDataDictionary.EnsureCapacityの使用 | api.md | constraints.md、patterns-utilities.md、web-loading.md | dynamics.md、persistence.md、networking-bandwidth.md |
| パフォーマンスの最適化(Updateループ) | patterns-performance.md | patterns-utilities.md、api.md | dynamics.md、web-loading.md、persistence.md |
| ビデオプレーヤーの構築 | patterns-video.md | events.md、web-loading.md | dynamics.md、persistence.md、image-loading-vram.md |
| デバッグ/トラブルシューティング | troubleshooting.md | constraints.md、networking.md、testing.md | patterns-*.md、dynamics.md、web-loading.md |
| 所有権/同期の競合のデバッグ | networking.md、troubleshooting.md | networking-antipatterns.md | dynamics.md、web-loading.md |
| SDKバージョン間の移行/アップグレード後の問題の修正 | sdk-migration.md | troubleshooting.md、networking.md、dynamics.md | web-loading.md、image-loading-vram.md |
| コンテキストの圧縮/引き継ぎ/所有権に配慮した複数ファイルのリファクタリング後に、複雑な作業を再開 | 現在のタスクの主要な参照ファイル | context-preservation.md | 無関係な分野の参照ファイル |
| 新しいUdonSharpスクリプトの作成(同期が必要か不明な場合) | constraints.md | networking.md | dynamics.md、web-loading.md、image-loading-vram.md |
| 新しいスクリプトファイルの設定(.cs/.assetの接続、プログラムアセットの生成) | editor-scripting.md | troubleshooting.md | networking.md、dynamics.md |
| VPM/パッケージ/asmdefのワークフロー、Assembly Version Defines、U# Assembly Definitionの接続、Auto Referencedの判断 | assembly-definitions.md | editor-scripting.md、troubleshooting.md | networking.md、dynamics.md、web-loading.md |
| エディター設定ツール/配置UX(カスタムインスペクター、シーン接続ヘルパー、IEditorOnly)の構築 | editor-scripting.md | constraints.md、assembly-definitions.md | networking.md、dynamics.md、web-loading.md |
パターン選択ガイド
6 つのパターンファイルで、さまざまな領域をカバーします。次の簡易ガイドを参考に、適切なファイルを選んでください。
Building a UI, menu, or HUD? -> patterns-ui.md
VR finger/touch interaction on Canvas? -> patterns-ui.md
Modular app with multiple screens? -> patterns-ui.md
Syncing state across players? -> patterns-networking.md
Multiple identical rooms from one model? -> patterns-networking.md (distant-room)
Optimizing Update() or heavy loops? -> patterns-performance.md
Heavy rebuild, replay, or reset/cancel? -> patterns-performance.md
Playing or streaming video? -> patterns-video.md
Need array helpers, event bus, or -> patterns-utilities.md
pseudo-delegates?
Basic interactions, timers, audio, -> patterns-core.md
pickups, or teleportation?
Station + trigger zone detection? -> troubleshooting.md
複数の懸念事項がある場合は、主要なパターンファイルとその依存ファイルを読み込んでください。たとえば、同期するビデオプレーヤーには
patterns-video.mdとpatterns-networking.mdの両方が必要です。
テンプレート選択ガイド
17 個のテンプレートで、一般的な出発点をカバーしています。最も近いものを選び、必要に応じて調整してください。
| 出発点 | テンプレート | 主な機能 |
|---|---|---|
| インタラクションとオブジェクト | ||
| インタラクティブなオブジェクト(クリック/使用) | BasicInteraction.cs | クールダウン、切り替え、音声フィードバック |
| 同期する切り替え/共有オブジェクト | SyncedObject.cs | 所有権チェック、FieldChangeCallback、後から参加したユーザーの初期化 |
| プレイヤーごとの移動設定 | PlayerSettings.cs | トリガーゾーンによる歩行/走行/ジャンプ速度 |
| 接触ベースの衝突検出 | ContactReceiver.cs | OnContactEnter/Exit、アバターとワールドの判定、連続発火の抑制(SDK 3.10.0 で導入、アクティブな対象は 3.10.5) |
| 状態とゲームロジック | ||
| ステートマシン/ゲーム進行 | StateMachine.cs | 時間指定の遷移、同期状態、後から参加したユーザーへの安全性 |
| 取り消し/履歴機能のあるゲーム | UndoableGameManager.cs | byte[] 履歴、NetworkCallable _OwnerProcessMove/_OwnerUndo/_OwnerReset |
| オブジェクトプール(プレイヤースロット) | MasterManagedPlayerPool.cs | FIFO リングバッファー、マスター管理、OnPlayerJoined/Left |
| 永続化とデータ | ||
| プレイヤーデータの保存/読み込み | DataPersistence.cs | PlayerData API、OnPlayerRestored、自動保存(SDK 3.7.4 で導入、アクティブな対象は 3.10.5) |
| ネットワークパターン | ||
| レート制限付き同期(スライダーのドラッグ) | RateLimitedSync.cs | 0.15s のクールダウン、後勝ち |
| バッチ同期(連続イベント) | BatchedSync.cs | 冪等なスケジュール、0.2s の遅延、単一パケット |
| 混雑を考慮した再試行 | CloggedRetrySync.cs | IsClogged チェック、線形バックオフ、MaxRetries |
| ローカルと同期の二重コピー | DualCopySync.cs | ローカル作業用コピーと同期用の転送、ダーティフラグ |
| 複数の値を 1 つのフィールドに格納 | PackedStateSync.cs | 1 つの Vector3 に 3 つの整数を格納し、同期のオーバーヘッドを削減 |
| ユーティリティ | ||
| 配列ヘルパー(List<T> の代替) | ArrayUtils.cs | 配列向けの Add、Remove、Contains、FindIndex、Shuffle |
| イベントバス(パブリッシュ/サブスクライブ) | EventBus.cs | サブスクライバーリスト(最大 32)、RegisterListener/RaiseEvent |
| カスタムエディターインスペクター | CustomInspector.cs | UdonSharpGUI、Undo、プロキシ同期 |
| 新しいスクリプト用の .asset の自動生成 | UdonSharpProgramAssetAutoGenerator.cs | AssetPostprocessor、ドメインリロード時のみ、自動コンパイル |
複数のニーズがありますか? まず主な懸念事項に最も近いテンプレートを選び、ほかのテンプレートからパターンを取り入れてください。たとえば、同期と取り消し機能が必要なゲームでは、
UndoableGameManager.csをベースにして、スロットリングにはRateLimitedSync.csのパターンを利用します。
ルール(制約とネットワーク)
コンパイルの制約とネットワークのルールは、常時読み込まれる ルール で定義されています。
| ルールファイル | 内容 |
|---|---|
rules/udonsharp-constraints.md | 使用できない機能、コード生成ルール、属性、同期可能な型 |
rules/udonsharp-networking.md | 所有権、同期モード、RequestSerialization、NetworkCallable、ネットワークイベント送信者の認証 |
rules/udonsharp-sync-selection.md | 同期パターンの選択、データ予算、最小化の原則 |
インストール後、自動読み込みできるよう、これらをエージェントのルールディレクトリに配置してください。
SDK バージョン
サポート中/最終確認済み:SDK 3.10.5
v4.0.0 以降のポリシーは、最新の安定版 SDK のみを対象とします。新しい安定版へのサポートは、このリポジトリで確認した後にのみ移行します。新しい安定版が自動的にサポートされることはありません。現在の最終確認済みターゲットは 3.10.5 です。
以下の表には、移行時の参考として、機能が導入された履歴を掲載しています。SDK 3.7.1~3.10.4 の項目は履歴情報にすぎず、このスキルのアクティブなサポート対象や検証対象ではありません。これはこのスキルのサポート範囲を示すものであり、VRChat 独自の SDK ポリシーを示すものではありません。特に過去の移行事例として明記されている場合を除き、主な生成例は SDK 3.10.5 を対象とします。
| SDK Version | Key Features | Status |
|---|---|---|
| 3.7.1 | StringBuilder、RegularExpressions、System.Random を追加 | 履歴情報 |
| 3.7.4 | Persistence API(PlayerData/PlayerObject)を追加 | 履歴情報 |
| 3.7.6 | マルチプラットフォームでのビルドと公開(PC と Android を同時に対応) | 履歴情報 |
| 3.8.0 | PhysBone の依存関係の並べ替え、Drone API(VRCDroneInteractable) | 履歴情報 |
| 3.8.1 | [NetworkCallable] 属性、パラメーター付きネットワークイベント、NetworkCalling.CallingPlayer/.InNetworkCall、NetworkEventTarget.Others/.Self | 履歴情報 |
| 3.9.0 | Camera Dolly API、Auto Hold Pickup の簡略化 | 履歴情報 |
| 3.10.0 | ワールド向け VRChat Dynamics(PhysBones、Contacts、VRC Constraints) | 履歴情報 |
| 3.10.1 | バグ修正と安定性の改善 | 履歴情報 |
| 3.10.2 | EventTiming の拡張、PhysBones の修正、シェーダーの時間グローバル変数 | 履歴情報 |
| 3.10.3 | VRCPlayerApi.isVRCPlus、VRCRaycast(アバター)、Mirror のレンダー順序の修正 | 履歴情報 |
| 3.10.4 | VRCTween、ボックス形状の Contacts、グローバル Avatar PhysBone Colliders、ワールドの VRCPhysBoneCollider への Udon アクセス、DataList/DataDictionary のカスタム容量、DataDictionary.EnsureCapacity、UdonSharpBehaviour が IUdonEventReceiver を実装し、レシーバー this を直接受け取る機能 | 履歴情報 |
| 3.10.5 | WorldQualitySettings、書き込み可能な VRCQualitySettings、アセンブリのバージョン定義、Pickup Outline Renderers、Pipeline Manager の検証 | アクティブ/最終確認済み |
公開には SDK 3.10.5 を使用してください。バージョン固有の API や移行手順を利用する前に、対応するリリースノートを確認してください。
公式リソース
| リソース | URL | 内容 |
|---|---|---|
| VRChat Creators | creators.vrchat.com/worlds/udon/ | Udon/SDK の公式ドキュメント |
| UdonSharp Docs | udonsharp.docs.vrchat.com | UdonSharp API リファレンス |
| VRChat Forums | ask.vrchat.com | Q&A、解決策 |
| VRChat Canny | feedback.vrchat.com | バグ報告、既知の問題 |
| GitHub | github.com/vrchat-community | サンプルとライブラリ |
参考資料
| ファイル | 内容 | 検索のヒント |
|---|---|---|
constraints.md | UdonSharpで利用可能なC#機能、使用できない機能、同期可能な型、属性、DataListと配列の使い分けの指針、DataList/DataDictionaryの容量API、高度な回避策(オブジェクト配列による疑似構造体)、同期されるVRCUrlリスト | List、async、try/catch、LINQ、generics、DataList、DataDictionary、DataList capacity、DataDictionary capacity、EnsureCapacity、DataList vs array、when to use DataList、VRCUrl array、VRCUrl sync、pseudo-struct、object array cast、multi-field state container |
networking.md | オーナーシップモデル、同期モード、RequestSerialization、NetworkCallable、ネットワークイベント送信者の認証、データ制限 | UdonSynced、SetOwner、BehaviourSyncMode、FieldChangeCallback、OnDeserialization、NetworkCalling、CallingPlayer、InNetworkCall、legacy event、underscore、authorization、master leave、ownership cascade |
networking-bandwidth.md | 帯域幅のスロットリング、ビットパッキング、同期データサイズの例、デバッグ、オーナー中心のアーキテクチャ | IsClogged、bandwidth、throttle、bit packing、data budget、IsMaster |
networking-antipatterns.md | 避けるべき6つのアンチパターン、テンプレートへのリンク付きの5つの高度な同期パターン | anti-pattern、race condition、ownership fight、late-joiner、PackedStateSync、BatchedSync |
persistence.md | ストレージ層の選択フローチャート(ローカル/同期/PlayerData/PlayerObject)、PlayerData/PlayerObject API(SDK 3.7.4で導入、対象バージョンは3.10.5)、プレイヤーごとのセーブデータ、ストレージ使用量の照会API(SDK 3.10.0で導入、対象バージョンは3.10.5) | storage layer、decision tree、local variable、PlayerData、PlayerObject、OnPlayerRestored、SetInt、TryGetInt、GetPlayerDataStorageUsage、GetPlayerDataStorageLimit、GetPlayerObjectStorageUsage、GetPlayerObjectStorageLimit、RequestStorageUsageUpdate、OnPersistenceUsageUpdated、storage quota、storage usage、which storage、when to use PlayerData |
dynamics.md | PhysBones、Contacts、VRC Constraints(SDK 3.10.0で導入、対象バージョンは3.10.5)、VRCTween、ボックス型Contacts、全アバター共通のPhysBoneコライダー、ワールドからのVRCPhysBoneColliderのUdonアクセス(SDK 3.10.4以降) | PhysBone、ContactReceiver、ContactSender、Box Contact、Global Avatar PhysBone Collider、VRCPhysBoneCollider、VRCTween、VRCConstraint、OnContactEnter |
patterns-core.md | 初期化、インタラクション、プレイヤー検出、タイマー、オーディオ、ピックアップ、アニメーション、UI、テレポート、遅延初期化ガード、リモートプレイヤー | Interact、OnEnable、Initialize、AudioSource、VRCPickup、Animator、UI、TeleportTo、remote players、_GetRemotePlayers、exclude local player、FindAll alternative |
patterns-networking.md | オブジェクトプーリング、NetworkCallableの送信者検証パターン、永続化との連携、ダイナミクスとのインタラクション、同期ゲーム状態、遠隔ルームの疑似マルチルーム化(状態と表示の分離、自身がオーナーとなるセッション調整、またはマスターが調整するセッション調停)、遅延イベントのデバウンス、配列同期のための文字列結合 | pool、MasterManagedPlayerPool、NetworkCallable、CallingPlayer、InNetworkCall、sender authorization、DamageReceiver、game state、distant room、pseudo multi-room、room assignment、roomIndex、LocalRoomPresenter、RoomAssignment、NoVariableSync、TeleportTo per-client、debounce、state machine、string join、array sync、paragraph separator、U+2029 |
patterns-performance.md | partial classパターン、更新ハンドラー、PostLateUpdate、空間クエリ、プラットフォーム最適化、Stopwatchによるフレーム予算、高負荷処理のアーキテクチャ(再構築、再生、リセット/キャンセル)、レート制限付きリゾルバー、GameObject検索のコスト階層 | Update、PostLateUpdate、Bounds、AnimatorHash、performance、mobile、PC、Stopwatch、frame budget、SendCustomEventDelayedFrames、heavy processing、rebuild、replay、reset、cancel、operation log、authoritative data、derived state、cursor rebuild、rate limit、URL scheduler、video load queue、GameObject.Find、Find cost、lookup cost tier、SerializeField vs Find、silent failure on rename、SendCustomEvent cost、cross-behaviour call、EventBus hot path、delayed loop spike、public method lookup、event dispatch tier |
patterns-utilities.md | 配列ヘルパー(Listの代替)、イベントバス、GameObjectリレー通信、疑似構造体の二重キャスト、抽象クラスのコールバック、キャンセル可能な遅延イベント、再入ガード、UdonEvent疑似デリゲート | ArrayUtils、EventBus、relay、subscriber、FindIndex、ShuffleArray、object array、pseudo struct、double cast、abstract class、callback、interface alternative、cancellable timer、re-entrance、emitting guard、UdonEvent、pseudo delegate |
patterns-ui.md | UI/Canvasパターン:移動禁止ガード、アバターのスケールに応じたUI、FOVに応じた配置、プラットフォーム対応レイアウト、動的なプレイヤーリスト、スクロール入力の抽象化、ルックアップテーブルによるローカライズ、ToggleとAnimatorの連携、PlayerObjectによる設定の永続化、リスナー方式のメニューイベント、指でのタッチ操作、モジュール式アプリのアーキテクチャ | Canvas、UI、menu、Immobilize、avatar scale、FOV、platform、Quest、VR、desktop、player list、scroll、localization、language、Toggle、Animator、PlayerObject、settings、persistence、listener、broadcast、finger touch、fingertip、haptic、FingerPointer、FingerTouchCanvas、touch canvas、app architecture、AppModule、AppManager、plugin lifecycle、CanvasGroup transition |
patterns-video.md | 動画プレイヤーの状態マシン、サーバー時刻による再生同期、途中参加者との同期、AVPro Blitのバッファリング、フォールバック付きエラー再試行、同期プレイリスト/キュー、プラットフォームに応じたURL選択 | video player、AVPro、VRCUnityVideoPlayer、BaseVRCVideoPlayer、playback sync、server time、GetServerTimeInMilliseconds、late joiner、VRCGraphics.Blit、OnVideoReady、OnVideoError、retry、fallback、playlist、queue、shuffle、repeat、Quest URL |
web-loading.md | 文字列/画像のダウンロード、VRCJson、信頼済みURL | VRCStringDownloader、VRCImageDownloader、VRCJson、DataDictionary、VRCUrl |
image-loading-vram.md | 画像読み込みの高度なVRAM管理:DestroyとDispose、ダブルバッファフェード、ストックモード、ミップマップバイアス | VRAM、texture memory、memory leak、Destroy、Dispose、double buffer、fade、mipmap、TextureInfo |
web-loading-advanced.md | 高度なデータ読み込み:StringDownloaderによるBase64テクスチャ埋め込み、クロスプラットフォーム圧縮、URLの二重キーインデックス、LRUデコードキャッシュ | Base64、LoadRawTextureData、StringDownloader texture、DXT1、ETC_RGB4、UNITY_ANDROID、LRU cache、packed resources、binary format |
api.md | VRCPlayerApi、Networking、NetworkCallingの送信者コンテキスト、列挙型リファレンス、VRCObjectPoolのメソッドとInteract駆動のオーナーシップパターン | GetPlayers、playerId、isMaster、isLocal、GetPosition、SetVelocity、NetworkCalling、CallingPlayer、InNetworkCall、Drone、VRCDroneApi、VRCObjectPool、TryToSpawn、Return、Shuffle、pool owner、Interact pool、pool forwarded spawn、pool ownership transfer |
events.md | すべてのUdonイベント(OnPlayerRestored、OnContactEnterを含む) | OnPlayerJoined、OnPlayerLeft、OnPlayerTriggerEnter、OnOwnershipTransferred、OnControllerColliderHitPlayer、CharacterController、OnMasterTransferred、OnAvatarChanged、OnSpawn、VRC Economy、OnPurchaseConfirmed、OnAsyncGpuReadbackComplete |
editor-scripting.md | エディタースクリプト、プロキシシステム、カスタムインスペクター、エディター専用セットアップコンポーネント(IEditorOnly)、ビルドパイプラインのコールバック、UdonSharpProgramAssetの自動生成 | UdonSharpEditor、UdonSharpBehaviourProxy、SerializedObject、UdonSharpProgramAsset、auto-generate、AssetPostprocessor、.asset missing、IEditorOnly、EditorOnly tag、setup helper、setup component、build exclusion、custom inspector、ContextMenu、IVRCSDKBuildRequestedCallback、OnBuildRequested、build callback、IPreprocessCallbackBehaviour、OnPreprocess |
assembly-definitions.md | UdonSharpのアセンブリ定義、Unityの.asmdefとU# Assembly Definitionの違い、VPMパッケージのワークフロー、Runtime/Editorの分離、Auto Referencedのトレードオフ | Version Defines、VRC_ENABLE_、asmdef、Assembly Definition、U# Assembly Definition、Source Assembly、VPM package、Auto Referenced、Runtime、Editor、package layout、prefab-first、code-integration API |
sync-examples.md | 同期パターンの例(ローカル/イベント/同期変数) | Continuous、Manual、NoVariableSync、sync example |
troubleshooting.md | よくあるエラーと解決方法 | NullReference、compile error、sync not working、FieldChangeCallback、VRCStation、seated player、trigger zone、OnPlayerTriggerEnter not firing、station collider、position polling、OnStationEntered |
sdk-migration.md | SDK移行ガイド(3.7から3.10)、バージョンごとの変更点とチェックリスト | migration、deprecated、upgrade、3.7、3.8、3.9、3.10 |
testing.md | テストとデバッグのガイド:ClientSimでのエディターテスト、Build and Test(単一クライアントおよび複数クライアント)、Debug.Logのパターン、リリース前のクリーンアップ、テスト用チェックリスト | ClientSim、Build and Test、multi-client、late joiner test、debug、Debug.Log、ownership test、sync test、testing checklist |
context-preservation.md | コンテキスト保持ガイド:コンテキストの圧縮や引き継ぎの際に、タスク固有の設計意図(信頼できる情報源、同期方式、オーナーシップ、途中参加時の動作、検証)を記録する方法、最小限のタスクコンテキストメモ、プライバシーに関するガイダンス、再開用チェックリスト | context preservation、design intent、compaction、handoff、resume、task context note、why this design、ownership rationale、design-context loss |
テンプレート(assets/templates/)
| テンプレート | 用途 |
|---|---|
BasicInteraction.cs | Interact() ハンドラーを備えたインタラクティブオブジェクト |
SyncedObject.cs | ネットワーク同期オブジェクト(Manual 同期、所有権ガード、後から参加したユーザー向けの初期化フラグ) |
PlayerSettings.cs | プレイヤーごとの移動設定(歩行/走行/ジャンプ速度) |
StateMachine.cs | 同期された状態と遷移を備えたステートマシン |
DataPersistence.cs | OnPlayerRestored を使用した PlayerData の保存/読み込み(SDK 3.7.4 で導入、対象バージョン 3.10.5) |
ContactReceiver.cs | ワールド側の衝突検出用コンタクトレシーバー(SDK 3.10.0 で導入、対象バージョン 3.10.5) |
CustomInspector.cs | UdonSharpEditor を使用したカスタムエディターインスペクター |
MasterManagedPlayerPool.cs | セキュリティを目的としないセッション調整用の、マスター管理プレイヤーオブジェクトプール。FIFO リングバッファ。OnPlayerJoined/Left。マスター引き継ぎ後の _VerifyAssignments |
EventBus.cs | サブスクライバーリスト型イベントバス(リスナー最大 32 件)。RegisterListener/UnregisterListener/RaiseEvent。インプレース圧縮 |
ArrayUtils.cs | List<T> の代替機能:GameObject[] 用の Add、Contains、AddUnique、Remove、RemoveAt、Insert。int[] 用の FindIndex/ShuffleArray |
UndoableGameManager.cs | byte[] 状態履歴を使用した履歴/取り消し同期。NetworkCallable の _OwnerProcessMove/_OwnerUndo/_OwnerReset |
PackedStateSync.cs | 3 つの int を 1 つの Vector3 UdonSynced フィールドにパック。OnPreSerialization/OnDeserialization |
RateLimitedSync.cs | _syncLocked/_changeCounter を使用した 0.15 秒の同期クールダウン。_OnSyncUnlock コールバック |
DualCopySync.cs | _dirty フラグを使用したローカルコピーと同期コピー。OnPreSerialization/OnDeserialization を厳密に分離 |
BatchedSync.cs | 0.2 秒の BatchDelay を使用した冪等な ScheduleBatchedSync。遅延コールバックの _FlushBatch |
CloggedRetrySync.cs | Networking.IsClogged チェック。線形バックオフ(RetryDelay * retryCount)。MaxRetries=5 |
UdonSharpProgramAssetAutoGenerator.cs | 新しいスクリプト用の UdonSharpProgramAsset を自動作成する AssetPostprocessor |
フック
| フック | プラットフォーム | 用途 |
|---|---|---|
validate-udonsharp.ps1 | Windows(PowerShell) | PostToolUse の制約検証 |
validate-udonsharp.sh | Linux/macOS(Bash) | PostToolUse の制約検証 |
Bash バリデーターには jq が必要です。利用できない場合、フックは入力を変更せずにそのまま渡し、
検証が成功したと黙って報告する代わりに VALIDATOR-WARNING: validation skipped (JQ_UNAVAILABLE) を出力します。
クイックリファレンス
CHEATSHEET.md- 1 ページのクイックリファレンス