diff --git a/authserver b/authserver index bbaae46..05417c8 100755 Binary files a/authserver and b/authserver differ diff --git a/lua_scripts/extensions/ObjectVariables.ext b/lua_scripts/extensions/ObjectVariables.ext new file mode 100644 index 0000000..74f330e --- /dev/null +++ b/lua_scripts/extensions/ObjectVariables.ext @@ -0,0 +1,115 @@ +-- +-- Copyright (C) 2010 - 2016 Eluna Lua Engine +-- This program is free software licensed under GPL version 3 +-- Please see the included DOCS/LICENSE.md for more information +-- + +-- filename.ext files are loaded before normal .lua files + +-- +-- This extension allows saving data to specific object for it's lifetime in current runtime session +-- Supports Map, Player, Creature, GameObject +-- +-- SetData sets a value +-- obj:SetData(key, val) +-- +-- GetData gets the data table or a specific value by key from it +-- local tbl = obj:GetData() +-- local val = obj:GetData(key) +-- + +local pairs = pairs + +local variableStores = { + Map = {}, + Player = {}, + Creature = {}, + GameObject = {}, +} + +local function DestroyMapData(event, obj) + local map = obj:GetMapId() + local inst = obj:GetInstanceId() + for k,v in pairs(variableStores) do + local mapdata = v[map] + if mapdata then + mapdata[inst] = nil + end + end +end + +local function DestroyObjData(event, obj) + local otype = obj:GetObjectType() + local guid = otype == "Map" and 1 or obj:GetGUIDLow() + + if otype == "Player" then + variableStores[otype][guid] = nil + return + end + + local map = obj:GetMapId() + local inst = obj:GetInstanceId() + local mapdata = variableStores[otype][map] + if mapdata then + local instancedata = mapdata[inst] + if instancedata then + instancedata[guid] = nil + end + end +end + +local function GetData(self, field) + local otype = self:GetObjectType() + local guid = otype == "Map" and 1 or self:GetGUIDLow() + local varStore = variableStores[otype] + + if otype == "Player" then + varStore[guid] = varStore[guid] or {} + if field ~= nil then + return varStore[guid][field] + end + return varStore[guid] + end + + local map = self:GetMapId() + local inst = self:GetInstanceId() + varStore[map] = varStore[map] or {} + varStore[map][inst] = varStore[map][inst] or {} + varStore[map][inst][guid] = varStore[map][inst][guid] or {} + + if field ~= nil then + return varStore[map][inst][guid][field] + end + return varStore[map][inst][guid] +end + +local function SetData(self, field, val) + local otype = self:GetObjectType() + local guid = otype == "Map" and 1 or self:GetGUIDLow() + local varStore = variableStores[otype] + + if otype == "Player" then + varStore[guid] = varStore[guid] or {} + varStore[guid][field] = val + return + end + + local map = self:GetMapId() + local inst = self:GetInstanceId() + varStore[map] = varStore[map] or {} + varStore[map][inst] = varStore[map][inst] or {} + varStore[map][inst][guid] = varStore[map][inst][guid] or {} + + varStore[map][inst][guid][field] = val +end + +for k,v in pairs(variableStores) do + _G[k].GetData = GetData + _G[k].SetData = SetData +end + +RegisterPlayerEvent(4, DestroyObjData) -- logout +RegisterServerEvent(31, DestroyObjData) -- creature delete +RegisterServerEvent(32, DestroyObjData) -- gameobject delete +RegisterServerEvent(17, DestroyMapData) -- map create +RegisterServerEvent(18, DestroyMapData) -- map destroy diff --git a/lua_scripts/extensions/StackTracePlus/LICENSE b/lua_scripts/extensions/StackTracePlus/LICENSE new file mode 100644 index 0000000..49afdbb --- /dev/null +++ b/lua_scripts/extensions/StackTracePlus/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2010 Ignacio Burgueño + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lua_scripts/extensions/StackTracePlus/README.md b/lua_scripts/extensions/StackTracePlus/README.md new file mode 100644 index 0000000..8216333 --- /dev/null +++ b/lua_scripts/extensions/StackTracePlus/README.md @@ -0,0 +1,128 @@ +# StackTracePlus # + +[![Build Status](https://travis-ci.org/ignacio/StackTracePlus.png?branch=master)](https://travis-ci.org/ignacio/StackTracePlus) + +[StackTracePlus](https://github.com/ignacio/StackTracePlus) provides enhanced stack traces for [Lua 5.1, Lua 5.2][1] and [LuaJIT][2]. + +StackTracePlus can be used as a replacement for debug.traceback. It gives detailed information about locals, tries to guess +function names when they're not available, etc, so, instead of + + lua5.1.exe: D:\trunk_git\sources\stacktraceplus\test\test.lua:10: attempt to concatenate a nil value + stack traceback: + D:\trunk_git\sources\stacktraceplus\test\test.lua:10: in function + (tail call): ? + D:\trunk_git\sources\stacktraceplus\test\test.lua:15: in main chunk + [C]: ? + +you'll get + + lua5.1.exe: D:\trunk_git\sources\stacktraceplus\test\test.lua:10: attempt to concatenate a nil value + Stack Traceback + =============== + (2) C function 'function: 00A8F418' + (3) Lua function 'g' at file 'D:\trunk_git\sources\stacktraceplus\test\test.lua:10' (best guess) + Local variables: + fun = table module + str = string: "hey" + tb = table: 027DCBE0 {dummy:1, blah:true, foo:bar} + (*temporary) = nil + (*temporary) = string: "text" + (*temporary) = string: "attempt to concatenate a nil value" + (4) tail call + (5) main chunk of file 'D:\trunk_git\sources\stacktraceplus\test\test.lua' at line 15 + (6) C function 'function: 002CA480' + +## Usage # + +StackTracePlus can be used as a replacement for `debug.traceback`, as an `xpcall` error handler or even from C code. Note that +only the Lua 5.1 interpreter allows the traceback function to be replaced "on the fly". LuaJIT and Lua 5.2 always calls luaL_traceback internally so there is no easy way to override that. + +```lua +local STP = require "StackTracePlus" + +debug.traceback = STP.stacktrace +function test() + local s = "this is a string" + local n = 42 + local t = { foo = "bar" } + local co = coroutine + local cr = coroutine.create + + error("an error") +end +test() +``` + +That script will output (only with Lua 5.1): + + lua5.1: example.lua:11: an error + Stack Traceback + =============== + (2) C function 'function: 006B5758' + (3) global C function 'error' + (4) Lua global 'test' at file 'example.lua:11' + Local variables: + s = string: "this is a string" + n = number: 42 + t = table: 006E5220 {foo:bar} + co = coroutine table + cr = C function: 003C7080 + (5) main chunk of file 'example.lua' at line 14 + (6) C function 'function: 00637B30' + +**StackTracePlus** is aware of the usual Lua libraries, like *coroutine*, *table*, *string*, *io*, etc and functions like +*print*, *pcall*, *assert*, and so on. + +You can also make STP aware of your own tables and functions by calling *add_known_function* and *add_known_table*. + +```lua +local STP = require "StackTracePlus" + +debug.traceback = STP.stacktrace +local my_table = { + f = function() end +} +function my_function() +end + +function test(data, func) + local s = "this is a string" + + error("an error") +end + +STP.add_known_table(my_table, "A description for my_table") +STP.add_known_function(my_function, "A description for my_function") + +test( my_table, my_function ) +``` + +Will output: + + lua5.1: ..\test\example2.lua:13: an error + Stack Traceback + =============== + (2) C function 'function: 0073AAA8' + (3) global C function 'error' + (4) Lua global 'test' at file '..\test\example2.lua:13' + Local variables: + data = A description for my_table + func = Lua function 'A description for my_function' (defined at line 7 of chunk ..\test\example2.lua) + s = string: "this is a string" + (5) main chunk of file '..\test\example2.lua' at line 19 + (6) C function 'function: 00317B30' + + +## Installation # +The easiest way to install is with [LuaRocks][3]. + + - luarocks install stacktraceplus + +If you don't want to use LuaRocks, just copy StackTracePlus.lua to Lua's path. + +## License # +**StackTracePlus** is available under the MIT license. + +[1]: http://www.lua.org/ +[2]: http://luajit.org/ +[3]: http://luarocks.org/ diff --git a/lua_scripts/extensions/StackTracePlus/StackTracePlus.ext b/lua_scripts/extensions/StackTracePlus/StackTracePlus.ext new file mode 100644 index 0000000..40c25c1 --- /dev/null +++ b/lua_scripts/extensions/StackTracePlus/StackTracePlus.ext @@ -0,0 +1,411 @@ +-- tables +local _G = _G +local string, io, debug, coroutine = string, io, debug, coroutine + +-- functions +local tostring, print, require = tostring, print, require +local next, assert = next, assert +local pcall, type, pairs, ipairs = pcall, type, pairs, ipairs +local error = error + +assert(debug, "debug table must be available at this point") + +local io_open = io.open +local string_gmatch = string.gmatch +local string_sub = string.sub +local table_concat = table.concat + +local _M = { + max_tb_output_len = 70 -- controls the maximum length of the 'stringified' table before cutting with ' (more...)' +} + +-- this tables should be weak so the elements in them won't become uncollectable +local m_known_tables = { [_G] = "_G (global table)" } +local function add_known_module(name, desc) + local ok, mod = pcall(require, name) + if ok then + m_known_tables[mod] = desc + end +end + +add_known_module("string", "string module") +add_known_module("io", "io module") +add_known_module("os", "os module") +add_known_module("table", "table module") +add_known_module("math", "math module") +add_known_module("package", "package module") +add_known_module("debug", "debug module") +add_known_module("coroutine", "coroutine module") + +-- lua5.2 +add_known_module("bit32", "bit32 module") +-- luajit +add_known_module("bit", "bit module") +add_known_module("jit", "jit module") + + +local m_user_known_tables = {} + +local m_known_functions = {} +for _, name in ipairs{ + -- Lua 5.2, 5.1 + "assert", + "collectgarbage", + "dofile", + "error", + "getmetatable", + "ipairs", + "load", + "loadfile", + "next", + "pairs", + "pcall", + "print", + "rawequal", + "rawget", + "rawlen", + "rawset", + "require", + "select", + "setmetatable", + "tonumber", + "tostring", + "type", + "xpcall", + + -- Lua 5.1 + "gcinfo", + "getfenv", + "loadstring", + "module", + "newproxy", + "setfenv", + "unpack", + -- TODO: add table.* etc functions +} do + if _G[name] then + m_known_functions[_G[name]] = name + end +end + + + +local m_user_known_functions = {} + +local function safe_tostring (value) + local ok, err = pcall(tostring, value) + if ok then return err else return (": '%s'"):format(err) end +end + +-- Private: +-- Parses a line, looking for possible function definitions (in a very na?ve way) +-- Returns '(anonymous)' if no function name was found in the line +local function ParseLine(line) + assert(type(line) == "string") + --print(line) + local match = line:match("^%s*function%s+(%w+)") + if match then + --print("+++++++++++++function", match) + return match + end + match = line:match("^%s*local%s+function%s+(%w+)") + if match then + --print("++++++++++++local", match) + return match + end + match = line:match("^%s*local%s+(%w+)%s+=%s+function") + if match then + --print("++++++++++++local func", match) + return match + end + match = line:match("%s*function%s*%(") -- this is an anonymous function + if match then + --print("+++++++++++++function2", match) + return "(anonymous)" + end + return "(anonymous)" +end + +-- Private: +-- Tries to guess a function's name when the debug info structure does not have it. +-- It parses either the file or the string where the function is defined. +-- Returns '?' if the line where the function is defined is not found +local function GuessFunctionName(info) + --print("guessing function name") + if type(info.source) == "string" and info.source:sub(1,1) == "@" then + local file, err = io_open(info.source:sub(2), "r") + if not file then + print("file not found: "..tostring(err)) -- whoops! + return "?" + end + local line + for i = 1, info.linedefined do + line = file:read("*l") + end + if not line then + print("line not found") -- whoops! + return "?" + end + return ParseLine(line) + else + local line + local lineNumber = 0 + for l in string_gmatch(info.source, "([^\n]+)\n-") do + lineNumber = lineNumber + 1 + if lineNumber == info.linedefined then + line = l + break + end + end + if not line then + print("line not found") -- whoops! + return "?" + end + return ParseLine(line) + end +end + +--- +-- Dumper instances are used to analyze stacks and collect its information. +-- +local Dumper = {} + +Dumper.new = function(thread) + local t = { lines = {} } + for k,v in pairs(Dumper) do t[k] = v end + + t.dumping_same_thread = (thread == coroutine.running()) + + -- if a thread was supplied, bind it to debug.info and debug.get + -- we also need to skip this additional level we are introducing in the callstack (only if we are running + -- in the same thread we're inspecting) + if type(thread) == "thread" then + t.getinfo = function(level, what) + if t.dumping_same_thread and type(level) == "number" then + level = level + 1 + end + return debug.getinfo(thread, level, what) + end + t.getlocal = function(level, loc) + if t.dumping_same_thread then + level = level + 1 + end + return debug.getlocal(thread, level, loc) + end + else + t.getinfo = debug.getinfo + t.getlocal = debug.getlocal + end + + return t +end + +-- helpers for collecting strings to be used when assembling the final trace +function Dumper:add (text) + self.lines[#self.lines + 1] = text +end +function Dumper:add_f (fmt, ...) + self:add(fmt:format(...)) +end +function Dumper:concat_lines () + return table_concat(self.lines) +end + +--- +-- Private: +-- Iterates over the local variables of a given function. +-- +-- @param level The stack level where the function is. +-- +function Dumper:DumpLocals (level) + local prefix = "\t " + local i = 1 + + if self.dumping_same_thread then + level = level + 1 + end + + local name, value = self.getlocal(level, i) + if not name then + return + end + self:add("\tLocal variables:\r\n") + while name do + if type(value) == "number" then + self:add_f("%s%s = number: %g\r\n", prefix, name, value) + elseif type(value) == "boolean" then + self:add_f("%s%s = boolean: %s\r\n", prefix, name, tostring(value)) + elseif type(value) == "string" then + self:add_f("%s%s = string: %q\r\n", prefix, name, value) + elseif type(value) == "userdata" then + self:add_f("%s%s = %s\r\n", prefix, name, safe_tostring(value)) + elseif type(value) == "nil" then + self:add_f("%s%s = nil\r\n", prefix, name) + elseif type(value) == "table" then + if m_known_tables[value] then + self:add_f("%s%s = %s\r\n", prefix, name, m_known_tables[value]) + elseif m_user_known_tables[value] then + self:add_f("%s%s = %s\r\n", prefix, name, m_user_known_tables[value]) + else + local txt = "{" + for k,v in pairs(value) do + txt = txt..safe_tostring(k)..":"..safe_tostring(v) + if #txt > _M.max_tb_output_len then + txt = txt.." (more...)" + break + end + if next(value, k) then txt = txt..", " end + end + self:add_f("%s%s = %s %s\r\n", prefix, name, safe_tostring(value), txt.."}") + end + elseif type(value) == "function" then + local info = self.getinfo(value, "nS") + local fun_name = info.name or m_known_functions[value] or m_user_known_functions[value] + if info.what == "C" then + self:add_f("%s%s = C %s\r\n", prefix, name, (fun_name and ("function: " .. fun_name) or tostring(value))) + else + local source = info.short_src + if source:sub(2,7) == "string" then + source = source:sub(9) -- uno m?s, por el espacio que viene (string "Baragent.Main", por ejemplo) + end + --for k,v in pairs(info) do print(k,v) end + fun_name = fun_name or GuessFunctionName(info) + self:add_f("%s%s = Lua function '%s' (defined at line %d of chunk %s)\r\n", prefix, name, fun_name, info.linedefined, source) + end + elseif type(value) == "thread" then + self:add_f("%sthread %q = %s\r\n", prefix, name, tostring(value)) + end + i = i + 1 + name, value = self.getlocal(level, i) + end +end + + +--- +-- Public: +-- Collects a detailed stack trace, dumping locals, resolving function names when they're not available, etc. +-- This function is suitable to be used as an error handler with pcall or xpcall +-- +-- @param thread An optional thread whose stack is to be inspected (defaul is the current thread) +-- @param message An optional error string or object. +-- @param level An optional number telling at which level to start the traceback (default is 1) +-- +-- Returns a string with the stack trace and a string with the original error. +-- +function _M.stacktrace(thread, message, level) + if type(thread) ~= "thread" then + -- shift parameters left + thread, message, level = nil, thread, message + end + + thread = thread or coroutine.running() + + level = level or 1 + + local dumper = Dumper.new(thread) + + local original_error + + if type(message) == "table" then + dumper:add("an error object {\r\n") + local first = true + for k,v in pairs(message) do + if first then + dumper:add(" ") + first = false + else + dumper:add(",\r\n ") + end + dumper:add(safe_tostring(k)) + dumper:add(": ") + dumper:add(safe_tostring(v)) + end + dumper:add("\r\n}") + original_error = dumper:concat_lines() + elseif type(message) == "string" then + dumper:add(message) + original_error = message + end + + dumper:add("\r\n") + dumper:add[[ +Stack Traceback +=============== +]] + --print(error_message) + + local level_to_show = level + if dumper.dumping_same_thread then level = level + 1 end + + local info = dumper.getinfo(level, "nSlf") + while info do + if info.what == "main" then + if string_sub(info.source, 1, 1) == "@" then + dumper:add_f("(%d) main chunk of file '%s' at line %d\r\n", level_to_show, string_sub(info.source, 2), info.currentline) + else + dumper:add_f("(%d) main chunk of %s at line %d\r\n", level_to_show, info.short_src, info.currentline) + end + elseif info.what == "C" then + --print(info.namewhat, info.name) + --for k,v in pairs(info) do print(k,v, type(v)) end + local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name or tostring(info.func) + dumper:add_f("(%d) %s C function '%s'\r\n", level_to_show, info.namewhat, function_name) + --dumper:add_f("%s%s = C %s\r\n", prefix, name, (m_known_functions[value] and ("function: " .. m_known_functions[value]) or tostring(value))) + elseif info.what == "tail" then + --print("tail") + --for k,v in pairs(info) do print(k,v, type(v)) end--print(info.namewhat, info.name) + dumper:add_f("(%d) tail call\r\n", level_to_show) + dumper:DumpLocals(level) + elseif info.what == "Lua" then + local source = info.short_src + local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name + if source:sub(2, 7) == "string" then + source = source:sub(9) + end + local was_guessed = false + if not function_name or function_name == "?" then + --for k,v in pairs(info) do print(k,v, type(v)) end + function_name = GuessFunctionName(info) + was_guessed = true + end + -- test if we have a file name + local function_type = (info.namewhat == "") and "function" or info.namewhat + if info.source and info.source:sub(1, 1) == "@" then + dumper:add_f("(%d) Lua %s '%s' at file '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "") + elseif info.source and info.source:sub(1,1) == '#' then + dumper:add_f("(%d) Lua %s '%s' at template '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "") + else + dumper:add_f("(%d) Lua %s '%s' at line %d of chunk '%s'\r\n", level_to_show, function_type, function_name, info.currentline, source) + end + dumper:DumpLocals(level) + else + dumper:add_f("(%d) unknown frame %s\r\n", level_to_show, info.what) + end + + level = level + 1 + level_to_show = level_to_show + 1 + info = dumper.getinfo(level, "nSlf") + end + + return dumper:concat_lines(), original_error +end + +-- +-- Adds a table to the list of known tables +function _M.add_known_table(tab, description) + if m_known_tables[tab] then + error("Cannot override an already known table") + end + m_user_known_tables[tab] = description +end + +-- +-- Adds a function to the list of known functions +function _M.add_known_function(fun, description) + if m_known_functions[fun] then + error("Cannot override an already known function") + end + m_user_known_functions[fun] = description +end + +return _M diff --git a/lua_scripts/extensions/_Misc.ext b/lua_scripts/extensions/_Misc.ext new file mode 100644 index 0000000..5eae744 --- /dev/null +++ b/lua_scripts/extensions/_Misc.ext @@ -0,0 +1,14 @@ +-- +-- Copyright (C) 2010 - 2016 Eluna Lua Engine +-- This program is free software licensed under GPL version 3 +-- Please see the included DOCS/LICENSE.md for more information +-- + +-- filename.ext files are loaded before normal .lua files + +-- Randomize random +math.randomseed(tonumber(tostring(os.time()):reverse():sub(1,6))) + +-- Set debug.traceback to use StackTracePlus to print full stack trace +local trace = require("StackTracePlus") +debug.traceback = trace.stacktrace diff --git a/worldserver b/worldserver index abd385a..45d208a 100755 Binary files a/worldserver and b/worldserver differ