麻将结算全链路语义(SETTLE_SEMANTICS)

麻将结算全链路语义(SETTLE_SEMANTICS)

第0条(基线)本文件语义以产品源码为权威源;引用只允许以文件与符号(函数、字段、协议名)给出;行号引用前必须复核现码。文件简称:PS=玩法服,GS=游戏服,CC=客户端核心,SC=场景服,MC=匹配中心,DF=麻将定义。进程链路:PS 到 MC 到 SC 到 GC 到 GS 到 CC。

第1章 正常链

第1条(对局结束触发)

  • Game_End 必须以幂等标志防重入;状态必须置对局结束。
  • 总回合号与当前回合号必须统一递增,并经同步协议发给场景服,供崩溃幂等公式使用;场景服侧接受非严格单调。
  • 花猪与流局二次结算必须以独立标志防重。

第2条(倍率与分数)

  • 局内禁止直接改总分;分数一律走挂账字段(加分与扣分),局末合并入总分后清零,防下局重复结算。
  • 番型与倍数由胡牌检测统一计算;GS 直接消费结果,禁止重复计算;客户端只展示,以服务器为准。
  • 全局分数必须平衡:总增量大于 0 时全部增量强制置 0 并记 CRITICAL。
  • 已结算玩家(胡牌时已发放)只上报增量:以标记与已结算增量的差值计算。

第3条(结算包)

  • 结算包每玩家条目必须含结算序号基线(未推进)与已结算标记。
  • 一回合一个 token;直发 key 必须用回合起始基线,否则同回合第二个 token 将导致已胡玩家双付。

第4条(发布通道)

  • 通道一(胡牌即时):胡牌时即时自动结算,key 为结算序号加回合号;失败必须回滚已结算标记并入重试队列。
  • 通道二(直发):结算发布到 MC,MC 校验房间后转 SC,SC 逐玩家分包、登记 pending 后发出,经 GC 转发到 GS 处理。
  • 通道三(增量):花猪、大叫、退税二次结算,带二次结算标记,key 与胡牌同槽。
  • 通道四(崩溃保底):崩溃处理与前三通道共用同一线性流水线。

第5条(GS 货币结算顺序)ApplyMahjongSettlement 必须按下列顺序:

  1. 状态守卫:无房间时按冻结余额分流------有冻结加合法上下文则重建房间;无冻结则幂等成功;有冻结但上下文非法则强制退款。
  2. key 幂等比较:小于期望跳过并成功返回;等于期望执行;大于期望返回失败并触发重试。
  3. 冻结 token 校验;跨房二次结算豁免。
  4. 冻结模型:赢家只发放净收益、冻结镜像不变;输家下调冻结镜像并同步下调入场冻结,防亏损凭空消失。
  5. 写前日志:必须先持久化已处理 token 再发放;发放失败回退 token。
  6. 段位分、排行榜、房间状态、可用余额快照;最终余额持久化失败不得回退 token(资金已发,防重复发奖)。

第6条(GS 到客户端展示)

  • 结算处理尾部必须下发结算协议,携带错误码(成功为 0)。
  • 成功路径必须回确认(含结算 key 与确认 token)供 SC 清理 pending;失败路径禁止回确认,SC 保留重试。
  • 客户端结算协议处理顺序:去重防护、存结算结果、发布结算事件。
  • 对局流水日志必须写入。

第7条(结算后房间状态)

  • SC 房间不得销毁;状态置等待装载,全员未准备。
  • PS 局尾必须清理:结算序号按本局实际最大 key 精确推进、杠记录清空、当前回合号清零防 key 溢出。

第2章 失败路径

第8条(错误码产生)错误码仅产生于 GS 结算处理两处:房间不匹配分支且本玩家不在结算包内;正常分支结算失败(未来 token、冻结 token 不匹配、写前日志持久化失败、发放失败、余额快照持久化失败)。错误码 MAHJONG_ERROR_SETTLE_FAIL = 3300025

第9条(客户端提示)客户端收到非零错误码时必须发布错误事件;UI 映射为结算异常提示文案;客户端只提示,不得主动重发;重试全部由服务端驱动。

第10条(重试层一:PS 本地队列)失败条目必须 5 秒重试、至多 10 次、超限丢弃记错,并以 xpcall 保护。入队点为胡牌失败与结束自动结算失败。

第11条(重试层二:SC 待确认重投)

  • 登记必须先于发送,两级表按玩家与房间归档。
  • 投递:目标中心无效永久放弃;不可达则计数并排期;成功则发送。
  • 定时重试每 tick 驱动;单条上限 4 次、跨会话总上限 12 次;耗尽暂停,重连再触发。
  • 上线补投优先,且存在 pending 时不得回上线成功(防冻结本金误退)。
  • 确认保护:已有 pending 时只更新中心 ID。
  • 确认收敛:确认 token 不小于结算 key 时幂等跳过清理;GS 成功才确认,失败不确认。

第3章 幂等与防重复

第12条(写前日志为 GS 玩家级唯一权威状态)

  • 状态定义:已处理结算 token 从 0 起,结算序号跟随该值。
  • 公式:结算 key 为结算序号加回合号;期望 key 为已处理 token 加一。
  • 三通道(胡牌、直发、崩溃)共用同一线性流水线:小于期望跳过、等于执行、大于重试。
  • 结算写前日志必须先持久化 key 再发放;持久化失败必须回退;发放后余额快照失败不回退。
  • 退款写前日志必须先推进 token 再发放;发放失败回退。
  • 崩溃回退仅在成功后推进 token。
  • 入场对齐:进房时必须把已处理 token 重置到冻结 token 基数,使结算序号与冻结 token 对齐。
  • 自动结算回放幂等:同 token 同金额重复回调视为幂等成功。
  • Guardians 结算通道(同房全量、跨房特殊)均走主结算。
  • 二次结算不推进 token,幂等由重试队列保证。

第13条(客户端去重)

  • 条件:已有结算结果且待显示时,必须跳过任何新结算。
  • 置位:待显示标记置位并深拷贝结果;清除:新局准备时清标记,结果保留供流水恢复,字段受保护不被快照覆盖。
  • 前置守卫:陈旧房间消息必须丢弃,EndGame 入口先查房间归属。

第14条(房号不匹配拒做货币操作)

  • 结算入口必须强校验:存档房号与结算房号不一致时禁止货币操作。
  • 跨房(原房号非零且新房号不同)仅回确认。
  • 有冻结但同房号信息缺损时对齐上下文继续。
  • 无冻结时保留引用置等待装载、回确认、保留流水。
  • 退款必须同样校验房号与冻结 token。

第4章 异常结算

第15条(房间销毁后结算)查房为空时必须记警告并返回失败,使调用方得知结算未发生;结算走主通道加自动结算兜底;场景服房间移除必须清理本房 pending 与孤儿 pending,防永久重试。

第16条(异常回滚与跨局残留)

  • 开局核心逻辑必须以 xpcall 包裹;失败时必须清定时器、重置结束毒丸、状态回等待、通知断开错误。
  • 每局开始必须重置挂账字段(加分、扣分、局分)。
  • 局末结算后挂账必须强制清零,即使自动结算失败;结算由结算包通道独立负责,防下局重复结算。
  • 二次结算必须以花猪与流局标志防重。

第17条(杠记录清空与流局退税)

  • 流局处理必须先备份再清空杠记录,再遍历退税,防循环异常导致记录残留;退税必须记录退税表与流水。
  • 局尾必须统一清空杠记录。

第18条(其他防御)

  • 场景服结算处理:房间不存在或匹配中心不匹配必须崩溃上报;不匹配时主动验证防悬挂。
  • GS 结算:冻结资金加非法上下文必须强制退款;无房间必须幂等成功并清理冻结 token。

第5章 同步锚定

第19条(同步锚定规则)全量快照同步必须保证多客户端收敛到服务端时间,禁止各客户端按本地时刻分叉:

  • 阶段变化才杀换三张与定缺定时器,等待响应阶段每次杀;仅离开进行中才杀回合定时器,防乱序快照误杀行动通知新建的定时器。
  • 全量快照替换必须经替换接口。
  • 状态码单调防护拒绝阶段回绕;座位号反回归防护;剩余时间单调递减守卫。
  • 进行中与等待响应不得由快照重启定时器,只更新回合信息兜底;若重启,各客户端锚定本地时刻产生分叉;回合定时器只由行动通知一次性锚定。
  • 换三张与定缺每次同步都必须重启定时器,使所有客户端向服务端时间收敛。
  • 全局倒计时锚点仅在非进行中且非零时建立。
  • 陈旧房间消息必须经统一入口丢弃。

第6章 缺陷与风险

第20条(S1-S8)

# 位置 缺陷 风险
S1 客户端去重 条件不校验房号:结果存在且待显示时,任何新结算(含新房新局)均被跳过;陈旧守卫只挡非空且不同房号的包 去重窗口跨房时存在展示丢失窗口
S2 PS 重试队列加 SC 重投 两个通道可产生同族结算;恰好一次依赖结算 key 幂等拦截,先失败后成功与先成功两条路径的终态一致性依赖 token 单调 必须测试双通道并发下恰好一次发奖
S3 GS 余额快照 发放后余额快照持久化失败返回失败但不回退 token;客户端提示自动重试,重试因 token 已推进必跳过,资金实际已发 提示误导,重试无实际效果
S4 GS 房间不匹配分支 存档房号为空时本玩家判定仍按结算包计算,错误码可能为 0 且不确认,该分支确认覆盖完整性待确认 pending 可能残留至重试耗尽
S5 SC 重试上限 耗尽仅暂停(等重连),总上限外永久放弃,无死信队列 极端场景结算永久丢失,有错误日志可审计
S6 GS 崩溃 key 旧协议不传回合号时兜底为已处理 token 加一,与携带回合号的公式可能错位竞争同槽 热更新新旧包混合期间崩溃结算与胡牌 key 不匹配
S7 PS 与 GS 结算包 一回合一个 token 依赖包内结算序号基线;旧包无该字段回退到存档值,历史曾导致同回合第二 token 双付 热更新灰度期间新旧包混跑必须关注
S8 客户端结算缓存 终局数据清理定时器 60 秒后才清;待显示标记在新局准备前无超时兜底 低风险

第7章 测试点

第21条(测试点清单)

  1. 正常发奖恰好一次:胡牌加结束双通道,赢家增量恰好入账一次。
  2. 结算 key 单调:多回合下已处理 token 严格递增。
  3. 重复直发:同包重发触发跳过与确认,SC 删除 pending。
  4. 失败重试不重复发奖:首次发放失败回退 token,重投成功后发奖一次。
  5. 写前日志崩溃恢复:token 已持久化但发放未执行,重启重投跳过,不重复发奖。
  6. key 大于期望:乱序未来 key 返回失败并进重试。
  7. key 小于期望且同房:历史 key 跳过。
  8. key 小于期望且跨房二次结算:落到冻结 token 校验并执行。
  9. 冻结 token 不匹配且同房:返回失败触发重试。
  10. 输家冻结镜像下调:增量为负时冻结下调且入场冻结同步。
  11. 输家全损:入场冻结为 0 时仅释放冻结,不发放。
  12. 房号不匹配:无货币变动。
  13. 不匹配跨房:仅确认不落账。
  14. 房间销毁后结算:返回失败且不崩溃。
  15. 开局异常恢复:房间回等待、毒丸复位、可重开。
  16. 跨局挂账残留:上局异常后新局挂账字段为 0。
  17. 流局清空杠记录:退税记录完整且杠记录已空。
  18. 全局平衡:总增量不大于 0;大于 0 时强制归零。
  19. 已结算玩家增量:只发增量。
  20. 客户端去重:待显示期间二次结算被跳过。
  21. 新局解除去重:准备后新结算正常显示。
  22. 错误码传播:结算失败码到客户端提示。
  23. 失败不确认:pending 保留可重投。
  24. 成功必确认:确认携带 token,SC 清理 pending。
  25. 重试上限:单条耗尽暂停,重连重触发。
  26. 中心 ID 非法:永久放弃防无限重试。
  27. 快照阶段单调:旧状态回绕被拒绝。
  28. 倒计时收敛:换三张与定缺每次同步重启定时器。
  29. 进行中定时器不重启:快照不重启回合定时器。
  30. 崩溃共享流水线:崩溃 key 与胡牌 key 同槽,先到执行后到跳过。
  31. 双通道恰好一次:自动结算队列与 SC 重投并发,最终仅一次发奖。
相关推荐
武子康1 小时前
vLLM 的 token 预算还有余量,为什么请求仍被抢占?
人工智能·llm·agent
东方护航数据恢复(深圳)1 小时前
本地小算力设备数据恢复经典案例实操全解_东方护航数据恢复深圳店
大数据·服务器·算法·ai·gpu算力
jingli92 小时前
恶意退款怎么办、仅退款怎么申诉:六类恶意退款识别特征+取证证据链+反制全流程(商家实操版)
人工智能·自动化·用户运营
Anastasiozzzz2 小时前
重新定义 Agent 基建:Redis 在现代 AI 与智能体系统中的工程实践
java·人工智能·redis·ai
蒲公英eric2 小时前
DVWA通关全记录:从漏洞复现到安全防御——总结篇
web安全·ai·dvwa·ai安全
苍苍竹林寺2 小时前
Module Builder——Gem200之Alarm模块
自动化·半导体·eap
林伽一2 小时前
从开源基础设施到垂直封装,AI 产业的技术主轴正在位移
人工智能·科技·ai·语言模型
cc_瀚海知行2 小时前
模型调用 3|怎样让程序可靠地接收模型输出?
人工智能·ai
洞见新研社3 小时前
豆包手机发售,AI代理进入“终端”竞赛
人工智能·ai