Files
erqiwang_youle/client/js/01_SubGame/codes/net/handlers/ResultHandler.js
T
joywayerandClaude Opus 5 c4c061b0e1 二七王:修复三处前端漏读(Task 12 一致性测试 Fix Round 1 · 类别 A)
一致性测试发现的 8 处不一致中,分诊出 3 处确属"deskinfo 里有、增量 handler
没读"的前端缺陷,本次修复:

- room.playerScores:reset() 不再清空,改为跨局保留字段;ResultHandler 从
  jiesuan 的 aset.seatlist[i].score(协议 §14「累积得分」)回填,避免一局
  中段(fapai 后至 jiesuan 前)总积分持续为空。
- call.currcall/call.calls:CallHandler.handleShangzhuang(step1→2 转场)
  清回默认值——deskinfo 从 ChooseMain 起就不再带 CallRun,这两个叫分过程量
  该阶段起无意义。
- ResultHandler._applyResult(jiesuan/解散共用)补齐结算清场:把 aset.*/
  turn.*/call.*/table.*/my.bottomCards/buryCards/cards 清回 reset() 默认值,
  与 deskinfo step6 只应用 Balance 分组时的重建结果对齐;顺带清掉出完最后一张
  牌的座位因 jiesuan.chupai 不带 cardsinhand 留下的幽灵手牌。

发现 3(curmultiple)、发现 6(seatlist 窗口期)判给服务端,发现 4/5
(table.playproc/pushlist)待裁决,均未改动。test_consistency.js 由 9
PASS/14 FAIL 转为 14 PASS/9 FAIL,EXCLUDE 白名单未改一字。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 18:57:54 +08:00

100 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///////////////////////////////////////////////////////////////
////////// EQW_ResultHandler: 结算(jiesuan)与解散(Free)///
///////////////////////////////////////////////////////////////
// 协议 §14:结算包由 chupai + bottom + aset 拼装,末局再加 account。
// 三种来源的组成不同:
// 正常出牌结算:chupai + bottom + aset(末局加 account)
// 投降结算: 只有 aset(末局加 account),无 chupai、无 bottom
// 解散结算: 只有 aset + account,且【走另一个入口】,见下
//
// 【解散的特殊性】(协议 §14.1,已对平台代码核实):
// 解散包的 route 是平台的 "room",平台 12_Logic.js 按 route 分流时把它交给
// Net[rpc] 而【不是】Game_Modify._ReceiveData——所以它根本进不了子游戏的分发表。
// 平台另有专门入口:07_Desk.js 的 Game_Modify.Free(Desk.deskfree)。
// 两个后果:
// 1. 取值路径比协议文档少一层——平台已把 deskfree 取出来传进来,
// 所以是 deskfree.data.aset,不是 data.deskfree.data.aset;
// 2. 参数可能是 null——解散若发生在开战后、首局发牌前,服务端 get_disbandRoom
// 返回 null,平台走「不带 deskfree」分支。这时只做房间收尾、不弹结算。
var EQW_ResultHandler = EQW_ResultHandler || {
handleJiesuan: function (data) {
if (!data.hasOwnProperty('aset')) {
console.error('[EQW_ResultHandler] jiesuan 缺 aset,已跳过该包');
return;
}
this._applyResult(data);
},
//平台解散入口。deskfree = { rpc:"jiesuan", data:{ success, aset, account } },可能为 null
handleFree: function (deskfree) {
if (!deskfree || !deskfree.data) {
//首局发牌前解散:没有结算数据,只做房间收尾,不弹结算面板
console.warn('[EQW_ResultHandler] 解散包无 deskfree 数据(首局发牌前解散)');
return;
}
var d = deskfree.data;
if (!d.hasOwnProperty('aset')) {
console.error('[EQW_ResultHandler] 解散包缺 aset,已跳过');
return;
}
this._applyResult(d);
},
//三种来源共用的落地逻辑:有哪组就写哪组,缺的保持 null
_applyResult: function (d) {
//结算是"清空过程量、只留结算数据"的快照点:deskinfo step6 只带 Balance(=aset),
//其余分组一律回到 reset() 默认值——jiesuan 也要收敛到同一状态,否则重连前后画面不一致
//(清单以 ResyncHandler.handleDeskinfo 在 step6 时实际重建出的字段集为准,不多清不少清)。
EQW_GameState.aset.banker = -1;
EQW_GameState.aset.call = -1;
EQW_GameState.aset.multiple = 0;
EQW_GameState.aset.flower = 0;
EQW_GameState.aset.curmultiple = 0;
EQW_GameState.aset.grade = 0;
EQW_GameState.aset.baozhu = 0;
EQW_GameState.aset.touxiang = 0;
EQW_GameState.turn.seat = -1;
EQW_GameState.turn.countdown = 0;
EQW_GameState.call.currcall = 0;
EQW_GameState.call.calls = [null, null, null];
//末轮若由 jiesuan.chupai 带出(无 cardsinhand),出牌者自己的手牌不会被清空,这里显式清掉,
//不留幽灵牌——deskinfo 在结算阶段的 MyCards 恒为 []
EQW_GameState.my.cards = [];
EQW_GameState.my.mustCard = [];
EQW_GameState.my.bottomCards = [];
EQW_GameState.my.buryCards = [];
EQW_GameState.table.ancard3s = 0;
EQW_GameState.table.playproc = null;
EQW_GameState.table.pushlist = [];
EQW_GameState.table.seatlist = [];
EQW_GameState.table.liangpai = null;
EQW_GameState.table.mingpai = null;
EQW_GameState._apply(EQW_GameState.result, d, {
chupai: 'chupai',
bottom: 'bottom',
aset: 'aset',
account: 'account'
});
EQW_GameState.aset.step = 6;
//三家总积分:jiesuan 的 aset.seatlist[i].score 就是"累积得分"(协议 §14),
//与 deskinfo.PlayerInfo 同源同值——deskinfo 恒有的 PlayerInfo 在增量路径上没有对应来源,
//只能从这里回填,否则一局中段(fapai 后至 jiesuan 前)room.playerScores 永远追不上服务端
if (d.aset && Object.prototype.toString.call(d.aset.seatlist) === '[object Array]') {
var scores = [];
for (var i = 0; i < d.aset.seatlist.length; i++) {
scores.push(d.aset.seatlist[i] && d.aset.seatlist[i].score);
}
EQW_GameState.room.playerScores = scores;
}
EventBus.emit(EQW_Events.EQW_ASET_RESULT);
//account 只在末局或解散时才有
if (d.hasOwnProperty('account')) {
EventBus.emit(EQW_Events.EQW_ACCOUNT_RESULT);
}
}
};