godot-multiplayer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGodot Multiplayer (4.x high-level)
Godot多人游戏(4.x高级版)
Connect peers, call functions remotely with , assign authority, and replicate state
with /. Targets Godot 4.3+ (ENet). Treat
all client input as untrusted; keep the server authoritative.
@rpcMultiplayerSpawnerMultiplayerSynchronizer连接对等端,使用远程调用函数,分配权限,并通过/复制状态。面向Godot 4.3+(基于ENet)。将所有客户端输入视为不可信;保持服务器的权威性。
@rpcMultiplayerSpawnerMultiplayerSynchronizerWhen to use
适用场景
- Use when adding networked multiplayer: hosting/joining over ENet, calling RPCs, assigning per-node authority, or auto-spawning/syncing nodes across peers.
When not to use: local split-screen (no networking); raw TCP/UDP/WebSocket protocol
work (low-level ); HTTP requests. For save/persistence → .
PacketPeersave-systems- 适用于添加联网多人游戏功能的场景:通过ENet托管/加入游戏、调用RPC、为每个节点分配权限,或在对等端之间自动生成/同步节点。
不适用场景:本地分屏游戏(无需网络);底层TCP/UDP/WebSocket协议开发(使用底层);HTTP请求。如需保存/持久化功能,请参考。
PacketPeersave-systemsCore workflow
核心工作流程
- Create a peer (), call
ENetMultiplayerPeerorcreate_server(port, max), and assign it tocreate_client(ip, port). The server's unique ID is alwaysmultiplayer.multiplayer_peer; clients get random positive IDs.1 - Handle connection signals on :
multiplayer,peer_connected(id),peer_disconnected(id),connected_to_server,connection_failed.server_disconnected - Define RPCs with . Call them on a
@rpc(...)viaCallable(all peers) orrpc()(one peer). Inside,rpc_id(peer_id)tells you who sent it.multiplayer.get_remote_sender_id() - Keep RPC signatures identical on every peer that runs the script — Godot checksums
all methods in a script; mismatches break silently.
@rpc - Assign authority per node with ; gate input/RPCs by
set_multiplayer_authority(id).is_multiplayer_authority() - Replicate state with (auto-instances scenes on clients) and
MultiplayerSpawner(auto-syncs selected properties).MultiplayerSynchronizer - Validate on the server. Don't trust client-reported positions/results.
- 创建对等端(),调用
ENetMultiplayerPeer或create_server(port, max),并将其分配给create_client(ip, port)。服务器的唯一ID始终为multiplayer.multiplayer_peer;客户端会获得随机的正整数ID。1 - 处理连接信号:监听上的
multiplayer、peer_connected(id)、peer_disconnected(id)、connected_to_server、connection_failed信号。server_disconnected - 定义RPC:使用注解。通过
@rpc(...)调用Callable(发送给所有对等端)或rpc()(发送给单个对等端)。在函数内部,可通过rpc_id(peer_id)获取发送方ID。multiplayer.get_remote_sender_id() - 保持RPC签名一致:运行该脚本的所有对等端上,RPC方法的签名必须完全相同——Godot会对脚本中所有方法进行校验和验证;不匹配会导致静默失败。
@rpc - 为节点分配权限:通过为每个节点设置权限;通过
set_multiplayer_authority(id)控制输入/RPC的执行。is_multiplayer_authority() - 复制状态:使用(在客户端自动实例化场景)和
MultiplayerSpawner(自动同步选定属性)。MultiplayerSynchronizer - 在服务器端验证:不要信任客户端上报的位置/结果。
Patterns
模式示例
1. Host or join (ENet)
1. 托管或加入游戏(ENet)
gdscript
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()gdscript
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. RPCs: client sends input to the server (any_peer, call_local)
2. RPC:客户端向服务器发送输入(any_peer, call_local)
gdscript
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)gdscript
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("fire") and is_multiplayer_authority():
request_fire.rpc_id(1) # 仅发送给服务器(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)
undefined@rpc("any_peer", "call_local", "reliable")
func request_fire() -> void:
var sender := multiplayer.get_remote_sender_id()
if not _can_fire(sender): # 服务器端验证
return
spawn_projectile.rpc(sender) # 通知所有对等端生成 projectile
@rpc("authority", "call_local", "reliable")
func spawn_projectile(owner_id: int) -> void:
_do_spawn(owner_id)
undefined3. Per-node authority (each player controls their own avatar)
3. 按节点分配权限(每个玩家控制自己的角色)
gdscript
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()gdscript
extends CharacterBody2D
func _ready() -> void:
# 节点名称为所属对等端的ID;该对等端拥有权限。
set_multiplayer_authority(name.to_int())
func _physics_process(delta: float) -> void:
if not is_multiplayer_authority():
return # 仅所有者可读取输入并移动角色
velocity = Input.get_vector("left", "right", "up", "down") * 200.0
move_and_slide()4. MultiplayerSynchronizer config (editor + replication)
4. MultiplayerSynchronizer配置(编辑器 + 复制)
gdscript
undefinedgdscript
undefinedAdd a MultiplayerSynchronizer child; in its Replication editor add the properties to
添加一个MultiplayerSynchronizer子节点;在其复制编辑器中添加需要同步的属性(例如position、velocity)。为每个属性设置“Sync”/“Spawn”标志。通过代码可设置可见范围:
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)
undefined@onready var sync: MultiplayerSynchronizer = $MultiplayerSynchronizer
func _ready() -> void:
# 仅向特定对等端复制此节点(例如私有信息)。
sync.set_visibility_for(target_peer_id, true)
undefinedPitfalls
常见陷阱
- RPC signature checksum. Every method in a script must exist with the same declaration on both client and server builds — even unused ones. A mismatch causes errors that may point at the wrong function. Argument names/count are not checked, but the set of RPCs and their annotations are.
@rpc - Default is
@rpc. Clients calling it are ignored unless you set"authority". Use"any_peer"so the host (also a player) runs it too."call_local" - NodePaths must match across peers. RPC routing uses the node's path/name; spawn nodes
with identical names on all peers (use or
MultiplayerSpawnerfor readable, deterministic names).add_child(node, true) - Trusting the client. Never let clients set authoritative state (health, position, hits) directly. Send intent, validate on the server, then broadcast results.
- RPC on non-Node classes fails. methods must be on
@rpc-derived classes, not plainNode/Resource.RefCounted - RPCs don't serialize Objects/Callables. Pass plain data (ints, strings, arrays, dictionaries, PackedArrays).
- Forgetting to reset the peer. To disconnect cleanly, set
.
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new() - Android needs INTERNET permission in the export preset or all networking is blocked.
- 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权限:在导出预设中添加INTERNET权限,否则所有网络功能会被阻止。
References
参考资料
- For setup, transfer modes/channels,
MultiplayerSpawnerauthentication (SceneMultiplayer/auth_callback), a lobby skeleton, and dedicated-server export notes, readcomplete_auth.references/replication-and-rpc.md
- 关于设置、传输模式/通道、
MultiplayerSpawner身份验证(SceneMultiplayer/auth_callback)、大厅框架以及专用服务器导出说明,请阅读complete_auth。references/replication-and-rpc.md
Related skills
相关技能
- — instancing the scenes that get spawned/synced.
godot-nodes-scenes - — connection signals and event flow.
godot-signals-groups - — exporting a headless dedicated server build.
godot-export
- —— 实例化需要生成/同步的场景。
godot-nodes-scenes - —— 连接信号和事件流。
godot-signals-groups - —— 导出无头专用服务器构建。
godot-export