Compare commits
No commits in common. "master" and "nalc-1.0" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
/projects/node_metadata.dia.autosave
|
|
58
README.md
Normal file
58
README.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
Minetest mod metatools
|
||||||
|
######################
|
||||||
|
|
||||||
|
A mod inspired by mgl512's itemframe issue
|
||||||
|
Version : 1.2.2
|
||||||
|
|
||||||
|
# Authors
|
||||||
|
- LeMagnesium / Mg / ElectronLibre : Source code writer
|
||||||
|
- Paly2 / Palige : Contributor for the source code
|
||||||
|
- Ataron : Texture creater
|
||||||
|
|
||||||
|
# Purpose
|
||||||
|
This mod's aim is to provide a way for admins to navigate through any (ok, not
|
||||||
|
ignores) nodes on the map, and see values of its metadatas at any of their
|
||||||
|
stratum.
|
||||||
|
|
||||||
|
# Media
|
||||||
|
"metatools_stick.png" by Ataron (CC-BY-NC-SA)
|
||||||
|
|
||||||
|
# Todo
|
||||||
|
- Rewrite the table stocking : a variable containing a copy of the global
|
||||||
|
table returned by :to_table(), on which we would work, and a save command to
|
||||||
|
apply it on the node
|
||||||
|
|
||||||
|
# Special thanks
|
||||||
|
- mgl512 (Le_Docteur) for its locked itemframe which gave me the idea of a tool
|
||||||
|
allowing to see/edit metadatas
|
||||||
|
- Ataron who created the stick's texture
|
||||||
|
- palige who agreed to test the mod for its first release, and contributed to the last version
|
||||||
|
|
||||||
|
# Command tutorial
|
||||||
|
- Soon to come, please refer to /meta help until then
|
||||||
|
|
||||||
|
Node metadatas look like this :
|
||||||
|
|
||||||
|
0 1 2 3 ...
|
||||||
|
Node/
|
||||||
|
|
|
||||||
|
+- fields
|
||||||
|
| |
|
||||||
|
| +- foo
|
||||||
|
| +- bar
|
||||||
|
| +- ...
|
||||||
|
+- inventory
|
||||||
|
|
|
||||||
|
+- main
|
||||||
|
| |
|
||||||
|
| +- 1
|
||||||
|
| +- 2
|
||||||
|
| +- 3
|
||||||
|
| +- ...
|
||||||
|
+- craft
|
||||||
|
| |
|
||||||
|
| +- 1
|
||||||
|
| +- 2
|
||||||
|
| +- 3
|
||||||
|
| +- ...
|
||||||
|
+- ...
|
|
@ -1,17 +0,0 @@
|
||||||
minetest.register_chatcommand("howlight", {
|
|
||||||
description = "Show the light level of the ground below you",
|
|
||||||
func = function(name)
|
|
||||||
local player = minetest.get_player_by_name(name)
|
|
||||||
if player then
|
|
||||||
local player_pos = vector.round(player:get_pos())
|
|
||||||
-- local pos = vector.new(player_pos.x, player_pos.y - 1 , player_pos.z)
|
|
||||||
local pos = player_pos
|
|
||||||
-- underground, light is always zero, so z-1 doesn't work.
|
|
||||||
local pos_string = minetest.pos_to_string(pos)
|
|
||||||
minetest.chat_send_player(name, "Light level at " .. pos_string .. " is " .. minetest.get_node_light(pos) .. ".")
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false, "You are not connected to minetestserver."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
|
@ -1 +0,0 @@
|
||||||
See metadata for nodes (and Entities in Poikilos' fork!)
|
|
684
init.lua
684
init.lua
|
@ -1,289 +1,17 @@
|
||||||
--[[
|
--[[
|
||||||
-- Metadata Tools
|
-- Metadata Tools
|
||||||
--
|
--
|
||||||
-- A mod providing write and read access to a nodes' metadata using commands
|
-- A mod providing write and read access to a nodes' metadata using commands
|
||||||
-- (c) 2015-2016 ßÿ Lymkwi/LeMagnesium/Mg and Paly2; & (c) 2017-2024 Poikilos
|
-- ßÿ Lymkwi/LeMagnesium/Mg ; 2015-2016
|
||||||
-- License: [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/)
|
-- License: WTFPL
|
||||||
|
-- Contributors :
|
||||||
|
-- - Lymkwi/LeMagnesium
|
||||||
|
-- - Paly2
|
||||||
--
|
--
|
||||||
-- Version: Poikilos fork of 1.2.2
|
-- Version: 1.2.2
|
||||||
--
|
--
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
|
|
||||||
local function isArray(t)
|
|
||||||
-- Check if a table only contains sequential values.
|
|
||||||
-- by kikito
|
|
||||||
-- [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/)
|
|
||||||
-- answered May 21, 2011 at 7:22
|
|
||||||
-- edited Mar 2, 2014 at 17:13
|
|
||||||
-- <https://stackoverflow.com/a/6080274/4541104>
|
|
||||||
local i = 0
|
|
||||||
for _ in pairs(t) do
|
|
||||||
i = i + 1
|
|
||||||
if t[i] == nil then return false end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- function string:endswith(ending)
|
|
||||||
-- from https://gist.github.com/kgriffs/124aae3ac80eefe57199451b823c24ec
|
|
||||||
-- return ending == "" or self:sub(-#ending) == ending
|
|
||||||
--end
|
|
||||||
function endswith(str, ending)
|
|
||||||
return ending == "" or str:sub(-#ending) == ending
|
|
||||||
end
|
|
||||||
|
|
||||||
function yamlSerializeTable(val, name, depth)
|
|
||||||
-- Make a table into a string.
|
|
||||||
-- (c) 2011 Henrik Ilgen, 2022 Poikilos
|
|
||||||
-- [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/)
|
|
||||||
-- answered May 21 '11 at 12:14 Henrik Ilgen
|
|
||||||
-- edited May 13, 2019 at 9:10
|
|
||||||
-- on <https://stackoverflow.com/a/6081639>
|
|
||||||
-- Only the first argument is required.
|
|
||||||
-- Get the object back from the string via:
|
|
||||||
-- a = loadstring(s)()
|
|
||||||
depth = depth or 0
|
|
||||||
|
|
||||||
local tmp = string.rep(" ", depth)
|
|
||||||
|
|
||||||
if name then
|
|
||||||
if name == "METATOOLS_ARRAY_ELEMENT" then
|
|
||||||
tmp = tmp .. "- "
|
|
||||||
else
|
|
||||||
tmp = tmp .. name .. ": "
|
|
||||||
end
|
|
||||||
-- else: should only occur for a value that is after a name already
|
|
||||||
-- given, such as for tables.
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(val) == "table" then
|
|
||||||
tmp = tmp .. "\n" -- Newline is after <name>: for tables.
|
|
||||||
-- tmp = tmp .. " # table" .. "\n" -- for debug only
|
|
||||||
if isArray(val) then
|
|
||||||
for k, v in pairs(val) do
|
|
||||||
tmp = tmp .. yamlSerializeTable(v, "METATOOLS_ARRAY_ELEMENT", depth + 1) .. "\n"
|
|
||||||
end
|
|
||||||
-- tmp = tmp .. string.rep(" ", depth)
|
|
||||||
else
|
|
||||||
for k, v in pairs(val) do
|
|
||||||
tmp = tmp .. yamlSerializeTable(v, k, depth + 1) .. "\n"
|
|
||||||
end
|
|
||||||
-- tmp = tmp .. string.rep(" ", depth)
|
|
||||||
end
|
|
||||||
while endswith(tmp, "\n\n") do
|
|
||||||
-- Removing repeated '\n' is necessary since any sub-value
|
|
||||||
-- (and any more deeply nested value) may be a table and
|
|
||||||
-- append "\n" (Then this depth appends "\n").
|
|
||||||
tmp = string.sub(tmp, ( #tmp - 1 ))
|
|
||||||
end
|
|
||||||
elseif type(val) == "number" then
|
|
||||||
tmp = tmp .. tostring(val)
|
|
||||||
elseif type(val) == "string" then
|
|
||||||
tmp = tmp .. string.format("%q", val)
|
|
||||||
-- %q: "surrounds the string with double quotes and properly
|
|
||||||
-- escapes double quotes, newlines, and some other characters
|
|
||||||
-- inside the string."
|
|
||||||
-- -<https://www.lua.org/pil/12.1.html>
|
|
||||||
elseif type(val) == "boolean" then
|
|
||||||
tmp = tmp .. (val and "true" or "false")
|
|
||||||
elseif type(val) == nil then
|
|
||||||
tmp = tmp .. "null"
|
|
||||||
else
|
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
|
||||||
end
|
|
||||||
return tmp
|
|
||||||
end
|
|
||||||
|
|
||||||
function serializeTable(val, name, depth, skipnewlines)
|
|
||||||
-- Make a table into a string.
|
|
||||||
-- (c) 2011 Henrik Ilgen, 2022 Poikilos (switch depth & skipnewlines param order)
|
|
||||||
-- [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/)
|
|
||||||
-- answered May 21 '11 at 12:14 Henrik Ilgen
|
|
||||||
-- edited May 13, 2019 at 9:10
|
|
||||||
-- on <https://stackoverflow.com/a/6081639>
|
|
||||||
-- Only the first argument is required.
|
|
||||||
-- Get the object back from the string via:
|
|
||||||
-- a = loadstring(s)()
|
|
||||||
skipnewlines = skipnewlines or false
|
|
||||||
depth = depth or 0
|
|
||||||
|
|
||||||
local tmp = string.rep(" ", depth)
|
|
||||||
|
|
||||||
if name then tmp = tmp .. name .. " = " end
|
|
||||||
|
|
||||||
if type(val) == "table" then
|
|
||||||
tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")
|
|
||||||
|
|
||||||
for k, v in pairs(val) do
|
|
||||||
tmp = tmp .. serializeTable(v, k, depth + 1, skipnewlines) .. "," .. (not skipnewlines and "\n" or "")
|
|
||||||
end
|
|
||||||
|
|
||||||
tmp = tmp .. string.rep(" ", depth) .. "}"
|
|
||||||
elseif type(val) == "number" then
|
|
||||||
tmp = tmp .. tostring(val)
|
|
||||||
elseif type(val) == "string" then
|
|
||||||
tmp = tmp .. string.format("%q", val)
|
|
||||||
elseif type(val) == "boolean" then
|
|
||||||
tmp = tmp .. (val and "true" or "false")
|
|
||||||
else
|
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
|
||||||
end
|
|
||||||
|
|
||||||
return tmp
|
|
||||||
end
|
|
||||||
|
|
||||||
local function token_indices(haystack, needle)
|
|
||||||
local results = {}
|
|
||||||
for i = 1, #haystack do
|
|
||||||
local try = haystack:sub(i,i + needle:len() - 1)
|
|
||||||
if try == needle then
|
|
||||||
table.insert(results, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return results
|
|
||||||
end
|
|
||||||
|
|
||||||
local function split_and_keep_token(s, needle)
|
|
||||||
local results = {}
|
|
||||||
local indices = token_indices(s, needle)
|
|
||||||
local start = 1
|
|
||||||
for k, v in pairs(indices) do
|
|
||||||
table.insert(results, s:sub(start, v))
|
|
||||||
start = v + 1
|
|
||||||
end
|
|
||||||
if start < #s then
|
|
||||||
table.insert(results, s:sub(start))
|
|
||||||
end
|
|
||||||
return results
|
|
||||||
end
|
|
||||||
|
|
||||||
local function delimit(table, tab, delimiter)
|
|
||||||
if not tab then
|
|
||||||
tab = ""
|
|
||||||
end
|
|
||||||
if not table then
|
|
||||||
return tab .. "nil"
|
|
||||||
end
|
|
||||||
if not delimiter then
|
|
||||||
delimiter = " "
|
|
||||||
end
|
|
||||||
local ret = ""
|
|
||||||
if delimiter ~= "\n" then
|
|
||||||
ret = tab
|
|
||||||
end
|
|
||||||
for k, v in pairs(table) do
|
|
||||||
if delimiter == "\n" then
|
|
||||||
ret = ret .. tab .. k .. ":" .. v .. "\n"
|
|
||||||
else
|
|
||||||
ret = ret .. k .. ":" .. v .. "\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
local function delimit_sequence(table, tab, delimiter)
|
|
||||||
if not tab then
|
|
||||||
tab = ""
|
|
||||||
end
|
|
||||||
if not table then
|
|
||||||
return tab .. "nil"
|
|
||||||
end
|
|
||||||
if not delimiter then
|
|
||||||
delimiter = " "
|
|
||||||
end
|
|
||||||
local ret = ""
|
|
||||||
if delimiter ~= "\n" then
|
|
||||||
ret = tab
|
|
||||||
end
|
|
||||||
for k, v in pairs(table) do
|
|
||||||
if delimiter == "\n" then
|
|
||||||
ret = ret .. tab .. v .. delimiter
|
|
||||||
else
|
|
||||||
ret = ret .. v .. delimiter
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
local function send_messages_sequence(username, table, tab)
|
|
||||||
if not tab then
|
|
||||||
tab = ""
|
|
||||||
end
|
|
||||||
if not table then
|
|
||||||
minetest.chat_send_player(username, tab .. "nil")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
for k, v in pairs(table) do
|
|
||||||
minetest.chat_send_player(username, tab .. v .. ",")
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function inv_to_tables(inv)
|
|
||||||
-- see bones mod
|
|
||||||
results = {}
|
|
||||||
for i = 1, inv:get_size("main") do
|
|
||||||
local stk = inv:get_stack("main", i)
|
|
||||||
table.insert(results, stk:to_table())
|
|
||||||
-- to_table shows everything:
|
|
||||||
-- meta:
|
|
||||||
-- metadata: ""
|
|
||||||
-- count:1
|
|
||||||
-- name:"default:sapling"
|
|
||||||
-- wear:0
|
|
||||||
end
|
|
||||||
return results
|
|
||||||
end
|
|
||||||
|
|
||||||
local function inv_to_table(inv, blank)
|
|
||||||
-- see bones mod
|
|
||||||
local results = {}
|
|
||||||
for i = 1, inv:get_size("main") do
|
|
||||||
local stk = inv:get_stack("main", i)
|
|
||||||
local stk_s = stk:to_string()
|
|
||||||
if #stk_s > 0 or blank then
|
|
||||||
table.insert(results, stk_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return results
|
|
||||||
end
|
|
||||||
|
|
||||||
local function send_messages(username, table, tab, blank)
|
|
||||||
if not tab then
|
|
||||||
tab = ""
|
|
||||||
end
|
|
||||||
if not table then
|
|
||||||
minetest.chat_send_player(username, tab .. "nil")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
for k, v in pairs(table) do
|
|
||||||
if blank or ((v ~= nil) and (dump(v) ~= "") and (dump(v) ~= "\"\"")) then
|
|
||||||
if type(v) == "table" then
|
|
||||||
minetest.chat_send_player(username, tab .. k .. ":")
|
|
||||||
send_messages(username, v, tab.."\t")
|
|
||||||
elseif k == "formspec" then
|
|
||||||
minetest.chat_send_player(username, tab .. k .. ":")
|
|
||||||
local chunks = split_and_keep_token(v, "]")
|
|
||||||
send_messages_sequence(username, chunks, tab.."\t")
|
|
||||||
else
|
|
||||||
minetest.chat_send_player(username, tab..k..":"..dump(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_nodedef_field(nodename, fieldname)
|
|
||||||
if not minetest.registered_nodes[nodename] then
|
|
||||||
-- print("metatools.get_nodedef_field: no registered node named " .. nodename)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
-- print("metatools.get_nodedef_field: checking " .. nodename .. " for " .. fieldname .. " in " .. dump(minetest.registered_nodes[nodename]))
|
|
||||||
-- print("* result:" .. dump(minetest.registered_nodes[nodename][fieldname]))
|
|
||||||
return minetest.registered_nodes[nodename][fieldname]
|
|
||||||
end
|
|
||||||
|
|
||||||
metatools = {} -- Public namespace
|
metatools = {} -- Public namespace
|
||||||
metatools.contexts = {}
|
metatools.contexts = {}
|
||||||
metatools.playerlocks = {} -- Selection locks of the players
|
metatools.playerlocks = {} -- Selection locks of the players
|
||||||
|
@ -292,408 +20,22 @@ local nodelock = {}
|
||||||
|
|
||||||
local modpath = minetest.get_modpath("metatools")
|
local modpath = minetest.get_modpath("metatools")
|
||||||
dofile(modpath .. "/assertions.lua")
|
dofile(modpath .. "/assertions.lua")
|
||||||
dofile(modpath .. "/chatcommands.lua")
|
|
||||||
|
|
||||||
minetest.register_craftitem("metatools:stick",{
|
minetest.register_craftitem("metatools:stick",{
|
||||||
description = "Meta stick",
|
description = "Meta stick",
|
||||||
inventory_image = "metatools_stick.png",
|
inventory_image = "metatools_stick.png",
|
||||||
stack_max = 1,
|
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
local username = user:get_player_name()
|
local username = user:get_player_name()
|
||||||
local userpos = user:get_pos()
|
|
||||||
if pointed_thing.type == "nothing" then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] You pointed at nothing."
|
|
||||||
)
|
|
||||||
return
|
|
||||||
elseif pointed_thing.type == "object" and pointed_thing.ref and pointed_thing.ref:get_luaentity() then
|
|
||||||
-- It must be a mob
|
|
||||||
-- (Otherwise [if not get_luaentity(),] it must be a player character,
|
|
||||||
-- so see next elseif case
|
|
||||||
local pointedObjRef = pointed_thing.ref
|
|
||||||
-- local objAsStr = minetest.serialize(pointedObjRef)
|
|
||||||
-- ^ if param is pointed_thing or pointed_thing.ref, minetest.serialize causes "2021-11-14 16:45:39: ERROR[Main]: ServerError: AsyncErr: ServerThread::run Lua: Runtime error from mod 'metatools' in callback item_OnUse(): /home/owner/minetest/bin/../builtin/common/serialize.lua:151: Can't serialize data of type userdata"
|
|
||||||
-- - even yamlSerializeTable returns [inserializeable datatype:userdata]
|
|
||||||
-- unrelated note: minetest.serialize(nil) returns "return nil"
|
|
||||||
-- TODO:
|
|
||||||
-- Show ObjectRef armor groups (See <https://git.minetest.org/minetest/minetest/src/branch/master/doc/lua_api.txt#L1825>)
|
|
||||||
-- documentation for ObjectRef: <https://git.minetest.org/minetest/minetest/src/branch/master/doc/lua_api.txt#L1825>
|
|
||||||
local objAsStr = yamlSerializeTable(pointedObjRef)
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] You pointed at an object (" .. objAsStr .. ")"
|
|
||||||
)
|
|
||||||
-- ^ (always?) says "[inserializeable datatype:userdata]", so:
|
|
||||||
local pointedObjRef = pointed_thing.ref
|
|
||||||
-- if pointed_thing.ref.get_hp then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" pointed_thing.ref:get_hp(): " .. pointedObjRef:get_hp()
|
|
||||||
)
|
|
||||||
-- end
|
|
||||||
-- minetest.log("action", "[metatools] You pointed at an object: " .. objAsStr)
|
|
||||||
local luaEntity = pointedObjRef:get_luaentity()
|
|
||||||
-- NOTE: For player name, use user:get_player_name()
|
|
||||||
-- NOTE: luaEntity is nil when clicking player!
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" LuaEntity.name: " .. luaEntity.name
|
|
||||||
)
|
|
||||||
-- ^ This is the entity name such as namespace:sheep_black where namespace is a mod name.
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" LuaEntity: " .. yamlSerializeTable(luaEntity, "", 1)
|
|
||||||
)
|
|
||||||
local animation = pointedObjRef:get_animation()
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" pointed_thing.ref:get_animation():" .. yamlSerializeTable(animation)
|
|
||||||
)
|
|
||||||
if luaEntity.state then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" luaEntity.state: " .. yamlSerializeTable(luaEntity.state)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
-- Hmm, animation.range, animation['range'] are nil
|
|
||||||
-- (same for other variables),
|
|
||||||
-- so API documentation is unclear:
|
|
||||||
-- `get_animation()`: returns `range`, `frame_speed`, `frame_blend` and
|
|
||||||
-- `frame_loop`.
|
|
||||||
-- yamlSerializeTable(animation) only gets:
|
|
||||||
-- y: 65
|
|
||||||
-- x: 35
|
|
||||||
-- minetest.chat_send_player(
|
|
||||||
-- username,
|
|
||||||
-- yamlSerializeTable(animation.range, " range")
|
|
||||||
-- )
|
|
||||||
-- else will return early (See "if not nodepos or ..." below)!
|
|
||||||
elseif pointed_thing.type == "object" and pointed_thing.ref and pointed_thing.ref:is_player() then
|
|
||||||
-- NOTE pointed_thing.ref.get_luaentity() is nil in this and all successive cases
|
|
||||||
-- local pointedObjRef = pointed_thing.ref
|
|
||||||
local player = pointed_thing.ref
|
|
||||||
local inv = player:get_inventory()
|
|
||||||
if pointed_thing.ref:get_player_name() then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" player name: " .. pointed_thing.ref:get_player_name()
|
|
||||||
)
|
|
||||||
else
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" player name: nil"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
if pointed_thing.ref:get_entity_name() then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" entity name: " .. pointed_thing.ref:get_entity_name()
|
|
||||||
)
|
|
||||||
end
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" inventories:"
|
|
||||||
)
|
|
||||||
-- local pointedEntitySAO = player:getluaobject()
|
|
||||||
-- local pointedPlayerSAO = player:getplayersao()
|
|
||||||
-- local pointedRemotePlayer = player:getplayer()
|
|
||||||
local inventories = {
|
|
||||||
["main"] = 32, -- The regular inventory grid
|
|
||||||
["hand"] = 1, -- item shown in hand in 3D (?)
|
|
||||||
["craft"] = 9, -- the 3x3 area for crafting
|
|
||||||
["craftpreview"] = 1, -- you can see but not take from preview
|
|
||||||
["craftresult"] = 1, -- you take the item from this to craft it
|
|
||||||
["bag1"] = 1, -- For bag itself (bag item placed here enables bag1contents)
|
|
||||||
["bag1contents"] = 32, -- The items in the bag
|
|
||||||
["bag2"] = 1,
|
|
||||||
["bag2contents"] = 32,
|
|
||||||
["bag3"] = 1,
|
|
||||||
["bag3contents"] = 32,
|
|
||||||
["bag4"] = 1,
|
|
||||||
["bag4contents"] = 32,
|
|
||||||
["more_chests:wifi"] = 32, -- on player since all chests are shared
|
|
||||||
["enderchest"] = 32 -- legacy, TM Mojang. See wifi instead.
|
|
||||||
}
|
|
||||||
-- NOTE: "hunger" is also an inventory but it is used as a savable variable
|
|
||||||
for inv_name, inv_max in pairs(inventories) do
|
|
||||||
local i = 0
|
|
||||||
local inv_count = 0
|
|
||||||
local inv_block_text = ""
|
|
||||||
for y=1,4,1 do
|
|
||||||
local sep = ""
|
|
||||||
local line = ""
|
|
||||||
local cols = 8
|
|
||||||
if inv_max == 9 then
|
|
||||||
cols = 3
|
|
||||||
end
|
|
||||||
for x=1,cols,1 do
|
|
||||||
i = i + 1 -- 1 to 32
|
|
||||||
if i > inv_max then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
line = line .. sep .. inv:get_stack(inv_name, i):get_name()
|
|
||||||
if inv:get_stack(inv_name, i):get_count() > 0 then
|
|
||||||
line = line .. " " .. inv:get_stack(inv_name, i):get_count()
|
|
||||||
inv_count = inv_count + 1
|
|
||||||
end
|
|
||||||
sep = ", "
|
|
||||||
end -- end for column
|
|
||||||
if i > inv_max then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
inv_block_text = inv_block_text .. " - " .. line .. "\n"
|
|
||||||
end -- end for row (newline)
|
|
||||||
if inv_count > 0 then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" " .. inv_name .." inventory:\n" .. inv_block_text
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- Next get player metadata "3d_armor_inventory" (contains a Lua return statement returning the 3d_armor table for the player)
|
|
||||||
local known_metas = {"3d_armor_inventory", "unified_inventory:bags", "sethome:home"}
|
|
||||||
for _, meta_name in pairs(known_metas) do
|
|
||||||
local attribute_meta = player:get_meta() -- see also 3d_armor init.lua
|
|
||||||
-- Other attributes: local known_metas = {"hbsprint:sprinting", "hbsprint:stamina", "homedecor:player_skin", "hunger_ng:eating_timestamp", "hunger_ng:hunger", "hunger_ng:hunger_bar", "skinsdb:skin_key", "sprinting", "stamina"}
|
|
||||||
local content_lua = attribute_meta:get_string(meta_name)
|
|
||||||
if content_lua and content_lua ~= "" then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" " .. meta_name .. " = " .. content_lua
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif pointed_thing.type == "object" and pointed_thing.ref then
|
|
||||||
-- NOTE pointed_thing.ref.get_luaentity() is nil in this and all successive cases
|
|
||||||
-- local pointedObjRef = pointed_thing.ref
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"A non-player non-Lua ObjRef was clicked (NotImplemented in this version of metatools):"
|
|
||||||
)
|
|
||||||
if pointed_thing.ref:get_entity_name() then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" entity name: " .. pointed_thing.ref:get_entity_name()
|
|
||||||
)
|
|
||||||
else
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
" entity name: nil"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local nodepos = pointed_thing.under
|
local nodepos = pointed_thing.under
|
||||||
-- > * `under` refers to the node position behind the pointed face
|
|
||||||
-- > * `above` refers to the node position in front of the pointed face.
|
|
||||||
-- -<https://git.minetest.org/minetest/minetest/src/branch/master/doc/lua_api.txt>
|
|
||||||
if not nodepos or not minetest.get_node(nodepos) then return end
|
if not nodepos or not minetest.get_node(nodepos) then return end
|
||||||
local nodename = minetest.get_node(nodepos).name
|
local nodename = minetest.get_node(nodepos).name
|
||||||
local node = minetest.registered_nodes[nodename]
|
local node = minetest.registered_nodes[nodename]
|
||||||
local meta = minetest.get_meta(nodepos)
|
local meta = minetest.get_meta(nodepos)
|
||||||
local metalist = meta:to_table()
|
local metalist = meta:to_table()
|
||||||
|
|
||||||
minetest.chat_send_player(
|
minetest.chat_send_player(username, "- meta::stick - Node located at "..minetest.pos_to_string(nodepos))
|
||||||
username,
|
minetest.chat_send_player(username, "- meta::stick - Metadata fields dump : " .. dump(meta:to_table()["fields"]):gsub('\n', ""))
|
||||||
"[metatools::stick] You pointed at the '" .. nodename .. "':"
|
minetest.log("action","[metatools] Player "..username.." saw metadatas of node at "..minetest.pos_to_string(nodepos))
|
||||||
)
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] pos:"
|
|
||||||
.. minetest.pos_to_string(nodepos)
|
|
||||||
)
|
|
||||||
-- minetest.chat_send_player(
|
|
||||||
-- username,
|
|
||||||
-- "[metatools::stick] drawtype:"
|
|
||||||
-- .. get_nodedef_field(nodename, "drawtype")
|
|
||||||
-- )
|
|
||||||
-- minetest.chat_send_player(
|
|
||||||
-- username,
|
|
||||||
-- "[metatools::stick] sunlight_propagates:"
|
|
||||||
-- .. (get_nodedef_field(nodename, "sunlight_propagates") and 'true' or 'false')
|
|
||||||
-- )
|
|
||||||
|
|
||||||
if #metalist > 0 then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] metadata: "
|
|
||||||
--.. delimit(meta:to_table()["fields"], "", "\n")
|
|
||||||
)
|
|
||||||
send_messages(username, metalist)
|
|
||||||
-- send_messages(username, meta:to_table()["fields"])
|
|
||||||
-- minetest.chat_send_player(
|
|
||||||
-- username,
|
|
||||||
-- "[metatools::stick] inventory: "
|
|
||||||
-- --.. delimit(meta:to_table()["fields"], "", "\n")
|
|
||||||
-- )
|
|
||||||
end
|
|
||||||
if meta["get_inventory"] then
|
|
||||||
local inventory = meta:get_inventory()
|
|
||||||
if inventory then -- this is never true for some reason
|
|
||||||
local this_inv_table = inv_to_table(inventory, true)
|
|
||||||
if #this_inv_table > 0 then
|
|
||||||
minetest.chat_send_player(username, "get_inventory():")
|
|
||||||
send_messages(username, this_inv_table, " ")
|
|
||||||
end
|
|
||||||
-- else
|
|
||||||
-- minetest.chat_send_player(username, "\tnil")
|
|
||||||
end
|
|
||||||
-- else
|
|
||||||
-- minetest.chat_send_player(username, "get_inventory:nil")
|
|
||||||
end
|
|
||||||
-- node is nil at this point if the node is an "unknown node"!
|
|
||||||
if node and node.frame_contents then
|
|
||||||
-- frames mod
|
|
||||||
local frame_contents = node.frame_contents
|
|
||||||
if frame_contents then
|
|
||||||
minetest.chat_send_player(username, "frame_contents: "..frame_contents)
|
|
||||||
-- else
|
|
||||||
-- minetest.chat_send_player(username, "\tnil")
|
|
||||||
end
|
|
||||||
-- else
|
|
||||||
-- minetest.chat_send_player(username, "get_inventory:nil")
|
|
||||||
end
|
|
||||||
if meta:get_string("item") ~= "" then
|
|
||||||
-- itemframes mod or xdecor:itemframe
|
|
||||||
local frame_contents = meta:get_string("item")
|
|
||||||
if frame_contents then
|
|
||||||
minetest.chat_send_player(username, "meta item: "..frame_contents)
|
|
||||||
-- else
|
|
||||||
-- minetest.chat_send_player(username, "\tnil")
|
|
||||||
end
|
|
||||||
-- else
|
|
||||||
-- minetest.chat_send_player(username, "get_inventory:nil")
|
|
||||||
end
|
|
||||||
local airname = minetest.get_name_from_content_id(minetest.CONTENT_AIR)
|
|
||||||
-- local litnode = nil
|
|
||||||
local litpos = nil
|
|
||||||
local litdist = nil
|
|
||||||
local litwhy = "unknown"
|
|
||||||
local litmsg = ""
|
|
||||||
local litid = nil
|
|
||||||
local litwhat = nil
|
|
||||||
local litindent = ""
|
|
||||||
local foundPointed = false
|
|
||||||
local offsets = {
|
|
||||||
[0] = {["x"] = 0, ["y"] = 0, ["z"] = 0},
|
|
||||||
[1] = {["x"] = 0, ["y"] = 1, ["z"] = 0},
|
|
||||||
[2] = {["x"] = 0, ["y"] = -1, ["z"] = 0},
|
|
||||||
[3] = {["x"] = 1, ["y"] = 0, ["z"] = 0},
|
|
||||||
[4] = {["x"] = -1, ["y"] = 0, ["z"] = 0},
|
|
||||||
[5] = {["x"] = 0, ["y"] = 0, ["z"] = 1},
|
|
||||||
[6] = {["x"] = 0, ["y"] = 0, ["z"] = -1},
|
|
||||||
}
|
|
||||||
-- local touching = {}
|
|
||||||
for key, value in pairs(offsets) do
|
|
||||||
local trydist = nil
|
|
||||||
local trywhy = nil
|
|
||||||
local trypos = vector.new(
|
|
||||||
nodepos.x + value.x,
|
|
||||||
nodepos.y + value.y,
|
|
||||||
nodepos.z + value.z
|
|
||||||
)
|
|
||||||
-- touching[key] = trypos
|
|
||||||
local trynode = minetest.get_node(trypos)
|
|
||||||
local tryid = nil
|
|
||||||
local tryname = nil
|
|
||||||
if (trynode) then
|
|
||||||
tryname = trynode.name
|
|
||||||
tryid = minetest.get_content_id(tryname)
|
|
||||||
|
|
||||||
-- print("tryname:" .. tryname)
|
|
||||||
-- print("trynode.name:" .. trynode.name)
|
|
||||||
-- if (tryid == minetest.CONTENT_AIR) then
|
|
||||||
if trynode.name == airname then
|
|
||||||
-- found:
|
|
||||||
if (userpos) then
|
|
||||||
trydist = vector.distance(userpos, trypos)
|
|
||||||
else
|
|
||||||
-- dummy value for "found" state:
|
|
||||||
trydist = vector.distance(nodepos, trypos)
|
|
||||||
end
|
|
||||||
trywhy = "air"
|
|
||||||
else
|
|
||||||
-- local trygroup = minetest.get_item_group(trynode.name, "air")
|
|
||||||
-- local drawtype = get_nodedef_field(tryname, "drawtype")
|
|
||||||
if (get_nodedef_field(tryname, "drawtype") == "airlike") then
|
|
||||||
trywhy = "airlike"
|
|
||||||
elseif (get_nodedef_field(tryname, "sunlight_propagates") == true) then
|
|
||||||
trywhy = "sunlight_propagates"
|
|
||||||
else
|
|
||||||
trynode = nil
|
|
||||||
-- print("[metatools::stick] " .. key .. ": "..tryname.." is not airlike, no sunlight_propagates")
|
|
||||||
end
|
|
||||||
if (trynode) then
|
|
||||||
-- found:
|
|
||||||
if (userpos) then
|
|
||||||
trydist = vector.distance(userpos, trypos)
|
|
||||||
else
|
|
||||||
-- dummy value for "found" state:
|
|
||||||
trydist = vector.distance(nodepos, trypos)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- if trydef.sunlight_propagates
|
|
||||||
end
|
|
||||||
else
|
|
||||||
trywhy = "non-node"
|
|
||||||
-- (non-node pos should work for the later light check)
|
|
||||||
-- found:
|
|
||||||
if (userpos) then
|
|
||||||
trydist = vector.distance(userpos, trypos)
|
|
||||||
else
|
|
||||||
-- dummy value for "found" state:
|
|
||||||
trydist = vector.distance(nodepos, trypos)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if (trydist) then
|
|
||||||
if (litpos == nil) or (trydist < litdist) then
|
|
||||||
litdist = trydist
|
|
||||||
litpos = trypos
|
|
||||||
litid = tryid -- nil if trywhy == "non-node"
|
|
||||||
litwhy = trywhy
|
|
||||||
if (key > 0) then
|
|
||||||
litwhat = "neighbor:"
|
|
||||||
litindent = " "
|
|
||||||
else
|
|
||||||
foundPointed = true
|
|
||||||
-- is the pointed node
|
|
||||||
break -- always use pointed node if lightable
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local nodelightsource = get_nodedef_field(nodename, "light_source")
|
|
||||||
if (nodelightsource) and (nodelightsource > 0) then
|
|
||||||
if not foundPointed then
|
|
||||||
litmsg = " # next to pointed light_source=" .. nodelightsource
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
-- litnode = minetest.find_node_near(nodepos, 1, minetest.get_name_from_content_id(minetest.CONTENT_AIR))
|
|
||||||
if (litpos) then
|
|
||||||
if (litwhat) then
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] nearby lit: #"..minetest.pos_to_string(litpos)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] "..litindent.."why lit:" .. litwhy .. litmsg
|
|
||||||
)
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] "..litindent.."light:" .. minetest.get_node_light(litpos)
|
|
||||||
)
|
|
||||||
else
|
|
||||||
minetest.chat_send_player(
|
|
||||||
username,
|
|
||||||
"[metatools::stick] nearby lit: ~ # no air/propogator for determining lighting"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
minetest.log("action","[metatools] Player " .. username .. " saw metadatas of node at " .. minetest.pos_to_string(nodepos))
|
|
||||||
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
3
mod.conf
3
mod.conf
|
@ -1,3 +0,0 @@
|
||||||
name = metatools
|
|
||||||
depends =
|
|
||||||
description = See metadata for nodes (and Entities in Poikilos' fork!)
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 8.2 KiB |
91
readme.md
91
readme.md
|
@ -1,91 +0,0 @@
|
||||||
# Minetest mod metatools
|
|
||||||
|
|
||||||
Get everything possible* about a node just by clicking it with metatools:stick!
|
|
||||||
|
|
||||||
## Differences in Poikilos' fork:
|
|
||||||
This is a hard fork oriented around getting information without typing any commands.
|
|
||||||
- All known* metadata is shown on click! There is no need for various commands to traverse the tree, though the original chat command code is intact.
|
|
||||||
- Click a node and get its inventory.
|
|
||||||
- Click an entity and list the entire LuaEntitySOA tree!
|
|
||||||
- See the "[Minetest API Notes](minetest-api-notes)" section below.
|
|
||||||
- The texture is redone so that doesn't any longer have an invasive and inappropriate CC-BY-NC-SA license from the upstream version of metatools.
|
|
||||||
|
|
||||||
`*` All metadata where how to obtain it is known by the maintainer of this repo (except where there is an open issue).
|
|
||||||
|
|
||||||
|
|
||||||
## Authors
|
|
||||||
Code:
|
|
||||||
- 2015-2016 LeMagnesium/Mg/ElectronLibre and Paly2/Palige (mod inspired by mgl512's itemframe issue)
|
|
||||||
- 2017-2022 Poikilos (Poikilos' fork of Version 1.2.2)
|
|
||||||
|
|
||||||
Textures:
|
|
||||||
- 2022 Poikilos (redone "metatools_stick.png" *replaces one with invasive and inappropriate CC-BY-NC-SA license [old texture was by Ataron]*)
|
|
||||||
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
This mod's aim is to provide a way for admins to navigate through any (ok, not
|
|
||||||
ignores) nodes on the map, and see values of its metadatas at any of their
|
|
||||||
stratum.
|
|
||||||
|
|
||||||
|
|
||||||
## Install
|
|
||||||
- Copy the repo folder containing init.lua to your Minetest mods folder (The resulting folder should be mods/metatools/).
|
|
||||||
- Enable the mod for the world.
|
|
||||||
- You can remove the "projects" folder to lighten the "game" if necessary (Keeping the png is useful but only for documentation--Nothing in "projects" is used by the mod code).
|
|
||||||
|
|
||||||
|
|
||||||
## Special thanks
|
|
||||||
- mgl512 (Le_Docteur) for its locked itemframe which gave me the idea of a tool
|
|
||||||
allowing to see/edit metadatas
|
|
||||||
- Ataron who created the stick's texture
|
|
||||||
- palige who agreed to test the mod for its first release, and contributed to the last version
|
|
||||||
|
|
||||||
|
|
||||||
## Use
|
|
||||||
- After following the "Install" steps above, open the world in Minetest.
|
|
||||||
- Type `/grantme all`
|
|
||||||
- Type `/giveme metatools:stick`
|
|
||||||
|
|
||||||
The chat commands from https://github.com/Lymkwi/minetest-mod-metatools are still present but usually not necessary:
|
|
||||||
- Type `/meta help` to see instructions on chat commands.
|
|
||||||
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Minetest API Notes
|
|
||||||
|
|
||||||
#### Entity Metadata
|
|
||||||
The magic sauce to get the entire LuaEntitySOA of a pointed_thing was finally discovered by accident (when researching unrelated API feature(s)) after no one would/could answer my question:
|
|
||||||
```Lua
|
|
||||||
local pointedObjRef = pointed_thing.ref;
|
|
||||||
-- . . . some other code is here, then ...
|
|
||||||
local luaEntity = pointedObjRef:get_luaentity();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Node metadata
|
|
||||||
![Node has fields and inventory; there are main and craft inventories, where each is a sequential table where each entry is an itemstack](projects/node_metadata.png)
|
|
||||||
|
|
||||||
```
|
|
||||||
Node
|
|
||||||
|
|
|
||||||
+-fields
|
|
||||||
| |
|
|
||||||
| +-foo
|
|
||||||
| +-bar
|
|
||||||
| +-...
|
|
||||||
+-inventory
|
|
||||||
|
|
|
||||||
+-main
|
|
||||||
| |
|
|
||||||
| +-1
|
|
||||||
| +-2
|
|
||||||
| +-3
|
|
||||||
| +-...
|
|
||||||
+-craft
|
|
||||||
| |
|
|
||||||
| +-1
|
|
||||||
| +-2
|
|
||||||
| +-3
|
|
||||||
| +-...
|
|
||||||
+-...
|
|
||||||
```
|
|
Binary file not shown.
Before Width: | Height: | Size: 753 B After Width: | Height: | Size: 3.4 KiB |
|
@ -1,6 +0,0 @@
|
||||||
SET MT_PROGRAM_DIR=C:\games\Minetest
|
|
||||||
IF EXIST "C:\Games\ENLIVEN" SET MT_PROGRAM_DIR=C:\Games\ENLIVEN
|
|
||||||
copy /y *.lua "%MT_PROGRAM_DIR%\games\ENLIVEN\mods\metatools\"
|
|
||||||
copy /y *.md "%MT_PROGRAM_DIR%\games\ENLIVEN\mods\metatools\"
|
|
||||||
copy /y textures\*.png "%MT_PROGRAM_DIR%\games\ENLIVEN\mods\metatools\textures\"
|
|
||||||
if NOT ["%errorlevel%"]==["0"] pause
|
|
Loading…
Reference in New Issue
Block a user