5.6 KiB
5.6 KiB
2026-09-22
给 Godot 项目 agame 接上局域网联机(ENet 基础版)
全流程通过 godot-ai MCP 操作编辑器完成,E:\GD_Projects\agame 项目。
落地结果
- 新增
autoload/net.gd(Autoload 名Net):传输层 + 开局/加入/断开 + 玩家生成回收 + 主菜单/HUD(代码建 UI,无 .tscn)。 - 新增
world/main.gd:把player.tscn注册给MultiplayerSpawner.spawn_function,spawn_function里set_multiplayer_authority(peer_id, true)+add_to_group("net_player")。 - 新增
player/player_sync.tres(SceneReplicationConfig),同步字段:.:position、Body:rotation,replication_mode = 1(ALWAYS)。 player/player.tscn:根下加Sync(MultiplayerSynchronizer,root_path保持默认..),绑定上面那个 .tres。world/main.tscn:删掉硬编码的 Player 实例,改挂MultiplayerSpawner(spawn_path = ..)。player/player.gd:加_is_local;远端玩家camera_rig.queue_free()+ 关物理 + 关 unhandled input。- 新增
tests/test_net_replication.gd(McpTestSuite),3 个用例 12 条断言全绿,钉住同步配置不被静默写坏。
关键结论 / 踩坑
- 节点 authority 不继承:必须
set_multiplayer_authority(id, true),否则子节点MultiplayerSynchronizer仍是服务器 authority,同步不发。 - 远端玩家必须拆相机并关物理,否则多台 Camera3D 抢渲染、双重模拟导致抖动。
- 去中心化 authority 模型跑通(host=1 本地操控 / client 远端回放,client 侧镜像)+ ENet 中继正常。
- 命令行调试入口:
Net._apply_cmdline()支持-- --host/-- --join <ip>。 项目已存在的无关报错:已修复: 插件目录已删除,但res://addons/ziva_agent/ziva_agent.gdextension文件缺失,每次启动都刷 3 行 ERROR。.godot/extension_list.cfg里残留了一行res://addons/ziva_agent/ziva_agent.gdextension。filesystem_manage(op="scan")不会清掉它(Godot 只在运行中观测到 .gdextension 增删时才重写该文件), 直接删掉那一行即可。已用 headless 启动验证:3 行 ERROR 消失。- AppID 仍是 480(Spacewar 测试,Steam 客户端未装 →
status:1),换 Steam P2P 时只需改Net.host_game/join_game。
输出文档
- 新增
docs/联机框架使用指南.md:面向零联机基础的人,含概念(peer/authority/复制 vs RPC)、文件地图、 三种跑法、四个「新功能怎么同步」配方、Steam P2P 迁移(直连 SteamID 版 + 大厅版)、调试与已知限制。 - Steam API 签名已用探针脚本让 GDScript 分析器逐个校验(本项目装的是 camelCase 风格 GodotSteam):
Steam.createLobby(type, max_members)返回 void,结果走lobby_created(connect_result, lobby_id)信号Steam.joinLobby(lobby_id)→lobby_joined(lobby_id, permissions, locked, response)信号Steam.requestLobbyList()→lobby_match_list(lobbies: Array)信号;成功码 = 1Steam.getSteamID();setLobbyData/getLobbyData/getLobbyOwner/getNumLobbyMembers/getLobbyMemberByIndexSteamMultiplayerPeer:create_host(port=0)、create_client(steam_id, port=0)、host_with_lobby(lobby_id)、connect_to_lobby(lobby_id)、add_peer(steam_id, port=0)、set_no_delay/set_no_nagle/set_debug_level
- 校验手法(可复用):写临时 .gd 调用候选 API,
script_create返回的 diagnostics 会指出「方法不存在」「返回 void 不能赋值」等,比查文档更快更准。 - 新增
docs/联机实战教程-由浅入深.md:九关递进教程(血量同步 → 颜色认领 → 头顶名牌 → 挥手 RPC → 两段式攻击 → 子弹 Spawner → 服务器权威血量 → 远端插值 → 玩家列表)。按键约定 H/G/K/J。 - 教程里引入的两个工程改动(后续实现时要跟着做):
player.gd加class_name PlayerController、main.gd加class_name GameWorld、bullet.gd加class_name Bullet、bullets.gd加class_name BulletPool, 这样跨脚本调用才有编译期检查。 - 写教程时抓到一个真 bug:
parent.broadcast_hit(...)是本地调用,伤害传不到对方机器,必须world.broadcast_hit.rpc(...)。GDScript 对漏.rpc()不报任何错,这是最阴的一类联机 bug。 - 第二个发现:
@rpc("authority")的检查是「发起方 peer id == 被调节点 authority」,所以服务器不能 调用别人玩家节点上的 authority 模式 RPC。广播函数必须放在 authority 为 1 的节点上(世界根节点 Main 天然满足)。 - 教程全部代码用「拼成一个文件做整体编译」的方式验证过:
diagnostics: []零错误。 GDScript 对动态成员访问极其宽容(Node上调脚本方法、Node3D.new()设脚本属性都不报错), 所以「编译通过」不等于「语义正确」,逻辑对错还得靠人读。
godot-ai MCP 使用注意(重要)
- autoload 的全局标识符在「正在运行的编辑器会话」里不可见:新加的 autoload,脚本里直接写
Net.xxx会报Identifier not found: Net。改用get_node_or_null("/root/Net")。 - Godot 在 Windows 上不往重定向的 stdout 写日志(
_console.exe更糟,它自己开控制台)。抓输出必须用引擎参数--log-file <path>。 game_manage.get_ui_elements/get_scene_tree看不到/root下的 autoload 节点,只认当前场景树。- 验证资源是否真被解析:写
res://tests/test_*.gd(继承McpTestSuite,方法名test_*,用assert_true/assert_eq/assert_gt),再test_run。