二七王:maipai 补发 playproc(增量路径与重连路径对齐)
前端一致性测试剩余 3 红的根因:do_burycard() 内部已调 new_playround 初始化好 round-1 的进行态,但 mod.js 组 maipai 包时没有放 playproc(协议 §9 字段表也没有), 「埋牌完成 → 庄家首出」这段窗口增量路径 table.playproc 为 null,重连路径却已有初值—— 与上一个 commit(8452535)给 maipai 补 seatlist 是同一个窗口、同一条理由,被漏在了同一处。 修法:复用既有的 get_playproc() 快照函数(与 chupai1/2/3、PushCards.playproc 同源, 本身就是逐字段深拷贝,不引入活引用风险)。可见性:此刻一张牌未出,round/start/currseat 等全部由桌面公开信息推出,cards 全空、shuai_demand 为 null,不含私密信息,故与 chupai1/2/3.playproc 一样三家整体下发、不受查牌模式门控。 协议文档 §9 同步补字段说明。test_rpc.js 新增 5 checks:庄闲同值、与重连快照比对、 round-1 初值断言、不查牌模式下仍恒有、深拷贝守卫;已用「退回修复必转红」反向验证 (3/5 转红)。既有 121 checks 未改一条断言,全绿(17 脚本 / 675 checks)。未涉及 shared/。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -225,6 +225,37 @@ t.eq('埋牌 seatlist 埋牌完成时为初始化空表', JS(mpZhuang3.data.seat
|
||||
t.eq('埋牌 不查牌 maipai 无 seatlist',
|
||||
en.sent.filter(m => m.rpc === 'maipai').every(m => m.data.seatlist === undefined), true);
|
||||
|
||||
// ---- ③b maipai.playproc:与 PushCards.playproc 同一个快照函数、同结构,且是深拷贝 ----
|
||||
// 曾经的缺陷:mod.js 组 maipai 包时没有放 playproc(do_burycard 内部已 new_playround 就地初始化好
|
||||
// round-1 的进行态),「埋牌完成 → 庄家首出」这段窗口增量路径的 table.playproc 是 null,
|
||||
// 重连路径却已有初值——与 seatlist 是同一个窗口、同一条理由,被漏在了同一处。
|
||||
t.eq('埋牌 maipai 带 playproc(庄闲同值)',
|
||||
JS(mpZhuang3.data.playproc), JS(E.get_deskinfo(e.o_room, 0).PushCards.playproc));
|
||||
t.eq('埋牌 maipai 闲家同一份 playproc(三家公开、不裁剪)',
|
||||
JS(mpXian3.data.playproc), JS(mpZhuang3.data.playproc));
|
||||
t.eq('埋牌 playproc 埋牌完成时为 round-1 初值(庄家首出、桌面全空)', mpZhuang3.data.playproc, {
|
||||
round: 1, start: 0, currseat: 0, startcount: -1, startflower: -1, starttype: -1,
|
||||
maxseat: -1, maxcard: -1, cards: [null, null, null], shuai_demand: null
|
||||
});
|
||||
// 反面:playproc 不受查牌门控——不像 seatlist,它只是桌面公开信息,不查牌模式下也恒有
|
||||
t.eq('埋牌 不查牌 maipai 仍带 playproc',
|
||||
en.sent.filter(m => m.rpc === 'maipai').every(m => m.data.playproc !== undefined), true);
|
||||
// 深拷贝守卫:playproc 是全程复用的活对象,new_playround 就地重置同一个对象。
|
||||
// 若下发挂的是活引用,埋牌后紧跟着打一手牌,已发出的 maipai.playproc 会被回改成下一状态的样子。
|
||||
const dcPj = P.new({ paiju_list: [] }, 0);
|
||||
const dcC = setup("00000", dcPj);
|
||||
mod.jiaofen(pack(0, { call: 65 })); mod.jiaofen(pack(1, { call: 0 })); mod.jiaofen(pack(2, { call: 0 }));
|
||||
mod.xuanzhu(pack(0, { flower: 1 }));
|
||||
const dcInner = mod.app.SendPack;
|
||||
let dcLive = null;
|
||||
mod.app.SendPack = m => { if (m.rpc === 'maipai' && m.data.cards !== undefined) dcLive = m.data.playproc; dcInner(m); };
|
||||
mod.maipai(pack(0, { cards: P.get_seat_cards(dcPj, 0).slice(0, 8) }));
|
||||
mod.app.SendPack = dcInner;
|
||||
const dcSnapAtSend = JS(dcLive);
|
||||
const dcHand = P.get_seat_cards(dcPj, dcPj.playproc.currseat);
|
||||
mod.chupai(pack(dcPj.playproc.currseat, { cards: [dcHand[dcHand.length - 1]] })); // 推进出一手,制造"若为活引用会被回改"的条件
|
||||
t.eq('埋牌 playproc 下发的是深拷贝快照(已发出的包不被后续出牌回改)', JS(dcLive), dcSnapAtSend);
|
||||
|
||||
// ---- ④ burycards:maipai 必须发服务端权威快照,不得回显客户端提交的 cards 原序 ----
|
||||
// 曾经的缺陷:msg.data.burycards = cards(请求包原样回显),而 PushCards.burycards 走 get_burycard()
|
||||
// 按主牌花色排序 —— 同一副埋牌底牌两条路径两种顺序(SSOT)。
|
||||
|
||||
Reference in New Issue
Block a user