Merge remote-tracking branch 'poikilos/master'

This commit is contained in:
bri cassa 2022-06-26 13:28:10 +02:00
commit 4e880fcb71
11 changed files with 679 additions and 78 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/projects/node_metadata.dia.autosave

View File

@ -1,58 +0,0 @@
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
| +- ...
+- ...

17
chatcommands.lua Normal file
View File

@ -0,0 +1,17 @@
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
description.txt Normal file
View File

@ -0,0 +1 @@
See metadata for nodes (and Entities in Poikilos' fork!)

580
init.lua
View File

@ -1,17 +1,289 @@
--[[
-- Metadata Tools
-- Metadata Tools
--
-- A mod providing write and read access to a nodes' metadata using commands
-- ßÿ Lymkwi/LeMagnesium/Mg ; 2015-2016
-- License: WTFPL
-- Contributors :
-- - Lymkwi/LeMagnesium
-- - Paly2
-- A mod providing write and read access to a nodes' metadata using commands
-- (c) 2015-2016 ßÿ Lymkwi/LeMagnesium/Mg and Paly2; (c) 2017-2022 Poikilos
-- License: [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/)
--
-- Version: 1.2.2
-- Version: Poikilos fork of 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.contexts = {}
metatools.playerlocks = {} -- Selection locks of the players
@ -20,22 +292,290 @@ local nodelock = {}
local modpath = minetest.get_modpath("metatools")
dofile(modpath .. "/assertions.lua")
dofile(modpath .. "/chatcommands.lua")
minetest.register_craftitem("metatools:stick",{
description = "Meta stick",
inventory_image = "metatools_stick.png",
stack_max = 1,
on_use = function(itemstack, user, pointed_thing)
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" then
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()
-- INFO: For player name, use user:get_player_name()
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 type is usually "node"
end
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
local nodename = minetest.get_node(nodepos).name
local node = minetest.registered_nodes[nodename]
local meta = minetest.get_meta(nodepos)
local node = minetest.registered_nodes[nodename]
local meta = minetest.get_meta(nodepos)
local metalist = meta:to_table()
minetest.chat_send_player(username, "- meta::stick - Node located at "..minetest.pos_to_string(nodepos))
minetest.chat_send_player(username, "- meta::stick - Metadata fields dump : " .. dump(meta:to_table()["fields"]):gsub('\n', ""))
minetest.log("action","[metatools] Player "..username.." saw metadatas of node at "..minetest.pos_to_string(nodepos))
minetest.chat_send_player(
username,
"[metatools::stick] You pointed at the '" .. nodename .. "':"
)
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,
})
@ -162,7 +702,7 @@ function meta_exec(struct)
for category, req in pairs(struct.required) do
if category == "position" and not assert_pos(req) then
return false, ("- %s - Failure : Invalid position : %s"):format(struct.scope, dump_normalize(req))
elseif category == "contextid" and not assert_contextid(req) then
return false, ("- %s - Failutre : Invalid contextid : %s"):format(struct.scope, dump_normalize(req))
@ -215,7 +755,7 @@ function meta_exec(struct)
if not assert_contextid(req.contextid) then
return false, ("- %s - Failure : Invalid context id : %s"):format(struct.scope, dump_normalize(req.contextid))
end
if not metatools.contexts[req.contextid].mode == req.mode then
return false, ("- %s - Failure : Invalid mode, %s is required"):format(struct.scope, dump_normalize(req.mode))
end
@ -350,7 +890,7 @@ function metatools.purge(contextid)
local inv = meta:get_inventory()
inv:set_lists({})
return true, "inventory purged"
else
meta:from_table(nil)
return true, "fields purged"
@ -543,7 +1083,7 @@ minetest.register_chatcommand("meta", {
format(summ.id, summ.mode, minetest.pos_to_string(summ.pos), summ.owner)
end
return true, retstr .. ("- meta::contexts - %d contexts"):format(#ctxs)
-- meta open (x,y,z) [fields|inventory]
elseif params[1] == "open" then
@ -702,7 +1242,7 @@ minetest.register_chatcommand("meta", {
}
}
})
-- meta purge
elseif params[1] == "purge" then
return meta_exec({
@ -782,7 +1322,7 @@ minetest.register_chatcommand("meta", {
}
}
})
else
return false, "- meta::list - Unknown subcommand '" .. params[2] .. "', please consult '/meta help' for help"
end
@ -822,7 +1362,7 @@ minetest.register_chatcommand("meta", {
}
}
})
-- meta itemstack add <itemstack>
elseif params[2] == "add" then
return meta_exec({

3
mod.conf Normal file
View File

@ -0,0 +1,3 @@
name = metatools
depends =
description = See metadata for nodes (and Entities in Poikilos' fork!)

BIN
projects/node_metadata.dia Normal file

Binary file not shown.

BIN
projects/node_metadata.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

91
readme.md Normal file
View File

@ -0,0 +1,91 @@
# 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: 3.4 KiB

After

Width:  |  Height:  |  Size: 753 B

6
update local.bat Normal file
View File

@ -0,0 +1,6 @@
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