/////////////////////////////////////////////////////////////// ////////// EQW_ResyncHandler: 重连(deskinfo)与开局(StartWar) /////////////////////////////////////////////////////////////// // 前端 04 §3:重连 = 重画。断线重连与硬刷新本质相同,复用同一条路径: // 填 GameState → emit EQW_RESYNC_ALL → 各组件据数据重建界面 // 【绝不为重连单写一套渲染】。 // // deskinfo 按 step 只带对应阶段的分组(协议文末): // 恒有 count / idx / PlayerInfo / step / MyCards // CallRun(step1) ChooseMain(step2) BuryCards(step3) PushCards(step5) Balance(step6) // // 【重连不重放一次性事件】:70 分坐庄的 3 秒开底是上庄时的一次性事件, // deskinfo 里没有 ancard3s,前端也不得补播。 var EQW_ResyncHandler = EQW_ResyncHandler || { //平台房间信息(roomcode / 总局数 / roomtype 位串) handleSetRoomDes: function (roomcode, asetcount, roomtype) { if (typeof asetcount === 'number') { EQW_GameState.room.asetCount = asetcount; } EQW_GameState.room.options = EQW_RoomOptions_Parse.parse(roomtype); }, //开局:makewar 可能差异化下发(sendtype:1 + seatlist[]),先取自己那份 handleStartWar: function (msg) { if (!msg || !msg.data) { console.warn('[EQW_ResyncHandler] StartWar 无数据,已忽略'); return; } var raw = msg.data.deskwar || msg.data; var mine = raw; if (raw && raw.sendtype === 1 && Object.prototype.toString.call(raw.seatlist) === '[object Array]') { mine = null; for (var i = 0; i < raw.seatlist.length; i++) { if (raw.seatlist[i] && raw.seatlist[i].seat === EQW_GameState.room.mySeat) { mine = raw.seatlist[i].data; break; } } if (!mine) { console.error('[EQW_ResyncHandler] StartWar 差异化下发里没有本座位的数据'); return; } } this.handleDeskinfo(mine); }, //重连:deskinfo 全量快照 handleDeskinfo: function (info) { if (!info) { console.warn('[EQW_ResyncHandler] deskinfo 为空,已忽略'); return; } EQW_GameState.reset(); //—— 恒有的部分 —— EQW_GameState._apply(EQW_GameState.room, info, { asetCount: 'count', asetIdx: 'idx', playerScores: 'PlayerInfo' }); EQW_GameState._apply(EQW_GameState.aset, info, { step: 'step' }); EQW_GameState._apply(EQW_GameState.my, info, { cards: 'MyCards' }); //—— 按阶段分组 —— if (info.CallRun) { this._applyCallRun(info.CallRun); } if (info.ChooseMain) { this._applyChooseMain(info.ChooseMain); } if (info.BuryCards) { this._applyBuryCards(info.BuryCards); } if (info.PushCards) { this._applyPushCards(info.PushCards); } if (info.Balance) { this._applyBalance(info.Balance); } EventBus.emit(EQW_Events.EQW_RESYNC_ALL); }, _applyCallRun: function (g) { EQW_GameState._apply(EQW_GameState.call, g, { currcall: 'nowcall', calls: 'call' }); EQW_GameState._apply(EQW_GameState.aset, g, { multiple: 'multiple' }); EQW_GameState._apply(EQW_GameState.turn, g, { seat: 'seat', countdown: 'countdown' }); }, _applyChooseMain: function (g) { EQW_GameState._apply(EQW_GameState.aset, g, { banker: 'banker', call: 'call', multiple: 'multiple', touxiang: 'touxiang', curmultiple: 'curmultiple' //与 shangzhuang 推送同源同值,漏读会让「抓分」角标掉档 }); EQW_GameState._apply(EQW_GameState.my, g, { bottomCards: 'bottomcards' }); //控制权由服务端在分组里显式给出(与 shangzhuang.nextseat 同源同值); //曾经这里写 turn.seat = aset.banker 自推,与 CallHandler 里那份是同一条规则的第二个写入处 EQW_GameState._apply(EQW_GameState.turn, g, { seat: 'seat', countdown: 'countdown' }); }, _applyBuryCards: function (g) { EQW_GameState._apply(EQW_GameState.aset, g, { banker: 'banker', call: 'call', multiple: 'multiple', flower: 'flower', curmultiple: 'curmultiple' //同上:一张牌未出时恒为 +3(大光),也必须重建 }); EQW_GameState._apply(EQW_GameState.my, g, { bottomCards: 'bottomcards' }); //控制权同上,读服务端给的 seat(与 xuanzhu.nextseat 同源同值) EQW_GameState._apply(EQW_GameState.turn, g, { seat: 'seat', countdown: 'countdown' }); }, _applyPushCards: function (g) { EQW_GameState._apply(EQW_GameState.aset, g, { banker: 'banker', call: 'call', multiple: 'multiple', flower: 'flower', grade: 'grade', curmultiple: 'curmultiple', //报无主:明牌按钮与余主公示的开关,增量路径由 chupai1/2/3 的 baozhu 维护, //重连路径必须从 PushCards.baozhu 一起恢复,否则重连后按钮凭空消失 baozhu: 'baozhu' }); EQW_GameState._apply(EQW_GameState.my, g, { buryCards: 'burycards', mustCard: 'mustcard' }); EQW_GameState._apply(EQW_GameState.table, g, { playproc: 'playproc', pushlist: 'pushlist', seatlist: 'seatlist', liangpai: 'liangpai' }); EQW_GameState._apply(EQW_GameState.turn, g, { countdown: 'countdown' }); //当前该谁出牌由 playproc.currseat 给出(服务端权威,前端不推导) if (g.playproc && typeof g.playproc.currseat === 'number') { EQW_GameState.turn.seat = g.playproc.currseat; } }, //结算阶段(step6):Balance 与 jiesuan 推送给的是同一份结算数据(服务端同源快照)。 //bottom(抠底明细)只有正常出牌结算才有、account(大局结算)只有末局/解散才有—— //缺就不写、保持 reset() 的 null,与 jiesuan 那条路径的取舍完全一致。 //【为什么必须接】结算面板还开着时断线重连/硬刷新,只恢复 aset 会让抠底明细与末局大结算空白。 _applyBalance: function (g) { EQW_GameState._apply(EQW_GameState.result, g, { aset: 'aset', bottom: 'bottom', account: 'account' }); } };