3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】Netcode for GameObjectsを使っていてServerRPCの戻り値が欲しい時 NetcodeGameObjectRpcAsync で “ちょうど良い” 非同期 RPC を実現する

Posted at

なぜ “戻り値つき RPC” が要るのか

2025 年現在、Netcode for GameObjects(以下 UNGO)の公式 RPC API は 戻り値をサポートしていません
旧 UNet 時代に存在した RpcResponse<T> 系 API は 完全に廃止され、代替案として「ServerRpcClientRpc の 2 段構えで値を送り返す」パターンを推奨すると明言されています。(Unity Multiplayer)

しかし実際の開発では――

  • サーバーに権限確認(例 : アイテムを拾って良い?)
  • サーバーだけが知る一時的な値取得(例 : マッチメイキングで割り当てられたチーム番号)

といった “1 回こっきりで値が欲しい” ケースが日常的に現れます。毎回 ServerRpc/ClientRpc を手書きし、UniTaskCompletionSource と Request ID を管理するのは 型安全でも生産的でもありません


NetcodeGameObjectRpcAsync とは

そこで作成したのが NetcodeGameObjectRpcAsync
https://github.com/harayuu9/NetcodeGameObjectRpcAsync

キーアイデア

  1. Source Generator呼び側RPC ラッパ も自動生成
  2. UniTask<T> で async/await フレンドリー
  3. サーバー実行時は RPC を迂回 – 同期呼び出しでオーバーヘッドゼロ
  4. Request ID と Task 管理を共通基盤に集約 – 重複コード撲滅

コンパイル順序的にも安全です。Roslyn Source Generator は C# コンパイルの 前段、UNGO の ILPostProcessor は 後段 で実行されるため、相互干渉しません。


使い方 ─ たった 3 ステップ

前提:Netcode v2.2 以降 / Unity 6000.1 LTS 以降 / UniTask

  1. パッケージを導入

    "com.github.harayuu9.netcodegameobjectrpcasync": "https://github.com/harayuu9/NetcodeGameObjectRpcAsync.git"
    
  2. NetworkBehaviour に属性を付与

    [RpcAsyncGenerator]
    public partial class PlayerController : NetworkBehaviour {  }
    
  3. “Core” メソッドを書く

    [RpcAwaitable]
    private bool TryPickupItemCore(int itemId) {  }
    

あとは await TryPickupItemAsync(itemId) を呼ぶだけ。自動生成コードは先頭に示した通りです。
フルサンプルコードはこちらをご覧ください


自動生成されるコードのポイント

処理 生成コードでの実装
サーバー直呼び最適化 if (IsServer) { … return UniTask.FromResult(result); }
Request ID 生成 RpcManager.GetNextRequestId()
キャンセル対応 cancellationToken.Register(() => …) で pending Task を安全に破棄
単一クライアントへのレスポンス RpcTarget.Single(senderClientId, RpcTargetUse.Temp)
例外伝搬 サーバー側 catchTrySetException

生成されたメソッド名先頭の __ は「コード生成物」を示す慣習的プレフィクスで、手書きコードとの衝突を避けています。


サポート範囲と設計上の制約

項目 詳細
戻り値型 bool, int, float, FixedString*, INetworkSerializable 実装構造体など UNGO が送れる型。ジェネリック T も同条件で可。
引数 同上。可変長配列 / List 等は未サポート(Netcode の伝送制限に準拠)。
実装場所 NetworkBehaviour 内の private/protected メソッドのみ。UNGO の RPC 制限に合わせ、外部 static メソッドや拡張メソッドはラップ不可。
並列リクエスト 1 メソッドにつき 同一クライアントから複数同時発行可RpcManagerrequestIndex で多重対応。

パフォーマンスとネットワーク負荷

  • 成功ケース 1 往復ServerRpcClientRpc のみ
  • 失敗ケースも 1 往復:例外情報は boolean flag で送信、スタックトレースはローカル log に残す方針
  • Direct Call:Host モードでは RPC を完全スキップ。メモリ確保なし、GC0 世代圧縮なし。
  • ID 管理ulong インクリメントで 2^64 – 1 コールまで衝突なし(≒枯渇不可)。

導入上の Tips

シナリオ 推奨アプローチ
権限昇格のトグル(例 : Admin UI) await SetAdminAsync(targetPlayerId, true) で即返、NetworkVariable に二重書きしない
ロード中のみ必要なデータ await GetLobbySeedAsync() で受け取ったらメモリにキャッシュし、RPC 経路は破棄
頻繁ポーリング 毎フレーム呼ぶ必要がある場合は NetworkVariableNetworkList へ移行推奨(帯域節約)

まとめ

「RPC に戻り値がない」という UNGO の設計制約を、ソースコード 3 行で超える。

  • 生産性:ボイラープレートを書かずに await 可能。
  • 安全性:型安全・例外転送・キャンセル対応。
  • 効率:サーバー直呼び最適化+1 往復のみの軽量通信。

ゲームプレイロジックを書きたいだけなのに戻り値問題でネットワーク層と格闘している」――そんな煩わしさを解決するものです。

リポジトリ:https://github.com/harayuu9/NetcodeGameObjectRpcAsync (Star 歓迎!)


3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?