local EventSystem = require('Event/EventSystem') local battle_begin_pb = require("Proto/battle_begin_pb") local reconnect_pb = require "Proto/battle_reconnect_pb" local Const_DelayFrames = LuaConst.WatchBattle_DelayFrames -- 观看落后真实的战斗 100帧(5秒) local Const_CachePlayFrames = 20 -- 缓冲误差(防止网络抖动) local WatchBattleManager = { } local private = { cacheBattleFrames = {}, -- 战斗帧数据 maxPlayFrame = 0, -- 播放到多少帧的限制 checkStr = nil, -- 需要校验服字符串 } function WatchBattleManager.Init() NetManager.RegisterMsgCB(MessageEnums.MessageWatchBattleReady, private.OnWatchBattleReady) NetManager.RegisterMsgCB(MessageEnums.MessageG2CWatchBattleReconnect, private.OnG2CWatchBattleReconnect) NetManager.RegisterMsgCB(MessageEnums.MessageG2CWatchBattleCheckInfo, private.OnG2CWatchBattleCheckInfo) end -- 进入战斗首次收到initfuben ,用于进入战斗 function WatchBattleManager.OnInitFubenInfo(initFubenInfo) MultiplayManager.HandleInitFubenInfo(initFubenInfo , false) MultiplayManager.IsFromStartEnter = true LogicUpdateManager.SetServerReplenishFrame(-1) EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.SyncBattle,"[sync]WatchInitFuben") LevelManager.SwitchLevel(initFubenInfo.mapCfgId, initFubenInfo.randomSeed, false, false) MultiplayManager.CurConnectType = LuaConst.SyncConnectType.WatchBattle LevelManager.SetIsInLevelWatchBattle(true) table.clear(private.cacheBattleFrames) KCPTransport.BindFrameCallBack() BattleExt.KCPFilterTankInit() private.maxPlayFrame = 0 end -- 进入战斗首次收到initfuben ,用于进入战斗 function WatchBattleManager.SendReady() EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.SyncBattle,"[sync]WatchReady") local msg = battle_begin_pb.WatchBattleReadyReq() msg.EndFrameLen = 0 NetManager.SendMessage(MessageEnums.MessageWatchBattleReady, msg) end function private.OnWatchBattleReady(msgResp) -- 暂时无处理逻辑 if msgResp.Resp.Code ~= 0 then logging.error(LTAG.ERROR, " MessageWatchBattleReady error code = ", msgResp.Resp.Code) --为了防止卡住,让玩家离开 EventSystem.Dispatch(EventID.Level_SendRoleLeaveFuben ,false) end end function WatchBattleManager.OnBattleFrameDatas(msg, type) table.insert(private.cacheBattleFrames, msg.BattleData) if not msg.IsEnd then return end --- 容错处理:当断线重连时出现了异常的状态,则不处理(在连续两次发送重连协议时会出现) if MultiplayManager.CurConnectType == LuaConst.SyncConnectType.None and type == reconnect_pb.FDWatch then logging.error(LTAG.ERROR, "[gws] 观战发现异常状态,不处理逻辑 !此log,在网路不好时出现菊花后易出现,不影响执行。") return end ---如果是重连过来的 if MultiplayManager.CurConnectType == LuaConst.SyncConnectType.WatchBattleReconnect then WatchBattleManager.OnBattleFrameDatas_Reconnect(msg, type) return end --- 如果是首次进入观战 或 中途推送的帧 ↓ local battleFrameBytes = table.concat(private.cacheBattleFrames) if type == reconnect_pb.FDWatch then BattleExt.SetServerMsgCount(0) LogicUpdateManager.ResetData() end local length, startFrame, endFrame = BattleExt.ParseBeginBattleData(battleFrameBytes) --先将补帧的数据放入cache中,再从cache放入到B2CFrameList中 。如果msg.BattleData的长度为0(即不用补帧),则startFrame, endFrame都是-1 table.clear(private.cacheBattleFrames) if type == reconnect_pb.FDWatch then EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.SyncBattle,"[sync]WatchGetBattleFrameDatas", length, startFrame, endFrame) end if type == reconnect_pb.FDWatch then -- 首次进入 local serverFrame = KCPTransport.GetCurserverFrame() private.maxPlayFrame = serverFrame-Const_DelayFrames local replenishFrame = KCPTransport.GetCurserverFrame()-Const_DelayFrames if replenishFrame <= 0 then replenishFrame = Const_DelayFrames end LogicUpdateManager.SetServerReplenishFrame(replenishFrame) --设置快速补帧的值 ,不做表现 ,打开界面通过OnFastPlayOver调用ExpLevelManager.EnterLevel完成 ; if LevelManager.IsSyncTeamPVP() or LevelManager.IsSyncSolo() then MultiplayManager.SetAllRolesActive() LevelManager.SetLoadingLevelEnd() else if not LevelManager.CurLevelFunc.isFreeToEnterAndLeave then -- 随进随出功能的设置快进 LevelManager.SetLoadingLevelEnd() end end LevelManager.EnterSyncLevel() else -- 每次tick local serverFrame = KCPTransport.GetCurserverFrame() if serverFrame > LogicUpdateManager._clientHandleFrame + Const_DelayFrames + Const_CachePlayFrames then private.maxPlayFrame = serverFrame-Const_DelayFrames end end MultiplayManager.CurConnectType = LuaConst.SyncConnectType.None MultiReconnectManager.SetInBattleReconnect(true) end function WatchBattleManager.GetMaxPlayFrame() return private.maxPlayFrame end --region-----------------重连相关代码 ↓------------- function private.OnG2CWatchBattleReconnect(msg) --不处理initfuben ,但是需要重刷新一下playerInfo local isFairLevel = LevelManager.IsFairLevel() for _,battleRoomRoleInfo in ipairs(msg.initInfo.roleList) do if LevelPlayerManager.PlayersArmyTable[battleRoomRoleInfo.playerID] == nil then LevelPlayerManager.SetSyncPlayerArmyTable(battleRoomRoleInfo, isFairLevel) logging.crit(LTAG.CRIT, "[gws]: 观战断线重连 ,发现中途有玩家进入!playerID = ", battleRoomRoleInfo.playerID) end end EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.SyncBattle,"[sync]WatchBattleReconnectInitFuben",BattleExt.GetCurServerFrame()) MultiplayManager.CurConnectType = LuaConst.SyncConnectType.WatchBattleReconnect table.clear(private.cacheBattleFrames) WatchBattleManager.SendReconnectReady() end function WatchBattleManager.SendReconnectReady() local msg = battle_begin_pb.WatchBattleReadyReq() msg.EndFrameLen = BattleExt.GetServerMsgCount() NetManager.SendMessage(MessageEnums.MessageWatchBattleReady, msg) end -- 收到重连的帧 function WatchBattleManager.OnBattleFrameDatas_Reconnect(msg, type) local battleFrameBytes = table.concat(private.cacheBattleFrames) local frameCount = BattleExt.ParseBattleReconnectFrameData(battleFrameBytes, true) -- 补帧帧总量 table.clear(private.cacheBattleFrames) MultiplayManager.CurConnectType = LuaConst.SyncConnectType.None EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.SyncBattle,"[sync]WatchBattleReconnectOver",frameCount, type) if type == reconnect_pb.FDWatchTick then logging.error(LTAG.ERROR, "[gws]: 观战重连:观战重连最后接收BattleFrameDatas时,其type是FDWatchTick 。需要服务器查下为啥!") end end --endregion----------------------重连相关代码 ↑------------ -- 收到校验字符串 function private.OnG2CWatchBattleCheckInfo(msg) private.checkStr = msg.checkStr end function WatchBattleManager.OnLevelStop(checkStr, isClickExitBtn) KCPTransport.UnBindFrameCallBack() if not string.isNilOrEmpty(private.checkStr) and not string.isNilOrEmpty(checkStr) and private.checkStr ~= checkStr then EventSystem.Dispatch(EventID.BI_LevelMiddle,BIManager.BIType.SyncBattle,"[sync]WatchBattleNotSame") end private.checkStr = nil private.maxPlayFrame = 0 EventSystem.Dispatch(EventID.WatchBattle_LevelStop, isClickExitBtn) end return WatchBattleManager