scenario-godot-multiplayer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGodot multiplayer (network programmer)
Godot 多人联机(网络程序员)
Target: Godot 4.7.2, SceneMultiplayer over ENet and WebSocket.
Expert level here means the networked game is proven with several processes, under injected latency, before anyone plays it: authority is a written decision per object, every client message is a request the server checks, and replication cost is measured in KiB/s. This skill builds the replication in code, runs a server and 2 to 3 clients headless on localhost (plus a browser client), and passes only on numbers from those runs. If a sibling skill named here is missing from your available skills, ask the user to install it (); unattended, proceed from tool schemas and flag the gap.
npx skills add scenario-labs/skills --skill <name>REQUIRED BACKGROUND: scenario-godot-expert (channels, , review loop, 4.7 traps).
gd_runStatus (2026-10-02): 16 live tests (up to 3 clients, ENet, WebSocket, exported server, headless Chrome) and 18 offline tests pass. Evidence: .
tests/live_evidence/godot-multiplayer/目标:Godot 4.7.2,基于 ENet 和 WebSocket 的 SceneMultiplayer。
这里的专家级标准意味着:在任何人开始游玩之前,必须通过多个进程和注入延迟来验证联机游戏:每个对象的权限归属都形成书面决定,每条客户端消息都是服务器会检查的请求,并且复制开销以 KiB/s 衡量。该 skill 会用代码构建复制系统,在 localhost 上以 headless 方式运行一个服务器和 2 至 3 个客户端(另加一个浏览器客户端),并且只有当这些运行所得的数值达标时才通过。如果可用 skills 中缺少此处命名的同级 skill,请要求用户安装();在无人值守情况下,则依据工具 schema 继续,并指出缺口。
npx skills add scenario-labs/skills --skill <name>必需背景: scenario-godot-expert(channels、、review loop、4.7 traps)。
gd_run状态(2026-10-02): 16 项实时测试(最多 3 个客户端、ENet、WebSocket、导出的服务器、headless Chrome)和 18 项离线测试均已通过。证据:。
tests/live_evidence/godot-multiplayer/Stance (the expert delta)
立场(专家级差异)
- Decide authority per object before writing code. Someone must own each object's data (AndrooDev, jff9oxO8v1s [00:04:01]). Client authority over the body is fine for casual co-op; competitive or cheat-prone games keep the body on the server and give clients their input only (Tamas Galffy, iP_xdJ0peFo [00:03:46, 00:06:47]; BatteryAcidDev, GqHTNmRspjU [00:00:33]). Deciding condition: cost of cheating against cost of input lag. Measured at 250 ms RTT: server authority shows your own move after 294 to 310 ms, client authority after 11 to 22 ms, and a client-authority cheater's 50 m jump stuck.
- Set authority from the node name in . Name each player node with its peer id;
_enter_treecalls_enter_treeso it holds beforeset_multiplayer_authority(name.to_int())(Travis Hunter, tK2ACXUGcrY [00:46:16]). Do not read a spawn-synced property there: on every client copy measured,_readywas still 0 inpeer_id._enter_tree - Every RPC is a request. Read
any_peerfirst (it is 0 after anmultiplayer.get_remote_sender_id(), measured), check that the sender owns the target and that the values are possible, then act. A forged teleport for another player and a 30 m jump were both rejected in the live test.await - The RPC checksum compares method names only, whatever the docs say. The high-level docs say it covers every declaration and skips arguments; two live runs in 4.7.2 (M2, round 1 and round 2) disagree. A name missing on one side logs "The rpc node checksum failed" on both sides and RPCs are matched by sorted index: the client called
@rpcand the server ranb. A different mode only fails per call ("not allowed"), a different argument count fails per call ("expected 2 argument(s)"), differentaor transfer mode passes silently. Keep server and client on one script per node path (one codebase: Davide Di Staso, nyKBuM9Y_-Q).call_local - Test with latency and three players. Localhost hides every latency bug; two players hide what a bystander sees (Galffy, iP_xdJ0peFo [00:09:58, 00:42:31]). adds delay, jitter and loss on localhost without root.
gd_net.UdpLagProxy - Replication cost is a design input. ALWAYS sends every network frame whether or not the value changed; ON_CHANGE is reliable and costs more than ALWAYS while values move (measured: 72.6 against 100 KiB/s for 50 moving props). A headless server is uncapped: 145 fps here, 2.2 to 2.4 times the bandwidth of 60 fps. Cap it (,
--max-fps) or setEngine.max_fps. Cut by visibility (Di Staso [00:14:29]).replication_interval - Know which connection event fires where. On a joining client, fires once per existing peer, server id 1 included;
peer_connectedfires on clients only, so send client info there, not fromconnected_to_server(docs delta 7; FinePointCGI e0JLO_5UgQo [00:22:50]). After the server leaves,peer_connectedreads 0: skip id 0 in registries and spawn loops (pA9RGn87Uag [00:47:31]). All measured (M14).get_unique_id() - The server stops speed hacks, not wall hacks. Server authority blocks impossible moves and infinite health; it does not stop wall hacks or aimbots, because every client still receives everyone's position. Interest management (synchronizer visibility, server line-of-sight checks) limits the leak (MfjEB1cowsE [00:18:55]; iP_xdJ0peFo [00:53:28]).
- The dedicated server is the same project exported in "dedicated server" mode. That mode adds the feature, which forces headless display and dummy audio even without
dedicated_server(measured on the exported macOS binary), and Strip Visuals removed the 3.1 MB texture from the server pack (BatteryAcidDev, jgJuX04cq7k [00:04:47]).--headless
- 编写代码前逐对象决定权限归属。 每个对象的数据都必须有明确的拥有者(AndrooDev、jff9oxO8v1s [00:04:01])。在休闲合作游戏中,允许客户端拥有角色身体(body)的权限;竞技或容易出现作弊的游戏则应让身体由服务器掌控,客户端只提交输入(Tamas Galffy、iP_xdJ0peFo [00:03:46, 00:06:47];BatteryAcidDev、GqHTNmRspjU [00:00:33])。决策依据是作弊收益与输入延迟之间的成本权衡。在 250 ms RTT 下实测:服务器权限下,自己的移动在 294 至 310 ms 后可见;客户端权限下为 11 至 22 ms;而采用客户端权限的作弊者进行的 50 m 跳跃会生效。
- 在 中根据节点名称设置权限归属。 将每个玩家节点命名为其 peer id;
_enter_tree调用_enter_tree,从而在set_multiplayer_authority(name.to_int())之前完成归属设置(Travis Hunter、tK2ACXUGcrY [00:46:16])。不要在该处读取通过 spawn 同步的属性:在每个客户端副本中实测,_ready在peer_id时仍为 0。_enter_tree - 每个 RPC 都是请求。 先读取
any_peer(实测在multiplayer.get_remote_sender_id()之后它会变为 0),检查发送者是否拥有目标对象以及参数值是否合理,然后再执行。实测中,伪造其他玩家传送以及 30 m 跳跃均被拒绝。await - 无论文档如何表述,RPC checksum 只比较方法名。 高层文档称其涵盖每个 声明并忽略参数;但 4.7.2 中两次实时运行(M2,第 1 轮和第 2 轮)结果不一致。如果某一端缺少某个名称,两端都会记录“The rpc node checksum failed”,且 RPC 按排序后的索引进行匹配:客户端调用了
@rpc,服务器却执行了b。另一种 mode 只会导致单次调用失败(“not allowed”),参数数量不同会导致单次调用失败(“expected 2 argument(s)”),而不同的a或 transfer mode 会静默通过。让服务器与客户端对同一节点路径使用同一份脚本(单一代码库:Davide Di Staso、nyKBuM9Y_-Q)。call_local - 在有延迟且有三名玩家时测试。 localhost 会掩盖所有延迟问题;两名玩家会掩盖旁观者看到的问题(Galffy、iP_xdJ0peFo [00:09:58, 00:42:31])。可在 localhost 上增加延迟、抖动和丢包,且无需 root。
gd_net.UdpLagProxy - 复制成本是设计输入。 ALWAYS 无论值是否变化都会在每个网络帧发送;ON_CHANGE 是 reliable,且在值持续变化时成本高于 ALWAYS(实测:50 个移动道具分别为 72.6 对 100 KiB/s)。headless 服务器不限制帧率:此处达到 145 fps,带宽是 60 fps 的 2.2 至 2.4 倍。应限制帧率(、
--max-fps)或设置Engine.max_fps。通过可见性裁剪复制内容(Di Staso [00:14:29])。replication_interval - 清楚连接事件在哪里触发。 在加入的客户端上,会针对每个已存在 peer 触发一次,包括服务器 id 1;
peer_connected只在客户端触发,因此应在那里发送客户端信息,而不是在connected_to_server中发送(文档差异 7;FinePointCGI、e0JLO_5UgQo [00:22:50])。服务器离开后,peer_connected读取为 0:在注册表和生成循环中跳过 id 0(pA9RGn87Uag [00:47:31])。以上均为实测结果(M14)。get_unique_id() - 服务器能阻止速度作弊,但阻止不了 wall hacks。 服务器权限可阻止不可能的移动和无限生命值;但无法阻止 wall hacks 或 aimbots,因为每个客户端仍会收到所有人的位置。兴趣管理(synchronizer 可见性、服务器视线检查)可限制信息泄露(MfjEB1cowsE [00:18:55];iP_xdJ0peFo [00:53:28])。
- 专用服务器就是同一项目以“dedicated server”模式导出的结果。 该模式添加 feature,强制使用 headless 显示和 dummy audio,即使未传入
dedicated_server也是如此(在导出的 macOS binary 上实测);Strip Visuals 会从服务器包中移除 3.1 MB texture(BatteryAcidDev、jgJuX04cq7k [00:04:47])。--headless
Establish first
首先确定
Genre and player count; who may cheat (competitive, co-op, friends only); platforms (browser means WebSocket or WebRTC, no ENet); topology (dedicated server, listen server, relay or P2P); a backend already chosen (Steam, Nakama, Colyseus, own server); hosting budget (cloud costs money: ask before any deployment); tick and target RTT (default 60 Hz server, play tested at 100 and 250 ms). Defaults: one project, server authority with input-only clients for anything competitive, ENet for desktop and mobile, WebSocket behind TLS () for the web.
wss://游戏类型和玩家数量;谁可能作弊(竞技、合作、仅好友);平台(浏览器意味着使用 WebSocket 或 WebRTC,不能用 ENet);拓扑(dedicated server、listen server、relay 或 P2P);是否已选定 backend(Steam、Nakama、Colyseus、自建服务器);托管预算(云服务需要花钱:部署前先询问);tick 和目标 RTT(默认服务器 60 Hz,并在 100 和 250 ms 下进行游戏测试)。默认方案:单一项目;竞技类游戏一律采用服务器权限和仅输入客户端;桌面和移动端使用 ENet;Web 使用 TLS()保护的 WebSocket。
wss://Workflow
工作流
- Network design note. Per object: owner, what replicates (synchronizer property and mode), what is an event (RPC with mode, transfer and channel), what a client may request. Streams of unreliable_ordered updates get their own transfer channel, channel last in (docs deltas 4, 5); idle players send nothing below a velocity threshold (pA9RGn87Uag [00:42:16]). GATE: no object without an owner; no client-owned health, score or inventory unless the brief accepts cheating.
@rpc - Build the replication in code. , then
gd_net.install_netkit(P)(net_build.gd,make_sync) writes scenes withmake_spawnerset in code; the Replication panel is for humans (SceneReplicationConfig). Players: name = peer id,references/gui-paths.md, authority inadd_child(node, true). GATE:_enter_treehas no flags (root paths resolve, no Object or RID property, nonet_audit.gd:scenenames, intervals match modes).@Node@2 - Session test on localhost. runs a server and 2 to 3 clients, each in its own APFS clone, all machine slots held first. Cover the lobby gate, a late joiner, a leaver, cheat RPCs, and a password through
gd_net.session(P, roles)plusauth_callbackon both sides (P5). GATE: every client sees every player, the late joiner sees all, the leaver's node is freed everywhere, authority report correct, forged RPCs rejected, logs clean.complete_auth - Latency pass. Rerun through at 100 and 250 ms, then 250 ms with 30 ms jitter and 5 % loss;
UdpLagProxymeasures how far behind the server truth a remote client shows a player. GATE: the numbers fit the genre, or prediction is planned (netfox or own).replication_delay() - Bandwidth pass. Server KiB/s per client from ENet counters (in the result), per mode, interval and visibility. GATE: under the budget at max players, fps capped.
bandwidth - Web and transports. Same session with ; for a browser build, export Web and run the client in headless Chrome (procedure P9). WebSocket is TCP: "unreliable" RPCs arrive reliable and ordered, with head-of-line blocking under loss; WebRTC gives unreliable browser channels but needs signalling, STUN/TURN and webrtc-native on desktop (WebRTC doc; wgIqB6JNcro [00:19:35]). An HTTPS page needs
transport="websocket". A background tab stopswss://and the socket drops: build reconnect (web doc). GATE: the browser client joins, sees all players, RTT measured._process - Dedicated server. , export, compare client and server packs (
gd_net.server_preset()), run the exported binary withoutpack_reportand connect clients. Set--headlessfor systemd or journald logs (docs delta 12; default false, measured). GATE:application/run/flush_stdout_on_print=truefeature true, displaydedicated_server, no client textures in the pack, exit 0.headless - Look. A windowed observer client captures the replicated world (); open it. GATE: players where the server says, colors per peer, nothing missing.
capture_at
- 网络设计说明。 逐对象记录:所有者、复制内容(synchronizer 属性和 mode)、哪些内容属于事件(带 mode、transfer 和 channel 的 RPC)、客户端可以提出哪些请求。unreliable_ordered 更新流应使用独立 transfer channel,且 channel 放在 参数列表末尾(文档差异 4、5);速度低于阈值的闲置玩家不发送任何数据(pA9RGn87Uag [00:42:16])。GATE:任何对象都不能没有所有者;除非任务说明接受作弊,否则客户端不得拥有生命值、分数或背包。
@rpc - 用代码构建复制系统。 ,然后
gd_net.install_netkit(P)(net_build.gd、make_sync)通过代码写入场景并设置make_spawner;Replication 面板供人工使用(SceneReplicationConfig)。玩家:名称 = peer id,references/gui-paths.md,在add_child(node, true)中设置 authority。GATE:_enter_tree无任何 flags(根路径可解析、不含 Object 或 RID 属性、没有net_audit.gd:scene名称、间隔与 modes 匹配)。@Node@2 - 在 localhost 上进行 session test。 启动一个服务器和 2 至 3 个客户端,每个客户端使用独立的 APFS clone,并先占用所有机器槽位。覆盖大厅门槛、迟加入者、离开者、作弊 RPC,以及通过
gd_net.session(P, roles)和双方auth_callback实现的密码流程(P5)。GATE:每个客户端都能看到所有玩家;迟加入者能看到所有玩家;离开者的节点在所有位置都被释放;authority 报告正确;伪造 RPC 被拒绝;日志干净。complete_auth - 延迟测试。 通过 在 100 和 250 ms 下重新运行,然后在 250 ms 下加入 30 ms 抖动和 5% 丢包;
UdpLagProxy衡量远端客户端显示的玩家状态落后服务器真实状态多少。GATE:数值应符合游戏类型,否则应规划 prediction(netfox 或自行实现)。replication_delay() - 带宽测试。 通过 ENet counters 获取每客户端的服务器 KiB/s(结果中的 ),按 mode、interval 和 visibility 分别统计。GATE:在最大玩家数和 fps 受限条件下低于预算。
bandwidth - Web 与传输协议。 使用 运行相同 session;对于浏览器构建,导出 Web 并在 headless Chrome 中运行客户端(流程 P9)。WebSocket 是 TCP:“unreliable” RPC 实际上会可靠、有序到达,并在丢包时产生队头阻塞;WebRTC 可为浏览器提供不可靠 channel,但需要 signalling、STUN/TURN,且桌面端需要 webrtc-native(WebRTC doc;wgIqB6JNcro [00:19:35])。HTTPS 页面需要
transport="websocket"。后台标签页会停止wss://并断开 socket:应构建重连机制(web doc)。GATE:浏览器客户端能够加入、看到所有玩家且完成 RTT 测量。_process - 专用服务器。 ,导出,对比客户端和服务器包(
gd_net.server_preset()),在不带pack_report的情况下运行导出的 binary 并连接客户端。为 systemd 或 journald 日志设置--headless(文档差异 12;默认 false,实测)。GATE:application/run/flush_stdout_on_print=truefeature 为 true,显示为dedicated_server,包内无客户端 textures,并以状态码 0 退出。headless - 观察。 窗口模式的 observer client 捕获复制后的世界();打开它。GATE:玩家位置与服务器一致、颜色按 peer 区分且没有缺失。
capture_at
Harness in one call
一次调用完成测试框架
python
import sys; sys.path[:0] = ["<skills>/scenario-godot-expert/scripts", "<skills>/scenario-godot-multiplayer/scripts"]
import gd_net
gd_net.install_netkit(P); gd_net.build_scenes(P) # res://net/world.tscn, player.tscn, props
roles = [gd_net.role("server", role="server", port=24010, lobby_size=2),
gd_net.role("c1", role="client", port=24011, index=0, delay_s=0.3, cheat_at=2.0),
gd_net.role("c2", role="client", port=24011, index=1, delay_s=0.3)]
with gd_net.UdpLagProxy(24011, 24010, rtt_ms=100, jitter_ms=0, loss=0.0):
s = gd_net.session(P, roles) # one APFS clone and one Godot per role
s["roles"]["c1"]["result"]["rtt_median_ms"] # every NetLab number is in AGENT_RESULTYour own game uses the same pattern: a job script per role (), user args after , printed by each process. Keep ports unique per project; two roles never share a project folder.
role(name, script=...)--AGENT_RESULTpython
import sys; sys.path[:0] = ["<skills>/scenario-godot-expert/scripts", "<skills>/scenario-godot-multiplayer/scripts"]
import gd_net
gd_net.install_netkit(P); gd_net.build_scenes(P) # res://net/world.tscn, player.tscn, props
roles = [gd_net.role("server", role="server", port=24010, lobby_size=2),
gd_net.role("c1", role="client", port=24011, index=0, delay_s=0.3, cheat_at=2.0),
gd_net.role("c2", role="client", port=24011, index=1, delay_s=0.3)]
with gd_net.UdpLagProxy(24011, 24010, rtt_ms=100, jitter_ms=0, loss=0.0):
s = gd_net.session(P, roles) # one APFS clone and one Godot per role
s["roles"]["c1"]["result"]["rtt_median_ms"] # every NetLab number is in AGENT_RESULT你自己的游戏也使用相同模式:每个 role 使用一个 job script(),用户参数放在 之后,每个进程都会输出 。每个项目应使用唯一端口;两个 role 不得共用项目文件夹。
role(name, script=...)--AGENT_RESULTPrediction, rollback and backends (not run here)
预测、回滚与后端(此处未运行)
netfox gives server authority with client prediction and rollback: input gathered on the network tick, logic in , around , for display (GqHTNmRspjU [00:06:58, 00:18:55, 00:21:24]; iP_xdJ0peFo [00:28:00]). Prove it on a small prototype first: it is opinionated (GqHTNmRspjU [00:34:53]). Deterministic input-only rollback fits fighting and RTS-like games with 2 to 8 players (David Snopek, zvqQPbT8rAE). Steam (GodotSteam, SteamMultiplayerPeer), Nakama, Colyseus and WebRTC P2P swap the peer and lobby calls; authority, spawner and synchronizer code stays the same (Gwizz, fUBdnocrc3Y; AndrooDev, wgIqB6JNcro [00:07:18]). None of these ran here: they need a third-party addon, an account or a signalling server. Verify against the installed release before quoting an API.
_rollback_tickNetworkTime.physics_factormove_and_slideTickInterpolatornetfox 提供服务器权限下的客户端 prediction 和 rollback:在网络 tick 上收集输入,在 中执行逻辑,在 周围使用 ,并使用 进行显示(GqHTNmRspjU [00:06:58, 00:18:55, 00:21:24];iP_xdJ0peFo [00:28:00])。应先在小型 prototype 上验证:它的设计取向非常强势(GqHTNmRspjU [00:34:53])。确定性的 input-only rollback 适合 2 至 8 人的格斗和类 RTS 游戏(David Snopek、zvqQPbT8rAE)。Steam(GodotSteam、SteamMultiplayerPeer)、Nakama、Colyseus 和 WebRTC P2P 只需替换 peer 和 lobby 调用;authority、spawner 和 synchronizer 代码保持不变(Gwizz、fUBdnocrc3Y;AndrooDev、wgIqB6JNcro [00:07:18])。此处未运行上述方案:它们需要第三方 addon、账户或 signalling server。引用 API 前,应针对已安装的版本进行验证。
_rollback_tickmove_and_slideNetworkTime.physics_factorTickInterpolatorNumbers
数值
| Value | Measured here (2026-10-02, M-series Mac, localhost) | Relative to |
|---|---|---|
| RPC round trip, no proxy | 16 to 19 ms | 60 fps both ends; one frame each way dominates |
| ENet RTT statistic | 15 to 23 ms | same |
| Own input to visible motion, server authority | 47 to 52 ms | about 3 frames |
| Remote view behind server truth | 20 to 30 ms, 0.07 m error at 3 m/s | no proxy |
| Same at 100 / 250 ms RTT | 70 to 80 / 150 to 155 ms; 0.22 / 0.44 m | |
| 50 props, ALWAYS, 60 fps | 72.6 KiB/s, moving or idle | 1 client |
| ON_CHANGE moving / idle | 98 to 101 / 2.3 KiB/s | same |
ALWAYS, | 21 to 22 KiB/s | same |
| ALWAYS, uncapped headless server (145 fps) | 160 to 175 KiB/s | same |
| 3.0 s; 1.50 s after setting 1.5 | server |
| Web export, single-thread | 40 MB, wasm 39.5 MB (10.1 MB gzip) | handoff to scenario-godot-performance-export |
| Dedicated server pack / client pack | 0.11 / 3.27 MB (3.1 MB texture stripped) | same project |
| 0 = unlimited (default); limit 2: third | M14; raise it to max players (jgJuX04cq7k [00:18:34]) |
| Value | Measured here (2026-10-02, M-series Mac, localhost) | Relative to |
|---|---|---|
| RPC 往返,无代理 | 16 至 19 ms | 两端均为 60 fps;每个方向一帧的延迟占主导 |
| ENet RTT 统计值 | 15 至 23 ms | 相同 |
| 从自身输入到可见移动,服务器权限 | 47 至 52 ms | 约 3 帧 |
| 远端视图落后服务器真实状态 | 20 至 30 ms,3 m/s 时误差为 0.07 m | 无代理 |
| 100 / 250 ms RTT 下的相同数值 | 70 至 80 / 150 至 155 ms;0.22 / 0.44 m | |
| 50 个道具,ALWAYS,60 fps | 72.6 KiB/s,无论移动或静止 | 1 个客户端 |
| ON_CHANGE,移动 / 静止 | 98 至 101 / 2.3 KiB/s | 相同 |
ALWAYS, | 21 至 22 KiB/s | 相同 |
| ALWAYS,未限帧的 headless 服务器(145 fps) | 160 至 175 KiB/s | 相同 |
默认 | 3.0 s;设置为 1.5 后为 1.50 s | 服务器 |
| Web 导出,单线程 | 40 MB,wasm 39.5 MB(gzip 后 10.1 MB) | 移交给 scenario-godot-performance-export |
| 专用服务器包 / 客户端包 | 0.11 / 3.27 MB(已剥离 3.1 MB texture) | 同一项目 |
| 0 = 无限制(默认);限制为 2 时:第三次 | M14;提高到最大玩家数(jgJuX04cq7k [00:18:34]) |
Quality gates
质量门槛
- Measurable: flags empty; every role
net_auditwith no unexpected engine error;okequals the player count everywhere; authority body 1, input = peer; teleport counts as expected; RTT andplayers_seen_maxat 100 and 250 ms; KiB/s per mode;replication_delayreviewed,rpc_auditok; exported server boot dict correct.rpc_pair_check - Visual: observer capture shows every player; under 250 ms no streak after a teleport; the browser screenshot shows the replicated players.
- 可量化:无任何 flags;每个 role 均为
net_audit,且没有意外引擎错误;所有位置的ok都等于玩家数量;authority 报告为 body 1、input = peer;teleport 次数符合预期;记录 100 和 250 ms 下的 RTT 与players_seen_max;记录各 mode 的 KiB/s;审核replication_delay,且rpc_audit为 ok;导出的服务器启动字典正确。rpc_pair_check - 视觉:observer capture 显示所有玩家;在 250 ms 下,teleport 后没有拖影;浏览器截图显示已复制的玩家。
Common mistakes
常见错误
| Mistake | What it looks like | Fix |
|---|---|---|
Players spawned only on the server without a spawner, or spawner | client sees nobody | |
Authority read from a synced property in | authority 1 everywhere on clients | authority from |
Runtime node without | | readable names |
| sender 0, validation passes or fails wrongly | read the sender first |
| RPC added on the server script only | checksum error, the wrong method runs | one script, or |
| Object or Resource as RPC argument | no error; receiver gets | send ids, paths or plain data |
| Client owns its body in a competitive game | speed and teleport hacks stick | input-only authority plus server simulation |
| Headless server not capped | 2.4 times the bandwidth | |
| "Attempt to call RPC with unknown peer ID" | keep relay on, or route through the server |
| Freeing a networked branch in the wrong order | "isn't currently active", "Node not found" | offline peer, free contents, drop custom API, free branch |
| Server export in normal mode | full-size pack, window opens | dedicated server export mode, Strip Visuals |
Server start inside | works from the editor; the release export never listens | |
Client info sent from | duplicate nodes on late joiners, a phantom player | |
| Client and server on different Godot versions | connection or protocol failures | same 4.7.2 build (protocol changed in 4.3) |
| Mistake | What it looks like | Fix |
|---|---|---|
仅在服务器上生成玩家但未使用 spawner,或 spawner 的 | 客户端看不到任何人 | 使用带 |
在 | 客户端上的 authority 全为 1 | 根据 |
运行时节点未使用 | 出现 | 使用可读名称 |
在 | sender 为 0,验证错误地通过或失败 | 先读取 sender |
| RPC 仅添加到服务器脚本中 | checksum 错误,执行了错误的方法 | 使用单一脚本,或运行 |
| 将 Object 或 Resource 作为 RPC 参数 | 不报错;接收方收到 | 发送 ids、paths 或普通数据 |
| 竞技游戏中由客户端拥有身体权限 | 速度与传送作弊会生效 | 使用仅输入权限和服务器模拟 |
| 未限制 headless 服务器帧率 | 带宽达到 2.4 倍 | 使用 |
为 P2P 式功能关闭 | 出现“Attempt to call RPC with unknown peer ID” | 保持 relay 开启,或通过服务器进行路由 |
| 以错误顺序释放 networked branch | 出现“isn't currently active”或“Node not found” | 将 peer 设为 offline,释放 contents,丢弃自定义 API,再释放 branch |
| 以普通模式导出服务器 | 包体积完整,窗口被打开 | 使用 dedicated server 导出模式和 Strip Visuals |
在 | 编辑器中正常,release 导出版本从不监听端口 | 使用 |
从 | 迟加入者出现重复节点或幽灵玩家 | 使用 |
| 客户端与服务器使用不同的 Godot 版本 | 连接或协议失败 | 使用相同的 4.7.2 构建(4.3 时协议发生过变化) |
Handoffs
交接
- Receives: the game scene and player controller from scenario-godot-gameplay and scenario-godot-3d-world or scenario-godot-2d; architecture rules from scenario-godot-architecture.
- Delivers: network design note, kit scenes or scripts, session evidence JSON, server preset; the web build size and headers go to scenario-godot-performance-export, CI jobs to scenario-godot-pipeline-automation, lobby screens to scenario-godot-ui.
- 接收:来自 scenario-godot-gameplay 以及 scenario-godot-3d-world 或 scenario-godot-2d 的游戏场景和玩家控制器;来自 scenario-godot-architecture 的架构规则。
- 交付:网络设计说明、kit 场景或脚本、session 证据 JSON、服务器 preset;Web 构建体积和 headers 移交给 scenario-godot-performance-export,CI jobs 移交给 scenario-godot-pipeline-automation,大厅界面移交给 scenario-godot-ui。
Godot 4.7 notes
Godot 4.7 注意事项
- became
get_rpc_config(4.5);get_node_rpc_configtables live on@rpc.Script.get_rpc_config() - is the property; the docs page spells
auth_timeout.auth_timout - 4.7.2 fixed peers that stopped replicating after deleting a spawner-spawned node.
- Godot 3 names (,
NetworkedMultiplayerENet,remote,rset) do not exist;get_rpc_sender_idflags them.gd_net.rpc_audit - WebRTC on desktop needs the webrtc-native extension: returns OK and only logs an error without it (measured).
initialize() - Open: under heavy machine load, 4 of 20 ALWAYS runs sent about 10 packets/s instead of 68 (ENet throttle at 0). Log in long sessions (P8).
NetUtil.enet_throttle() - Two peers leaving in one server frame log "Unable to send packet on channel 0" (ENet) or (WebSocket); harmless, whitelisted by exact text.
ready_state != STATE_OPEN
- 已更名为
get_rpc_config(4.5);get_node_rpc_config表位于@rpc。Script.get_rpc_config() - 是正确属性名;文档页面将其拼写为
auth_timeout。auth_timout - 4.7.2 修复了删除 spawner 生成节点后停止复制的问题。
- Godot 3 的名称(、
NetworkedMultiplayerENet、remote、rset)不存在;get_rpc_sender_id会标记这些名称。gd_net.rpc_audit - 桌面端 WebRTC 需要 webrtc-native extension:缺少该 extension 时,会返回 OK,但只记录错误(实测)。
initialize() - 尚未解决:在机器负载较高时,20 次 ALWAYS 运行中有 4 次只发送约 10 packets/s,而非 68 packets/s(ENet throttle 为 0)。在长时间 session 中记录 (P8)。
NetUtil.enet_throttle() - 两个 peer 在同一服务器帧内离开时,会记录“Unable to send packet on channel 0”(ENet)或 (WebSocket);无害,已按确切文本加入白名单。
ready_state != STATE_OPEN
References
参考资料
- : P1 to P14 with code, test ids and results.
references/procedures.md - : claims by expert with timestamps and verified corrections.
references/expert-notes.md - ,
references/critique.md(Replication panel, Run Instances, Network Profiler),references/gui-paths.md.references/sources.md - ,
scripts/gd_net.py: the harness and kit.scripts/agentkit/multiplayer/
- :P1 至 P14,包含代码、测试 ID 和结果。
references/procedures.md - :专家观点、时间戳和已验证的修正。
references/expert-notes.md - 、
references/critique.md(Replication 面板、Run Instances、Network Profiler)、references/gui-paths.md。references/sources.md - 、
scripts/gd_net.py:测试框架和 kit。scripts/agentkit/multiplayer/