-- game protocol NetProtocol = {} -- listeners for protocol down -- listeners are all function -- the front listener will be called before the behinds -- example : -- receive protocol down 1 1 local listeners = {} NetProtocol.noSendProtcol = false NetProtocol.CachingSomeReceives = false function NetProtocol.AddListener(id1, id2, func) local key = id1.."_"..id2 if listeners[key] == nil then listeners[key] = {} else NetProtocol.InfoFormat("NetProtocol::AddListener Error id1:{0} id2:{1}",id1,id2) end table.insert(listeners[key], func) end function NetProtocol.RemoveListener(id1, id2, func) local key = id1.."_"..id2 if listeners[key] == nil then return end for i, value in ipairs(listeners[key]) do if value == func then table.remove(listeners[key], i) return end end end function NetProtocol.DispatchListener(id1, id2, data) local key = id1.."_"..id2 if listeners[key] == nil then NetProtocol.InfoFormat("NetProtocol::DispatchListener Error id1:{0},id2:{1}",id1,id2) return end for i, value in ipairs(listeners[key]) do if value ~= nil then value(id1, id2, data) ServiceConnProxy.Instance:RecvHeart() -- table.remove(listeners[key], i) -- return end end end -- log function NetProtocol.TableToString(t) return "" -- local s = "" -- for key, value in pairs(t) do -- if type(value) ~= "table" then -- if value ~= nil then -- if string.len(tostring(value)) > 0 then -- s = s..key.."_"..tostring(value).."\n" -- else -- s = s..key.."_".." ".."\n" -- end -- else -- s = s..key.."_".."nil".."\n" -- end -- else -- s = s..key.."_"..NetProtocol.TableToString(value) -- end -- end -- return s end -- pack data -> dataBytes function NetProtocol.Pack(id1, id2, data) local dataUp = _G[string.format("Data_Up_%d_%d", id1, id2)] if dataUp == nil then return nil end local start = 0 return NetProtocol.PackStruct(dataUp, data) end -- unpack struct data -> bytes function NetProtocol.PackStruct(struct, data) local dataBytes = NetUtil.GetNewBytes() -- pack for key, value in ipairs(struct) do local name = value.name local t = value.type local lenFrom = value.lenFrom if name ~= nil and t ~= nil then if lenFrom ~= nil then local number if type(lenFrom) == "number" then number = lenFrom elseif data[lenFrom] ~= nil then number = data[lenFrom] end for i = 1, number do dataBytes = NetUtil.Append(dataBytes, NetProtocol.PackValue(t, data[name][i])) end else dataBytes = NetUtil.Append(dataBytes, NetProtocol.PackValue(t, data[name])) end end end return dataBytes end -- pack value -> bytes array function NetProtocol.PackValue(t, value) -- array function PackArray(t, array) local dataBytes = NetUtil.GetNewBytes() for i = 1, #array do if array[i] ~= nil then if type(array[i]) ~= "table" then dataBytes = NetUtil.Append(dataBytes, NetProtocol.PackValue(t, array[i])) else dataBytes = NetUtil.Append(dataBytes, PackArray(t, array[i])) end end end return dataBytes end if type(t) ~= "table" and type(value) == "table" then return PackArray(t, value) end -- struct if type(t) == "table" then return NetProtocol.PackStruct(t, value) end -- char if t == "char" then return NetUtil.CharTo1Bytes(value) end -- char32 if t == "char32" then return NetUtil.CharsToBytes(value, 32) end -- uint2 if t == "uint2" then return NetUtil.UintTo2Bytes(value) end -- uint4 if t == "uint4" then return NetUtil.UintTo4Bytes(value) end -- uint8 if t == "uint8" then return NetUtil.UintTo8Bytes(tostring(value)) end -- int2 if t == "int2" then return NetUtil.IntTo2Bytes(value) end -- int4 if t == "int4" then return NetUtil.IntTo4Bytes(value) end -- log pack fail return nil end local ProtobufPool_Get = ProtobufPool.Get -- unpack dataBytes -> data function NetProtocol.Unpack(id1, id2, dataStr) -- if id1 > 4 then local cmd = Proto_Include[id1] if cmd == nil then return nil end local param = cmd[id2] if param == nil then return nil end -- local str = "" -- for i = 1, dataBytes.Length do -- str = str..(string.char(dataBytes[i - 1])) -- end local msg = ProtobufPool_Get(param) -- local msg = param() -- local str = Slua.ToString(dataBytes) if not NetConfig.IsHeart(id1, id2) then -- NetProtocol.InfoFormat("NetProtocol::Unpack Proto id1:{0} id2:{1}",id1,id2) end local memSample = Debug_LuaMemotry.SampleBegin("NetProtocolParseFromString") -- local memSample = Debug_LuaMemotry.SampleBegin(table.concat(keys)) msg:ParseFromString(dataStr) Debug_LuaMemotry.SampleEnd(memSample) return msg,param -- end -- local dataDown = _G[string.format("Data_Down_%d_%d", id1, id2)] -- if dataDown == nil then -- return nil -- end -- local start = 0 -- local _, data = NetProtocol.UnpackStruct(dataDown, dataBytes, start) -- return data end -- unpack struct bytes -> data function NetProtocol.UnpackStruct(struct, bytes, start) local data = {} local length = start for key, value in ipairs(struct) do local name = value.name local t = value.type local lenFrom = value.lenFrom if name ~= nil and t ~= nil then if lenFrom ~= nil then local number if type(lenFrom) == "number" then number = lenFrom elseif data[lenFrom] ~= nil then number = data[lenFrom] end data[name] = {} for i = 1, number do local len, value = NetProtocol.UnpackValue(t, bytes, start) start = start + len data[name][i] = value end else local len, value = NetProtocol.UnpackValue(t, bytes, start) start = start + len data[name] = value end end end return start - length, data end -- unpack bytes -> value function NetProtocol.UnpackValue(t, bytes, start) local len -- struct if type(t) == "table" then return NetProtocol.UnpackStruct(t, bytes, start) end -- int4 if t == "int4" then len = 4 return len, NetUtil.BytesToInt4(NetUtil.GetBytes(bytes, start, len)) end -- uint2 if t == "uint2" then len = 2 return len, NetUtil.BytesToUInt2(NetUtil.GetBytes(bytes, start, len)) end -- uint4 if t == "uint4" then len = 4 return len, NetUtil.BytesToUInt4(NetUtil.GetBytes(bytes, start, len)) end -- uint8 if t == "uint8" then len = 8 return len, NetUtil.BytesToUInt8(NetUtil.GetBytes(bytes, start, len)) end -- char if t == "char" then len = 1 return len, tonumber(NetUtil.BytesToChar(NetUtil.GetBytes(bytes, start, len))) end -- char32 if t == "char32" then len = 32 return len, NetUtil.BytesToChars(NetUtil.GetBytes(bytes, start, len)) end -- log unpack fail NetProtocol.InfoFormat("NetProtocol.UnpackValue Error type:{0}",t) return nil, nil end -- send function NetProtocol.Send(id1, id2, data) if id1 ~= 2 and id2 ~= 22 then NetProtocol.InfoFormat("NetProtocol::Send Request id1:{0} id2:{1}",id1,id2) end local dataBytes = NetProtocol.Pack(id1, id2, data) if dataBytes == nil then NetProtocol.InfoFormat("NetProtocol::Send Error Pack Error: id1:{0} id2:{1}",id1, id2) return end -- log if not NetConfig.IsHeart(id1, id2) then NetProtocol.InfoFormat("NetProtocol::Send Success id1:{0} id2:{1}",id1,id2) end -- send NetManager.GameSend( id1, id2, dataBytes ) end local currentIndex = 1 local currentTime = 0 -- send function NetProtocol.SendProto(data) if(NetProtocol.noSendProtcol)then return end ServiceConnProxy.Instance:UpdateSendHeartTime() local id1 = data.cmd local id2 = data.param if not NetConfig.IsHeart(id1, id2) then if not NetConfig.IsCare(id1, id2) then NetProtocol.InfoFormat("NetProtocol::SendProto id1:{0} id2:{1}",id1,id2) end end -- new way begin local str = data:SerializeToString() local now = ServerTime.ServerTime if(now)then now = math.floor(now/1000) else now = 0 end local delta = now - currentTime if(delta >0)then currentIndex = 1 elseif(delta < 0)then now = currentTime +1 currentIndex = 1 else currentIndex = currentIndex+1 end local nonce = xCmd_pb.Nonce() currentTime = now local sign = currentTime .. "_" .. currentIndex .. "_!^ro&" nonce.index = currentIndex nonce.timestamp = currentTime sign = NetUtil.getSha1(sign) if(#sign ~= 40)then LogUtility.ErrorFormat("sign error 看到此錯誤請貼給張國兵!!!sign:{0},sign size:{1}",sign,#sign) return end nonce.sign = sign local nonceStr = nonce:SerializeToString() if(Game.NetConnectionManager and Game.NetConnectionManager.EnableNonce)then NetManagerHelper.GameSend(id1, id2,nonceStr, str) else NetManagerHelper.GameSend(id1, id2, str) end end local ProtobufPool_Add = ProtobufPool.Add -- receive local function _Receive(id1, id2, data) -- local data = dataBytes -- local startTime = os.clock() -- startTime = math.floor(startTime * 1000) -- local packageSize = data and #data or 0 local dataClass if(not NetConfig.IsNoPbUnpack(id1,id2))then -- local memSample = Debug_LuaMemotry.SampleBegin("NetProtocolUnpack") data,dataClass = NetProtocol.Unpack(id1, id2, data) -- Debug_LuaMemotry.SampleEnd(memSample) end if data == nil then -- NetProtocol.InfoFormat("NetProtocol::Receive Error: id1:{0},id2:{1}",id1,id2) return end -- log if not NetConfig.IsHeart(id1, id2) then if not NetConfig.IsCare(id1, id2) then -- NetProtocol.InfoFormat("NetProtocol::Receive id1:{0},id2:{1}",id1,id2) end end -- protocol down -- local protocolDown = _G[string.format("Protocol_Down_%d", id1)] -- if protocolDown ~= nil then -- protocolDown["Receive_"..id2](data) -- end -- dispatch -- local memSample = Debug_LuaMemotry.SampleBegin("NetProtocolDispatch") -- NetProtocol.InfoFormat("NetProtocol::Receive id1:{0},id2:{1}",id1,id2) NetProtocol.DispatchListener(id1, id2, data) -- Debug_LuaMemotry.SampleEnd(memSample) ProtobufPool_Add(dataClass,data) -- local endTime = os.clock() -- endTime = math.floor(endTime * 1000) -- local deltaTime = endTime - startTime -- ProtocolStatistics.Instance():Receive(id1, id2, packageSize, deltaTime) end local cachedReceives = {} local function _CacheReceive(id1,id2,str) local cache = ReusableTable.CreateArray() cache[1],cache[2],cache[3] = id1,id2,str cachedReceives[#cachedReceives + 1] = cache end local cacheIDMap = {} function NetProtocol.NeedCacheReceive(id1,id2) local map = cacheIDMap[id1] if(map==nil) then map = {} cacheIDMap[id1] = map end map[id2] = true end function NetProtocol.Receive(id1, id2, str) NetProtocol.InfoFormat("NetProtocol::Receive id1:{0} id2:{1}",id1,id2) if(NetProtocol.CachingSomeReceives) then local map = cacheIDMap[id1] if(map and map[id2]) then _CacheReceive(id1,id2,str) return end end local memSample = Debug_LuaMemotry.SampleBegin("NetProtocolReceive") _Receive(id1, id2, str) Debug_LuaMemotry.SampleEnd(memSample) end function NetProtocol.CallCachedReceives() local cache for i=1,#cachedReceives do cache = cachedReceives[i] _Receive(cache[1],cache[2],cache[3]) ReusableTable.DestroyAndClearArray(cache) end TableUtility.ArrayClear(cachedReceives) end function NetProtocol.InfoFormat(fmt,...) if(Game.NetConnectionManager and Game.NetConnectionManager.EnableLog)then LogUtility.InfoFormat(fmt,...) end end function NetProtocol.Info(text) if(Game.NetConnectionManager and Game.NetConnectionManager.EnableLog)then LogUtility.Info(text) end end