141 lines
3.8 KiB
Lua
141 lines
3.8 KiB
Lua
-- luacheck: globals whosit, std luanti+luajit
|
|
whosit = _G.whosit or {}
|
|
_G.whosit = whosit
|
|
|
|
-- provide table.pack if luajit is built without LUA52COMPAT
|
|
local pack = table.pack or function(...) return {n = select("#", ...), ...} end
|
|
local unpack = unpack or table.unpack
|
|
|
|
-- use efficient deque or implement our own FIFO type of thing
|
|
local formspec_log = futil and futil.Deque and futil.Deque()
|
|
if not formspec_log then
|
|
-- no deque implementation found
|
|
local deq = {}
|
|
deq.size = function(self)
|
|
return #self
|
|
end
|
|
deq.push_front = function(self, v)
|
|
table.insert(self, v)
|
|
end
|
|
deq.pop_back = function(self)
|
|
local v = self[1]
|
|
table.remove(self, 1)
|
|
return v
|
|
end
|
|
deq.iterate = function(self)
|
|
local i = 0
|
|
return function()
|
|
i = i + 1
|
|
local v = self[i]
|
|
if v then
|
|
return v
|
|
end
|
|
end
|
|
end
|
|
deq.__index = deq
|
|
formspec_log = setmetatable({}, deq)
|
|
end
|
|
|
|
local LOG_SIZE = 30
|
|
|
|
-- use deque for logging, pushing oldest log item out
|
|
local function log_add(msg)
|
|
core.log('error', type(msg) == "string" and msg or dump(msg))
|
|
formspec_log:push_front(msg)
|
|
if formspec_log:size() > LOG_SIZE then
|
|
formspec_log:pop_back()
|
|
end
|
|
end
|
|
|
|
|
|
local function formspec_log_clear()
|
|
formspec_log:clear()
|
|
end
|
|
|
|
|
|
-- passes to xpcall to be able to capture the call stack
|
|
local function error_printer(err)
|
|
log_add(err)
|
|
log_add(debug.traceback("----------------------", 2))
|
|
return "error was logged"
|
|
end
|
|
|
|
|
|
-- Takes any function and returns a function that takes and returns
|
|
-- same [multiple] values if no error happens. On error, logs it.
|
|
local function safe_wrap(func)
|
|
local function wrap_f(...)
|
|
local res = pack(xpcall(func, error_printer, ...))
|
|
if res[1] then
|
|
-- no error, just return rest of the values
|
|
return select(2, unpack(res))
|
|
else
|
|
-- error was logged by error_printer already
|
|
local msg = dump(res[2])
|
|
if msg then
|
|
log_add(msg)
|
|
end
|
|
return nil
|
|
end
|
|
end
|
|
return wrap_f
|
|
end
|
|
|
|
|
|
local function formspec_log_show(playername)
|
|
local log_items = {}
|
|
for item in formspec_log:iterate() do
|
|
table.insert(log_items, type(item) == "string" and item or dump(item))
|
|
end
|
|
local formspec_template = [[ formspec_version[6] size[16,9] textarea[0.1,0.4;15.8,8.5;log;log;%s] ]]
|
|
local log_text = core.formspec_escape(table.concat(log_items,'\n'))
|
|
core.show_formspec(playername, "yl_commons:formspec_log", string.format(formspec_template, log_text))
|
|
end
|
|
|
|
|
|
-- These commands will allow us to see the errors saved in
|
|
-- the `formspec_log` after they happen.
|
|
core.register_chatcommand(
|
|
"whosit_log_show",
|
|
{
|
|
privs = { server = true },
|
|
func = function(playername, _params)
|
|
formspec_log_show(playername)
|
|
return true
|
|
end,
|
|
}
|
|
)
|
|
|
|
core.register_chatcommand(
|
|
"whosit_log_clear",
|
|
{
|
|
privs = { server = true },
|
|
func = function(playername, _params)
|
|
formspec_log_clear(playername)
|
|
return true
|
|
end,
|
|
}
|
|
)
|
|
|
|
|
|
whosit.original_callbacks = {}
|
|
local original_callbacks = whosit.original_callbacks
|
|
|
|
function whosit.safe_override_on_use(item_name, func)
|
|
local def = core.registered_items[item_name]
|
|
if not (original_callbacks[item_name] or {}).on_use then
|
|
local orig = original_callbacks[item_name] or {}
|
|
original_callbacks[item_name] = orig
|
|
orig.on_use = def.on_use
|
|
end
|
|
|
|
def.on_use = function(itemstack, user, pointed_thing)
|
|
local status, res = safe_wrap(func)(itemstack, user, pointed_thing)
|
|
if status then
|
|
return res
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
end
|