二七王:服务端下发面四处缺陷修复(增量路径与重连路径对齐)
前端一致性测试(同一局真包:逐包增量回放 vs 一次性 deskinfo 重连)暴露的四处
服务端缺陷,均属「同一份数据两条路径给的不一样 / 有一条根本没给」:
① chupai1/2/3 补发 playproc(本轮进行态)
与 deskinfo.PushCards 共用新增的 get_playproc() 快照函数,结构取值完全一致。
playproc 是全程复用的活对象(new_playround 就地重置),故快照做逐字段深拷贝,
避免已发出的包被后续出牌回改。可见性:全部字段由桌面公开信息推出,
与既有 PushCards.playproc 一样三家无差别下发。
② deskinfo ChooseMain(step2)/BuryCards(step3) 补发 curmultiple
与 shangzhuang 推送同源同值;此刻一张牌未出、捡分恒 0,必为 +3(大光)。
原先重连重建为 0,顶部「抓分」角标掉档。
③ maipai 补发 seatlist
与 chupai/PushCards 同一张表、同一道查牌模式门控;埋牌完成时为初始化空表。
④ bottomcards / burycards 收敛到单一权威源(SSOT)
- burycards:maipai 原样回显了客户端请求包里 cards 的顺序,改取 get_burycard()
权威快照,与 PushCards.burycards 同一函数。请求包只承载「意图」,其顺序不可信。
- bottomcards:get_bottomcards 按「调用时的 flower」排序,导致上庄推送(flower=-1)
与重连 BuryCards(flower 已定) 两种顺序。底牌是选主【之前】就翻给玩家看的、
发牌结束即固定的快照,故改为发牌时算一次并冻结,get_bottomcards 返回其副本
(order_cards 是原地排序,交出本体会被调用方就地重排)。三个调用点无需改动。
协议文档同步 7 处(新增 playproc/seatlist/curmultiple 字段说明与两处排序口径)。
新增 test_rpc.js「下发面一致性」用例组 21 checks,含 28 轮真实牌局逐包逐座位比对
(249 次、0 不一致)与深拷贝守卫;每条均已用「退回修复必转红」反向验证。
既有 649 checks 未改一条断言,全绿(17 脚本 / 670 checks)。未涉及 shared/。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -322,6 +322,19 @@ youle_erqiwang.maipai = function(pack){
|
||||
msg.data.success = true;
|
||||
msg.data.seat = o_paiju.playproc.currseat;
|
||||
msg.data.countdown = o_desk.method.get_countdown_chupai();
|
||||
if (!_cfg.nocheck){
|
||||
//三家座位牌况(缺门/无对 + 报副统计),仅可查牌下发——与 chupai1/2/3、重连包
|
||||
//PushCards.seatlist 同一份数据、同一道门控。埋牌完成时它是刚初始化的空表
|
||||
//(每家 [[0,0],[0,0],[0,0],[0,0],[-1,-1]]),本身不含任何信息;但「埋牌完成 →
|
||||
//庄家首出」这段窗口内前端也要有表可画,漏发会让增量路径此刻为空、重连路径却有表。
|
||||
//可见性:表内只有「某家缺某花色/某花色无对」(由公开的跟牌行为推出)与报无主后
|
||||
//全场公示的余主数量(design §9 明确要求向全体三人展示),故三家整表下发不构成泄露
|
||||
msg.data.seatlist = o_paiju.seatlist;
|
||||
}
|
||||
//埋牌底牌(本次埋下的 8 张):取服务端权威快照,【不回显客户端提交的 cards 原序】。
|
||||
//get_burycard 与重连包 PushCards.burycards 是同一个函数、同一套按本局主牌花色的排序,
|
||||
//两条路径因此顺序一致(SSOT);直接回显 cards 会把客户端的选牌顺序当成下发顺序。
|
||||
var _burycards = cls_youle_erqiwang_paiju.get_burycard(o_paiju);
|
||||
for (var i = 0; i < o_room.seatlist.length; i++) {
|
||||
msg.conmode = o_room.seatlist[i].conmode;
|
||||
msg.fromid = o_room.seatlist[i].fromid;
|
||||
@@ -329,7 +342,7 @@ youle_erqiwang.maipai = function(pack){
|
||||
msg.data.cards = o_paiju.method.get_seat_cards(i);
|
||||
//埋牌底牌(本次埋下的 8 张)。与 shangzhuang.bottomcards(底牌,发牌留桌 8 张)
|
||||
//是两批不同的牌,字段名刻意区分,勿混用
|
||||
msg.data.burycards = cards;
|
||||
msg.data.burycards = _burycards;
|
||||
delete msg.data.liangpai;
|
||||
} else {
|
||||
delete msg.data.cards;
|
||||
@@ -474,6 +487,16 @@ youle_erqiwang.chupai = function(pack){
|
||||
msg.data.countdown = o_desk.method.get_countdown_chupai();
|
||||
//当前抓分倍数(design §7.2.0):随本包一起下发、不另开推送;三家同值,grade 本就公开
|
||||
msg.data.curmultiple = o_paiju.method.get_curmultiple();
|
||||
//本轮进行态(design §5.1):与重连包 PushCards.playproc 同一个快照函数、同一结构。
|
||||
//没有它,前端在非重连时就拿不到「本轮谁先手/谁最大/三家各出了什么/第几轮」,只能自己
|
||||
//累积推导——那就是把对局推进逻辑搬到前端(前端红线「数据驱动、前端无对局状态机」)。
|
||||
//注意 re.idx==3 时 do_playcard 已在内部调用 new_playround 就地开了新一轮,
|
||||
//故 chupai3 带的是【新一轮】的进行态(与 nextseat 同步),这与此刻重连拿到的完全一致。
|
||||
//可见性:round/start/currseat/startcount/startflower/starttype/maxseat/maxcard 都是
|
||||
//由桌面公开信息直接推出的;cards 就是本轮已摊在桌上的牌;shuai_demand 是首家甩牌的
|
||||
//分量构成,而甩出的牌本身已公开、chupai1 也已把等价的 shuai 下发给三家。全部对三家可见,
|
||||
//无需逐座位裁剪(重连包 PushCards.playproc 本就对三家无差别下发,两条路径口径一致)
|
||||
msg.data.playproc = cls_youle_erqiwang_paiju.get_playproc(o_paiju);
|
||||
if (re.shuaicuo){
|
||||
msg.data.shuaicuo = 1; //甩错:本次甩牌被收回,只打出了最小一张(§5.4.5)
|
||||
}
|
||||
@@ -550,6 +573,8 @@ youle_erqiwang.chupai = function(pack){
|
||||
delete msg.data.nextseat;
|
||||
delete msg.data.countdown;
|
||||
delete msg.data.baozhu;
|
||||
//本轮进行态只对「还要继续出牌」有意义;本包已转为 jiesuan,不带
|
||||
delete msg.data.playproc;
|
||||
delete msg.data.cardsinhand;
|
||||
delete msg.data.maxseat;
|
||||
delete msg.data.grade;
|
||||
|
||||
Reference in New Issue
Block a user