[T.6] 团队项目:技术规格说明书
技术栈
语言
- 前端:GDScript
- 后端:Go
应用开发框架
- 前端:Godot4
- 后端:Nakama 设计协议层部分,管理房间、游戏、玩家等,自动完成流量控制与断线重连等机制;内部逻辑、游戏引擎使用 Go 语言直接编写
运行环境
- 前端:无特殊要求
- 后端:
- Go 1.22.4 + Nakama 3.22.0
- 使用 Docker / Docker Compose 编译插件、拉起后端环境
架构设计
子系统
整个系统分为前端、后端、部署三个子系统。
前端
功能: 与用户交互,连接上权威服务器进行游玩
模块:
- 包括 GODOT 模块
后端
功能: 游戏引擎,记录用户游玩数据、处理游玩逻辑
模块:
- CockroachDB(游戏数据存储)
- Nakama(网关、用户管理、实时服务)
- Paradiced Go 插件(权威,处理游戏逻辑)
部署
功能: 提供游戏房间的公网访问
模块:
- 腾讯云
- Docker / Docker Compose
子系统关联
- Godot 前端只发送请求意图,后端返回权威状态。
- 对局主链路由 HSM 控制,任何中断均通过 Decision 机制恢复。
- 客户端断线重连后,以 FullSync / StateSync 为准重新对齐。
系统开发目标
前端
总体 UI 与交互
- Godot 客户端完成登录、入房、发包、收包、断线重连。
- 实现供玩家竞速的主地图场景。
- 关键状态(位置、HP / LP、回合阶段、可操作列表)可正确显示。
后端
协议层
- 完成 Nakama 全生命周期对接:
MatchInit、MatchLoop、MatchStop - 设计状态同步信息:
StateSync、TurnSync、Decision、Available、GameOver、FullSync - Presence 管理:加入、离开、断线标记、重连恢复
- 客户端消息路由:
OpRollDice、OpUseItem、OpUseSkill、OpUserChoice、OpMiniGameResultSubmit - 拒绝机制:统一
OpActionRejected + ErrorCode返回(如ErrNotCurrentTurn、ErrInvalidState)
分层状态机
- 第一层全局状态完整实现:
match_init -> round_mini_game -> round_prep -> turn_loop -> boss_battle -> game_over - 第二层回合状态完整实现:
turn_upkeep -> main_action -> turn_moving -> turn_landed -> turn_event -> turn_end - 第三层回合中断状态完整实现:
wait_decision入栈 / 出栈、超时默认选项执行 Phase:HSM 发布状态时机Phase,Action 发布动作时机Phase,Phase用于触发事件系统Snapshot:支持保存并恢复关键状态(状态 ID、当前玩家、回合信息、决策等待态)
事件与行为
- 核心行为:
damage、heal、modify_lp、move、draw_event、add_buff、remove_buff、respawn、fell_down、teleport等 Trigger机制:可在pre_damage/pre_move/pre_event等时机拦截、改写行为甚至派生新的行为EventBus支持 Buff、道具、技能、事件多Phase订阅、优先级执行,用于接受信号NeedConfirm流程:可触发DecisionRequest,并在UserChoice后继续执行- 信号广播:
on_buff_applied、on_buff_removed等Phase可以被其他 Buff、道具、事件监听以修改其影响的行为
领域模型
- 领域实体:
Player、Buff、Item、GameEvent分别抽象了各个游戏实体的属性与行为 - 常量类型:
Phase、StateID、Faction、CellType、ErrorCode、EntryType等内容使用枚举常量定义,减少字符串或者数字的内涵使用 - ID 类型:
PlayerID/BuffID/ItemID/ ...,游戏引擎执行阶段全局唯一的 ID,用于代指某个领域实体
地图与随机引擎
- 地图引擎支持关键格类型:
normal/fragile/fog/checkpoint/boss - 路径计算可重复:输入相同状态与步数,输出路径与落点可预测
- 检查点恢复有效:死亡或坠落场景能回到最近检查点
- 随机引擎可复现:每局唯一随机源,固定 seed 可复现抽取序列
- 抽奖池语义明确:Good / Neutral / Bad 由调用方决定,LP 仅影响池内权重
错误处理
协议消息统一响应结构:
{
"success": true,
"code": 0,
"message": "ok",
"data": {}
}
- 全局成功:
0 - 通用错误:
-1 - 系统错误:
1 - 业务错误:按模块分段(例如
1xx登录、2xx对局、3xx协议)
单元测试
前端(待补)
OpCode路由测试:每个客户端消息都能进入正确处理器并返回正确反馈
后端
hsm:三层状态转移、状态栈入出栈、决策超时、快照恢复action:可修改与不可修改 Action、前后触发、队列衍生执行event:Phase 发布、订阅优先级、NeedConfirm 分支gamemap:路径边界、Fragile / Fog / Checkpoint / Boss 行为rng:固定 seed 一致性、LP 权重影响、池类型边界errors:错误包装、errors.As识别、上下文保留gamelog:回合分段起止、条目追加顺序、序列化正确性nakama:验证广播 / 单播消息数量与字段正确性net:状态、玩家、日志映射正确,构造信息正确
压力测试
前端
前端应该没有压力测试吧。
后端
- 高并发连接:单机 20 在线连接,持续运行无崩溃
- 自动测试:CLI 连续多少多少局,比如一个晚上,不发生崩溃
- 断线重连:CLI 测试时插入随机断线,恢复后
StateSync关键字段一致 - 协议健壮:注入未知
OpCode、空字段、越权请求,服务端可拒绝且不中断全局对局
真实测试
前端
前端的真实测试,通过脚本模拟用户的真实物理输入,验证 UI 响应、表现层渲染以及与后端的网络握手是否正常。
- 使用 GUT 框架中的
InputSender模块。编写 GDScript 测试脚本,通过代码直接向特定 Control 节点(如掷骰子按钮、道具确认按钮)注入InputEventMouseButton以模拟真实物理点击,验证事件总线的响应 - 前端依靠后端的
Action Log驱动动画,测试脚本需要在短时间内瞬间向前端的消费者队列塞入 50 条连续的MoveAction和DamageAction。断言游戏表现层是否能按顺序平滑播完所有动画,而不发生信号丢失、协程死锁或动画卡顿 - 利用 Godot 的
--headless命令行参数,编写外层 Shell 脚本瞬间拉起 3 个无头客户端和一个带 UI 的观察客户端,模拟多玩家真实对局中的点对点数据交互和断线重连表现
后端
直接利用 Nakama 的 SDK 建立 WebSocket 连接,完全绕过 Godot 前端的 UI 限制发包,测试一些恶意攻击的部分。
1. 越权
- 在 A 玩家的回合(此时状态机应处于
TurnLoopState的移动阶段),控制 B 玩家的 Bot 强行向服务端发送OpRollDice(掷骰子)或OpUseItem(使用道具)的数据包
2. 伪造
- 在
WaitDecisionState(等待玩家选择道具目标)阶段,恶意 Bot 故意构造 JSON / Protobuf 载荷,发送一个自己背包里根本不存在的道具 ID,或者把对敌人造成的伤害值手动修改为9999
3. 重放
- 攻击模拟:利用 Go 的协程(
goroutine),让恶意 Bot 在 5 毫秒内并发向后端发送 100 次相同的“使用稀有回血道具”的网络请求
文档编写
- 协议文档:后端协议层的路由,以及返回的详细类型,用于前后端进行对接
- 状态机文档:后端状态转移实现一致
- 错误处理文档:覆盖错误类型到错误码映射
- 启动使用文档:
README.md、startup.md、cli.md能指导构建可运行的后端

浙公网安备 33010602011771号