Files
erqiwang_youle/docs/server/development-guide
joywayerandClaude Opus 5 b255730c1b 文档:新增「前端数据驱动架构」规范(前端无对局状态机 + 防作弊四条)
前端的阶段/状态/显示一律以服务器为准,前端不得自建状态机、不得本地推导或推进流程;
由此推出请求包只带意图、服务端按可见性下发两条防作弊约束。

- client 05 §6 改为「数据驱动架构:服务端状态的投影」,新增 6.1 前端无对局状态机、
  6.2 视图=f(服务端快照)(丢弃 this.data 仅凭最近快照重画须一致)、6.3 本地 UI 态白名单
  (并澄清与 04 §5.6 乐观清除例外的关系);原条目归入 6.4
- client 04 §1 新增「请求包只带意图,不带结论」;§5.3 补「不得据本地推断补齐未下发状态」
- server 03 新增 §1.3 按可见性下发(下发即泄露)、§1.4 状态机唯一在服务端并随包下发
- server 04 §4 补「前端不是数据源」;§8 新增「只接受意图入参,客户端回传结论一律忽略」
- 两份 README 红线速查与审查速查表同步补条目

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 20:02:55 +08:00
..

服务端 · 子游戏开发指导文档

本套文档是友乐游戏平台下「子游戏服务端」开发的通用指导与规范。 它讲清楚三件事:框架怎么运作、子游戏怎么接进去、开发时必须守哪些规矩。

文中以「麻将」一类房卡棋牌作举例,但所有结论都是框架通用的,不绑定任何具体玩法。 新开发者按本套文档即可理解运作流程、动手接入并写出符合规范的子游戏。


这套文档写给谁

  • 新接手子游戏服务端的开发者:先读完 01、02 建立全局认知,再按 03、04 动手。
  • 正在开发/维护某个子游戏的开发者:03、04 是日常红线,改任何东西前回查。
  • 做代码审查的人:04 是审查清单的来源。

阅读顺序

篇 文档 解决什么问题
00 本文 README 这套文档是什么、怎么读、红线速查
01 01-服务端环境与框架基础.md 平台与子游戏的关系、核心对象模型、三层路由、房间生命周期
02 02-子游戏接入与开发流程.md 三文件架构、export/import 接口、makewar/重连、一次操作的完整数据流
03 03-数据收发与通信协议.md 包结构、收发包方式、下发面发全 / 按可见性裁剪 / 状态机唯一在服务端、主动推送、成败标志协议、前后端对接点
04 04-开发规范与红线.md 可编辑范围、ES5/require、数据权威(含前端不是数据源)、模块职责、房间隔离、请求合法性验证、测试纪律

建议第一次从 01 顺序读到 04;之后把 03/04 当手册随用随查。


一页纸:核心运作模型

客户端数据包 { app, route, rpc, data }
        │
        ▼
packet_face.ReceivePack         按 pack.app  找到「应用」
        │
        ▼
app.ReceivePack                 按 pack.route 找到「模块」(子游戏)
        │
        ▼
mod.DoPack                      按 pack.rpc   调到「方法」 mod[rpc](pack)
        │
        ▼
子游戏 RPC handler              校验玩家 → 取对局状态 → 执行业务 → 主动推送
        │
        ▼
o_room.method.sendpack_toseat   按座位取连接信息(conmode/fromid) → 下发客户端
  • 平台框架负责:网络收发、应用/模块/房间/玩家对象、路由、房卡、战绩、房间生命周期。
  • 子游戏负责:玩法规则、对局状态、每个操作的处理与广播。两者通过 export / import 两组接口对接。

上图是入站半程(前端 → 服务端 handler)。完整的往返链路(含服务端 sendpack_toseat 推回 → 前端 Game_Modify._ReceiveData 按 rpc 分发)见 03 §6「端到端收发全链路」,前端侧细节见 前端 04 网络对接与启动编排。


命名约定:哪些是框架契约,哪些只是示例

本套文档的代码示例里出现的具体名字,绝大多数是举例,并非强制标准。请区分两类:

  • 框架契约(必须照用)——由平台代码决定,改了就对接不上:
    • 数据包四字段 { app, route, rpc, data },其中 app 固定为 "youle";
    • 平台真实回调的 export 钩子名、你调用的 import 接口名(如 makewar、get_deskinfo、check_player、deduct_roomcard、save_grade);
    • 成败字段 data.success;
    • 平台 API 名(cls_mod.new、min_loadJsFile、o_room.method.sendpack_toseat / sendpack_toother 等)。
  • 示例命名(可自定)——本项目的举例,你的子游戏可按自己的风格命名:
    • 业务 rpc 名(如 playCard、declareHu,只需前后端约定一致即可);
    • handler / 类 / 文件 / 变量 / 分层目录名(如 RpcHandler.handlePlayCard、OperationManager、ResponseBuilder、BroadcastManager、RoomAdapter、GameController、game/、rpc/、rules/ 等)。

一句话:平台接缝上的名字是契约、要照用;接缝之内你自己代码里的名字都是示例、可自定。 后续 01–04 的代码块同样遵循这条约定,不再逐处重复声明。


红线速查(详见 04)

以下每一条都有过真实事故或返工,改代码前先对照。

  • 可编辑范围:服务端只能改子游戏目录 server/<游戏容器目录>/<你的游戏>/(容器目录名由接入方自定,非框架强制,换任何不与框架冲突的目录皆可),server/ 其余皆平台代码,禁改。接入新游戏还需在 server/youle/app.js 里加一行 min_loadJsFile 加载其 mod.js(唯一必须触碰的平台文件,属游戏注册接入点)。
  • 双运行时:代码同时跑在 Node 与浏览器/友乐平台。必须严格 ES5;require 只能写在文件开头 if (typeof require !== 'undefined') {} 守卫块内,禁止函数体内/中途 require。
  • 成败标志唯一是 data.success:前端只认 if (!data.success);主动推送的 data 必须自带 success(mod 的 return 值不可靠下发前端);禁止用 status/code 判成败、禁止 status 兼容兜底。
  • 数据权威:同一业务数据只有一个权威来源,下游只读不重算;权威字段缺失要显式报错/返回 null,禁止 || 0、|| []、|| '' 兜底掩盖。
  • 模块职责边界:一个职能只在一个模块实现,其他模块调用而非重造。
  • 房间隔离:一切随对局变化的状态都挂 o_room.o_desk.data.*;禁止模块级单例/全局变量存对局态;缓存/定时器/决策表不得只用 seat 作 key,必须 房间 + seat;结束/解散/开新局时按房间清理全部定时器与残留状态。
  • 服务端自动操作复用真人链路:服务端代替玩家做的操作(如 AI 托管)必须复用「真人操作」的同一套处理入口与广播链路,对前端透明,不为它单开一套下发分支。
  • 服务器权威 + 发全下发面:房卡、胜负、积分、状态等关键数据与操作一律以服务器为准、前端只作显示不自算;因此服务端每个下发包必须携带前端界面所需的全部核心数据,漏发修在服务端发包处、前端不补(详见 03 §1.2 / 04 §4)。
  • 状态机唯一在服务端:前端是数据驱动的、不持有对局状态机(见前端 05 §6),所以阶段、控制权(轮到谁)、该座位 availableActions、倒计时锚点必须由服务端唯一维护并在相关下发包里显式给出;任何状态变更都要有包承载——没有包的状态变化等于逼前端去猜。超时裁定在服务端,不接受前端上报"我超时了"(详见 03 §1.4)。
  • 前端不是数据源,只收「意图」:请求包只接受「操作类型 + 目标标识」;协议不定义 score/isWin/phase/nextSeat/handCards 之类结论入参,即便客户端硬塞也一律不读、不落地,全部按服务端权威数据重算;包内 seat 只作一致性校验、身份由连接反查(详见 04 §8)。
  • 发全 ≠ 发多,按可见性下发:他人手牌、牌堆剩余序列、未公开判定、尚未揭晓的结果不发给不该看到的座位(差异化下发逐座位裁剪)。下发即泄露——包到了客户端就能被抓包看到,"前端拿到但不渲染"不算防护(详见 03 §1.3)。
  • 测试纪律:测试失败先用证据裁定「业务缺陷 vs 测试脚本缺陷」,禁止 skip/软化断言/吞异常掩盖;正式代码不得为兼容测试而加逻辑。

与既有文档的关系

  • 本套文档是平台级收发包/子游戏开发规范的落地版:结合本仓库真实代码,给出可直接照做的接入步骤与红线,并对其中已被本项目实践修正的部分(如成败标志由 status 收敛为 success)以本套为准。
  • 各子游戏内部的架构细节(模块划分、算法)仍以各自 <游戏容器目录>/<游戏>/docs/ 为准。
  • 平台无关的通用工程与架构规范(分层、可扩展模式、配置化、数据权威、反模式与审查清单)见 工程与架构通则:本套讲"平台怎么接、红线是什么",工程通则讲"该怎么设计、怎么长久演进",互补阅读。