二七王:I-3/I-2/M-2 服务端补齐阶段·控制权·结算重连下发面
I-3 阶段与控制权改由服务端唯一维护并逐包下发: - fapai / jiaofen / shangzhuang / xuanzhu / maipai / jiesuan 各补 step(取自 o_paiju.step) - shangzhuang / xuanzhu 补 nextseat(控制权 = o_paiju.banker,选主/投降/埋牌均只由庄家做) - deskinfo 的 ChooseMain / BuryCards 各补 seat(控制权,与增量推送 nextseat 同源同值) - 各下发点的真实值先用探针跑真实一局逐个核实;顺带发现 shangzhuang.data.seat 是 最后一个叫分者而非控制权(本局实测 2 vs 庄家 0),故控制权另起名 nextseat - get_paiju_account 统一把 step 置 6:解散结算此前无人推进 step,包里给不出诚实的阶段值 I-2 结算阶段的重连包补发抠底明细与大局结算: - get_paiju_account 末尾一并冻结 tmp_jiesuan_bottom / tmp_jiesuan_account - get_deskinfo case 6 的 Balance 据此补 bottom / account,与 jiesuan 推送同源同值、 门控一致(投降/解散无 bottom、非末局无 account);新局开始时三份快照一并清除 - 修复「结算面板开着时断线重连/硬刷新 → 抠底明细与末局大结算空白」 M-2 seatlist 不再以活引用挂进下发包: - 新增 get_seatlist() 深拷贝快照,maipai / chupai / deskinfo.PushCards 三处改用它 测试:test_rpc 新增 I-3/I-2/M-2 三节(131→166 checks)、test_desk 新增 fapai 阶段与控制权用例(6→10);全部新增守卫已逐条做「退回修复必转红」反向验证(15/15)。 test_leak 的可见性规则同步收紧到「本局结算(step6)后埋牌底牌才全场公开」, 并修掉一处把阶段写死成 step5 的报错文案;整局泄露审计仍全绿。 协议文档同步补充上述字段说明。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,4 +18,29 @@ t.eq('轮庄 庄2赢连庄', nextFirstseat(2, 0), 2);
|
||||
t.eq('轮庄 庄2闲赢下家(回0)', nextFirstseat(2, 1), 0);
|
||||
t.eq('轮庄 庄0闲赢下家1', nextFirstseat(0, 1), 1);
|
||||
|
||||
// ============ I-3 发牌包必须自带阶段 step 与控制权 seat ============
|
||||
// 红线「状态机唯一在服务端」:阶段与「轮到谁」必须由服务端在包里显式给出。
|
||||
// 曾经 fapai 只有 seat 没有 step,前端只能按 rpc 名硬编码 step=1——那就是把阶段推导
|
||||
// 搬到了前端。反向验证:把 class.desk.js 里的 msg.data.step 删掉,本组第一条必转红。
|
||||
function firstFapai() {
|
||||
const sent = [];
|
||||
const o_room = {
|
||||
seatlist: [{ conmode: 0, fromid: 0 }, { conmode: 0, fromid: 1 }, { conmode: 0, fromid: 2 }],
|
||||
asetcount: 6, method: { sendpack_toother: () => { } }
|
||||
};
|
||||
const prevApp = global.youle_erqiwang.app;
|
||||
global.youle_erqiwang.app = { SendPack: m => sent.push(JSON.parse(JSON.stringify(m))) };
|
||||
const desk = D.new(o_room);
|
||||
D.do_new_paiju(desk, 1); // 首个叫分者 = 1 号位(刻意不用 0,避免"恒等于 0"的假绿)
|
||||
global.youle_erqiwang.app = prevApp;
|
||||
return { desk, pj: desk.paiju_list[desk.paiju_list.length - 1], fapai: sent.filter(m => m.rpc === 'fapai') };
|
||||
}
|
||||
const fp = firstFapai();
|
||||
t.eq('发牌 fapai 带 step,且 = 牌局的真实阶段(1 叫分)', fp.fapai.map(m => m.data.step), [1, 1, 1]);
|
||||
t.eq('发牌 fapai.step 与 paiju.step 同源(不是写死的常量)', fp.fapai[0].data.step, fp.pj.step);
|
||||
t.eq('发牌 fapai 控制权 seat = 当前等待叫分者(firstseat=1)',
|
||||
fp.fapai.map(m => m.data.seat), [1, 1, 1]);
|
||||
t.eq('发牌 fapai.seat 与 get_callgrade_seat() 同源',
|
||||
fp.fapai[0].data.seat, fp.pj.method.get_callgrade_seat());
|
||||
|
||||
process.exit(t.done('desk') ? 0 : 1);
|
||||
|
||||
Reference in New Issue
Block a user