godot-multiplayer について
godot-multiplayerは、Godot 4.7でネットワーク対応ゲームを作るためのスキルです。ENet接続、RPC、ノード権限、状態同期と、サーバー側での入力検証を扱います。
主な機能
- 01ENetホストとクライアントの設定
- 02@rpcによるリモート呼び出し
- 03ノード単位の権限設定
- 04ピア間のシーン生成と状態同期
- 05サーバー側での入力検証
活用シーン
- 01オンラインゲームのホストと参加
- 02プレイヤー入力のサーバー送信
- 03各ピアでのノード生成
- 04選択したノードプロパティの同期
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill godot-multiplayerインストール後、Claude Code で/godot-multiplayerを入力して読み込まれたか確認します。
同梱ファイルreferences/replication-and-rpc.md
詳細
Godot Multiplayer(4.x ハイレベル)
ピアを接続し、@rpc で関数をリモート呼び出しし、オーソリティを割り当て、MultiplayerSpawner/MultiplayerSynchronizer で状態を複製します。対象は Godot 4.7(ENet)です。すべてのクライアント入力は信頼できないものとして扱い、サーバーをオーソリティにしてください。
使用する場面
- ネットワーク型マルチプレイヤーを追加する場合に使用します。ENet 経由でのホスト/参加、RPC の呼び出し、ノードごとのオーソリティ割り当て、またはピア間でのノードの自動スポーン/同期が対象です。
使用しない場面: ローカルの画面分割(ネットワーク不要)、低レベルの PacketPeer を使った生の TCP/UDP/WebSocket プロトコル処理、HTTP リクエスト。セーブ/永続化には save-systems を使用します。
基本的なワークフロー
- ピアを作成します(
ENetMultiplayerPeer)。create_server(port, max)またはcreate_client(ip, port)を呼び出し、multiplayer.multiplayer_peerに割り当てます。サーバーの一意な ID は常に1で、クライアントにはランダムな正の ID が割り当てられます。 multiplayerの接続シグナルを処理します:peer_connected(id)、peer_disconnected(id)、connected_to_server、connection_failed、server_disconnected。@rpc(...)で RPC を定義します。Callableに対してrpc()(全ピア)またはrpc_id(peer_id)(1 つのピア)を呼び出します。関数内ではmultiplayer.get_remote_sender_id()で送信元を確認できます。- スクリプトを実行するすべてのピアで、RPC のシグネチャを同一に保ちます。 Godot はスクリプト内のすべての
@rpcメソッドのチェックサムを検証するため、不一致があると警告なしに動作しなくなります。 - ノードごとに
set_multiplayer_authority(id)でオーソリティを割り当てます。is_multiplayer_authority()で入力/RPC を制御します。 MultiplayerSpawner(クライアント上でシーンを自動インスタンス化)とMultiplayerSynchronizer(選択したプロパティを自動同期)で状態を複製します。- サーバーで検証します。 クライアントから報告された位置/結果を信用しないでください。
パターン
1. ホストまたは参加(ENet)
const PORT := 7000
const MAX_PLAYERS := 8
func host() -> void:
var peer := ENetMultiplayerPeer.new()
var err := peer.create_server(PORT, MAX_PLAYERS)
if err != OK:
push_error("Cannot host: %s" % err); return
multiplayer.multiplayer_peer = peer
multiplayer.peer_connected.connect(_on_peer_connected)
func join(ip := "127.0.0.1") -> void:
var peer := ENetMultiplayerPeer.new()
peer.create_client(ip, PORT)
multiplayer.multiplayer_peer = peer
multiplayer.connected_to_server.connect(func(): print("connected"))
func leave() -> void:
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
2. RPC:クライアントからサーバーに入力を送信(any_peer、call_local)
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("fire") and is_multiplayer_authority():
request_fire.rpc_id(1) # send only to the server (id 1)
# Clients may call this; it runs on the server (and locally if server is a player).
@rpc("any_peer", "call_local", "reliable")
func request_fire() -> void:
var sender := multiplayer.get_remote_sender_id()
if not _can_fire(sender): # server-side validation
return
spawn_projectile.rpc(sender) # tell everyone to spawn it
@rpc("authority", "call_local", "reliable")
func spawn_projectile(owner_id: int) -> void:
_do_spawn(owner_id)
3. ノードごとのオーソリティ(各プレイヤーが自分のアバターを操作)
extends CharacterBody2D
func _ready() -> void:
# The node name is the owning peer's id; that peer is the authority.
set_multiplayer_authority(name.to_int())
func _physics_process(delta: float) -> void:
if not is_multiplayer_authority():
return # only the owner reads input & moves
velocity = Input.get_vector("left", "right", "up", "down") * 200.0
move_and_slide()
4. MultiplayerSynchronizer の設定(エディター+レプリケーション)
# Add a MultiplayerSynchronizer child; in its Replication editor add the properties to
# sync (e.g. position, velocity). Set "Sync"/"Spawn" flags per property. From code you
# can scope visibility:
@onready var sync: MultiplayerSynchronizer = $MultiplayerSynchronizer
func _ready() -> void:
# Only replicate this node to a specific peer (e.g. private info).
sync.set_visibility_for(target_peer_id, true)
注意点
- RPC シグネチャのチェックサム。 スクリプト内のすべての
@rpcメソッドは、使用されていないものも含めて、クライアントとサーバーのビルドの両方に同じ宣言で存在する必要があります。不一致があると、別の関数を指しているように見えるエラーが発生する場合があります。引数の名前/数は検証されませんが、RPC の種類とアノテーションは検証されます。 @rpcのデフォルトは"authority"です。"any_peer"を設定しない限り、クライアントから呼び出しても無視されます。ホストもプレイヤーとして実行するには"call_local"を使用します。- ピア間で NodePath を一致させる必要があります。 RPC のルーティングにはノードのパス/名前が使われます。すべてのピアで同一の名前でノードをスポーンしてください(
MultiplayerSpawnerを使うか、読みやすく決定的な名前にはadd_child(node, true)を使います)。 - クライアントを信用しないでください。 クライアントに権威のある状態(体力、位置、ヒット数)を直接設定させてはいけません。意図を送信し、サーバーで検証してから、結果をブロードキャストします。
- Node 以外のクラスで RPC を使うと失敗します。
@rpcメソッドはResource/RefCountedなどの通常クラスではなく、Node派生クラスに定義する必要があります。 - RPC は Objects/Callables をシリアライズできません。 通常のデータ(整数、文字列、配列、辞書、PackedArrays)を渡してください。
- ピアのリセットを忘れないでください。 正しく切断するには、
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()と設定します。 - Android では INTERNET 権限が必要です。 エクスポートプリセットで設定しないと、すべてのネットワーク通信がブロックされます。
参考資料
MultiplayerSpawnerの設定、転送モード/チャンネル、SceneMultiplayerの認証(auth_callback/complete_auth)、ロビーの基本構成、専用サーバーのエクスポートに関する注意点については、references/replication-and-rpc.mdを参照してください。
関連スキル
godot-nodes-scenes— スポーン/同期するシーンのインスタンス化。godot-signals-groups— 接続シグナルとイベントフロー。godot-export— ヘッドレス専用サーバービルドのエクスポート。
コメント
Markdown 対応