This moves review into a separate permission, aside from "server". The benefit is that we can grant this to more people without the need to pass out "server" privs, which has a lot more powers than needeed. This doesn't grant noclip. This needs to be done separately. Scoring will be disabled for those with the review priv.
235 lines
7.0 KiB
Lua
235 lines
7.0 KiB
Lua
|
|
--[[
|
|
|
|
Copyright (C) 2015 - Auke Kok <sofar@foo-projects.org>
|
|
|
|
"inspector" is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as
|
|
published by the Free Software Foundation; either version 2.1
|
|
of the license, or (at your option) any later version.
|
|
|
|
--]]
|
|
|
|
local S = minetest.get_translator("inspector")
|
|
local FE = minetest.formspec_escape
|
|
|
|
local function dehash_vector(s)
|
|
return {
|
|
x = 256 * string.byte(s, 1) + string.byte(s, 2) - 32768,
|
|
y = 256 * string.byte(s, 3) + string.byte(s, 4) - 32768,
|
|
z = 256 * string.byte(s, 5) + string.byte(s, 6) - 32768,
|
|
}
|
|
end
|
|
|
|
local indent_string = " "
|
|
|
|
local function indent(level, text, emphasize)
|
|
local result = text
|
|
for i = 1, level do
|
|
if emphasize then
|
|
result = "-> " .. string.gsub(result, "\n", "\n" .. indent_string)
|
|
else
|
|
result = indent_string .. string.gsub(result, "\n", "\n" .. indent_string)
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
local function adjusted_dump(o)
|
|
local result = dump(o, indent_string)
|
|
if result == "{\n" .. indent_string .. "\n}" then result = "{}" end
|
|
return result
|
|
end
|
|
|
|
local function inspect_pos(pos)
|
|
local node = minetest.get_node(pos)
|
|
local desc = "===== node data =====\n"
|
|
desc = desc .. indent(1, "name = " .. node.name) .. "\n"
|
|
desc = desc .. indent(1, "param1 = " .. node.param1) .. "\n"
|
|
desc = desc .. indent(1, "param2 = " .. node.param2) .. "\n"
|
|
local light = minetest.get_node_light({x = pos.x, y = pos.y + 1, z = pos.z}, nil)
|
|
if light then
|
|
desc = desc .. indent(1, "light = " .. light) .. "\n"
|
|
end
|
|
|
|
local timer = minetest.get_node_timer(pos)
|
|
if timer:get_timeout() ~= 0 then
|
|
desc = desc .. "==== node timer ====\n"
|
|
desc = desc .. indent(1, "timeout = " .. timer:get_timeout()) .. "\n"
|
|
desc = desc .. indent(1, "elapsed = " .. timer:get_elapsed()) .. "\n"
|
|
end
|
|
|
|
local nodedef = minetest.registered_items[node.name]
|
|
local meta = minetest.get_meta(pos)
|
|
local metatable = meta:to_table()
|
|
|
|
if metatable.fields.offsets then
|
|
local offsets = minetest.deserialize(metatable.fields.offsets)
|
|
metatable.fields.offsets = nil
|
|
desc = desc .. "==== triggers ====\n"
|
|
for so, _ in pairs(offsets) do
|
|
local off = dehash_vector(so)
|
|
local npos = vector.add(pos, off)
|
|
local nname = minetest.get_node(npos).name
|
|
desc = desc .. nname .. " at " .. minetest.pos_to_string(npos) ..
|
|
" (offset is " .. minetest.pos_to_string(off) .. ")\n"
|
|
end
|
|
desc = desc .. "\n"
|
|
end
|
|
if metatable.fields.roffsets then
|
|
local roffsets = minetest.deserialize(metatable.fields.roffsets)
|
|
metatable.fields.roffsets = nil
|
|
desc = desc .. "==== triggered by ====\n"
|
|
for so, _ in pairs(roffsets) do
|
|
local off = dehash_vector(so)
|
|
local npos = vector.add(pos, off)
|
|
local nname = minetest.get_node(npos).name
|
|
desc = desc .. nname .. " at " .. minetest.pos_to_string(npos) ..
|
|
" (offset is " .. minetest.pos_to_string(off) .. ")\n"
|
|
end
|
|
desc = desc .. "\n"
|
|
end
|
|
|
|
|
|
desc = desc .. "==== meta ====\n"
|
|
desc = desc .. indent(1, "meta.fields = " .. adjusted_dump(metatable.fields)) .. "\n"
|
|
local inventory = meta:get_inventory()
|
|
desc = desc .. indent(1, "meta.inventory = ") .. "\n"
|
|
for key, list in pairs(inventory:get_lists()) do
|
|
desc = desc .. indent(2, key .. " : ") .. "\n"
|
|
local size = #list
|
|
for i = 1, size do
|
|
local stack = list[i]
|
|
if not stack:is_empty() then
|
|
desc = desc .. indent(3, "\"" .. stack:get_name() .. "\" - " .. stack:get_count()) .. "\n"
|
|
end
|
|
end
|
|
end
|
|
|
|
if nodedef then -- Some built in nodes have no nodedef
|
|
|
|
-- combine nodedef table with its "superclass" table
|
|
local combined_fields = {}
|
|
local nodedef_fields = {}
|
|
for key, value in pairs(getmetatable(nodedef).__index) do combined_fields[key] = value end
|
|
for key, value in pairs(nodedef) do
|
|
nodedef_fields[key] = true
|
|
if combined_fields[key] == nil then combined_fields[key] = value end
|
|
end
|
|
|
|
-- sort
|
|
local key_list = {}
|
|
for key, _ in pairs(combined_fields) do table.insert(key_list, key) end
|
|
table.sort(key_list)
|
|
|
|
desc = desc .. "==== nodedef ====\n"
|
|
for _, key in ipairs(key_list) do
|
|
desc = desc .. indent(1, key .. " = " .. adjusted_dump(nodedef[key]), nodedef_fields[key]) .. "\n"
|
|
end
|
|
end
|
|
|
|
return desc
|
|
end
|
|
|
|
minetest.register_tool("inspector:inspector", {
|
|
description = S("Inspector tool"),
|
|
inventory_image = "inspector.png",
|
|
liquids_pointable = true, -- makes it hard to use underwater.
|
|
|
|
on_use = function(itemstack, user, pointed_thing)
|
|
if not user
|
|
or not minetest.check_player_privs(user, "review")
|
|
and not boxes.players_editing_boxes[user:get_player_name()] then
|
|
return
|
|
end
|
|
|
|
local t = "Node"
|
|
|
|
local desc = ""
|
|
if pointed_thing.type == "nothing" then
|
|
return
|
|
elseif pointed_thing.type == "node" then
|
|
local pos = pointed_thing.under
|
|
|
|
if pointed_thing.type ~= "node" then
|
|
desc = "..."
|
|
else
|
|
desc = inspect_pos(pos)
|
|
end
|
|
elseif pointed_thing.type == "object" then
|
|
local ref = pointed_thing.ref
|
|
local obj = ref:get_properties()
|
|
if ref.get_physics_override then
|
|
obj.physics_override = ref:get_physics_override()
|
|
end
|
|
desc = adjusted_dump(obj)
|
|
t = "Entity"
|
|
end
|
|
|
|
local formspec = "size[12,8]"..
|
|
"label[0.5,0.5;" .. t .. " Information]"..
|
|
"textarea[0.5,1.5;11.5,7;text;Contents:;"..
|
|
minetest.formspec_escape(desc).."]"..
|
|
"button_exit[2.5,7.5;3,1;close;Close]"
|
|
|
|
fsc.show(user:get_player_name(), formspec, {}, function() end)
|
|
end,
|
|
on_place = function(itemstack, user, pointed_thing)
|
|
if not user
|
|
or not minetest.check_player_privs(user, "review")
|
|
and not boxes.players_editing_boxes[user:get_player_name()] then
|
|
return
|
|
end
|
|
|
|
local desc = ""
|
|
if pointed_thing.type == "nothing" then
|
|
return
|
|
elseif pointed_thing.type == "node" then
|
|
local pos = pointed_thing.above
|
|
|
|
if pointed_thing.type ~= "node" then
|
|
desc = "..."
|
|
else
|
|
desc = inspect_pos(pos)
|
|
end
|
|
elseif pointed_thing.type == "object" then
|
|
local ref = pointed_thing.ref
|
|
local entity = ref:get_luaentity()
|
|
desc = dump(entity)
|
|
end
|
|
|
|
local formspec = "size[12,8]"..
|
|
"label[0.5,0.5;"..FE(S("Node Information")).."]"..
|
|
"textarea[0.5,1.5;11.5,7;text;"..FE(S("Contents:"))..";"..
|
|
FE(desc).."]"..
|
|
"button_exit[2.5,7.5;3,1;close;"..FE(S("Close")).."]"
|
|
|
|
fsc.show(user:get_player_name(), formspec, {}, function() end)
|
|
end
|
|
})
|
|
|
|
minetest.register_chatcommand("inspect", {
|
|
params = "inspect",
|
|
description = S("Inspect a position"),
|
|
privs = {review = true},
|
|
func = function(name, param)
|
|
local paramlist = {}
|
|
for p in string.gmatch(param, "%S+") do
|
|
paramlist[#paramlist + 1] = p
|
|
end
|
|
local pos = {x = paramlist[1], y = paramlist[2], z = paramlist[3]}
|
|
if not pos.x or not pos.y or not pos.z then
|
|
return false, S("Need 3 parameters for X, Y and Z")
|
|
end
|
|
local desc = inspect_pos(pos)
|
|
local formspec = "size[12,8]"..
|
|
"label[0.5,0.5;"..FE(S("Node Information")).."]"..
|
|
"textarea[0.5,1.5;11.5,7;text;"..FE(S("Contents:"))..";"..
|
|
minetest.formspec_escape(desc).."]"..
|
|
"button_exit[2.5,7.5;3,1;close;"..FE(S("Close")).."]"
|
|
|
|
fsc.show(name, formspec, {}, function() end)
|
|
return true
|
|
end,
|
|
})
|