Difference between revisions of "MetaDataRef"

From Minetest Developer Wiki
Jump to navigation Jump to search
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Meta data is data about something. You can store meta data in nodes and stacks.
+
{{UnofficialLua}}
  
Node meta data can be gotten via <source enclose="none">minetest.get_meta(pos)</source>, and item stack meta data from <source enclose="none">stack:get_meta()</source>.
+
See [https://minetest.gitlab.io/minetest/class-reference/#metadataref MetaDataRef] and [https://minetest.gitlab.io/minetest/metadata/ Metadata] in the Lua API documentation.
  
 
'''Warning''' all metadata is sent to client, don't store sensitive stuff here.
 
'''Warning''' all metadata is sent to client, don't store sensitive stuff here.
  
== Methods ==
+
== Example ==
* <source enclose="none">set_string(name, value)</source>
+
This adds a chatcommand, that opens a formspecs in that you can change the color and name of an item, if you havethe rename priv.
* <source enclose="none">get_string(name)</source>
+
<source>
* <source enclose="none">set_int(name, value)</source>
+
minetest.register_privilege("rename", {
* <source enclose="none">get_int(name)</source>
+
description = "Can rename Items and Nodes",
* <source enclose="none">set_float(name, value)</source>
+
give_to_singleplayer = false
* <source enclose="none">get_float(name)</source>
+
})
* <source enclose="none">to_table()</source> — returns <source enclose="none">nil</source> or <source enclose="none">{fields = {...}, inventory = {list1 = {}, ...}}</source>
 
* <source enclose="none">from_table(nil</source> or <source enclose="none">{})</source>
 
 
 
=== Nodes only ===
 
 
 
* <source enclose="none">get_inventory()</source> — returns [[InvRef]], only on nodes
 
* <source enclose="none">mark_as_private(name)</source> — nodes only, stops the field from being sent to the client
 
  
 +
minetest.register_chatcommand("rename", {
 +
    func = function(name, param)
 +
        minetest.show_formspec(name, "rename:renameform",
 +
                "size[4,4.5]" ..
 +
                "label[0,0;rename]" ..
 +
                "field[1,1.5;3,1;name;New Node/Item name;]" ..
 +
"field[1,2.5;3,1;color;New Color;]" ..
 +
                "button_exit[1,3;2,1;exit;Rename Now!]")
 +
    end
 +
})
  
== Special Handling ==
 
  
=== Nodes ===
+
minetest.register_on_player_receive_fields(function(player,
 +
        formname, fields)
 +
    if formname ~= "rename:renameform" then
  
You can use the following keys in node meta data for a special use:
+
        return false
 +
    end
  
* <code>formspec</code> — Defines a right-click inventory menu. See "[[formspec|Formspec]]".
+
    local has, missing = minetest.check_player_privs(player:get_player_name(), {
* <code>infotext</code> — Text shown on the screen when the node is pointed at
+
            rename = true})
  
 +
    if has then
 +
      local itemstack = player:get_wielded_item()
 +
      local meta = itemstack:get_meta()
 +
      meta:set_string("description", fields.name)
 +
meta:set_string("color", fields.color)
 +
      player:set_wielded_item(itemstack)
  
=== Item Stacks ===
+
      return true
 
+
    else
You can use the following keys in stack meta data for a special use:
+
        minetest.chat_send_player(player:get_player_name(), "You have no privilige to rename things :( ")
 
+
    end
* <code>description</code> — Overrides the tooltip in an inventory
+
</source>
 
 
== Example ==
 
 
<source>
 
<source>
 
local meta = minetest.get_meta(pos)
 
local meta = minetest.get_meta(pos)

Latest revision as of 14:06, 25 October 2022

Mbox warning.png This page contains unofficial, low-quality Lua API documentation and is likely to be outdated or wrong. Do not rely on it!
For the official and up-to-date documentation, see Lua API Documentation.
Mbox warning.png This page has been proposed for deletion for the following reason: "Contains unofficial and potentially outdated, redundant and inconsistent Lua API information"
If you don't think that this page should be deleted, please explain why on the talk page.

See MetaDataRef and Metadata in the Lua API documentation.

Warning all metadata is sent to client, don't store sensitive stuff here.

Example

This adds a chatcommand, that opens a formspecs in that you can change the color and name of an item, if you havethe rename priv.

minetest.register_privilege("rename", {
	description = "Can rename Items and Nodes",
	give_to_singleplayer = false
})

minetest.register_chatcommand("rename", {
    func = function(name, param)
        minetest.show_formspec(name, "rename:renameform",
                "size[4,4.5]" ..
                "label[0,0;rename]" ..
                "field[1,1.5;3,1;name;New Node/Item name;]" ..
								"field[1,2.5;3,1;color;New Color;]" ..
                "button_exit[1,3;2,1;exit;Rename Now!]")
    end
})


minetest.register_on_player_receive_fields(function(player,
        formname, fields)
    if formname ~= "rename:renameform" then

        return false
    end

    local has, missing = minetest.check_player_privs(player:get_player_name(), {
            rename = true})

    if has then
      local itemstack = player:get_wielded_item()
      local meta = itemstack:get_meta()
      meta:set_string("description", fields.name)
			meta:set_string("color", fields.color)
      player:set_wielded_item(itemstack)

      return true
    else
        minetest.chat_send_player(player:get_player_name(), "You have no privilige to rename things :( ")
    end
local meta = minetest.get_meta(pos)
meta:set_string("formspec",
        "invsize[8,9;]"..
        "list[context;main;0,0;8,4;]"..
        "list[current_player;main;0,5;8,4;]")
meta:set_string("infotext", "Chest");
local inv = meta:[NodeMetaRef]get_inventory()
inv:set_size("main", 8*4)
print(dump(meta:[NodeMetaRef]to_table()))
meta:from_table({
    inventory = {
        main = {
[1] = "default:dirt",
[2] = "",
[3] = "",
[4] = "",
[5] = "",
[6] = "",
[7] = "",
[8] = "",
[9] = "",
[10] = "",
[11] = "",
[12] = "",
[13] = "",
[14] = "default:cobble",
[15] = "",
[16] = "",
[17] = "",
[18] = "",
[19] = "",
[20] = "default:cobble",
[21] = "",
[22] = "",
[23] = "",
[24] = "",
[25] = "",
[26] = "",
[27] = "",
[28] = "",
[29] = "",
[30] = "",
[31] = "",
[32] = ""}
    },
    fields = {
        formspec = "invsize[8,9;]list[context;main;0,0;8,4;]list[current_player;main;0,5;8,4;]",
        infotext = "Chest"
    }
})

An excerpt from an e-mail between Minetest developers

> When I attach a Lua table to a node I seem to have a
> choice: to store things with many calls to
> meta.set_int/meta.set_string etc. or via meta:from_table.
> meta:from_table lets me store an arbitrary table under "fields":
> 
> local meta = minetest.get_meta(pos)
> local mt = meta:to_table()
> 
> len = tonumber(mt.fields.length_remaining)
> 
> ... only I have noticed that every key under fields can only store
> strings. So as a general purpose 'table' store, this is not so useful.
> I came upon this because I wanted to store the initial position of a
> node. This requires either:
> 
> meta:set_int('x', pos.x)
> meta:set_int('y', pos.y)
> meta:set_int('z', pos.z)
> 
> or something like:
> 
> mt.fields.tail_pos = "return {" .. pos.x .. "," .. pos.y .. "," .. pos.z .. "}"
> 
> and then something like this to read it back:
> tail_pos = loadstring(mt.fields.tail_pos)()
> 
> 
> ...correct? Or am I missing an obvious alternate solution? The api
> docs are not detailed on this.

Answer by celeron55:

For simplicity, all the fields are internally strings, and don't store
any type information. I can see the inconvenience though.

You shouldn't use loadstring() directly, because then somebody could
create a world which stores arbitrary Lua code, which can eg. remove
all files, or something similar.

For storing Lua variables with type information, you can use
minetest.serialize() and minetest.deserialize(). They take any
serializable Lua table, which can contain:
- tables
- strings
- numbers
- functions that don't access anything outside of what is stored in
  the data itself and what is passed as a parameter))
and make it into a string, and the other way around, and they
will not execute any foreign code (unless you do certain
complicated-ish stupid things, which probably won't happen).

You can check out the implementation in builtin/serialize.lua.

So if you want to store a position in the data of a node, you can use:
  local pos = {x=this, y=and, z=that}
  meta:set_string("tail_pos", minetest.serialize(pos))
and
  local pos = minetest.deserialize(meta:get_string("tail_pos")).

Keep in mind though that that thing isn't very largely in use, and
there might be unnoticed problems.