mcpField
G
godot-multiplayer

godot-multiplayer

github.com/gamedev-skills开发5.4k6.6k 次安装1 天前更新
代码仓库

关于 godot-multiplayer

godot-multiplayer 是面向 Godot 4.7 联机游戏开发的技能,涵盖 ENet 连接、RPC、节点权限和状态复制,并说明如何在服务器端验证客户端输入。

主要功能

  1. 01配置 ENet 主机与客户端
  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、分配节点权限,或在对等方之间自动生成/同步节点。

不适用场景: 本地分屏(无网络);原始 TCP/UDP/WebSocket 协议处理(低级 PacketPeer);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)(单个对等方)。在函数内部,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 方法必须属于派生自 Node 的类,不能属于普通的 Resource/RefCounted。
  • 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