RPC
レプリケーションが処理するのは、時間と共に変化する「継続的な状態」(位置・体力・スコアなど)です。しかし、ゲームには「一度きりのイベント」(武器の射撃・チャットメッセージの送信・スキルの発動など)も必要です。リモートプロシージャコール(RPC)はこのギャップを埋めるもので、同期バッファには何も保存せずに、クライアントが他のクライアント上で関数を呼び出せるようにします。
RPCは「撃ちっ放し(fire-and-forget)」のため、一度配信されると保持されません。RPCが送信された後に参加したクライアントは、そのRPCを受信しません。途中参加したクライアントでも状態を維持する必要がある場合は、プロパティを複製してください。
概要
FusionのRPCは、FusionClientから送信されます。ルーティングは自動的に行われ、呼び出す関数がFusionReplicatorを子ノードに持つノードに属している場合はオブジェクト対象RPCとなり、それ以外はブロードキャストRPCとなります。
すべてのRPCメソッドはFusionClientに存在します。受信関数には、通常通り@rpcアノテーションを追加してください。
3つの呼び出し形式
rpc() - 全員に送信
GDScript
FusionClient.rpc(my_method, arg1, arg2)
すべてのピアに送信します(rpc_to(FusionClient.TARGET_ALL, ...)と同等です)。
rpc_to() - 列挙型で指定する対象に送信
GDScript
FusionClient.rpc_to(FusionClient.TARGET_MASTER, my_method, arg1)
FusionClient.rpc_to(FusionClient.TARGET_OWNER, my_method, arg1) # オブジェクト対象RPCのみ
FusionClient.rpc_to(FusionClient.TARGET_PLUGIN, my_method, arg1)
第一引数はFusionClient.RpcTarget列挙型の値です。
rpc_to_player() - 特定のプレイヤーに送信
GDScript
FusionClient.rpc_to_player(player_id, my_method, arg1, arg2)
数値のID(0より大きい値が必須)を指定して、特定プレイヤーを対象にします。
RpcTarget列挙型
すべてFusionClientの定数です。
| 定数 | 説明 |
|---|---|
TARGET_ALL |
すべてのピア(デフォルト) |
TARGET_MASTER |
マスタークライアントのみ |
TARGET_PLUGIN |
サーバープラグインのみ(カスタムPhotonプラグイン) |
TARGET_OWNER |
オブジェクトの所有者のみ - オブジェクト対象RPCのみで使用可能、ブロードキャストRPCではエラー |
ルーティング:オブジェクト対象 vs ブロードキャスト
ルーティングは、呼び出す関数のオブジェクトによって自動的に決定されます。
- オブジェクト対象RPC:呼び出す関数のオブジェクトの子ノードに
FusionReplicatorがある場合、RPCはリモートクライアント上のそのネットワークオブジェクトに送信されます。 - ブロードキャストRPC:呼び出す関数のオブジェクトが
nullまたはFusionReplicatorがない場合、RPCは登録されたすべてのブロードキャストレシーバーに配信されます。
オブジェクト対象RPC
オブジェクト対象RPCは、クライアント間で特定のネットワークオブジェクトのメソッドを呼び出します。呼び出す関数は、FusionReplicatorの子ノードを持つノードに属している必要があります。
GDScript
@rpc("any_peer", "call_local")
func take_damage(amount: int):
health -= amount
func attack():
# 呼び出す関数がこのノードに属しているので、FusionReplicatorによってルーティングされる
FusionClient.rpc(take_damage, 10)
# 所有者にのみ送信
FusionClient.rpc_to(FusionClient.TARGET_OWNER, take_damage, 10)
ブロードキャストRPC
ブロードキャストRPCは、特定のネットワークオブジェクトを対象とせずに、すべてのクライアントにメッセージを配信します。受信ノードを登録し、FusionClient経由で送信します。
GDScript
func _ready():
FusionClient.register_broadcast_receiver(self)
func _exit_tree():
if FusionClient:
FusionClient.unregister_broadcast_receiver(self)
@rpc("any_peer", "call_local")
func chat_message(sender: String, text: String):
print("[%s]: %s" % [sender, text])
func send_chat(text: String):
FusionClient.rpc(chat_message, sender, text)
クラッシュを防ぐため、必ず_exit_tree()でブロードキャストレシーバーの登録を解除してください。
@rpcアノテーション
Godotの@rpcアノテーションによって、送信を許可する対象・呼び出す関数が送信者のローカルで実装されるかどうかを設定できます。
GDScript
@rpc("any_peer", "call_local") # どのピアでも送信可能、ローカルで実行される
@rpc("authority") # 権限者のみ送信可能(デフォルト)
@rpc("any_peer", "call_remote") # どのピアでも送信可能、リモートでのみ実行される
- Mode:
"authority"は送信前にhas_authority()をチェックします。"any_peer"は誰でも送信が許可されます。 - Sync:
"call_remote"(デフォルト)はリモートにのみ送信されます。"call_local"は送信直後に送信者でも実行されます。
サポートする引数型
FusionのRPCは、ほとんどのGodot組み込み型に加え、ネットワークオブジェクトのノード参照をサポートしています。
bool, int, float, String,Vector2, Vector3, Vector4, Quaternion, Color, PackedByteArray, Array, Dictionary, ネットワークオブジェクトのNode参照(FusionのObjectIdにエンコードされる)
RPCが到着する前にオブジェクトがデスポーンした場合、受信時にNode参照がnullになることがあります。