--[[ 功能: 协议处理类的基类 格式化字符串说明: i: 32位无符号整数 I: 32位有符号整数 h: 16位无符号整数 H: 16位有符号整数 c: 8位无符号整数 C: 8位有符号整数 l: 64位无符号整数 L: 64位有符号整数 s: 字符串 示例: self:SendFmtToGame(10003, "ihs", val_int, val_short, val_string) 表示发送一条10003协议, 协议内容由 一个32位有符号整数, 一个16位有符号整数, 一个字符串,共三个字段组成 val_int, val_short, val_str = self:ReadFmt("ihs") 表示从当前协议缓冲区中读取一个三个字段组成的协议, 返回值直接赋值给val_int, val_short, val_str ]] UserMsgAdapter = UserMsgAdapter or BaseClass() local UserMsgAdapter = UserMsgAdapter local networkMgr = networkMgr local Time = Time local Status = Status local print = print local rawget = rawget local unpack = unpack local tostring = tostring local tonumber = tonumber local string_sub = string.sub local table_insert = table.insert local string_len = string.len local ByteBuffer = ByteBuffer local table_concat = table.concat local logWarn = logWarn local Util = Util local can_print_cmd = RuntimePlatform and ApplicationPlatform ~= RuntimePlatform.Android and ApplicationPlatform ~= RuntimePlatform.IPhonePlayer UserMsgAdapter.SPLIT_CHAT = '糴' --协议传输分隔符 function UserMsgAdapter:__init() UserMsgAdapter.Instance = self UserMsgAdapter.send_byteBuff = false UserMsgAdapter.receive_byteBuff = false UserMsgAdapter.register_list = {} UserMsgAdapter.new_fmt_mode = false --新的协议解释类型 self.is_game_connected = false --是否已经连接服务器 self.reconnect_times = 0 --重连次数 UserMsgAdapter.result_list = {} self.cmd_callback_queue = Array.New() --协议callback队列 self.curr_frame_receive_count = 0 UserMsgAdapter.write_cmd = 0 -- local function onUpdate() -- self:Update() -- end -- TimerQuest.AddPeriodQuest(GlobalTimerQuest, onUpdate, 0.2, -1) LateUpdateBeat:Add(UserMsgAdapter.Update,self) UserMsgAdapter.initEvents(self) end function UserMsgAdapter:getInstance() if UserMsgAdapter.Instance == nil then UserMsgAdapter.Instance = UserMsgAdapter.New() end return UserMsgAdapter.Instance end function UserMsgAdapter:IsGameConnected() return self.is_game_connected end function UserMsgAdapter:IsWaitPlayerHandle() return self.wait_player_handle end function UserMsgAdapter:initEvents() --当连接建立时-- local function OnConnect() logWarn("Game Server connected!!") self.is_game_connected = true EventSystem.Fire(GlobalEventSystem,EventName.GAME_CONNECT) end --异常断线-- local function OnException() self.is_game_connected = false -- networkMgr:SendConnect() --判断在游戏中进行静默重连, 10004进入游戏之后,is_back_from_game为false if LoginModel.Instance and LoginModel.Instance.is_back_from_game == false then self.reconnect_times = 0 self.default_auto_connect = 4 UserMsgAdapter.ReconnectHandler(self) --判断从游戏中返回,在选角、创角界面,普通重连,is_back_from_game为true nil -- elseif LoginModel.Instance and ((LoginModel.Instance.is_back_from_game or LoginModel.Instance.is_back_from_game == nil) )then --and LoginModel.Instance.account_data_10000) then elseif LoginModel.Instance == nil or LoginModel.Instance.is_back_from_game ~= true then self.reconnect_times = 0 self.default_auto_connect = 0 UserMsgAdapter.ReconnectHandler(self) end EventSystem.Fire(GlobalEventSystem,EventName.GAME_DISCONNECT) -- LogError("OnException------->>>>") end --连接中断,或者被踢掉-- local function OnDisconnect() self.is_game_connected = false if LoginModel.Instance == nil or LoginModel.Instance.is_back_from_game == false then self.reconnect_times = 0 self.default_auto_connect = 2 UserMsgAdapter.ReconnectHandler(self) end EventSystem.Fire(GlobalEventSystem,EventName.GAME_DISCONNECT) -- LogError("OnDisconnect------->>>>") end --收到服务端消息-- local function OnMessage(buffer) -- if currProtoType == ProtocalType.BINARY then UserMsgAdapter.receiveMessage(self, buffer) -- end ---------------------------------------------------- --print('OnMessage-------->>>') end EventSystem.Bind(GlobalEventSystem,Protocal.Connect, OnConnect) EventSystem.Bind(GlobalEventSystem,Protocal.Message, OnMessage) EventSystem.Bind(GlobalEventSystem,Protocal.Exception, OnException) EventSystem.Bind(GlobalEventSystem,Protocal.Disconnect, OnDisconnect) end function UserMsgAdapter:ReconnectHandler() if LoginModel.Instance and LoginModel.Instance.not_show_reconnect then return end --玩家选择重连、返回处理 if self.wait_player_handle then return end --静默连接处理 if not ClientConfig.is_ban_auto_connect and self.default_auto_connect and self.default_auto_connect > 0 then self.default_auto_connect = self.default_auto_connect - 1 self.default_auto_connect = self.default_auto_connect > 0 and self.default_auto_connect or nil self:SetIsAutoConnecting(true) local function default_connect() local function on_connect( ) if LoginModel.Instance then LoginModel.Instance.reconnect_on_game = true end --清除所有model的缓存(部分model除外) LuaMemManager:getInstance():ClearModelData( ) EventSystem.Fire(GlobalEventSystem,EventName.SHOW_LOADING_VIEW) EventSystem.Fire(GlobalEventSystem,LoginStateEvent.START_GAME_CONNECT) end LoginController.Instance:CheckResUpdate(on_connect, false) self:AddConnectCheckTimer() end GlobalTimerQuest:AddDelayQuest(default_connect,2) return end if self.has_show_alert_view then return end self.has_show_alert_view = true local function ok() self.wait_player_handle = false local run = function() if LoginModel.Instance then LoginModel.Instance.reconnect_on_game = true end --清除所有model的缓存(部分model除外) LuaMemManager:getInstance():ClearModelData( ) EventSystem.Fire(GlobalEventSystem,EventName.SHOW_LOADING_VIEW) EventSystem.Fire(GlobalEventSystem,LoginStateEvent.START_GAME_CONNECT) end LoginController.Instance:CheckResUpdate(run, false) self:AddConnectCheckTimer() self.has_show_alert_view = false end local function cancle() self.wait_player_handle = false local run = function() LoginModel.Instance.reconnect_on_game = false EventSystem.Fire(GlobalEventSystem,EventName.SHOW_LOADING_VIEW) EventSystem.Fire(GlobalEventSystem,EventName.CHANGE_ACCOUNT) end LoginController.Instance:CheckResUpdate(run, false) self.has_show_alert_view = false end if self.reconnect_times < 4 then self.reconnect_times = self.reconnect_times + 1 local check_gameout_state = function() if LoginModel.Instance:IsGameOutState() then LoginModel.Instance:ResetGameOutState() self.reconnect_times = 0 return true else return false end end if self.reconnect_times == 4 then local function func() if check_gameout_state() then return end self.wait_player_handle = true Alert.show("无法重连到服务器,请确认网络后重试", Alert.Type.One, cancle, cancle, "返回登录") end GlobalTimerQuest:AddDelayQuest(func,2) else local function func() if LoginModel.Instance.not_show_reconnect then return end if check_gameout_state() then return end self.wait_player_handle = true Alert.show("网络已断开链接", Alert.Type.Two, ok, cancle, "重连", "返回登录") end GlobalTimerQuest:AddDelayQuest(func,2) end end end function UserMsgAdapter:SetIsAutoConnecting( flag ) self.is_auto_connecting = flag end function UserMsgAdapter:GetIsAutoConnecting( ) return self.is_auto_connecting end function UserMsgAdapter:AddConnectCheckTimer() self:RemoveConnectCheckTimer() local time = 0 local last_net_available = Util.NetAvailable local function onTimer() time = time + 1 if time >= 12 or self.is_game_connected or (LoginModel.Instance and LoginModel.Instance.is_back_from_game and not LoginModel.Instance.account_data_10000) then self:RemoveConnectCheckTimer() if time >= 12 then Message.show("重连失败") self:ReconnectHandler() end return end --print("Net Available Check...") if not self.is_game_connected and LoginModel:getInstance().reconnect_on_game then if not last_net_available and Util.NetAvailable then networkMgr:SendConnect() end end last_net_available = Util.NetAvailable end self.connect_timer = GlobalTimerQuest:AddPeriodQuest(onTimer,1,-1) end function UserMsgAdapter:RemoveConnectCheckTimer() if self.connect_timer then GlobalTimerQuest:CancelQuest(self.connect_timer) self.connect_timer = nil end end function UserMsgAdapter:Update() if self.cmd_callback_queue:GetSize() > 0 and (not self.cmd_handler_time or Time.time - self.cmd_handler_time > 0.5) then local size = self.cmd_callback_queue:GetSize() if size <= 4 then UserMsgAdapter.ImmeHandlerCallback(self, self.cmd_callback_queue:PopFront()) else -- local len = math.ceil(size * 0.25) -- print("---------------------------->self.curr_frame_receive_count= ", self.curr_frame_receive_count) for i = 1, self.curr_frame_receive_count + 1 do --保证比增加的量多一个 if i > size then break end UserMsgAdapter.ImmeHandlerCallback(self, self.cmd_callback_queue:PopFront()) end -- for i = 1, len do --保证比增加的量多一个 -- self:ImmeHandlerCallback(self.cmd_callback_queue:PopFront()) -- end end self.curr_frame_receive_count = 0 end end function UserMsgAdapter:ImmeHandlerCallback(buffer) if buffer then self.cmd_handler_time = Time.time local cmd = buffer:ReadUshort() local can_rar = buffer:ReadByte() local call_back = UserMsgAdapter.register_list[cmd] if can_print_cmd then if cmd ~= 10006 and cmd ~= 12008 and cmd ~= 12001 and cmd then logWarn("receive cmd = "..cmd) end end if call_back then UserMsgAdapter.receive_byteBuff = buffer call_back() end self.cmd_handler_time = false end end function UserMsgAdapter:receiveMessage(buffer) if self.cmd_callback_queue:GetSize() == 0 --没有队列 and (not self.last_handler_time or Time.time - self.last_handler_time >= 0.01) --超过一定的频率 and (not self.cmd_handler_time or Time.time - self.cmd_handler_time > 0.5) then --保护措施 self.last_handler_time = Time.time self.curr_frame_receive_count = 0 UserMsgAdapter.ImmeHandlerCallback(self, buffer) else self.curr_frame_receive_count = self.curr_frame_receive_count + 1 self.cmd_callback_queue:PushBack(buffer) end --print('receiveMessage->call_back: cmd:>'..cmd) end --发送一次性封装好的数据给服务器 function UserMsgAdapter.SendAllFmtToGame(cmd, fmt_str, ...) UserMsgAdapter.WriteBegin(cmd) UserMsgAdapter.WriteFMT(fmt_str, ...) UserMsgAdapter.SendToGame() end --发送一次性封装好的数据给服务器 function UserMsgAdapter.SendAllFmtToGame2(cmd, fmt_str, ...) local args_list = {...} networkMgr:SendAllFmtToGame(cmd, fmt_str, table_concat(args_list, UserMsgAdapter.SPLIT_CHAT)) end function UserMsgAdapter.WriteBegin(cmd) UserMsgAdapter.send_byteBuff = ByteBuffer.New() UserMsgAdapter.send_byteBuff:WriteShort(cmd) if can_print_cmd then if cmd ~= 10006 and cmd ~= 12001 and cmd then logWarn("send cmd="..cmd) end end UserMsgAdapter.write_cmd = cmd or 0 end function UserMsgAdapter.WriteFMT(fmt_str, ...) if fmt_str then local args_list = {...} local buffer = UserMsgAdapter.send_byteBuff local function writeStream(buffer,type,value) -- log("send Message = "..value) if value == nil then GameError.Instance:SendErrorToPHP("UserMsgAdapter WriteFMT nil cmd is = "..UserMsgAdapter.write_cmd.." "..debug.traceback()) if type == "s" then value = "" else value = 0 end end if type == "c" then buffer:WriteByte(value) elseif type == "i" then buffer:WriteUint(tonumber(value)) elseif type == "I" then buffer:WriteInt(value) elseif type == "h" then buffer:WriteUshort(value) elseif type == "H" then buffer:WriteShort(value) elseif type == "l" then buffer:WriteUlong(value) elseif type == "L" then buffer:WriteLong(value) elseif type == "s" then buffer:WriteString(value) elseif type == "B" then buffer:WriteBytes(value) end end for i = 1, string_len(fmt_str) do writeStream(buffer,string_sub(fmt_str,i,i),args_list[i]) end end end function UserMsgAdapter.SendToGame() if UserMsgAdapter.send_byteBuff then networkMgr:SendMessage(UserMsgAdapter.send_byteBuff) end UserMsgAdapter.send_byteBuff = false end function UserMsgAdapter.ReadFmt(fmt_str) if UserMsgAdapter.receive_byteBuff and fmt_str then local buffer = UserMsgAdapter.receive_byteBuff local function readStream(buffer,type) local value = nil if type == "c" then value = buffer:ReadByte() elseif type == "i" then value = buffer:ReadUint() elseif type == "I" then value = buffer:ReadInt() elseif type == "h" then value = buffer:ReadUshort() elseif type == "H" then value = buffer:ReadShort() elseif type == "l" then value = tonumber(tostring(buffer:ReadUlong())) elseif type == "L" then value = tonumber(tostring(buffer:ReadLong())) elseif type == "s" then value = buffer:ReadString() elseif type == "B" then value = buffer:ReadBytes() end -- log("receive message = "..value) return value end local len = string_len(fmt_str) if len == 1 then return readStream(buffer, fmt_str) else for i = 1, len do UserMsgAdapter.result_list[i] = readStream(buffer,string_sub(fmt_str,i,i)) end return unpack(UserMsgAdapter.result_list) end end end function UserMsgAdapter.ReadFmt2(fmt_str) -- return UserMsgAdapter.ReadFmt(fmt_str) local result = networkMgr:ReadFmt(UserMsgAdapter.receive_byteBuff, fmt_str) if result then local list = Split(result, UserMsgAdapter.SPLIT_CHAT) if list then local n_v = nil for k, v in ipairs(list) do n_v = tonumber(v) if n_v then list[k] = n_v end end return unpack(list) end end end function UserMsgAdapter.RegisterMsgOperate(id, register_func) UserMsgAdapter.register_list[id] = register_func end