local NetManager = { receiveCallbacks = {}, msgCallbacks = {}, isClosedMap = {}, chatReconnectWaitTime = 1, connectIPMap = {}, receiveCallbackPool = {}, alreadyConnected = {}, mainReconnectWaitTime = 0, sendQueue = {}, tillBeforeOverCount = 0, msgId = 0 } local CSApplication = CS.UnityEngine.Application local CSNotReachable = CS.UnityEngine.NetworkReachability.NotReachable local MAX_CHAT_WAIT_TIME = 16 local MAX_MAIN_WAIT_TIME = 10 local JOIN_CHAT_INTERVAL = 15 local TILL_BEFORE_INTERVAL = 0.5 local NetErrorCode = CS.BF.NetErrorCode local pb = require "pb" local ProtoMsgDispatch = require "app/proto/proto_msg_dispatch" local protoPaths = { "assets/proto/protocol.bytes", } NetManager.MAIN_SOCKET_NAME = 0 NetManager.CHAT_SOCKET_NAME = 1 NetManager.LOGIN_TYPE = { TOKEN = "token", ANONYMOUS = "anonymous", GOOGLE = "google", APPLE = "apple", FACEBOOK = "facebook", } function NetManager:getGate() if EDITOR_MODE then return "http://game.juzugame.com:3000" else return "https://d3ksek7t8d0wbt.cloudfront.net/" end end function NetManager:init(callback) self.chatReconnectWaitTime = 1 CS.BF.BFMain.Instance.NetMgr:InitNetClientCount(1) -- 只有主链接,没有聊天,但是聊天逻辑先不删 if self.initSucc then if callback then return callback() end end self.initSucc = true -- pb.option "int64_as_string" --如果需要uint64再加上 local loadCount = #protoPaths for i, path in ipairs(protoPaths) do ResourceManager:loadOriginAssetAsync(path, GConst.TYPEOF_UNITY_CLASS.TEXT_ASSET, function(_, textAsset) pb.load(textAsset.bytes) ResourceManager:unload(path) loadCount = loadCount - 1 if loadCount == 0 then if callback then return callback() end end end) end end function NetManager:setChatUrl(url) local arr = string.split(url, ":") self.chatDomain = arr[1] self.chatPort = arr[2] end function NetManager:getChatDomain() return self.chatDomain end function NetManager:getChatPort() return self.chatPort end function NetManager:getIsBusy() return self.isSending end function NetManager:isNotReachable() return CSApplication.internetReachability == CSNotReachable end function NetManager:connect(domain, port, callback, socketName) socketName = socketName or NetManager.MAIN_SOCKET_NAME if self:isAvailable(socketName) then if callback then callback() end return end self.alreadyConnected[socketName] = false self.isClosedMap[socketName] = false if socketName == NetManager.MAIN_SOCKET_NAME then UIManager:showWaitNet(true) end self.connectIPMap[socketName] = "" CS.BF.BFMain.Instance.NetMgr:AddLuaOnConnected(function(name) self.alreadyConnected[name] = true Logger.log("[NetManager]connect success:%s", name) local connectIP = self:getConnectIP(name) self.connectIPMap[socketName] = connectIP if name == NetManager.MAIN_SOCKET_NAME then if self.reconnectMainId then SchedulerManager:unscheduleGlobal(self.reconnectMainId) self.reconnectMainId = nil end self.mainReconnectWaitTime = 0 UIManager:hideWaitNet() else self.chatReconnectWaitTime = 1 if self.reconnectChatId then SchedulerManager:unscheduleGlobal(self.reconnectChatId) self.reconnectChatId = nil end if DataManager.ChatData then DataManager.ChatData:onConnect() end self:joinChatChannel() end if callback then callback() end end) CS.BF.BFMain.Instance.NetMgr:AddLuaOnDisconnected(function(name) -- self:onDisconnect(name) self:disconnectAndReconnect() end) CS.BF.BFMain.Instance.NetMgr:AddLuaOnReceiveMessage(function(name, group, recvId, bytes) if name == NetManager.MAIN_SOCKET_NAME then self.recvId = recvId if self.reconnectMainFlag then -- 如果是在重连状态下收到消息就设置下重连所需要的数据 self:setReconnectData() end end self:onReceive(group, bytes) end) CS.BF.BFMain.Instance.NetMgr:AddLuaOnError(function(name, errorCode, errorMsg) self:onError(name, errorCode, errorMsg) end) CS.BF.BFMain.Instance.NetMgr:AddLuaOnReconnectSuccess(function(name) Logger.log("[NetManager]reconnect succes:%s", name) self:trySend() if name == NetManager.MAIN_SOCKET_NAME then if self.reconnectMainId then SchedulerManager:unscheduleGlobal(self.reconnectMainId) self.reconnectMainId = nil end self.mainReconnectWaitTime = 0 if self.reconnectMainFlag then self.reconnectMainFlag = false end if self.activeReconnectMainFlag then self.activeReconnectMainFlag = false UIManager:hideWaitNet() if UIManager:getWaitNetCount() == 0 then UIManager:hideMessageBoxByTag(GConst.GAME_OBJECT_TYPE.MESSAGEBOX_RECONNECT) end end local durationTime = 0 if self.disconnectTime then durationTime = Time:getServerTime() - self.disconnectTime self.disconnectTime = nil end BIReport:postNetWorkOpt(BIReport.NETWORK_OPT_TYPE.RECONNECT, UIManager:getTopUIIndex(), nil, durationTime) else self.chatReconnectWaitTime = 1 if self.reconnectChatId then SchedulerManager:unscheduleGlobal(self.reconnectChatId) self.reconnectChatId = nil end if self.joinChatId then SchedulerManager:unscheduleGlobal(self.joinChatId) self.joinChatId = nil end if DataManager.ChatData then DataManager.ChatData:onConnect() end self:joinChatChannel() end end) CS.BF.BFMain.Instance.NetMgr:SetLuaOnDecodePbCallback(function(name, group, recvId, data) local msgName = ProtoMsgDispatch:getReqMsgNameByMsgId(group) if msgName == nil then return end Logger.logHighlight("[NetManager]===onReceive===name:%s, msgId:%s", msgName, group) -- 这里保证即使协议有问题解不出来也不要卡住 local ok, pbData = pcall(function() local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName) return pb.decode(fullMsgName, data) end) if ok and pbData then pbData.status = not pbData.err_code and 0 or ProtoMsgDispatch:getErrCodeEnum(pbData.err_code) if pbData.status ~= 0 then if msgName == "ReconnectRsp" then -- Reconnect失败就直接回登录界面 self:closeAll() else self:closeAndClear() local accountInfo = LocalData:getAccountInfo() local loginType local lastLoginType if accountInfo.google_id and accountInfo.google_id ~= "" then loginType = SDKManager.BF_LOGIN_TYPE.GOOGLE lastLoginType = NetManager.LOGIN_TYPE.GOOGLE elseif accountInfo.apple_id and accountInfo.apple_id ~= "" then loginType = SDKManager.BF_LOGIN_TYPE.APPLE lastLoginType = NetManager.LOGIN_TYPE.APPLE end if loginType then SDKManager:login(function(params) if not params.token then return end LocalData:setLastLoginInfo(lastLoginType, params.id, params.token) ModuleManager.LoginManager:saveAuthArgs(true) ModuleManager.LoginManager:initSocket() end, loginType) else LocalData:setLastLoginInfo() ModuleManager.LoginManager:saveAuthArgs(true) local params = { content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN), okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), noShowClose = true, okFunc = function() ModuleManager.LoginManager:initSocket() end, boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, top = true, } GFunc.showMessageBox(params) end end else UIManager:hideWaitNet(true) LocalData:setLastLoginInfo(NetManager.LOGIN_TYPE.TOKEN, pbData.id, pbData.token) LocalData:setAccountInfo(pbData) BIReport:updateAccountId(pbData.id) pbData.send_id = pbData.send_id or 0 pbData.err_code = nil CS.BF.BFMain.Instance.NetMgr.decodePbStr = json.encode(pbData) CS.BF.BFMain.Instance.NetMgr.rspGroup = group CS.BF.BFMain.Instance.NetMgr.decodeFinish = true end end end) CS.BF.BFMain.Instance.NetMgr:SetLuaAuthCallback(function(isSuccess) if not isSuccess then local params = { content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN), okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), noShowClose = true, okFunc = function() ModuleManager.LoginManager:goToLoginScene() end, boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, top = true, } GFunc.showMessageBox(params) end end) local configuration = CS.BF.NetConnectConfiguration(CS.BF.NetServiceType.TCPService, tostring(socketName)) configuration:EnableMessageType(CS.BF.NetIncomingMessageType.DebugMessage) configuration:EnableMessageType(CS.BF.NetIncomingMessageType.WarningMessage) configuration:EnableMessageType(CS.BF.NetIncomingMessageType.ErrorMessage) if socketName == NetManager.MAIN_SOCKET_NAME then configuration.EnableSilenceReconnect = false -- game连接不用自动重连 configuration.ReconnectTimeoutTime = GConst.WAIT_NET_RSP_TIME -- 每次重连超时时间 configuration.AlreadySendMessageCacheCount = 3 else -- configuration.ReconnectTimeoutTime = 8 -- 每次重连超时时间 -- configuration.ReconnectBaseInterval = 1 -- 每次重连间隔时间 -- configuration.AutoReconnectCount = 5 -- 重连次数 -- 自动重连可能有bug,先手动重连 configuration.EnableSilenceReconnect = false -- chat连接不用自动重连 configuration.ReconnectTimeoutTime = MAX_CHAT_WAIT_TIME -- 每次重连超时时间 configuration.AlreadySendMessageCacheCount = 3 end CS.BF.BFMain.Instance.NetMgr:ConnectWithConfiguration(socketName, configuration, domain, tonumber(port)) end function NetManager:isConnected(socketName) if not self.initSucc then return false end return CS.BF.BFMain.Instance.NetMgr:IsConnected(socketName) end function NetManager:isAvailable(socketName) if not self.initSucc then return false end return CS.BF.BFMain.Instance.NetMgr:IsAvailable(socketName) end function NetManager:isDisconnected(socketName) if not self.initSucc then return true end return CS.BF.BFMain.Instance.NetMgr:IsDisconnected(socketName) end function NetManager:getConnectIP(socketName) if not self.initSucc then return "" end return CS.BF.BFMain.Instance.NetMgr:GetConnectIP(socketName) end function NetManager:_sendBytes(clientName, bytes, group, cmd) self.isSending = true CS.BF.BFMain.Instance.NetMgr:Send(clientName, group, cmd, bytes) end ---- 后台发送协议,不锁定界面 function NetManager:sendOnBackground(msgName, params, callback, socketName) self:_send(msgName, params, callback, socketName, false) end ---- 后台发送协议,不锁定界面,且不会有回复 function NetManager:sendOnBackgroundWithoutRsp(msgName, params, socketName) self:_send(msgName, params, nil, socketName, false, true) end function NetManager:saveAuthArgs(authArgs) local msgFullName = ProtoMsgDispatch:getMsgFullNameByMsgName(ProtoMsgType.FromMsgEnum.AuthReq) local bytes = pb.encode(msgFullName, authArgs) CS.BF.BFMain.Instance.NetMgr.authReqData = bytes end function NetManager:saveChatAuthArgs(token) local msgFullName = ProtoMsgDispatch:getMsgFullNameByMsgName(ProtoMsgType.FromMsgEnum.ChatAuthReq) local args = { id = DataManager.PlayerData:getUid(), token = token } CS.BF.BFMain.Instance.NetMgr.ChatAuthReqData = pb.encode(msgFullName, args) end function NetManager:send(binder, msgName, params, responseData, callback, lockGame, noRsp, getType) if responseData.rewards then responseData.rewards = GFunc.formatRewardsToServerStruct(responseData.rewards) end if responseData.costs then responseData.costs = GFunc.formatRewardsToServerStruct(responseData.costs) end responseData.err_code = GConst.ERROR_STR.SUCCESS self:_send(binder, msgName, params, responseData, callback, lockGame, noRsp, getType) end function NetManager:sendTillBeforeOver(binder, msgName, params, responseData, callback, lockGame, noRsp, getType) if responseData.rewards then responseData.rewards = GFunc.formatRewardsToServerStruct(responseData.rewards) end if responseData.costs then responseData.costs = GFunc.formatRewardsToServerStruct(responseData.costs) end responseData.err_code = GConst.ERROR_STR.SUCCESS self:_send(binder, msgName, params, responseData, callback, lockGame, noRsp, getType, true) end function NetManager:_send(binder, msgName, params, responseData, callback, lockGame, noRsp, getType, beforeOver) local socketName = NetManager.MAIN_SOCKET_NAME if self:isDisconnected(socketName) then if socketName == NetManager.MAIN_SOCKET_NAME then if UIManager:getWaitNetCount() > 0 then self:disconnect(socketName) else if self.reconnectMainId then SchedulerManager:unscheduleGlobal(self.reconnectMainId) self.reconnectMainId = nil end self:reconnectMain() end else self:disconnect(socketName) end else if beforeOver then UIManager:showWaitNet() self.tillBeforeOverCount = self.tillBeforeOverCount + 1 end local pipedMsgName, pipedParams = self:pipedMessage(msgName, params) table.insert(self.sendQueue, { binder = binder, originMsgName = msgName, msgName = pipedMsgName, params = pipedParams, responseData = responseData, socketName = socketName, callback = callback, lockGame = lockGame, noRsp = noRsp, getType = getType, beforeOver = beforeOver, }) if not self:isNotSave(msgName) then self:saveSendQueue() end self:trySend() end end function NetManager:trySend() local binder local originMsgName local curMsgName local curParams local responseData local getType local curSocketName local curCallback local curLockGame local noRsp local beforeOver if not self.isSending and self.sendQueue[1] then -- 没有正在发送的消息,并且有发送队列, 则继续发送 local cache = self.sendQueue[1] binder = cache.binder originMsgName = cache.originMsgName curMsgName = cache.msgName curParams = GFunc.getTable(cache.params) responseData = cache.responseData getType = cache.getType curSocketName = cache.socketName curCallback = cache.callback curLockGame = cache.lockGame noRsp = cache.noRsp beforeOver = cache.beforeOver end if curMsgName then if EDITOR_MODE then local subName = curMsgName local reqData if curMsgName == ProtoMsgType.FromMsgEnum.PipedReq then reqData = curParams.data Logger.logHighlight("[NetManager]===onSend===name:%s params:%s", ProtoMsgDispatch:getReqMsgNameByMsgId(curParams.msg_id), json.encode(reqData)) else reqData = curParams Logger.logHighlight("[NetManager]===onSend===name:%s params:%s", subName, json.encode(reqData)) end end local msgFullName = ProtoMsgDispatch:getMsgFullNameByMsgName(curMsgName) if curMsgName == ProtoMsgType.FromMsgEnum.PipedReq then local msgName = ProtoMsgDispatch:getReqMsgNameByMsgId(curParams.msg_id) local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName) if curParams.data and type(curParams.data) == "table" then curParams.data = pb.encode(fullMsgName, curParams.data) end end local bytes = pb.encode(msgFullName, curParams) if bytes then if curLockGame then UIManager:showWaitNet() end local msgId = ProtoMsgDispatch:getMsgIdByMsgName(curMsgName) self:_sendBytes(curSocketName, bytes, msgId, 0) if noRsp then return end local msg = ProtoMsgDispatch:getRspMsgByMsgName(originMsgName) if not self.receiveCallbacks[msg] then self.receiveCallbacks[msg] = {} end local receiveCallback = self:getReceiveCallback() receiveCallback.binder = binder receiveCallback.lockGame = curLockGame receiveCallback.callback = curCallback receiveCallback.responseData = responseData receiveCallback.getType = getType receiveCallback.beforeOver = beforeOver table.insert(self.receiveCallbacks[msg], receiveCallback) else Logger.logError("[NetManager]send data error %s", curMsgName) end end end -- 静默重连 function NetManager:silentReconnectMain() self.reconnectMainFlag = true self:setReconnectData() CS.BF.BFMain.Instance.NetMgr:Reconnect(NetManager.MAIN_SOCKET_NAME) end -- 主动重连 function NetManager:reconnectMain() UIManager:showWaitNet(true) -- 强制重新计时 if self.activeReconnectMainFlag then -- 说明之前已经在主动重连中,为了保证引用计数正确,这里减一 UIManager:hideWaitNet() else self.activeReconnectMainFlag = true end self.reconnectMainFlag = true self:setReconnectData() CS.BF.BFMain.Instance.NetMgr:Reconnect(NetManager.MAIN_SOCKET_NAME) end function NetManager:getReceiveCallback() if #self.receiveCallbackPool > 0 then return table.remove(self.receiveCallbackPool) end return {} end function NetManager:recycleReceiveCallback(receiveCallback) receiveCallback.callback = nil receiveCallback.lockGame = true table.insert(self.receiveCallbackPool, receiveCallback) end function NetManager:disconnectAll() if self.alreadyConnected[NetManager.MAIN_SOCKET_NAME] then self:showReconnectMain() else self:closeAll() end end function NetManager:disconnectAndReconnect() if self.alreadyConnected[NetManager.MAIN_SOCKET_NAME] then if self.reconnectMainId then return end self.reconnectMainId = self:performWithDelayGlobal(function () self.reconnectMainId = nil self:silentReconnectMain() end, self.mainReconnectWaitTime) self.mainReconnectWaitTime = self.mainReconnectWaitTime + 1 else self:closeAll() end end function NetManager:showReconnectMain() if self.reconnectMainId then SchedulerManager:unscheduleGlobal(self.reconnectMainId) self.reconnectMainId = nil end if UIManager:isDisconnectMsgBoxVisible() then return end local params = { content = I18N:getGlobalText(I18N.GlobalConst.RECONNECT), okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), cancelText = I18N:getGlobalText(I18N.GlobalConst.RELOGIN), noShowClose = true, okFunc = function() self:reconnectMain() end, cancelFunc = function() ModuleManager.LoginManager:goToLoginScene() end, boxType = GConst.MESSAGE_BOX_TYPE.MB_OK_CANCEL, tag = GConst.GAME_OBJECT_TYPE.MESSAGEBOX_RECONNECT, top = true, } GFunc.showMessageBox(params) end function NetManager:disconnect(socketName) if self.isClosedMap[socketName] then return end if socketName == NetManager.CHAT_SOCKET_NAME then self.isClosedMap[socketName] = true CS.BF.BFMain.Instance.NetMgr:Close(socketName) if self.reconnectChatId then return end if DataManager.ChatData then DataManager.ChatData:onDisconnect() end self.reconnectChatId = self:performWithDelayGlobal(function () self.reconnectChatId = nil if not self:isConnected(NetManager.CHAT_SOCKET_NAME) then ModuleManager.LoginManager:connectByChannel(nil, NetManager.CHAT_SOCKET_NAME) end end, self.chatReconnectWaitTime) self.chatReconnectWaitTime = self.chatReconnectWaitTime*2 if self.chatReconnectWaitTime > MAX_CHAT_WAIT_TIME then self.chatReconnectWaitTime = MAX_CHAT_WAIT_TIME end else if self.alreadyConnected[socketName] then -- 如果是成功连接过 if UIManager:getWaitNetCount() > 0 then -- 当前在等待服务器回消息 if not self.activeReconnectMainFlag then self:showReconnectMain() end else -- 否则就悄咪咪的重连 if self.mainReconnectWaitTime > MAX_MAIN_WAIT_TIME then self:showReconnectMain() else if self.reconnectMainId then return end self.reconnectMainId = self:performWithDelayGlobal(function () self.reconnectMainId = nil self:silentReconnectMain() end, self.mainReconnectWaitTime) self.mainReconnectWaitTime = self.mainReconnectWaitTime + 1 end end else -- 从来没有连上过 self:closeAll() end end end function NetManager:onDisconnect(socketName) self:disconnect(socketName) end function NetManager:performWithDelayGlobal(func, delay) local sid = SchedulerManager:performWithDelayGlobal(func, delay) return sid end function NetManager:scheduleGlobal(func, delay) local sid = SchedulerManager:scheduleGlobal(func, delay) return sid end function NetManager:closeAll(errorType) if self.isClosedMap[NetManager.MAIN_SOCKET_NAME] then return end self:closeAndClear() UIManager:showDisconnect(errorType) end function NetManager:onReceive(msgId, data) self.isSending = false --Logger.logHighlight("MSGID:"..msgId) local msgName = ProtoMsgDispatch:getReqMsgNameByMsgId(msgId) if msgName == nil then return end -- 这里保证即使协议有问题解不出来也不要卡住 local ok, pbData = pcall(function() local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName) return pb.decode(fullMsgName, data) end) local msg = ProtoMsgDispatch:getRspMsgByMsgName(msgName) if ok and pbData then if not pbData.err_code then pbData.status = 0 else pbData.status = ProtoMsgDispatch:getErrCodeEnum(pbData.err_code) end if EDITOR_MODE then Logger.logHighlight("[NetManager]===onReceive===name:%s, msgId:%s, data:%s", msgName, msgId, json.encode(pbData)) end self:dispatch(msgName, pbData) else if EDITOR_MODE then Logger.logHighlight("[NetManager]===onReceive failed===name:%s, msgId:%s", msgName, msgId) end end local sendInfo local sendMsgName if self.sendQueue[1]then sendMsgName = self.sendQueue[1].msgName if sendMsgName == ProtoMsgType.FromMsgEnum.PipedReq then sendMsgName = ProtoMsgDispatch:getReqMsgNameByMsgId(self.sendQueue[1].params.msg_id) end if ProtoMsgDispatch:getRspMsgByMsgName(sendMsgName) == msgName then sendInfo = table.remove(self.sendQueue, 1) self:saveSendQueue() end end if not ok or not pbData then local reqDataStr = GConst.EMPTY_STRING if sendInfo then if sendInfo.msgName == ProtoMsgType.FromMsgEnum.PipedReq then reqDataStr = json.encode(sendInfo.params.data) else reqDataStr = json.encode(sendInfo.params) end end BIReport:postPbDecodefailed(sendMsgName, reqDataStr) elseif pbData.err_code ~= GConst.ERROR_STR.SUCCESS then local reqDataStr = GConst.EMPTY_STRING if sendInfo then if sendInfo.msgName == ProtoMsgType.FromMsgEnum.PipedReq then reqDataStr = json.encode(sendInfo.params.data) else reqDataStr = json.encode(sendInfo.params) end end BIReport:postNetError(sendMsgName, pbData.err_code, reqDataStr) end local callbacks = self.receiveCallbacks[msg] if callbacks and #callbacks > 0 then local receiveCallback = table.remove(callbacks, 1) local lockGame = true local receiveFunc = nil local responseData = nil if receiveCallback then lockGame = receiveCallback.lockGame receiveFunc = receiveCallback.callback responseData = receiveCallback.responseData if pbData.err_code == GConst.ERROR_STR.SUCCESS and pbData.rewards then local getType = receiveCallback.getType if sendMsgName == "ActPayReq" then getType = PayManager:getItemGetType(pbData.act_type, pbData.id) elseif sendMsgName == "ActPaidResultReq" then -- 支付上报统一处理 if pbData.gift then for _, gift in ipairs(pbData.gift) do getType = PayManager:getItemGetType(gift.act_type, gift.id) break end end elseif sendMsgName == "AppStorePaidReq" then -- ios支付上报统一处理 if pbData.gift then for _, gift in ipairs(pbData.gift) do getType = PayManager:getItemGetType(gift.act_type, gift.id) break end end end if EDITOR_MODE and not getType then Logger.logFatal("sendMessage server have rewards but not getType, check it! manager = ", receiveCallback.binder.__cname) end GFunc.addRewards(pbData.rewards, getType) end if pbData.err_code == GConst.ERROR_STR.SUCCESS and pbData.costs and not self:getNotAddCostsRsp(msgName) then local getType = receiveCallback.getType if sendMsgName == "ActPayReq" then getType = PayManager:getItemGetType(pbData.mall_type, pbData.id) elseif sendMsgName == "ActPaidResultReq" then -- 支付上报统一处理 if pbData.gift then for _, gift in ipairs(pbData.gift) do getType = PayManager:getItemGetType(gift.mall_type, gift.id) break end end end if EDITOR_MODE and not getType then Logger.logFatal("sendMessage server have costs but not getType, check it! manager = ", receiveCallback.binder.__cname) end GFunc.addCosts(pbData.costs, getType) end if EDITOR_MODE and not self:getNotCheckResponse(ProtoMsgDispatch:getReqMsgByMsgName(msgName)) then -- 检查responseData local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName) local serverResult = pb.decode(fullMsgName, data) self:checkCoin(responseData, serverResult) if not GFunc.checkTableValueSame(responseData, serverResult, true) then Logger.logWarningBox(msgName .. " : responseData not equate, please check it!") Logger.logHighlight("------responseData not equate-------------") Logger.printTable(responseData) Logger.printTable(serverResult) end end if receiveCallback.beforeOver then UIManager:hideWaitNet() self.tillBeforeOverCount = self.tillBeforeOverCount - 1 if self.tillBeforeOverCount < 0 then self.tillBeforeOverCount = 0 end end self:recycleReceiveCallback(receiveCallback) if lockGame then UIManager:hideWaitNet() end if ok and pbData and receiveFunc then if sendInfo then if sendInfo.msgName == ProtoMsgType.FromMsgEnum.PipedReq then pbData.reqData = sendInfo.params.data else pbData.reqData = sendInfo.params end end receiveFunc(receiveCallback.binder, pbData) end end end if sendInfo then self:trySend() end end function NetManager:onError(socketName, errorType, errorMsg) self.isSending = false if socketName == NetManager.MAIN_SOCKET_NAME then Logger.logHighlight("game net error:errorType = %d, errorMsg = %s", errorType, errorMsg) if errorType == NetErrorCode.ConnectFailed or errorType == NetErrorCode.ExceptionError or errorType == NetErrorCode.ReceiveBufferError or errorType == NetErrorCode.BeginSendError or errorType == NetErrorCode.PeerDisconnect or errorType == NetErrorCode.DataParseError then self:disconnect(socketName) elseif errorType == NetErrorCode.ServerRefuseReconnect or errorType == NetErrorCode.ServerKickNtfClient or errorType == NetErrorCode.OtherDeviceLogin then -- 服务器拒绝客户端的重连请求,需要关闭连接,重新登录 self:closeAll(errorType) elseif errorType == NetErrorCode.DNSParseDomainNameError then self:closeAll() else -- 未定义的error self:disconnectAndReconnect() end if not self.disconnectTime then self.disconnectTime = Time:getServerTime() BIReport:postNetWorkOpt(BIReport.NETWORK_OPT_TYPE.DISCONNECT, UIManager:getTopUIIndex(), errorType) end elseif socketName == NetManager.CHAT_SOCKET_NAME then Logger.logHighlight("chat net error:errorType = %d, errorMsg = %s", errorType, errorMsg) self:disconnect(socketName) end end function NetManager:setReconnectData() local msgFullName = ProtoMsgDispatch:getMsgFullNameByMsgName(ProtoMsgType.FromMsgEnum.ReconnectReq) CS.BF.BFMain.Instance.NetMgr.loginReqData = pb.encode(msgFullName, { recv_id = self.recvId }) end function NetManager:dispatch(msgName, data) if self.msgCallbacks[msgName] then for module, callback in pairs(self.msgCallbacks[msgName]) do callback(module, data) end end end function NetManager:getKickOutReasonEnum(enum) return ProtoMsgDispatch:getKickOutReasonEnum(enum) end function NetManager:joinChatChannel() -- if self.joinChatId then -- SchedulerManager:unscheduleGlobal(self.joinChatId) -- self.joinChatId = nil -- end -- if DataManager.ChatData:getIsJoinWorldRoom() then -- return -- end -- local wordChannelId = DataManager.ChatData:getChatWorld():getLocalChatWorldChannleId() -- local args = { -- id = wordChannelId, -- adjust = true -- 登录时第一次进入房间必须能接受调整,手动切房间的时候为false -- } -- self:send(ProtoMsgType.FromMsgEnum.JoinWorldRoomReq, args, function(data) -- if data.status == 0 then -- DataManager.ChatData:initChat(data) -- else -- self.joinChatId = self:performWithDelayGlobal(function () -- self.joinChatId = nil -- self:joinChatChannel() -- end, JOIN_CHAT_INTERVAL) -- end -- end, NetManager.CHAT_SOCKET_NAME, true) end function NetManager:registerMsgCallback(msgName, module, callback) if not self.msgCallbacks[msgName] then self.msgCallbacks[msgName] = {} end self.msgCallbacks[msgName][module] = callback end if NOT_PUBLISH then NetManager._registerMsgCallback = NetManager.registerMsgCallback function NetManager:registerMsgCallback(msgName, module, callback) if debug.getinfo(2, "f").func ~= ServerPushManager.addServerPushListener then Logger.logFatal("this method only called by ServerPushManager.addServerPushListener") end self:_registerMsgCallback(msgName, module, callback) end end function NetManager:unRegisterMsgCallback(msgName, module) if self.msgCallbacks[msgName] then self.msgCallbacks[msgName][module] = nil end end function NetManager:clearMsgCallbacks() self.msgCallbacks = {} self.receiveCallbacks = {} end function NetManager:closeAndClear() if not self.initSucc then return end if self.tillBeforeOverSid then SchedulerManager:unscheduleGlobal(self.tillBeforeOverSid) self.tillBeforeOverSid = nil end if self.reconnectMainId then SchedulerManager:unscheduleGlobal(self.reconnectMainId) self.reconnectMainId = nil end if self.reconnectChatId then SchedulerManager:unscheduleGlobal(self.reconnectChatId) self.reconnectChatId = nil end if self.joinChatId then SchedulerManager:unscheduleGlobal(self.joinChatId) self.joinChatId = nil end self.isSending = false self.sendQueue = {} self.tillBeforeOverCount = 0 self.msgId = 0 self.activeReconnectMainFlag = false self.reconnectMainFlag = false CS.BF.BFMain.Instance.NetMgr:RemoveAllLuaCallback() local mainSocketName = NetManager.MAIN_SOCKET_NAME local chatSocketName = NetManager.CHAT_SOCKET_NAME self.isClosedMap[mainSocketName] = true self.isClosedMap[chatSocketName] = true self.alreadyConnected[mainSocketName] = false self.alreadyConnected[chatSocketName] = false CS.BF.BFMain.Instance.NetMgr:Close(mainSocketName) -- CS.BF.BFMain.Instance.NetMgr:Close(chatSocketName) self:clearMsgCallbacks() UIManager:hideWaitNet(true) end function NetManager:saveSendQueue() local list = {} for _, info in ipairs(self.sendQueue) do if not self:isNotSave(info.msgName) then table.insert(list, { msgName = info.msgName, params = info.params, socketName = info.socketName, }) end end if EDITOR_MODE and #list > 0 then local printList = {} for k, v in ipairs(list) do local msgName = v.msgName local params = v.params if msgName == ProtoMsgType.FromMsgEnum.PipedReq then msgName = ProtoMsgDispatch:getReqMsgNameByMsgId(params.msg_id) params = params.data end table.insert(printList, { msgName = msgName, params = params, socketName = v.socketName, }) end Logger.logHighlight("[NetManager]剩余消息队列缓存:%s", json.encode(printList)) end LocalData:saveSendQueue(list) end function NetManager:isNotSave(msgName) if msgName == ProtoMsgType.FromMsgEnum.LoginReq or msgName == ProtoMsgType.FromMsgEnum.SyncReq or msgName == ProtoMsgType.FromMsgEnum.IdleRewardReq or msgName == ProtoMsgType.FromMsgEnum.IdleExtraRewardReq or msgName == ProtoMsgType.FromMsgEnum.MailCycleReq or msgName == ProtoMsgType.FromMsgEnum.GMReq then return true end return false end function NetManager:getNotCheckResponse(msgName) return true end function NetManager:getNotAddCostsRsp(msgName) if msgName == ProtoMsgType.FromMsgEnum.ChapterTrainRsp then return true end return false end function NetManager:pipedMessage(msgName, params) if msgName == ProtoMsgType.FromMsgEnum.LoginReq or msgName == ProtoMsgType.FromMsgEnum.SyncReq or msgName == ProtoMsgType.FromMsgEnum.IdleRewardReq or msgName == ProtoMsgType.FromMsgEnum.IdleExtraRewardReq or msgName == ProtoMsgType.FromMsgEnum.MailCycleReq or msgName == ProtoMsgType.FromMsgEnum.GMReq then return msgName, params end local msgId = ProtoMsgDispatch:getMsgIdByMsgName(msgName) self.msgId = self.msgId + 1 local pipedStruct = { id = self.msgId, ts = Time:getServerTime() * 1000, msg_id = msgId, data = params, } return ProtoMsgType.FromMsgEnum.PipedReq, pipedStruct end if EDITOR_MODE then function NetManager:_checkDebugFuncMap() if self._debugFuncMap == nil then self._debugFuncMap = { [BaseModule.sendMessage] = true, [BaseModule.sendMessageTillBeforeOver] = true, } end end NetManager._releaseSend = NetManager.send function NetManager:send(obj, msgName, params, responseData, callback, lockGame, noRsp, getType) -- 参数检查 if (responseData.rewards or responseData.costs) and not getType and msgName ~= ProtoMsgType.FromMsgEnum.GMReq then Logger.logFatal("sendMessage have rewards or have costs but not getType, check it! manager = ", self.__cname) return end if not params then Logger.logFatal("NetManager send params is nil %s", msgName) end if not responseData then Logger.logFatal("NetManager send responseData is nil %s", msgName) end local msgFullName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName) local bytes = pb.encode(msgFullName, params) if not bytes then Logger.logFatal("NetManager send params error %s", msgName) return end if not self:getNotCheckResponse(msgName) then local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(ProtoMsgDispatch:getRspMsgByMsgName(msgName)) for name, number, type in pb.fields(fullMsgName) do if name ~= "err_code" and responseData[name] == nil then Logger.logFatal("NetManager send responseData error %s not have %s", msgName, name) return end end end -- end 参数检查 self:_checkDebugFuncMap() local currFunc = debug.getinfo(2, "f").func if obj ~= NetManager and self._debugFuncMap[currFunc] == nil then Logger.logFatal("you can not call NetManager:send directly") end local findCallback = false if obj ~= NetManager and obj.__cname ~= "PayManager" then for _, fieldValue in pairs(obj.class) do if fieldValue == callback then findCallback = true end end else findCallback = true end if not findCallback then Logger.logFatal("[NetManager]callback of NetManager:send is not %s function", obj.__cname) end self:_releaseSend(obj, msgName, params, responseData, callback, lockGame, noRsp, getType) end NetManager._releaseSendTillBeforeOver = NetManager.sendTillBeforeOver function NetManager:sendTillBeforeOver(obj, msgName, params, responseData, callback, ...) self:_checkDebugFuncMap() local currFunc = debug.getinfo(2, "f").func if obj ~= NetManager and self._debugFuncMap[currFunc] == nil then Logger.logFatal("[NetManager]you can not call NetManager:send directly") end self:_releaseSendTillBeforeOver(obj, msgName, params, responseData, callback, ...) end end function NetManager:checkCoin(responseData, serverResponseData) --- 特殊处理金币 -- if responseData.rewards and serverResponseData.rewards then -- local coinCount = 0 -- for i, info in ipairs(serverResponseData.rewards) do -- if info.item and info.item.id == GConst.ItemConst.ITEM_ID_GOLD then -- local serverGoldBigNum = BigNumOpt.cloneBigNum(info.item.count) -- local rspGoldBigNum = BigNumOpt.cloneBigNum(responseData.rewards[i].item.count) -- if serverGoldBigNum.unit > rspGoldBigNum.unit then -- serverGoldBigNum.value, serverGoldBigNum.unit = BigNumOpt.numToTargetUnit(serverGoldBigNum.value, serverGoldBigNum.unit, rspGoldBigNum.unit) -- elseif serverGoldBigNum.unit < rspGoldBigNum.unit then -- rspGoldBigNum.value, rspGoldBigNum.unit = BigNumOpt.numToTargetUnit(rspGoldBigNum.value, rspGoldBigNum.unit, serverGoldBigNum.unit) -- end -- if serverGoldBigNum.unit == rspGoldBigNum.unit and serverGoldBigNum.value ~= rspGoldBigNum.value then -- --- 百分之一的差距忽略不计 -- local minCount = math.floor(serverGoldBigNum.value * 0.99 + 0.000001) -- local maxCount = math.floor(serverGoldBigNum.value * 1.01 + 0.000001) -- if minCount <= rspGoldBigNum.value and rspGoldBigNum.value <= maxCount then -- responseData.rewards[i].item.count = info.item.count -- if EDITOR_MODE then -- Logger.logHighlight("[NetManager]------金币有误差,且在-1%%~1%%-------------") -- else -- if EDITOR_MODE then -- Logger.logFatal("[NetManager]------金币有误差,不在-1%%~1%%-------------") -- end -- end -- end -- else -- responseData.rewards[i].item.count = info.item.count -- end -- end -- end -- end -- if responseData.costs and serverResponseData.costs then -- local coinCount = 0 -- for i, info in ipairs(serverResponseData.costs) do -- if info.item and info.item.id == GConst.ItemConst.ITEM_ID_GOLD then -- local serverGoldBigNum = BigNumOpt.cloneBigNum(info.item.count) -- local rspGoldBigNum = BigNumOpt.cloneBigNum(responseData.costs[i].item.count) -- if serverGoldBigNum.unit > rspGoldBigNum.unit then -- serverGoldBigNum.value, serverGoldBigNum.unit = BigNumOpt.numToTargetUnit(serverGoldBigNum.value, serverGoldBigNum.unit, rspGoldBigNum.unit) -- elseif serverGoldBigNum.unit < rspGoldBigNum.unit then -- rspGoldBigNum.value, rspGoldBigNum.unit = BigNumOpt.numToTargetUnit(rspGoldBigNum.value, rspGoldBigNum.unit, serverGoldBigNum.unit) -- end -- if serverGoldBigNum.unit == rspGoldBigNum.unit and serverGoldBigNum.value ~= rspGoldBigNum.value then -- --- 百分之一的差距忽略不计 -- local minCount = math.floor(serverGoldBigNum.value * 0.99 + 0.000001) -- local maxCount = math.floor(serverGoldBigNum.value * 1.01 + 0.000001) -- if minCount <= rspGoldBigNum.value and rspGoldBigNum.value <= maxCount then -- responseData.costs[i].item.count = info.item.count -- if EDITOR_MODE then -- Logger.logHighlight("[NetManager]------金币有误差,且在-1%%~1%%-------------") -- end -- else -- if EDITOR_MODE then -- Logger.logFatal("[NetManager]------金币有误差,不在-1%%~1%%-------------") -- end -- end -- else -- responseData.costs[i].item.count = info.item.count -- end -- end -- end -- end --- end return NetManager