From b9a423071bf4d06980035fdeee34a04d1f68c9d0 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Thu, 27 Aug 2026 22:06:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=8C=E4=B8=83=E7=8E=8B=EF=BC=9ABalance.rea?= =?UTF-8?q?dystate=20=E6=94=B9=E4=B8=BA=E6=B7=B1=E6=8B=B7=E8=B4=9D?= =?UTF-8?q?=E4=B8=8B=E5=8F=91=EF=BC=8C=E6=89=A9=E5=B1=95=E6=B7=B1=E6=8B=B7?= =?UTF-8?q?=E8=B4=9D=E5=AE=88=E5=8D=AB=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit o_desk.prepare 是 do_prepare 就地置 1、do_new_paiju 就地重建的活数组, 整根挂进 deskinfo.Balance.readystate 会让「已发出的包」随后续准备操作被回改。 与 get_playproc / get_seatlist / get_pushlist / get_bottomcards 同一条标准,改为下发副本。 test_rpc 扩展既有的深拷贝守卫:正面(内容逐格相等)+ 非空转(活数组确实变过) + 反面(已发出的包不被回改、改副本不影响本体)。反向验证:去掉 .concat() 后两条断言转红。 Co-Authored-By: Claude Opus 5 (1M context) --- server/games/erqiwang/class.export.js | 7 ++++++- server/games/erqiwang/test/test_rpc.js | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/server/games/erqiwang/class.export.js b/server/games/erqiwang/class.export.js index c5c98c2..c69a77b 100644 --- a/server/games/erqiwang/class.export.js +++ b/server/games/erqiwang/class.export.js @@ -215,7 +215,12 @@ var cls_youle_erqiwang_export = cls_youle_erqiwang_export || { case 6: //结算 deskinfo.Balance = {}; //玩家的准备状态 - deskinfo.Balance.readystate = o_room.o_desk.prepare; + //【返回副本】o_room.o_desk.prepare 是一张全程就地改写的活数组 + //(do_prepare 每次准备就地把某一格置 1,do_new_paiju 又就地重建), + //把它本体挂进下发包会让「已发出的包」随后续准备操作被回改。 + //与 get_playproc / get_seatlist / get_pushlist / get_bottomcards 同一条标准: + //平台真实链路虽然立刻序列化看不出来,但这是隐患,不留。 + deskinfo.Balance.readystate = o_room.o_desk.prepare.concat(); if (o_room.o_desk.prepare[seat] == 0){ //结算面板的三件套:与 jiesuan 推送【同源同值】(都取 get_paiju_account 末尾 //冻结的那份快照)。只给 aset 会让「结算面板还开着时断线重连/硬刷新」丢掉 diff --git a/server/games/erqiwang/test/test_rpc.js b/server/games/erqiwang/test/test_rpc.js index 0287038..06c82aa 100644 --- a/server/games/erqiwang/test/test_rpc.js +++ b/server/games/erqiwang/test/test_rpc.js @@ -770,4 +770,19 @@ t.eq('座位牌况 get_seatlist 内容与活表逐格相等', JS(slNow), JS(sl.p slNow[0][0][0] = 9; t.eq('座位牌况 get_seatlist 是深拷贝(改副本不影响本体)', sl.pj.seatlist[0][0][0] !== 9, true); +// ===================== Balance.readystate 必须以深拷贝下发(不把活数组挂进下发包)===================== +// o_desk.prepare 是一张全程就地改写的活数组(do_prepare 把某一格置 1、do_new_paiju 就地重建)。 +// 它此前被整根挂进 deskinfo.Balance.readystate,与 playproc / seatlist / pushlist 同级的隐患: +// 已发出的包会随后续准备操作被回改。标准与 get_playproc 一致——下发副本。 +const rs = driveToSettle("00000"); +const rsLive = E.get_deskinfo(rs.c.o_room, 0).Balance.readystate; +t.eq('准备状态 内容与活数组逐格相等', JS(rsLive), JS(rs.c.o_desk.prepare)); +t.eq('准备状态 发包时刻三家皆未准备 → 用例起点明确', JS(rsLive), JS([0, 0, 0])); +rs.c.o_desk.prepare[1] = 1; //模拟「包已发出之后,1 号位按了准备」(do_prepare 的就地写) +t.eq('准备状态 活数组确实变过 → 用例非空转', JS(rs.c.o_desk.prepare), JS([0, 1, 0])); +t.eq('准备状态 下发的是深拷贝(已发出的包不被后续准备操作回改)', JS(rsLive), JS([0, 0, 0])); +// 反面:改副本不得影响本体 +rsLive[2] = 9; +t.eq('准备状态 是深拷贝(改副本不影响本体)', rs.c.o_desk.prepare[2], 0); + process.exit(t.done('rpc') ? 0 : 1);