local debugger_reLoadFile =nil local debugger_xpcall = nil local debugger_stackInfo = nil local coro_debugger = nil local debugger_require = require local debugger_exeLuaString = nil local checkSetVar = nil local loadstring_ = nil local debugger_sendMsg = nil if (loadstring) then loadstring_ = loadstring else loadstring_ = load end --只针对 luadebug 调试 jit版本不存在这个问题 local setfenv = setfenv if (not setfenv) then setfenv = function(fn, env) local i = 1 while true do local name = debug.getupvalue(fn, i) if name == "_ENV" then debug.upvaluejoin( fn, i, (function() return env end), 1 ) break elseif not name then break end i = i + 1 end return fn end end local ZZBase64 = {} local LuaDebugTool_ = nil if (LuaDebugTool) then LuaDebugTool_ = LuaDebugTool elseif (CS and CS.LuaDebugTool) then LuaDebugTool_ = CS.LuaDebugTool end local LuaDebugTool = LuaDebugTool_ local loadstring = loadstring_ local getinfo = debug.getinfo local function createSocket() local base = _G local string = require("string") local math = require("math") local socket = require("socket.core") local _M = socket ----------------------------------------------------------------------------- -- Exported auxiliar functions ----------------------------------------------------------------------------- function _M.connect4(address, port, laddress, lport) return socket.connect(address, port, laddress, lport, "inet") end function _M.connect6(address, port, laddress, lport) return socket.connect(address, port, laddress, lport, "inet6") end if (not _M.connect) then function _M.connect(address, port, laddress, lport) local sock, err = socket.tcp() if not sock then return nil, err end if laddress then local res, err = sock:bind(laddress, lport, -1) if not res then return nil, err end end local res, err = sock:connect(address, port) if not res then return nil, err end return sock end end function _M.bind(host, port, backlog) if host == "*" then host = "0.0.0.0" end local addrinfo, err = socket.dns.getaddrinfo(host) if not addrinfo then return nil, err end local sock, res err = "no info on address" for i, alt in base.ipairs(addrinfo) do if alt.family == "inet" then sock, err = socket.tcp4() else sock, err = socket.tcp6() end if not sock then return nil, err end sock:setoption("reuseaddr", true) res, err = sock:bind(alt.addr, port) if not res then sock:close() else res, err = sock:listen(backlog) if not res then sock:close() else return sock end end end return nil, err end _M.try = _M.newtry() function _M.choose(table) return function(name, opt1, opt2) if base.type(name) ~= "string" then name, opt1, opt2 = "default", name, opt1 end local f = table[name or "nil"] if not f then base.error("unknown key (" .. base.tostring(name) .. ")", 3) else return f(opt1, opt2) end end end ----------------------------------------------------------------------------- -- Socket sources and sinks, conforming to LTN12 ----------------------------------------------------------------------------- -- create namespaces inside LuaSocket namespace local sourcet, sinkt = {}, {} _M.sourcet = sourcet _M.sinkt = sinkt _M.BLOCKSIZE = 2048 sinkt["close-when-done"] = function(sock) return base.setmetatable( { getfd = function() return sock:getfd() end, dirty = function() return sock:dirty() end }, { __call = function(self, chunk, err) if not chunk then sock:close() return 1 else return sock:send(chunk) end end } ) end sinkt["keep-open"] = function(sock) return base.setmetatable( { getfd = function() return sock:getfd() end, dirty = function() return sock:dirty() end }, { __call = function(self, chunk, err) if chunk then return sock:send(chunk) else return 1 end end } ) end sinkt["default"] = sinkt["keep-open"] _M.sink = _M.choose(sinkt) sourcet["by-length"] = function(sock, length) return base.setmetatable( { getfd = function() return sock:getfd() end, dirty = function() return sock:dirty() end }, { __call = function() if length <= 0 then return nil end local size = math.min(socket.BLOCKSIZE, length) local chunk, err = sock:receive(size) if err then return nil, err end length = length - string.len(chunk) return chunk end } ) end sourcet["until-closed"] = function(sock) local done return base.setmetatable( { getfd = function() return sock:getfd() end, dirty = function() return sock:dirty() end }, { __call = function() if done then return nil end local chunk, err, partial = sock:receive(socket.BLOCKSIZE) if not err then return chunk elseif err == "closed" then sock:close() done = 1 return partial else return nil, err end end } ) end sourcet["default"] = sourcet["until-closed"] _M.source = _M.choose(sourcet) return _M end local function createJson() local math = require("math") local string = require("string") local table = require("table") local object = nil ----------------------------------------------------------------------------- -- Module declaration ----------------------------------------------------------------------------- local json = {} -- Public namespace local json_private = {} -- Private namespace -- Public constants json.EMPTY_ARRAY = {} json.EMPTY_OBJECT = {} -- Public functions -- Private functions local decode_scanArray local decode_scanComment local decode_scanConstant local decode_scanNumber local decode_scanObject local decode_scanString local decode_scanWhitespace local encodeString local isArray local isEncodable ----------------------------------------------------------------------------- -- PUBLIC FUNCTIONS ----------------------------------------------------------------------------- --- Encodes an arbitrary Lua object / variable. -- @param v The Lua object / variable to be JSON encoded. -- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode) function json.encode(v) -- Handle nil values if v == nil then return "null" end local vtype = type(v) -- Handle strings if vtype == "string" then return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string end -- Handle booleans if vtype == "number" or vtype == "boolean" then return tostring(v) end -- Handle tables if vtype == "table" then local rval = {} -- Consider arrays separately local bArray, maxCount = isArray(v) if bArray then for i = 1, maxCount do table.insert(rval, json.encode(v[i])) end else -- An object, not an array for i, j in pairs(v) do if isEncodable(i) and isEncodable(j) then table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j)) end end end if bArray then return "[" .. table.concat(rval, ",") .. "]" else return "{" .. table.concat(rval, ",") .. "}" end end -- Handle null values if vtype == "function" and v == json.null then return "null" end assert(false, "encode attempt to encode unsupported type " .. vtype .. ":" .. tostring(v)) end --- Decodes a JSON string and returns the decoded value as a Lua data structure / value. -- @param s The string to scan. -- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1. -- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil, -- and the position of the first character after -- the scanned JSON object. function json.decode(s, startPos) startPos = startPos and startPos or 1 startPos = decode_scanWhitespace(s, startPos) assert(startPos <= string.len(s), "Unterminated JSON encoded object found at position in [" .. s .. "]") local curChar = string.sub(s, startPos, startPos) -- Object if curChar == "{" then return decode_scanObject(s, startPos) end -- Array if curChar == "[" then return decode_scanArray(s, startPos) end -- Number if string.find("+-0123456789.e", curChar, 1, true) then return decode_scanNumber(s, startPos) end -- String if curChar == '"' or curChar == [[']] then return decode_scanString(s, startPos) end if string.sub(s, startPos, startPos + 1) == "/*" then return json.decode(s, decode_scanComment(s, startPos)) end -- Otherwise, it must be a constant return decode_scanConstant(s, startPos) end --- The null function allows one to specify a null value in an associative array (which is otherwise -- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null } function json.null() return json.null -- so json.null() will also return null ;-) end ----------------------------------------------------------------------------- -- Internal, PRIVATE functions. -- Following a Python-like convention, I have prefixed all these 'PRIVATE' -- functions with an underscore. ----------------------------------------------------------------------------- --- Scans an array from JSON into a Lua object -- startPos begins at the start of the array. -- Returns the array and the next starting position -- @param s The string being scanned. -- @param startPos The starting position for the scan. -- @return table, int The scanned array as a table, and the position of the next character to scan. function decode_scanArray(s, startPos) local array = {} -- The return value local stringLen = string.len(s) assert( string.sub(s, startPos, startPos) == "[", "decode_scanArray called but array does not start at position " .. startPos .. " in string:\n" .. s ) startPos = startPos + 1 -- Infinite loop for array elements repeat startPos = decode_scanWhitespace(s, startPos) assert(startPos <= stringLen, "JSON String ended unexpectedly scanning array.") local curChar = string.sub(s, startPos, startPos) if (curChar == "]") then return array, startPos + 1 end if (curChar == ",") then startPos = decode_scanWhitespace(s, startPos + 1) end assert(startPos <= stringLen, "JSON String ended unexpectedly scanning array.") object, startPos = json.decode(s, startPos) table.insert(array, object) until false end --- Scans a comment and discards the comment. -- Returns the position of the next character following the comment. -- @param string s The JSON string to scan. -- @param int startPos The starting position of the comment function decode_scanComment(s, startPos) assert( string.sub(s, startPos, startPos + 1) == "/*", "decode_scanComment called but comment does not start at position " .. startPos ) local endPos = string.find(s, "*/", startPos + 2) assert(endPos ~= nil, "Unterminated comment in string at " .. startPos) return endPos + 2 end --- Scans for given constants: true, false or null -- Returns the appropriate Lua type, and the position of the next character to read. -- @param s The string being scanned. -- @param startPos The position in the string at which to start scanning. -- @return object, int The object (true, false or nil) and the position at which the next character should be -- scanned. function decode_scanConstant(s, startPos) local consts = {["true"] = true, ["false"] = false, ["null"] = nil} local constNames = {"true", "false", "null"} for i, k in pairs(constNames) do if string.sub(s, startPos, startPos + string.len(k) - 1) == k then return consts[k], startPos + string.len(k) end end assert(nil, "Failed to scan constant from string " .. s .. " at starting position " .. startPos) end --- Scans a number from the JSON encoded string. -- (in fact, also is able to scan numeric +- eqns, which is not -- in the JSON spec.) -- Returns the number, and the position of the next character -- after the number. -- @param s The string being scanned. -- @param startPos The position at which to start scanning. -- @return number, int The extracted number and the position of the next character to scan. function decode_scanNumber(s, startPos) local endPos = startPos + 1 local stringLen = string.len(s) local acceptableChars = "+-0123456789.e" while (string.find(acceptableChars, string.sub(s, endPos, endPos), 1, true) and endPos <= stringLen) do endPos = endPos + 1 end local stringValue = "return " .. string.sub(s, startPos, endPos - 1) local stringEval = loadstring(stringValue) assert( stringEval, "Failed to scan number [ " .. stringValue .. "] in JSON string at position " .. startPos .. " : " .. endPos ) return stringEval(), endPos end --- Scans a JSON object into a Lua object. -- startPos begins at the start of the object. -- Returns the object and the next starting position. -- @param s The string being scanned. -- @param startPos The starting position of the scan. -- @return table, int The scanned object as a table and the position of the next character to scan. function decode_scanObject(s, startPos) local object = {} local stringLen = string.len(s) local key, value assert( string.sub(s, startPos, startPos) == "{", "decode_scanObject called but object does not start at position " .. startPos .. " in string:\n" .. s ) startPos = startPos + 1 repeat startPos = decode_scanWhitespace(s, startPos) assert(startPos <= stringLen, "JSON string ended unexpectedly while scanning object.") local curChar = string.sub(s, startPos, startPos) if (curChar == "}") then return object, startPos + 1 end if (curChar == ",") then startPos = decode_scanWhitespace(s, startPos + 1) end assert(startPos <= stringLen, "JSON string ended unexpectedly scanning object.") -- Scan the key key, startPos = json.decode(s, startPos) assert(startPos <= stringLen, "JSON string ended unexpectedly searching for value of key " .. key) startPos = decode_scanWhitespace(s, startPos) assert(startPos <= stringLen, "JSON string ended unexpectedly searching for value of key " .. key) assert( string.sub(s, startPos, startPos) == ":", "JSON object key-value assignment mal-formed at " .. startPos ) startPos = decode_scanWhitespace(s, startPos + 1) assert(startPos <= stringLen, "JSON string ended unexpectedly searching for value of key " .. key) value, startPos = json.decode(s, startPos) object[key] = value until false -- infinite loop while key-value pairs are found end -- START SoniEx2 -- Initialize some things used by decode_scanString -- You know, for efficiency local escapeSequences = { ["\\t"] = "\t", ["\\f"] = "\f", ["\\r"] = "\r", ["\\n"] = "\n", ["\\b"] = "" } setmetatable( escapeSequences, { __index = function(t, k) -- skip "\" aka strip escape return string.sub(k, 2) end } ) -- END SoniEx2 --- Scans a JSON string from the opening inverted comma or single quote to the -- end of the string. -- Returns the string extracted as a Lua string, -- and the position of the next non-string character -- (after the closing inverted comma or single quote). -- @param s The string being scanned. -- @param startPos The starting position of the scan. -- @return string, int The extracted string as a Lua string, and the next character to parse. function decode_scanString(s, startPos) assert(startPos, "decode_scanString(..) called without start position") local startChar = string.sub(s, startPos, startPos) -- START SoniEx2 -- PS: I don't think single quotes are valid JSON assert(startChar == '"' or startChar == [[']], "decode_scanString called for a non-string") --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart) local t = {} local i, j = startPos, startPos while string.find(s, startChar, j + 1) ~= j + 1 do local oldj = j i, j = string.find(s, "\\.", j + 1) local x, y = string.find(s, startChar, oldj + 1) if not i or x < i then i, j = x, y - 1 end table.insert(t, string.sub(s, oldj + 1, i - 1)) if string.sub(s, i, j) == "\\u" then local a = string.sub(s, j + 1, j + 4) j = j + 4 local n = tonumber(a, 16) assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j) -- math.floor(x/2^y) == lazy right shift -- a % 2^b == bitwise_and(a, (2^b)-1) -- 64 = 2^6 -- 4096 = 2^12 (or 2^6 * 2^6) local x if n < 128 then x = string.char(n % 128) elseif n < 2048 then -- [110x xxxx] [10xx xxxx] x = string.char(192 + (math.floor(n / 64) % 32), 128 + (n % 64)) else -- [1110 xxxx] [10xx xxxx] [10xx xxxx] x = string.char(224 + (math.floor(n / 4096) % 16), 128 + (math.floor(n / 64) % 64), 128 + (n % 64)) end table.insert(t, x) else table.insert(t, escapeSequences[string.sub(s, i, j)]) end end table.insert(t, string.sub(j, j + 1)) assert( string.find(s, startChar, j + 1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")" ) return table.concat(t, ""), j + 2 -- END SoniEx2 end --- Scans a JSON string skipping all whitespace from the current start position. -- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached. -- @param s The string being scanned -- @param startPos The starting position where we should begin removing whitespace. -- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string -- was reached. function decode_scanWhitespace(s, startPos) local whitespace = " \n\r\t" local stringLen = string.len(s) while (string.find(whitespace, string.sub(s, startPos, startPos), 1, true) and startPos <= stringLen) do startPos = startPos + 1 end return startPos end --- Encodes a string to be JSON-compatible. -- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-) -- @param s The string to return as a JSON encoded (i.e. backquoted string) -- @return The string appropriately escaped. local escapeList = { ['"'] = '\\"', ["\\"] = "\\\\", ["/"] = "\\/", [""] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t" } function json_private.encodeString(s) local s = tostring(s) return s:gsub( ".", function(c) return escapeList[c] end ) -- SoniEx2: 5.0 compat end -- Determines whether the given Lua type is an array or a table / dictionary. -- We consider any table an array if it has indexes 1..n for its n items, and no -- other data in the table. -- I think this method is currently a little 'flaky', but can't think of a good way around it yet... -- @param t The table to evaluate as an array -- @return boolean, number True if the table can be represented as an array, false otherwise. If true, -- the second returned value is the maximum -- number of indexed elements in the array. function isArray(t) -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable -- (with the possible exception of 'n') if (t == json.EMPTY_ARRAY) then return true, 0 end if (t == json.EMPTY_OBJECT) then return false end local maxIndex = 0 for k, v in pairs(t) do if (type(k) == "number" and math.floor(k) == k and 1 <= k) then -- k,v is an indexed pair if (not isEncodable(v)) then return false end -- All array elements must be encodable maxIndex = math.max(maxIndex, k) else if (k == "n") then if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements else -- Else of (k=='n') if isEncodable(v) then return false end end -- End of (k~='n') end -- End of k,v not an indexed pair end -- End of loop across all pairs return true, maxIndex end --- Determines whether the given Lua object / table / variable can be JSON encoded. The only -- types that are JSON encodable are: string, boolean, number, nil, table and json.null. -- In this implementation, all other types are ignored. -- @param o The object to examine. -- @return boolean True if the object should be JSON encoded, false if it should be ignored. function isEncodable(o) local t = type(o) return (t == "string" or t == "boolean" or t == "number" or t == "nil" or t == "table") or (t == "function" and o == json.null) end return json end local debugger_print = print local debug_server = nil local breakInfoSocket = nil local json = createJson() local LuaDebugger = { fileMaps = {}, Run = true, --表示正常运行只检测断点 StepIn = false, StepInLevel = 0, StepNext = false, StepNextLevel = 0, StepOut = false, breakInfos = {}, runTimeType = nil, isHook = true, pathCachePaths = {}, isProntToConsole = 1, isFoxGloryProject = false, isDebugPrint = true, hookType = "lrc", currentFileName = "", currentTempFunc = nil, --分割字符串缓存 splitFilePaths = {}, DebugLuaFie = "", version = "0.9.3", serVarLevel = 4 } local debug_hook = nil local _resume = coroutine.resume coroutine.resume = function(co, ...) if (LuaDebugger.isHook) then if coroutine.status(co) ~= "dead" then debug.sethook(co, debug_hook, "lrc") end end return _resume(co, ...) end local _wrap = coroutine.wrap coroutine.wrap = function(fun,dd) local newFun =_wrap(function() debug.sethook(debug_hook, "lrc") return fun(); end) return newFun end LuaDebugger.event = { S2C_SetBreakPoints = 1, C2S_SetBreakPoints = 2, S2C_RUN = 3, C2S_HITBreakPoint = 4, S2C_ReqVar = 5, C2S_ReqVar = 6, --单步跳过请求 S2C_NextRequest = 7, --单步跳过反馈 C2S_NextResponse = 8, -- 单步跳过 结束 没有下一步 C2S_NextResponseOver = 9, --单步跳入 S2C_StepInRequest = 10, C2S_StepInResponse = 11, --单步跳出 S2C_StepOutRequest = 12, --单步跳出返回 C2S_StepOutResponse = 13, --打印 C2S_LuaPrint = 14, S2C_LoadLuaScript = 16, C2S_SetSocketName = 17, C2S_LoadLuaScript = 18, C2S_DebugXpCall = 20, S2C_DebugClose = 21, S2C_SerVar = 24, C2S_SerVar = 25, S2C_ReLoadFile = 26, C2S_ReLoadFile = 27, } --@region print function print(...) if (LuaDebugger.isProntToConsole == 1 or LuaDebugger.isProntToConsole == 3) then debugger_print(...) end if (LuaDebugger.isProntToConsole == 1 or LuaDebugger.isProntToConsole == 2) then if (debug_server) then local arg = {...} --这里的...和{}符号中间需要有空格号,否则会出错 local str = "" if (#arg == 0) then arg = {"nil"} end for k, v in pairs(arg) do str = str .. tostring(v) .. "\t" end local sendMsg = { event = LuaDebugger.event.C2S_LuaPrint, data = {msg = ZZBase64.encode(str), type = 1} } local sendStr = json.encode(sendMsg) debug_server:send(sendStr .. "__debugger_k0204__") end end end function luaIdePrintWarn(...) if (LuaDebugger.isProntToConsole == 1 or LuaDebugger.isProntToConsole == 3) then debugger_print(...) end if (LuaDebugger.isProntToConsole == 1 or LuaDebugger.isProntToConsole == 2) then if (debug_server) then local arg = {...} --这里的...和{}符号中间需要有空格号,否则会出错 local str = "" if (#arg == 0) then arg = {"nil"} end for k, v in pairs(arg) do str = str .. tostring(v) .. "\t" end local sendMsg = { event = LuaDebugger.event.C2S_LuaPrint, data = {msg = ZZBase64.encode(str), type = 2} } local sendStr = json.encode(sendMsg) debug_server:send(sendStr .. "__debugger_k0204__") end end end function luaIdePrintErr(...) if (LuaDebugger.isProntToConsole == 1 or LuaDebugger.isProntToConsole == 3) then debugger_print(...) end if (LuaDebugger.isProntToConsole == 1 or LuaDebugger.isProntToConsole == 2) then if (debug_server) then local arg = {...} --这里的...和{}符号中间需要有空格号,否则会出错 local str = "" if (#arg == 0) then arg = {"nil"} end for k, v in pairs(arg) do str = str .. tostring(v) .. "\t" end local sendMsg = { event = LuaDebugger.event.C2S_LuaPrint, data = {msg = ZZBase64.encode(str), type = 3} } local sendStr = json.encode(sendMsg) debug_server:send(sendStr .. "__debugger_k0204__") end end end --@endregion --@region 辅助方法 local function debugger_lastIndex(str, p) local startIndex = string.find(str, p, 1) while startIndex do local findstartIndex = string.find(str, p, startIndex + 1) if (not findstartIndex) then break else startIndex = findstartIndex end end return startIndex end local function debugger_convertParentDir(dir) local index, endindex = string.find(dir, "/%.%./") if (index) then local file1 = string.sub(dir, 1, index - 1) local startIndex = debugger_lastIndex(file1, "/") file1 = string.sub(file1, 1, startIndex - 1) local file2 = string.sub(dir, endindex) dir = file1 .. file2 dir = debugger_convertParentDir(dir) return dir else return dir end end local function debugger_getFilePathInfo(file) local fileName = nil local dir = nil file = file:gsub("/.\\", "/") file = file:gsub("\\", "/") file = file:gsub("//", "/") if file:find("@") == 1 then file = file:sub(2) end local findex = file:find("%./") if (findex == 1) then file = file:sub(3) end file = debugger_convertParentDir(file) local fileLength = string.len(file) local suffixNames = { ".lua", ".lua.txt", ".txt", ".bytes" } table.sort( suffixNames, function(name1, name2) return string.len(name1) > string.len(name2) end ) local suffixLengs = {} for i, suffixName in ipairs(suffixNames) do table.insert(suffixLengs, string.len(suffixName)) end local fileLength = string.len(file) for i, suffix in ipairs(suffixNames) do local suffixName = string.sub(file, fileLength - suffixLengs[i] + 1) if (suffixName == suffix) then file = string.sub(file, 1, fileLength - suffixLengs[i]) break end end local fileNameStartIndex = debugger_lastIndex(file, "/") if (fileNameStartIndex) then fileName = string.sub(file, fileNameStartIndex + 1) dir = string.sub(file, 1, fileNameStartIndex) file = dir .. fileName else fileNameStartIndex = debugger_lastIndex(file, "%.") if (not fileNameStartIndex) then fileName = file dir = "" else dir = string.sub(file, 1, fileNameStartIndex) dir = dir:gsub("%.", "/") fileName = string.sub(file, fileNameStartIndex + 1) file = dir .. fileName end end return file, dir, fileName end --@endregion ----=============================工具方法============================================= --@region 工具方法 local function debugger_strSplit(input, delimiter) input = tostring(input) delimiter = tostring(delimiter) if (delimiter == "") then return false end local pos, arr = 0, {} -- for each divider found for st, sp in function() return string.find(input, delimiter, pos, true) end do table.insert(arr, string.sub(input, pos, st - 1)) pos = sp + 1 end table.insert(arr, string.sub(input, pos)) return arr end local function debugger_strTrim(input) input = string.gsub(input, "^[ \t\n\r]+", "") return string.gsub(input, "[ \t\n\r]+$", "") end local function debugger_dump(value, desciption, nesting) if type(nesting) ~= "number" then nesting = 3 end local lookupTable = {} local result = {} local function _v(v) if type(v) == "string" then v = '"' .. v .. '"' end return tostring(v) end local traceback = debugger_strSplit(debug.traceback("", 2), "\n") print("dump from: " .. debugger_strTrim(traceback[3])) local function _dump(value, desciption, indent, nest, keylen) desciption = desciption or "" local spc = "" if type(keylen) == "number" then spc = string.rep(" ", keylen - string.len(_v(desciption))) end if type(value) ~= "table" then result[#result + 1] = string.format("%s%s%s = %s", indent, _v(desciption), spc, _v(value)) elseif lookupTable[value] then result[#result + 1] = string.format("%s%s%s = *REF*", indent, desciption, spc) else lookupTable[value] = true if nest > nesting then result[#result + 1] = string.format("%s%s = *MAX NESTING*", indent, desciption) else result[#result + 1] = string.format("%s%s = {", indent, _v(desciption)) local indent2 = indent .. " " local keys = {} local keylen = 0 local values = {} for k, v in pairs(value) do keys[#keys + 1] = k local vk = _v(k) local vkl = string.len(vk) if vkl > keylen then keylen = vkl end values[k] = v end table.sort( keys, function(a, b) if type(a) == "number" and type(b) == "number" then return a < b else return tostring(a) < tostring(b) end end ) for i, k in ipairs(keys) do _dump(values[k], k, indent2, nest + 1, keylen) end result[#result + 1] = string.format("%s}", indent) end end end _dump(value, desciption, "- ", 1) for i, line in ipairs(result) do print(line) end end --@endregion local function debugger_valueToString(v) local vtype = type(v) local vstr = nil if (vtype == "userdata") then if (LuaDebugger.isFoxGloryProject) then return "userdata",vtype else return tostring(v), vtype end elseif (vtype == "table" or vtype == "function" or vtype == "boolean") then local value = vtype xpcall(function() value = tostring(v) end,function() value = vtype end) return value, vtype elseif (vtype == "number" or vtype == "string" ) then return v, vtype else return tostring(v), vtype end end local function debugger_setVarInfo(name, value) local valueStr, valueType = debugger_valueToString(value) local nameStr,nameType = debugger_valueToString(name) if(valueStr == nil) then valueStr = valueType end local valueInfo = { name =nameStr, valueType = valueType, valueStr = ZZBase64.encode(valueStr) } return valueInfo end local function debugger_getvalue(f) local i = 1 local locals = {} -- get locals while true do local name, value = debug.getlocal(f, i) if not name then break end if (name ~= "(*temporary)") then locals[name] = value end i = i + 1 end local func = getinfo(f, "f").func i = 1 local ups = {} while func do -- check for func as it may be nil for tail calls local name, value = debug.getupvalue(func, i) if not name then break end if (name == "_ENV") then ups["_ENV_"] = value else ups[name] = value end i = i + 1 end return {locals = locals, ups = ups} end --获取堆栈 debugger_stackInfo = function(ignoreCount, event) local datas = {} local stack = {} local varInfos = {} local funcs = {} local index = 0 for i = ignoreCount, 100 do local source = getinfo(i) local isadd = true if (i == ignoreCount) then local file = source.source if (file:find(LuaDebugger.DebugLuaFie)) then return end if (file == "=[C]") then isadd = false end end if not source then break end if (isadd) then local fullName, dir, fileName = debugger_getFilePathInfo(source.source) local info = { src = fullName, scoreName = source.name, currentline = source.currentline, linedefined = source.linedefined, what = source.what, nameWhat = source.namewhat } index = i local vars = debugger_getvalue(i + 1) table.insert(stack, info) table.insert(varInfos, vars) table.insert(funcs, source.func) end if source.what == "main" then break end end local stackInfo = {stack = stack, vars = varInfos, funcs = funcs} local data = { stack = stackInfo.stack, vars = stackInfo.vars, funcs = stackInfo.funcs, event = event, funcsLength = #stackInfo.funcs, upFunc = getinfo(ignoreCount - 3, "f").func } LuaDebugger.currentTempFunc = data.funcs[1] return data end --===========================点断信息================================================== --根据不同的游戏引擎进行定时获取断点信息 --CCDirector:sharedDirector():getScheduler() local debugger_setBreak = nil local function debugger_receiveDebugBreakInfo() -- if (jit) then -- if (LuaDebugger.debugLuaType ~= "jit") then -- local msg = "当前luajit版本为: " .. jit.version .. " 请使用LuaDebugjit 进行调试!" -- print(msg) -- end -- end if (breakInfoSocket) then local msg, status = breakInfoSocket:receive() if(LuaDebugger.isLaunch and status == "closed") then os.exit() end if (msg) then local netData = json.decode(msg) if netData.event == LuaDebugger.event.S2C_SetBreakPoints then debugger_setBreak(netData.data) elseif netData.event == LuaDebugger.event.S2C_LoadLuaScript then LuaDebugger.loadScriptBody = netData.data debugger_exeLuaString() debugger_sendMsg(breakInfoSocket,LuaDebugger.event.C2S_LoadLuaScript,LuaDebugger.loadScriptBody) elseif netData.event == LuaDebugger.event.S2C_ReLoadFile then LuaDebugger.reLoadFileBody = netData.data LuaDebugger.isReLoadFile = false LuaDebugger.reLoadFileBody.isReLoad = debugger_reLoadFile(LuaDebugger.reLoadFileBody) print("重载结果:",LuaDebugger.reLoadFileBody.isReLoad) LuaDebugger.reLoadFileBody.script = nil debugger_sendMsg( breakInfoSocket, LuaDebugger.event.C2S_ReLoadFile, { stack = LuaDebugger.reLoadFileBody } ) end end end end local function splitFilePath(path) if (LuaDebugger.splitFilePaths[path]) then return LuaDebugger.splitFilePaths[path] end local pos, arr = 0, {} -- for each divider found for st, sp in function() return string.find(path, "/", pos, true) end do local pathStr = string.sub(path, pos, st - 1) table.insert(arr, pathStr) pos = sp + 1 end local pathStr = string.sub(path, pos) table.insert(arr, pathStr) LuaDebugger.splitFilePaths[path] = arr return arr end debugger_setBreak = function(datas) local breakInfos = LuaDebugger.breakInfos for i, data in ipairs(datas) do data.fileName = string.lower(data.fileName) data.serverPath = string.lower(data.serverPath) local breakInfo = breakInfos[data.fileName] if (not breakInfo) then breakInfos[data.fileName] = {} breakInfo = breakInfos[data.fileName] end if (not data.breakDatas or #data.breakDatas == 0) then breakInfo[data.serverPath] = nil else local fileBreakInfo = breakInfo[data.serverPath] if (not fileBreakInfo) then fileBreakInfo = { pathNames = splitFilePath(data.serverPath), --命中次數判斷計數器 hitCounts = {} } breakInfo[data.serverPath] = fileBreakInfo end local lineInfos = {} for li, breakData in ipairs(data.breakDatas) do lineInfos[breakData.line] = breakData if (breakData.hitCondition and breakData.hitCondition ~= "") then breakData.hitCondition = tonumber(breakData.hitCondition) else breakData.hitCondition = 0 end if (not fileBreakInfo.hitCounts[breakData.line]) then fileBreakInfo.hitCounts[breakData.line] = 0 end end fileBreakInfo.lines = lineInfos --這裡添加命中次數判斷 for line, count in pairs(fileBreakInfo.hitCounts) do if (not lineInfos[line]) then fileBreakInfo.hitCounts[line] = nil end end end local count = 0 for i, linesInfo in pairs(breakInfo) do count = count + 1 end if (count == 0) then breakInfos[data.fileName] = nil end end --debugger_dump(breakInfos, "breakInfos", 6) --检查是否需要断点 local isHook = false for k, v in pairs(breakInfos) do isHook = true break end --这样做的原因是为了最大限度的使手机调试更加流畅 注意这里会连续的进行n次 if (isHook) then if (not LuaDebugger.isHook) then debug.sethook(debug_hook, "lrc") end LuaDebugger.isHook = true else if (LuaDebugger.isHook) then debug.sethook() end LuaDebugger.isHook = false end end local function debugger_checkFileIsBreak(fileName) return LuaDebugger.breakInfos[fileName] end --=====================================断点信息 end ---------------------------------------------- local controller_host = "192.168.1.102" local controller_port = 7003 debugger_sendMsg = function(serverSocket, eventName, data) local sendMsg = { event = eventName, data = data } local sendStr = json.encode(sendMsg) serverSocket:send(sendStr .. "__debugger_k0204__") end function debugger_conditionStr(condition, vars, callBack) local function loadScript() local currentTabble = {} local locals = vars[1].locals local ups = vars[1].ups if (ups) then for k, v in pairs(ups) do currentTabble[k] = v end end if (locals) then for k, v in pairs(locals) do currentTabble[k] = v end end setmetatable(currentTabble, {__index = _G}) local fun = loadstring("return " .. condition) setfenv(fun, currentTabble) return fun() end local status, msg = xpcall( loadScript, function(error) print(error) end ) if (status and msg) then callBack() end end --执行lua字符串 debugger_exeLuaString = function() local function loadScript() local script = LuaDebugger.loadScriptBody.script if (LuaDebugger.loadScriptBody.isBreak) then local currentTabble = {_G = _G} local frameId = LuaDebugger.loadScriptBody.frameId frameId = frameId local func = LuaDebugger.currentDebuggerData.funcs[frameId] local vars = LuaDebugger.currentDebuggerData.vars[frameId] local locals = vars.locals local ups = vars.ups for k, v in pairs(ups) do currentTabble[k] = v end for k, v in pairs(locals) do currentTabble[k] = v end setmetatable(currentTabble, {__index = _G}) local fun = loadstring(script) setfenv(fun, currentTabble) fun() else local fun = loadstring(script) fun() end end local status, msg = xpcall( loadScript, function(error) -- debugger_sendMsg(debug_server, LuaDebugger.event.C2S_LoadLuaScript, LuaDebugger.loadScriptBody) end ) LuaDebugger.loadScriptBody.script = nil if (LuaDebugger.loadScriptBody.isBreak) then LuaDebugger.serVarLevel = LuaDebugger.serVarLevel+1 LuaDebugger.currentDebuggerData = debugger_stackInfo(LuaDebugger.serVarLevel, LuaDebugger.event.C2S_HITBreakPoint) LuaDebugger.loadScriptBody.stack = LuaDebugger.currentDebuggerData.stack end LuaDebugger.loadScriptBody.complete = true end --@region 调试中修改变量值 --根据key 值在 value 查找 local function debugger_getTablekey(key,keyType,value) if(keyType == -1) then return key elseif(keyType == 1) then return tonumber(key) elseif(keyType == 2) then local valueKey = nil for k,v in pairs(value) do local nameType = type(k) if(nameType == "userdata" or nameType == "table") then if (not LuaDebugger.isFoxGloryProject) then valueKey = tostring(k) if(key == valueKey) then return k end break end end end end end local function debugger_setVarValue(server, data) local newValue = nil local level = LuaDebugger.serVarLevel+LuaDebugger.setVarBody.frameId local firstKeyName = data.keys[1] --@region vars check local localValueChangeIndex = -1 local upValueChangeIndex = -1 local upValueFun = nil local oldValue = nil local i = 1 local locals = {} -- get locals while true do local name, value = debug.getlocal(level, i) if not name then break end if(firstKeyName == name) then localValueChangeIndex = i oldValue = value end if (name ~= "(*temporary)") then locals[name] = value end i = i + 1 end local func = getinfo(level, "f").func i = 1 local ups = {} while func do -- check for func as it may be nil for tail calls local name, value = debug.getupvalue(func, i) if not name then break end if(localValueChangeIndex == -1 and firstKeyName == name) then upValueFun = func oldValue = value upValueChangeIndex = i end if (name == "_ENV") then ups["_ENV_"] = value else ups[name] = value end i = i + 1 end --@endregion local vars = {locals = locals, ups = ups} local function loadScript() local currentTabble = {} local locals = vars.locals local ups = vars.ups if (ups) then for k, v in pairs(ups) do currentTabble[k] = v end end if (locals) then for k, v in pairs(locals) do currentTabble[k] = v end end setmetatable(currentTabble, {__index = _G}) local fun = loadstring("return " .. data.value) setfenv(fun, currentTabble) newValue = fun() end local status, msg = xpcall( loadScript, function(error) print(error, "============================") end ) local i = 1 -- local 查找并替换 local keyLength = #data.keys if(keyLength == 1) then if(localValueChangeIndex ~= -1) then debug.setlocal(level, localValueChangeIndex, newValue) elseif(upValueFun ~= nil) then debug.setupvalue( upValueFun, upValueChangeIndex, newValue ) else --全局变量查找 if(_G[firstKeyName]) then _G[firstKeyName] = newValue end end else if(not oldValue) then if(_G[firstKeyName]) then oldValue = _G[firstKeyName] end end local tempValue = oldValue for i=2,keyLength-1 do if(tempValue) then oldValue = oldValue[debugger_getTablekey(data.keys[i],data.numberTypes[i],oldValue)] end end if(tempValue) then oldValue[debugger_getTablekey(data.keys[keyLength],data.numberTypes[keyLength],oldValue)] = newValue end end local varInfo = debugger_setVarInfo(data.varName, newValue) data.varInfo = varInfo LuaDebugger.serVarLevel = LuaDebugger.serVarLevel+1 LuaDebugger.currentDebuggerData = debugger_stackInfo(LuaDebugger.serVarLevel, LuaDebugger.event.C2S_HITBreakPoint) end --@endregion --调试修改变量值统一的 _resume checkSetVar = function() if (LuaDebugger.isSetVar) then LuaDebugger.isSetVar = false debugger_setVarValue(debug_server,LuaDebugger.setVarBody) LuaDebugger.serVarLevel = LuaDebugger.serVarLevel+1 _resume(coro_debugger, LuaDebugger.setVarBody) xpcall( checkSetVar, function(error) print("设置变量", error) end ) elseif(LuaDebugger.isLoadLuaScript) then LuaDebugger.isLoadLuaScript = false debugger_exeLuaString() LuaDebugger.serVarLevel = LuaDebugger.serVarLevel+1 _resume(coro_debugger, LuaDebugger.reLoadFileBody) xpcall( checkSetVar, function(error) print("执行代码", error) end ) elseif(LuaDebugger.isReLoadFile) then LuaDebugger.isReLoadFile = false LuaDebugger.reLoadFileBody.isReLoad = debugger_reLoadFile(LuaDebugger.reLoadFileBody) print("重载结果:",LuaDebugger.reLoadFileBody.isReLoad) LuaDebugger.reLoadFileBody.script = nil LuaDebugger.serVarLevel = LuaDebugger.serVarLevel+1 _resume(coro_debugger, LuaDebugger.reLoadFileBody) xpcall( checkSetVar, function(error) print("重新加载文件", error) end ) end end local function getSource(source) source = string.lower(source) if (LuaDebugger.pathCachePaths[source]) then LuaDebugger.currentLineFile = LuaDebugger.pathCachePaths[source] return LuaDebugger.pathCachePaths[source] end local fullName, dir, fileName = debugger_getFilePathInfo(source) LuaDebugger.currentLineFile = fullName LuaDebugger.pathCachePaths[source] = fileName return fileName end local function debugger_GeVarInfoBytUserData(server, var) local fileds = LuaDebugTool.getUserDataInfo(var) local varInfos = {} --c# vars for i = 1, fileds.Count do local filed = fileds[i - 1] local valueInfo = { name = filed.name, valueType = filed.valueType, valueStr = ZZBase64.encode(filed.valueStr), isValue = filed.isValue, csharp = true } table.insert(varInfos, valueInfo) end return varInfos end local function debugger_getValueByScript(value, script) local val = nil local status, msg = xpcall( function() local fun = loadstring("return " .. script) setfenv(fun, value) val = fun() end, function(error) print(error, "====>") val = nil end ) return val end local function debugger_getVarByKeys(value, keys, index) local str = "" local keyLength = #keys for i = index, keyLength do local key = keys[i] if (key == "[metatable]") then else if (i == index) then if (string.find(key, "%.")) then if (str == "") then i = index + 1 value = value[key] end if (i >= #keys) then return index, value end return debugger_getVarByKeys(value, keys, i) else str = key end else if (string.find(key, "%[")) then str = str .. key elseif (type(key) == "string") then if (string.find(key, "table:") or string.find(key, "userdata:") or string.find(key, "function:")) then if (str ~= "") then local vl = debugger_getValueByScript(value, str) value = vl if (value) then for k, v in pairs(value) do local ktype = type(k) if (ktype == "userdata" or ktype == "table" or ktype == "function") then local keyName = debugger_valueToString(k) if (keyName == key) then value = v break end end end end str = "" if (i == keyLength) then return #keys, value else return debugger_getVarByKeys(value, keys, i + 1) end else str = str .. '["' .. key .. '"]' end else str = str .. '["' .. key .. '"]' end else str = str .. "[" .. key .. "]" end end end end local v = debugger_getValueByScript(value, str) return #keys, v end --[[ @desc: 查找c# 值 author:k0204 time:2018-04-07 21:32:31 return ]] local function debugger_getCSharpValue(value, searchIndex, keys) local key = keys[searchIndex] local val = LuaDebugTool.getCSharpValue(value, key) if (val) then --1最后一个 直接返回 if (searchIndex == #keys) then return #keys, val else --2再次获得 如果没有找到那么 进行lua 层面查找 local vindex, val1 = debugger_getCSharpValue(val, searchIndex + 1, keys) if (not val1) then --组建新的keys local tempKeys = {} for i = vindex, #keys do table.insert(tempKeys, keys[i]) end local vindx, val1 = debugger_searchVarByKeys(value, searckKeys, 1) return vindx, val1 else return vindex, val1 end end else --3最终这里返回 所以2 中 没有当val1 不为空的处理 return searchIndex, val end end local function debugger_searchVarByKeys(value, keys, searckKeys) local index, val = debugger_getVarByKeys(value, searckKeys, 1) if (not LuaDebugTool or not LuaDebugTool.getCSharpValue or type(LuaDebugTool.getCSharpValue) ~= "function") then return index, val end if (val) then if (index == #keys) then return index, val else local searchStr = "" --进行c# 值查找 local keysLength = #keys local searchIndex = index + 1 local sindex, val = debugger_getCSharpValue(val, searchIndex, keys) return sindex, val end else --进行递减 local tempKeys = {} for i = 1, #searckKeys - 1 do table.insert(tempKeys, keys[i]) end if (#tempKeys == 0) then return #keys, nil end return debugger_searchVarByKeys(value, keys, tempKeys) end end --[[ @desc: 获取metatable 信息 author:k0204 time:2018-04-06 20:27:12 return ]] local function debugger_getmetatable(value, metatable, vinfos, server, variablesReference, debugSpeedIndex, metatables) for i, mtable in ipairs(metatables) do if (metatable == mtable) then return vinfos end end table.insert(metatables, metatable) for k, v in pairs(metatable) do local val = nil if (type(k) == "string") then xpcall( function() val = value[k] end, function(error) val = nil end ) if (val == nil) then xpcall( function() if (string.find(k, "__")) then val = v end end, function(error) val = nil end ) end end if (val) then local vinfo = debugger_setVarInfo(k, val) table.insert(vinfos, vinfo) if (#vinfos > 10) then debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = vinfos, isComplete = 0 } ) vinfos = {} end end end local m = getmetatable(metatable) if (m) then return debugger_getmetatable(value, m, vinfos, server, variablesReference, debugSpeedIndex, metatables) else return vinfos end end local function debugger_sendTableField(luatable, vinfos, server, variablesReference, debugSpeedIndex, valueType) if (valueType == "userdata") then if (tolua and tolua.getpeer) then luatable = tolua.getpeer(luatable) else return vinfos end end if (luatable == nil) then return vinfos end for k, v in pairs(luatable) do local vinfo = debugger_setVarInfo(k, v) table.insert(vinfos, vinfo) if (#vinfos > 10) then debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = vinfos, isComplete = 0 } ) vinfos = {} end end return vinfos end local function debugger_sendTableValues(value, server, variablesReference, debugSpeedIndex) local vinfos = {} local luatable = {} local valueType = type(value) local userDataInfos = {} local m = nil if (valueType == "userdata") then m = getmetatable(value) vinfos = debugger_sendTableField(value, vinfos, server, variablesReference, debugSpeedIndex, valueType) if (LuaDebugTool) then local varInfos = debugger_GeVarInfoBytUserData(server, value, variablesReference, debugSpeedIndex) for i, v in ipairs(varInfos) do if (v.valueType == "System.Byte[]" and value[v.name] and type(value[v.name]) == "string") then local valueInfo = { name = v.name, valueType = "string", valueStr = ZZBase64.encode(value[v.name]) } table.insert(vinfos, valueInfo) else table.insert(vinfos, v) end if (#vinfos > 10) then debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = vinfos, isComplete = 0 } ) vinfos = {} end end end else m = getmetatable(value) vinfos = debugger_sendTableField(value, vinfos, server, variablesReference, debugSpeedIndex, valueType) end if (m) then vinfos = debugger_getmetatable(value, m, vinfos, server, variablesReference, debugSpeedIndex, {}) end debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = vinfos, isComplete = 1 } ) end --获取lua 变量的方法 local function debugger_getBreakVar(body, server) local variablesReference = body.variablesReference local debugSpeedIndex = body.debugSpeedIndex local vinfos = {} local function exe() local frameId = body.frameId local type_ = body.type local keys = body.keys --找到对应的var local vars = nil if (type_ == 1) then vars = LuaDebugger.currentDebuggerData.vars[frameId + 1] vars = vars.locals elseif (type_ == 2) then vars = LuaDebugger.currentDebuggerData.vars[frameId + 1] vars = vars.ups elseif (type_ == 3) then vars = _G end if (#keys == 0) then debugger_sendTableValues(vars, server, variablesReference, debugSpeedIndex) return end local index, value = debugger_searchVarByKeys(vars, keys, keys) if (value) then local valueType = type(value) if (valueType == "table" or valueType == "userdata") then debugger_sendTableValues(value, server, variablesReference, debugSpeedIndex) else if (valueType == "function") then value = tostring(value) end debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = ZZBase64.encode(value), isComplete = 1, varType = valueType } ) end else debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = {}, isComplete = 1, varType = "nil" } ) end end xpcall( exe, function(error) -- print("获取变量错误 错误消息-----------------") -- print(error) -- print(debug.traceback("", 2)) debugger_sendMsg( server, LuaDebugger.event.C2S_ReqVar, { variablesReference = variablesReference, debugSpeedIndex = debugSpeedIndex, vars = { { name = "error", valueType = "string", valueStr = ZZBase64.encode("无法获取属性值:" .. error .. "->" .. debug.traceback("", 2)), isValue = false } }, isComplete = 1 } ) end ) end local function ResetDebugInfo() LuaDebugger.Run = false LuaDebugger.StepIn = false LuaDebugger.StepNext = false LuaDebugger.StepOut = false LuaDebugger.StepNextLevel = 0 end local function debugger_loop(server) server = debug_server --命令 local command local eval_env = {} local arg while true do local line, status = server:receive() if (status == "closed") then if(LuaDebugger.isLaunch) then os.exit() else debug.sethook() coroutine.yield() end end if (line) then local netData = json.decode(line) local event = netData.event local body = netData.data if (event == LuaDebugger.event.S2C_DebugClose) then if(LuaDebugger.isLaunch) then os.exit() else debug.sethook() coroutine.yield() end elseif event == LuaDebugger.event.S2C_SetBreakPoints then --设置断点信息 local function setB() debugger_setBreak(body) end xpcall( setB, function(error) print(error) end ) elseif event == LuaDebugger.event.S2C_RUN then --开始运行 LuaDebugger.runTimeType = body.runTimeType LuaDebugger.isProntToConsole = body.isProntToConsole LuaDebugger.isFoxGloryProject = body.isFoxGloryProject LuaDebugger.isLaunch = body.isLaunch ResetDebugInfo() LuaDebugger.Run = true local data = coroutine.yield() LuaDebugger.serVarLevel = 4 LuaDebugger.currentDebuggerData = data debugger_sendMsg( server, data.event, { stack = data.stack } ) elseif event == LuaDebugger.event.S2C_ReqVar then -- 获取变量信息 --请求数据信息 debugger_getBreakVar(body, server) elseif event == LuaDebugger.event.S2C_NextRequest then -- 设置单步跳过 ResetDebugInfo() LuaDebugger.StepNext = true LuaDebugger.StepNextLevel = 0 --设置当前文件名和当前行数 local data = coroutine.yield() LuaDebugger.serVarLevel = 4 --重置调试信息 LuaDebugger.currentDebuggerData = data debugger_sendMsg( server, data.event, { stack = data.stack } ) elseif (event == LuaDebugger.event.S2C_StepInRequest) then --单步跳入 --单步跳入 ResetDebugInfo() LuaDebugger.StepIn = true local data = coroutine.yield() LuaDebugger.serVarLevel = 4 --重置调试信息 LuaDebugger.currentDebuggerData = data debugger_sendMsg( server, data.event, { stack = data.stack, eventType = data.eventType } ) elseif (event == LuaDebugger.event.S2C_StepOutRequest) then --单步跳出 ResetDebugInfo() LuaDebugger.StepOut = true local data = coroutine.yield() LuaDebugger.serVarLevel = 4 --重置调试信息 LuaDebugger.currentDebuggerData = data debugger_sendMsg( server, data.event, { stack = data.stack, eventType = data.eventType } ) elseif event == LuaDebugger.event.S2C_LoadLuaScript then LuaDebugger.loadScriptBody = body LuaDebugger.isLoadLuaScript = true local data = coroutine.yield() debugger_sendMsg( server, LuaDebugger.event.C2S_LoadLuaScript, LuaDebugger.loadScriptBody ) elseif event == LuaDebugger.event.S2C_SerVar then LuaDebugger.isSetVar = true LuaDebugger.setVarBody = body local data = coroutine.yield() debugger_sendMsg( server, LuaDebugger.event.C2S_SerVar, { stack = data, eventType = data.eventType } ) elseif event == LuaDebugger.event.S2C_ReLoadFile then LuaDebugger.isReLoadFile = true LuaDebugger.reLoadFileBody = body local data = coroutine.yield() debugger_sendMsg( server, LuaDebugger.event.C2S_ReLoadFile, { stack = data, eventType = data.eventType } ) end end end end coro_debugger = coroutine.create(debugger_loop) debug_hook = function(event, line) if(not LuaDebugger.isHook) then return end if(LuaDebugger.Run) then if(event == "line") then local isCheck = false for k, breakInfo in pairs(LuaDebugger.breakInfos) do for bk, linesInfo in pairs(breakInfo) do if(linesInfo.lines and linesInfo.lines[line]) then isCheck = true break end end if(isCheck) then break end end if(not isCheck) then return end else LuaDebugger.currentFileName = nil LuaDebugger.currentTempFunc = nil return end end --跳出 if (LuaDebugger.StepOut) then if (event == "line" or event == "call") then return end local tempFun = getinfo(2, "f").func if (LuaDebugger.currentDebuggerData.funcsLength == 1) then ResetDebugInfo() LuaDebugger.Run = true else if (LuaDebugger.currentDebuggerData.funcs[2] == tempFun) then local data = debugger_stackInfo(3, LuaDebugger.event.C2S_StepInResponse) --挂起等待调试器作出反应 _resume(coro_debugger, data) checkSetVar() end end return end -- debugger_dump(LuaDebugger,"LuaDebugger") -- print(LuaDebugger.StepNextLevel,"LuaDebugger.StepNextLevel") local file = nil if (event == "call") then -- end -- if(not LuaDebugger.StepOut) then if (not LuaDebugger.Run) then LuaDebugger.StepNextLevel = LuaDebugger.StepNextLevel + 1 end -- print("stepIn",LuaDebugger.StepNextLevel) local stepInfo = getinfo(2, "S") local source = stepInfo.source if (source:find(LuaDebugger.DebugLuaFie) or source == "=[C]") then return end file = getSource(source) LuaDebugger.currentFileName = file elseif (event == "return" or event == "tail return") then -- end -- if(not LuaDebugger.StepOut) then if (not LuaDebugger.Run) then LuaDebugger.StepNextLevel = LuaDebugger.StepNextLevel - 1 end LuaDebugger.currentFileName = nil elseif (event == "line") then --@region 判断命中断点 --判断命中断点 --判断命中断点 --判断命中断点 --判断命中断点 local isHit = false local stepInfo = nil if (not LuaDebugger.currentFileName) then stepInfo = getinfo(2, "S") local source = stepInfo.source if (source == "=[C]" or source:find(LuaDebugger.DebugLuaFie)) then return end file = getSource(source) LuaDebugger.currentFileName = file end file = LuaDebugger.currentFileName --判断断点 local breakInfo = LuaDebugger.breakInfos[file] local breakData = nil if (breakInfo) then local ischeck = false for k, lineInfo in pairs(breakInfo) do local lines = lineInfo.lines if (lines and lines[line]) then ischeck = true break end end if (ischeck) then --并且在断点中 -- local info = stepInfo -- if (not info) then -- print("info ---------------") -- info = getinfo(2) -- end local hitPathNames = splitFilePath(LuaDebugger.currentLineFile) local hitCounts = {} local debugHitCounts = nil for k, lineInfo in pairs(breakInfo) do local lines = lineInfo.lines local pathNames = lineInfo.pathNames debugHitCounts = lineInfo.hitCounts if (lines and lines[line]) then breakData = lines[line] --判断路径 hitCounts[k] = 0 local hitPathNamesCount = #hitPathNames local pathNamesCount = #pathNames local checkCount = 0; while (true) do if (pathNames[pathNamesCount] ~= hitPathNames[hitPathNamesCount]) then break else hitCounts[k] = hitCounts[k] + 1 end pathNamesCount = pathNamesCount - 1 hitPathNamesCount = hitPathNamesCount - 1 checkCount = checkCount+1 if (pathNamesCount <= 0 or hitPathNamesCount <= 0) then break end end if(checkCount>0) then break; end if(checkCount==0) then breakData = nil -- break; end else breakData = nil end end if (breakData) then local hitFieName = "" local maxCount = 0 for k, v in pairs(hitCounts) do if (v > maxCount) then maxCount = v hitFieName = k end end local hitPathNamesLength = #hitPathNames if (hitPathNamesLength == 1 or (hitPathNamesLength > 1 and maxCount > 1)) then if (hitFieName ~= "") then local hitCount = breakData.hitCondition local clientHitCount = debugHitCounts[breakData.line] clientHitCount = clientHitCount + 1 debugHitCounts[breakData.line] = clientHitCount if (clientHitCount >= hitCount) then isHit = true end end end end end end --@endregion if (LuaDebugger.StepIn) then local data = debugger_stackInfo(3, LuaDebugger.event.C2S_NextResponse) --挂起等待调试器作出反应 if (data) then LuaDebugger.currentTempFunc = data.funcs[1] _resume(coro_debugger, data) checkSetVar() return end end if (LuaDebugger.StepNext) then if (LuaDebugger.StepNextLevel <= 0) then local data = debugger_stackInfo(3, LuaDebugger.event.C2S_NextResponse) -- 挂起等待调试器作出反应 if (data) then LuaDebugger.currentTempFunc = data.funcs[1] _resume(coro_debugger, data) checkSetVar() return end end end if (isHit) then local data = debugger_stackInfo(3, LuaDebugger.event.C2S_HITBreakPoint) if (breakData and breakData.condition) then debugger_conditionStr( breakData.condition, data.vars, function() _resume(coro_debugger, data) checkSetVar() end ) else --挂起等待调试器作出反应 _resume(coro_debugger, data) checkSetVar() end end end end debugger_xpcall = function() --调用 coro_debugger 并传入 参数 local data = debugger_stackInfo(4, LuaDebugger.event.C2S_HITBreakPoint) if(data.stack and data.stack[1]) then data.stack[1].isXpCall = true end --挂起等待调试器作出反应 _resume(coro_debugger, data) checkSetVar() end --调试开始 local function start() local fullName, dirName, fileName = debugger_getFilePathInfo(getinfo(1).source) LuaDebugger.DebugLuaFie = fileName local socket = createSocket() print(controller_host) print(controller_port) local server = socket.connect(controller_host, controller_port) debug_server = server if server then --创建breakInfo socket socket = createSocket() breakInfoSocket = socket.connect(controller_host, controller_port) if (breakInfoSocket) then breakInfoSocket:settimeout(0) debugger_sendMsg( breakInfoSocket, LuaDebugger.event.C2S_SetSocketName, { name = "breakPointSocket" } ) debugger_sendMsg( server, LuaDebugger.event.C2S_SetSocketName, { name = "mainSocket", version = LuaDebugger.version } ) xpcall( function() debug.sethook(debug_hook, "lrc") end, function(error) print("error:", error) end ) -- if (jit) then -- if (LuaDebugger.debugLuaType ~= "jit") then -- print("error======================================================") -- local msg = "当前luajit版本为: " .. jit.version .. " 请使用LuaDebugjit 进行调试!" -- print(msg) -- end -- end _resume(coro_debugger, server) end end end function StartDebug(host, port,reLoad) if (not host) then print("error host nil") end if (not port) then print("error prot nil") end if (type(host) ~= "string") then print("error host not string") end if (type(port) ~= "number") then print("error host not number") end controller_host = host controller_port = port xpcall( start, function(error) -- body print(error) end ) --代码重载 if(isReLoad) then xpcall(function() debugger_reLoadFile = require("luaideReLoadFile") end,function() print("左侧luaide按钮->打开luaIde最新调试文件所在文件夹->luaideReLoadFile.lua->拷贝到项目中") print("具体使用方式请看luaideReLoadFile中文件注释") debugger_reLoadFile = function() print("未实现代码重载") end end) end return debugger_receiveDebugBreakInfo, debugger_xpcall end --base64 local string = string ZZBase64.__code = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', }; ZZBase64.__decode = {} for k,v in pairs(ZZBase64.__code) do ZZBase64.__decode[string.byte(v,1)] = k - 1 end function ZZBase64.encode(text) local len = string.len(text) local left = len % 3 len = len - left local res = {} local index = 1 for i = 1, len, 3 do local a = string.byte(text, i ) local b = string.byte(text, i + 1) local c = string.byte(text, i + 2) -- num = a<<16 + b<<8 + c local num = a * 65536 + b * 256 + c for j = 1, 4 do --tmp = num >> ((4 -j) * 6) local tmp = math.floor(num / (2 ^ ((4-j) * 6))) --curPos = tmp&0x3f local curPos = tmp % 64 + 1 res[index] = ZZBase64.__code[curPos] index = index + 1 end end if left == 1 then ZZBase64.__left1(res, index, text, len) elseif left == 2 then ZZBase64.__left2(res, index, text, len) end return table.concat(res) end function ZZBase64.__left2(res, index, text, len) local num1 = string.byte(text, len + 1) num1 = num1 * 1024 --lshift 10 local num2 = string.byte(text, len + 2) num2 = num2 * 4 --lshift 2 local num = num1 + num2 local tmp1 = math.floor(num / 4096) --rShift 12 local curPos = tmp1 % 64 + 1 res[index] = ZZBase64.__code[curPos] local tmp2 = math.floor(num / 64) curPos = tmp2 % 64 + 1 res[index + 1] = ZZBase64.__code[curPos] curPos = num % 64 + 1 res[index + 2] = ZZBase64.__code[curPos] res[index + 3] = "=" end function ZZBase64.__left1(res, index,text, len) local num = string.byte(text, len + 1) num = num * 16 local tmp = math.floor(num / 64) local curPos = tmp % 64 + 1 res[index ] = ZZBase64.__code[curPos] curPos = num % 64 + 1 res[index + 1] = ZZBase64.__code[curPos] res[index + 2] = "=" res[index + 3] = "=" end function ZZBase64.decode(text) local len = string.len(text) local left = 0 if string.sub(text, len - 1) == "==" then left = 2 len = len - 4 elseif string.sub(text, len) == "=" then left = 1 len = len - 4 end local res = {} local index = 1 local decode = ZZBase64.__decode for i =1, len, 4 do local a = decode[string.byte(text,i )] local b = decode[string.byte(text,i + 1)] local c = decode[string.byte(text,i + 2)] local d = decode[string.byte(text,i + 3)] --num = a<<18 + b<<12 + c<<6 + d local num = a * 262144 + b * 4096 + c * 64 + d local e = string.char(num % 256) num = math.floor(num / 256) local f = string.char(num % 256) num = math.floor(num / 256) res[index ] = string.char(num % 256) res[index + 1] = f res[index + 2] = e index = index + 3 end if left == 1 then ZZBase64.__decodeLeft1(res, index, text, len) elseif left == 2 then ZZBase64.__decodeLeft2(res, index, text, len) end return table.concat(res) end function ZZBase64.__decodeLeft1(res, index, text, len) local decode = ZZBase64.__decode local a = decode[string.byte(text, len + 1)] local b = decode[string.byte(text, len + 2)] local c = decode[string.byte(text, len + 3)] local num = a * 4096 + b * 64 + c local num1 = math.floor(num / 1024) % 256 local num2 = math.floor(num / 4) % 256 res[index] = string.char(num1) res[index + 1] = string.char(num2) end function ZZBase64.__decodeLeft2(res, index, text, len) local decode = ZZBase64.__decode local a = decode[string.byte(text, len + 1)] local b = decode[string.byte(text, len + 2)] local num = a * 64 + b num = math.floor(num / 16) res[index] = string.char(num) end return StartDebug