From 7de12f99e52c8eaf5399642cf04052cd50b212e8 Mon Sep 17 00:00:00 2001 From: xiekaidong Date: Fri, 5 May 2023 10:42:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=90=AC=E8=BF=90=E4=B8=80=E4=B8=8Bb5=E7=9A=84?= =?UTF-8?q?=E7=BD=91=E7=BB=9C=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lua/app/common/event_manager.lua | 1 + lua/app/common/local_data.lua | 56 + lua/app/common/server_push_manager.lua | 23 + lua/app/common/server_push_manager.lua.meta | 10 + lua/app/game.lua | 5 + lua/app/module/base_module.lua | 13 + lua/app/module/battle/battle_manager.lua | 8 + lua/app/module/login/login_manager.lua | 330 ++++++ lua/app/module/login/login_ui.lua | 40 +- lua/app/module/login/test_login_ui.lua | 19 + lua/app/net/net_manager.lua | 1170 +++++++++++++++++++ lua/app/net/net_manager.lua.meta | 10 + 12 files changed, 1684 insertions(+), 1 deletion(-) create mode 100644 lua/app/common/server_push_manager.lua create mode 100644 lua/app/common/server_push_manager.lua.meta create mode 100644 lua/app/net/net_manager.lua create mode 100644 lua/app/net/net_manager.lua.meta diff --git a/lua/app/common/event_manager.lua b/lua/app/common/event_manager.lua index 920719a3..ab62e9e5 100644 --- a/lua/app/common/event_manager.lua +++ b/lua/app/common/event_manager.lua @@ -22,6 +22,7 @@ EventManager.CUSTOM_EVENT = { ELIMINATION_OVER = "ELIMINATION_OVER", SHOW_ELIMINATION_TUTORAIL = "SHOW_ELIMINATION_TUTORAIL", BOARD_FILL_OVER = "BOARD_FILL_OVER", + LOGIN_REQ_SUCCESS = "LOGIN_REQ_SUCCESS", -- BORAD_TOUCH_BEGIN = "BORAD_TOUCH_BEGIN", -- BORAD_TOUCH_OVER = "BORAD_TOUCH_OVER" } diff --git a/lua/app/common/local_data.lua b/lua/app/common/local_data.lua index bc2668ee..66b245f3 100644 --- a/lua/app/common/local_data.lua +++ b/lua/app/common/local_data.lua @@ -25,6 +25,7 @@ local LOCAL_DATA_KEY = { IS_NEW_PLAYER = "IS_NEW_PLAYER", DISTINCT_ID = "DISTINCT_ID", LAST_LOGIN_TIME = "LAST_LOGIN_TIME", + GATE = "GATE", } LocalData.KEYS = LOCAL_DATA_KEY @@ -202,6 +203,44 @@ function LocalData:getIosOrders() end end +function LocalData:setLastLoginInfo(loginType, id, token) + local str = json.encode({ + type = loginType, + id = id, + token = token + }) + if not loginType then + self:setString(LOCAL_DATA_KEY.LAST_LOGIN_TYPE, "") + elseif loginType ~= "token" then + self:setString(LOCAL_DATA_KEY.LAST_LOGIN_TYPE, loginType) + end + self:setString(LOCAL_DATA_KEY.LAST_LOGIN_INFO, str) +end + +function LocalData:getLastLoginInfo() + local str = self:getString(LOCAL_DATA_KEY.LAST_LOGIN_INFO, "{}") + local info = json.decode(str) + info.type = info.type or NetManager.LOGIN_TYPE.ANONYMOUS + info.id = info.id or DeviceHelper:getDeviceId() + info.token = info.token + return info +end + +function LocalData:getLastLoginType() + local str = self:getString(LOCAL_DATA_KEY.LAST_LOGIN_TYPE, "") + if str == "" then + str = NetManager.LOGIN_TYPE.ANONYMOUS + end + if str ~= NetManager.LOGIN_TYPE.ANONYMOUS and + str ~= NetManager.LOGIN_TYPE.APPLE and + str ~= NetManager.LOGIN_TYPE.GOOGLE and + str ~= NetManager.LOGIN_TYPE.FACEBOOK + then + str = NetManager.LOGIN_TYPE.ANONYMOUS + end + return str +end + function LocalData:setLastLoginName(name) name = name or "" self:setString(LOCAL_DATA_KEY.LAST_LOGIN_NAME, name) @@ -211,6 +250,23 @@ function LocalData:getLastLoginName() return self:getString(LOCAL_DATA_KEY.LAST_LOGIN_NAME, "") end +function LocalData:saveSendQueue(sendQueue) + local str = json.encode(sendQueue) + self:setString(LOCAL_DATA_KEY.SEND_QUEUE, str) +end + +function LocalData:saveEmptySendQueue() + if self.emptyTableJsonStr == nil then + self.emptyTableJsonStr = json.encode({}) + end + self:setString(LOCAL_DATA_KEY.SEND_QUEUE, self.emptyTableJsonStr) +end + +function LocalData:getSendQueue() + local sendQueue = json.decode(self:getString(LOCAL_DATA_KEY.SEND_QUEUE, "{}")) + return sendQueue +end + function LocalData:setShakeMode(value) -- 0-close 1-open self:setInt(self:getString(LOCAL_DATA_KEY.SHAKE_MODE), value) end diff --git a/lua/app/common/server_push_manager.lua b/lua/app/common/server_push_manager.lua new file mode 100644 index 00000000..1378228d --- /dev/null +++ b/lua/app/common/server_push_manager.lua @@ -0,0 +1,23 @@ +local ServerPushManager = {} + +---- 注册推送监听 +function ServerPushManager:addServerPushListener(msgName, module, callback) + NetManager:registerMsgCallback(msgName, module, callback) +end + +---- 移除推送监听 +function ServerPushManager:removeServerPushListener(msgName, module) + NetManager:unRegisterMsgCallback(msgName, module) +end + +---- 初始化全局推送监听 +function ServerPushManager:initWhenLogin() + self:addServerPushListener(ProtoMsgType.FromMsgEnum.KickOutNtf, UIManager, UIManager.showKickOut) +end + +---- 移除全局推送监听 +function ServerPushManager:removeWhenLoginOut() + self:removeServerPushListener(ProtoMsgType.FromMsgEnum.KickOutNtf, UIManager) +end + +return ServerPushManager \ No newline at end of file diff --git a/lua/app/common/server_push_manager.lua.meta b/lua/app/common/server_push_manager.lua.meta new file mode 100644 index 00000000..44c1c77f --- /dev/null +++ b/lua/app/common/server_push_manager.lua.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a2863b1c3518d154f9c509e0bc0f65c1 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 3b8b241bab4a4ac9a22fcce9c64f1242, type: 3} diff --git a/lua/app/game.lua b/lua/app/game.lua index 2625711b..43bd3754 100644 --- a/lua/app/game.lua +++ b/lua/app/game.lua @@ -73,11 +73,13 @@ function Game:initOther() BF.exports.EffectManager = require "app/common/effect_manager" BF.exports.SpineManager = require "app/common/spine_manager" BF.exports.WebRequestManager = require "app/common/webrequest_manager" + BF.exports.NetManager = require "app/net/net_manager" BF.exports.I18N = require "app/common/i18n_manager" BF.exports.CellManager = require "app/common/cell_manager" BF.exports.Time = require "app/common/time" BF.exports.BaseData = require "app/userdata/base_data" BF.exports.BaseObject = require "app/bf/unity/base_object" + BF.exports.ServerPushManager = require "app/common/server_push_manager" BF.exports.SafeAreaManager = require "app/common/safe_area_manager" BF.exports.BaseModule = require "app/module/base_module" BF.exports.ModuleManager = require "app/common/module_manager" @@ -98,6 +100,7 @@ function Game:initOther() DataManager:init() DOTweenManager:init() ModuleManager:init() + NetManager:init() -- 例如EmmyLua等IDE或者插件无法识别BF.exports.xx的全局变量赋值语法,这里专门处理一下 self:specialForIdea() @@ -140,11 +143,13 @@ function Game:specialForIdea() EffectManager = EffectManager or require "app/common/effect_manager" SpineManager = SpineManager or require "app/common/spine_manager" WebRequestManager = WebRequestManager or require "app/common/webrequest_manager" + NetManager = NetManager or require "app/net/net_manager" I18N = I18N or require "app/common/i18n_manager" CellManager = CellManager or require "app/common/cell_manager" Time = Time or require "app/common/time" BaseData = BaseData or require "app/userdata/base_data" BaseObject = BaseObject or require "app/bf/unity/base_object" + ServerPushManager = ServerPushManager or require "app/module/login/server_push_manager" SafeAreaManager = SafeAreaManager or require "app/common/safe_area_manager" BaseModule = BaseModule or require "app/module/base_module" ModuleManager = ModuleManager or require "app/common/module_manager" diff --git a/lua/app/module/base_module.lua b/lua/app/module/base_module.lua index 23a1ee55..270b1017 100644 --- a/lua/app/module/base_module.lua +++ b/lua/app/module/base_module.lua @@ -72,6 +72,19 @@ function BaseModule:removeAllEventListeners() end end +-- 阻塞式,等待服务器回复以后再回调callback +function BaseModule:sendMessage(msgName, params, responseData, callback, getType, lockGame) + if lockGame == nil then + lockGame = true + end + NetManager:send(self, msgName, params, responseData, callback, lockGame, nil, getType) +end + +-- 阻塞式,等待所有指令完成以后再发送此消息,并且锁界面,等待服务器回复以后再回调callback +function BaseModule:sendMessageTillBeforeOver(msgName, params, responseData, callback, getType) + NetManager:sendTillBeforeOver(self, msgName, params, responseData, callback, true, nil, getType) +end + -- 各个模块的manager按各自需求来重写clear即可 function BaseModule:clear() end diff --git a/lua/app/module/battle/battle_manager.lua b/lua/app/module/battle/battle_manager.lua index 99938027..eaca0ae0 100644 --- a/lua/app/module/battle/battle_manager.lua +++ b/lua/app/module/battle/battle_manager.lua @@ -341,4 +341,12 @@ function BattleManager:getBattleUnitAttribute(hashCode) end end +function BattleManager:clearOnExitScene() + if self.battleController == nil then + return + end + self:clear() + self.returnFunc = nil +end + return BattleManager \ No newline at end of file diff --git a/lua/app/module/login/login_manager.lua b/lua/app/module/login/login_manager.lua index af8e0485..5ca67d2a 100644 --- a/lua/app/module/login/login_manager.lua +++ b/lua/app/module/login/login_manager.lua @@ -73,4 +73,334 @@ function LoginManager:getClientInfo() return clientInfo end + +function LoginManager:initSocket() + local isConnected = NetManager:isConnected(NetManager.MAIN_SOCKET_NAME) + if EDITOR_MODE then + Logger.logError("LoginMgr:initSocket:%s", isConnected) + end + if not isConnected then + NetManager:init( + function() + self:connectByChannel( + function() + if EDITOR_MODE then + Logger.logError("主链接链接成功") + end + self:_login() + end + ) + end + ) + end +end + +function LoginManager:connectByChannel(callback, socketName) + socketName = socketName or NetManager.MAIN_SOCKET_NAME + local domain + local port + if socketName == NetManager.MAIN_SOCKET_NAME then + local gate = LocalData:getString(LocalData.KEYS.GATE) + local arr = string.split(gate, ":") + domain = arr[1] + port = arr[2] + else + domain = NetManager:getChatDomain() + port = NetManager:getChatPort() + end + NetManager:connect(domain, port, function() + if callback then + callback() + end + end, socketName) +end + +function LoginManager:goToLoginScene() + ModuleManager.BattleManager:clearOnExitScene() + NetManager:closeAndClear() + UIManager:backToLoginWithoutLogout() + DataManager:clear() +end + + +function LoginManager:_login() + LocalData:saveEmptySendQueue() + + local skipGuide = nil + if EDITOR_MODE then + -- skipGuide = LocalData:getSkipTutorial() + end + local clientInfo = self:getClientInfo() + if EDITOR_MODE then + print("LoginReq===============================xxxx1") + for k, v in pairs(clientInfo) do + print(k, " = ", v) + end + print("LoginReq===============================xxxx2") + end + local args = { + client_info = clientInfo, + skip_guide = skipGuide, + } + self:sendMessage( + ProtoMsgType.FromMsgEnum.LoginReq, + args, + {}, + self.loginFinish + ) +end + +function LoginManager:loginFinish(data) + if data.status == 0 then + UIManager:clearUIPrefabCache() -- 先清理下缓存 + ConfigManager:preLoadConfig() + ServerPushManager:initWhenLogin() + DataManager:initWithServerData(data) + + EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.LOGIN_REQ_SUCCESS) + -- ModuleManager.MailManager:getMailList(true) + DataManager:setLoginSuccess(true) + BIReport:postGameLoginFinish() + + local info = LocalData:getLastLoginInfo() + BIReport:postAccountLoginFinish(info.type) + else + local info = LocalData:getLastLoginInfo() + BIReport:postAccountLoginFailed(info.type, data.err_code) + end +end + +function LoginManager:saveAuthArgs(name) + local args = LocalData:getLastLoginInfo() + if name then + args.type = NetManager.LOGIN_TYPE.ANONYMOUS + args.id = name + args.token = nil + LocalData:setLastLoginName(name) + LocalData:setLastLoginInfo(args.type, args.id, args.token) + end + + args.client_info = self:getClientInfo() + local sendQueue = LocalData:getSendQueue() + args.sync = + { + pip = GFunc.getArray() + } + + if sendQueue and sendQueue[1] then + local ProtoMsgDispatch = require "app/proto/proto_msg_dispatch" + local pb = require "pb" + for _, info in ipairs(sendQueue) do + local curParams = info.params + local needAd = false + if info.msgName == ProtoMsgType.FromMsgEnum.PipedReq then + local msgName = ProtoMsgDispatch:getReqMsgNameByMsgId(curParams.msg_id) + if msgName then + local fullMsgName = ProtoMsgDispatch:getMsgFullNameByMsgName(msgName) + if fullMsgName then + if curParams.data and type(curParams.data) == "table" then + local ok, pbData = pcall(function() + return pb.encode(fullMsgName, curParams.data) + end) + if ok then + needAd = true + curParams.data = pbData + end + end + end + end + end + if needAd then + table.insert(args.sync.pip, curParams) + end + end + end + + NetManager:saveAuthArgs(args) +end + + +function LoginManager:resetServerListStartTime() + self.accountLoginSuccess = false + self.connectStartTimes = os.clock() + self.retryTimes = 0 +end + +function LoginManager:addServerListCallback(callback) + self.loginCallback = callback +end + +function LoginManager:removeAllLoginData() + self.loginCallback = nil + self.versionInfoStr = nil + self.versionInfo = nil + -- self.connectStartTimes = nil + self.retryTimes = 0 +end + +function LoginManager:showServerNotOpenMessage() + local params = { + content = I18N:getGlobalText(I18N.GlobalConst.SERVER_MAINTAINED), + boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, + okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), + okFunc = function() + self:checkServerOpen() + end, + } + GFunc.showMessageBox(params) +end + +function LoginManager:getIsNeedHotUpdate() + local serverVersion = self.versionInfo.version + local clientVersion = CS.BF.BFMain.Instance.GameLaunchMgr:GetCurrentVersion() + if serverVersion == nil or serverVersion == "" or clientVersion == nil or clientVersion == "" then + return true + end + return serverVersion ~= clientVersion +end + +function LoginManager:showNewVersionFoundMessage() + local params = { + content = I18N:getGlobalText(I18N.GlobalConst.NEW_VERSION_FOUND), + boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, + okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), + okFunc = function() + local storeUrl = self.versionInfo.store_url + if storeUrl == nil or storeUrl == "" then + CS.UnityEngine.Application.Quit() + else + CS.UnityEngine.Application.OpenURL(storeUrl) + end + end, + } + GFunc.showMessageBox(params) +end + +function LoginManager:getIsclientLessThanMinVersion() + local minVersion = self.versionInfo.min_version + local clientVersion = CS.BF.BFMain.Instance.GameLaunchMgr:GetCurrentVersion() + if minVersion == nil or minVersion == "" or clientVersion == nil or clientVersion == "" then + return true + end + if minVersion == clientVersion then + return false + end + + local update, bigVersion = GFunc.compareVersionThan(minVersion, clientVersion, false) + + return bigVersion or false +end + +function LoginManager:checkServerOpen() + local serverOpenTime = tonumber(self.versionInfo.open_time or 0) + local clientTime = os.time()*1000 + if clientTime < serverOpenTime then -- 未开服 + self:showServerNotOpenMessage() + return + end + + if EDITOR_MODE or GConst.SKIP_VERSION then + CS.BF.BFMain.Instance.GameLaunchMgr.LaunchRequester:SetVersionInfo(self.versionInfoStr) + if self.loginCallback and self.versionInfo then + self.loginCallback(self.versionInfo.game_urls) + end + else + -- 需要更新整包 + if self:getIsclientLessThanMinVersion() then + self:showNewVersionFoundMessage() + elseif self:getIsNeedHotUpdate() then -- 需要热更新 + Game:destroyAll() + CS.BF.BFMain.Instance.GameLaunchMgr:LaunchForRelogin(self.versionInfoStr) + else + CS.BF.BFMain.Instance.GameLaunchMgr.LaunchRequester:SetVersionInfo(self.versionInfoStr) + if self.loginCallback then + self.loginCallback(self.versionInfo.game_urls) + end + end + end +end + +function LoginManager:getServerList(callback) + if self.accountLoginSuccess then + if self.authSid then + self:unscheduleGlobal(self.authSid) + self.authSid = nil + end + return + end + self.loginCenterUrl = CS.BF.BFPlatform.GetLoginCenterURL() + self.retryTimes = self.retryTimes + 1 + + SDKManager:getServerList(function(isSuccess, data) + if self.accountLoginSuccess then + if self.authSid then + self:unscheduleGlobal(self.authSid) + self.authSid = nil + end + return + end + if isSuccess and data and data ~= "" then + self.versionInfoStr = data + local jsonData = json.decode(data or "") + if not jsonData.game_urls[1] then -- 保证服务器列表中必须有一个服务器 + local params = { + content = I18N:getGlobalText(I18N.GlobalConst.GET_SEVER_ERROR), + okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), + noShowClose = true, + okFunc = function() + self:getServerList() + end, + boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, + top = true, + } + GFunc.showMessageBox(params) + return + end + + UIManager:hideToast() + -- BIReport:postRequestVersionSuccess(self.loginCenterUrl, (os.clock() - self.connectStartTimes)*1000, self.retryTimes - 1) + self.accountLoginSuccess = true + if self.authSid then + self:unscheduleGlobal(self.authSid) + self.authSid = nil + end + + self.versionInfo = jsonData + Logger.printTable(jsonData) + self:checkServerOpen() + else + -- BIReport:postRequestVersionFailed(self.loginCenterUrl, (os.clock() - self.connectStartTimes)*1000, self.retryTimes - 1) + local params = { + content = I18N:getGlobalText(I18N.GlobalConst.GET_SEVER_ERROR), + okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), + noShowClose = true, + okFunc = function() + self:getServerList() + end, + boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, + top = true, + } + GFunc.showMessageBox(params) + end + end) + + if self.authSid then + self:unscheduleGlobal(self.authSid) + end + self.authSid = self:performWithDelayGlobal(function() + -- BIReport:postRequestVersionFailed(self.loginCenterUrl, (os.clock() - self.connectStartTimes)*1000, self.retryTimes - 1) + local params = { + content = I18N:getGlobalText(I18N.GlobalConst.GET_SEVER_ERROR), + okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), + noShowClose = true, + okFunc = function() + self:getServerList() + end, + boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, + top = true, + } + GFunc.showMessageBox(params) + end, 5) +end + return LoginManager \ No newline at end of file diff --git a/lua/app/module/login/login_ui.lua b/lua/app/module/login/login_ui.lua index dd4ae8ad..84c0f597 100644 --- a/lua/app/module/login/login_ui.lua +++ b/lua/app/module/login/login_ui.lua @@ -11,6 +11,7 @@ function LoginUI:getPrefabPath() end function LoginUI:onClose() + ModuleManager.LoginManager:removeAllLoginData() end function LoginUI:onLoadRootComplete() @@ -26,6 +27,8 @@ function LoginUI:onLoadRootComplete() self.progressTx:setText("") uiMap["login_ui.loading_text"]:setText(I18N:getGlobalText(I18N.GlobalConst.LOADING_DESC)) + self:initListener() + local distinctId = LocalData:getDistinctId() if distinctId == nil or distinctId == "" then distinctId = CS.ThinkingAnalytics.ThinkingAnalyticsAPI.GetDistinctId() @@ -49,10 +52,30 @@ function LoginUI:onLoadRootComplete() GFunc.copyStr(distinctId) end) + ModuleManager.LoginManager:resetServerListStartTime() + ModuleManager.LoginManager:addServerListCallback(function(serverList) + if EDITOR_MODE then + Logger.logHighlight("------------serverList------------") + Logger.printTable(serverList) + end + + self:refreshServerList(serverList) + ModuleManager.LoginManager:saveAuthArgs() + ModuleManager.LoginManager:initSocket() + + local info = LocalData:getLastLoginInfo() + BIReport:postAccountLoginClick(info.type) + end) + ModuleManager.LoginManager:getServerList() + CS.BF.BFMain.Instance.LuaMgr:OnGameInitSucc() LocalData:save() +end - self:preloadAndEnterMaincity() +function LoginUI:initListener() + self:addEventListener(EventManager.CUSTOM_EVENT.LOGIN_REQ_SUCCESS, function() + self:preloadAndEnterMaincity() + end) end function LoginUI:preloadAndEnterMaincity() @@ -103,4 +126,19 @@ function LoginUI:updateProgress() end end +function LoginUI:refreshServerList(serverList) + self.serverList = serverList or {} + if not ModuleManager.LoginManager.selectIndex or ModuleManager.LoginManager.selectIndex <= 0 then + ModuleManager.LoginManager.selectIndex = 1 + else + ModuleManager.LoginManager.selectIndex = ModuleManager.LoginManager.selectIndex + 1 + end + if ModuleManager.LoginManager.selectIndex > #self.serverList then + ModuleManager.LoginManager.selectIndex = 1 + end + + local defaultUrl = self.serverList[ModuleManager.LoginManager.selectIndex].url + LocalData:setString(LocalData.KEYS.GATE, defaultUrl) +end + return LoginUI \ No newline at end of file diff --git a/lua/app/module/login/test_login_ui.lua b/lua/app/module/login/test_login_ui.lua index 5be4ca76..8eed09f7 100644 --- a/lua/app/module/login/test_login_ui.lua +++ b/lua/app/module/login/test_login_ui.lua @@ -11,6 +11,7 @@ function TestLoginUI:getPrefabPath() end function TestLoginUI:onClose() + ModuleManager.LoginManager:removeAllLoginData() if self.dropList then self.dropList.onValueChanged:RemoveAllListeners() end @@ -53,15 +54,33 @@ function TestLoginUI:onLoadRootComplete() end end) + self:addEventListener(EventManager.CUSTOM_EVENT.LOGIN_REQ_SUCCESS, function() + self:preloadAndEnterMaincity() + end) + local accountId = LocalData:getAccountInfo().id or GConst.EMPTY_STRING local copyTx = uiMap["test_login_ui.copy_account_tx"] copyTx:setVisible(accountId ~= GConst.EMPTY_STRING) copyTx:addClickListener(function() GFunc.copyStr(accountId) end) + + ModuleManager.LoginManager:resetServerListStartTime() + ModuleManager.LoginManager:addServerListCallback(function(serverList) + self:refreshServerList(serverList) + end) + ModuleManager.LoginManager:getServerList() end function TestLoginUI:loginGame() + local uiMap = self.root:genAllChildren() + local name = uiMap["test_login_ui.login_node.input_field"]:getComponent(GConst.TYPEOF_UNITY_CLASS.UI_INPUT_FIELD).text + if name == "" then + name = nil + end + -- ModuleManager.LoginManager:saveAuthArgs(name) + -- ModuleManager.LoginManager:initSocket() + self.uiMap["test_login_ui.login_node.login_btn"]:setTouchEnable(false) -- first 可以卸载了, 此项目只会启动时检查一次热更,之后不会再次检查 CS.BF.BFMain.Instance.LuaMgr:OnGameInitSucc() diff --git a/lua/app/net/net_manager.lua b/lua/app/net/net_manager.lua new file mode 100644 index 00000000..e2b8d42c --- /dev/null +++ b/lua/app/net/net_manager.lua @@ -0,0 +1,1170 @@ +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.lastMsgName ~= nil + return false +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) + 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 + 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 + self:closeAndClear() + local lastLoginType = LocalData:getLastLoginType() + if lastLoginType == NetManager.LOGIN_TYPE.GOOGLE or lastLoginType == NetManager.LOGIN_TYPE.APPLE then + local loginType = SDKManager.BF_LOGIN_TYPE.GOOGLE + if lastLoginType == NetManager.LOGIN_TYPE.APPLE then + loginType = SDKManager.BF_LOGIN_TYPE.APPLE + end + SDKManager:login(function(params) + if not params.token then + return + end + LocalData:setLastLoginInfo(lastLoginType, params.id, params.token) + ModuleManager.LoginManager:saveAuthArgs() + ModuleManager.LoginManager:initSocket() + end, loginType) + else + LocalData:setLastLoginInfo() + ModuleManager.LoginManager:saveAuthArgs() + 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 + else + 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: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 + + 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 NOT_PUBLISH then + Logger.printTable(responseData) + end + if pbData.rewards then + local getType = receiveCallback.getType + if sendMsgName == "MallPayReq" then + getType = PayManager:getItemGetType(pbData.mall_type, pbData.id) + elseif sendMsgName == "MallPaidResultReq" 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 rewards but not getType, check it! manager = ", receiveCallback.binder.__cname) + end + + GFunc.addRewards(pbData.rewards, getType) + end + if pbData.costs and not self:getNotAddCostsRsp(msgName) then + local getType = receiveCallback.getType + if sendMsgName == "MallPayReq" then + getType = PayManager:getItemGetType(pbData.mall_type, pbData.id) + elseif sendMsgName == "MallPaidResultReq" 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:disconnect(socketName) + 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.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) + if not EDITOR_MODE then + return false + end + + if msgName == ProtoMsgType.FromMsgEnum.LoginReq or + msgName == ProtoMsgType.FromMsgEnum.SyncReq or + msgName == ProtoMsgType.FromMsgEnum.ArenaInfoReq or + msgName == ProtoMsgType.FromMsgEnum.SummonReq or + msgName == ProtoMsgType.FromMsgEnum.MineResearchADReq or + msgName == ProtoMsgType.FromMsgEnum.MineResearchResultReq or + msgName == ProtoMsgType.FromMsgEnum.IdleRewardReq or + msgName == ProtoMsgType.FromMsgEnum.IdleExtraRewardReq or + msgName == ProtoMsgType.FromMsgEnum.GMReq or + msgName == ProtoMsgType.FromMsgEnum.MallPayReq or + msgName == ProtoMsgType.FromMsgEnum.ChapterPassReq or + msgName == ProtoMsgType.FromMsgEnum.MallPaidResultReq or + msgName == ProtoMsgType.FromMsgEnum.MineDoReq or + msgName == ProtoMsgType.FromMsgEnum.TaskTutorRewardReq or + msgName == ProtoMsgType.FromMsgEnum.BlessingReq or + msgName == ProtoMsgType.FromMsgEnum.MarkGuideReq or + msgName == ProtoMsgType.FromMsgEnum.EnterDungeonReq or + msgName == ProtoMsgType.FromMsgEnum.FinishedArenaReq or + msgName == ProtoMsgType.FromMsgEnum.SettleArenaReq or + msgName == ProtoMsgType.FromMsgEnum.SevenDayRewardReq or + msgName == ProtoMsgType.FromMsgEnum.MonCardRewardReq or + msgName == ProtoMsgType.FromMsgEnum.ChapterStageRewardReq or + msgName == ProtoMsgType.FromMsgEnum.BattlePassRewardReq or + msgName == ProtoMsgType.FromMsgEnum.ChapterRebornReq or + msgName == ProtoMsgType.FromMsgEnum.MineReceiveAwardReq or + msgName == ProtoMsgType.FromMsgEnum.MailExtractReq or + msgName == ProtoMsgType.FromMsgEnum.MailListReq or + msgName == ProtoMsgType.FromMsgEnum.MailDeleteReq or + msgName == ProtoMsgType.FromMsgEnum.ExistReq or + msgName == ProtoMsgType.FromMsgEnum.BindReq or + msgName == ProtoMsgType.FromMsgEnum.DeleteReq + then + return true + end + return false +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 \ No newline at end of file diff --git a/lua/app/net/net_manager.lua.meta b/lua/app/net/net_manager.lua.meta new file mode 100644 index 00000000..0da757cb --- /dev/null +++ b/lua/app/net/net_manager.lua.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 03c05c9e525f1184a9df9e3de931efa8 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 3b8b241bab4a4ac9a22fcce9c64f1242, type: 3}