mcpField
G
godot-multiplayer

godot-multiplayer

github.com/gamedev-skills開発5.4k6.6k 回インストール今日更新
リポジトリ

godot-multiplayer について

godot-multiplayerは、Godot 4.7でネットワーク対応ゲームを作るためのスキルです。ENet接続、RPC、ノード権限、状態同期と、サーバー側での入力検証を扱います。

主な機能

  1. 01ENetホストとクライアントの設定
  2. 02@rpcによるリモート呼び出し
  3. 03ノード単位の権限設定
  4. 04ピア間のシーン生成と状態同期
  5. 05サーバー側での入力検証

活用シーン

  1. 01オンラインゲームのホストと参加
  2. 02プレイヤー入力のサーバー送信
  3. 03各ピアでのノード生成
  4. 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 を使用します。

基本的なワークフロー

  1. ピアを作成します(ENetMultiplayerPeer)。create_server(port, max) または create_client(ip, port) を呼び出し、multiplayer.multiplayer_peer に割り当てます。サーバーの一意な ID は常に 1 で、クライアントにはランダムな正の ID が割り当てられます。
  2. multiplayer の接続シグナルを処理します: peer_connected(id)、peer_disconnected(id)、connected_to_server、connection_failed、server_disconnected。
  3. @rpc(...) で RPC を定義します。 Callable に対して rpc()(全ピア)または rpc_id(peer_id)(1 つのピア)を呼び出します。関数内では multiplayer.get_remote_sender_id() で送信元を確認できます。
  4. スクリプトを実行するすべてのピアで、RPC のシグネチャを同一に保ちます。 Godot はスクリプト内のすべての @rpc メソッドのチェックサムを検証するため、不一致があると警告なしに動作しなくなります。
  5. ノードごとに set_multiplayer_authority(id) でオーソリティを割り当てます。 is_multiplayer_authority() で入力/RPC を制御します。
  6. MultiplayerSpawner(クライアント上でシーンを自動インスタンス化)と MultiplayerSynchronizer(選択したプロパティを自動同期)で状態を複製します。
  7. サーバーで検証します。 クライアントから報告された位置/結果を信用しないでください。

パターン

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 — ヘッドレス専用サーバービルドのエクスポート。

コメント