Private nodemeta (#5702)
authorsfan5 <sfan5@live.de>
Wed, 10 May 2017 13:29:21 +0000 (15:29 +0200)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Wed, 10 May 2017 13:29:21 +0000 (15:29 +0200)
* Private node metadata that isn't sent to the client

doc/lua_api.txt
games/minimal/mods/default/init.lua
games/minimal/mods/experimental/init.lua
src/mapblock.cpp
src/nodemetadata.cpp
src/nodemetadata.h
src/rollback_interface.cpp
src/script/lua_api/l_nodemeta.cpp
src/script/lua_api/l_nodemeta.h
src/serialization.h

index 901dd3c463e2b0cdf0cdc065ace6e16c595adfe7..a295d7d0e2c0f4e904956f76143b5253d7923201 100644 (file)
@@ -2895,6 +2895,10 @@ Can be obtained via `minetest.get_meta(pos)`.
 #### Methods
 * All methods in MetaDataRef
 * `get_inventory()`: returns `InvRef`
+* `mark_as_private(name or {name1, name2, ...})`: Mark specific vars as private
+  This will prevent them from being sent to the client. Note that the "private"
+  status will only be remembered if an associated key-value pair exists, meaning
+  it's best to call this when initializing all other meta (e.g. on_construct).
 
 ### `ItemStackMetaRef`
 ItemStack metadata: reference extra data and functionality stored in a stack.
index 64970f922bdc56cfb8f900d3e058f61d26996d85..7d26f38a0a73b024c5f7c7fb7a08f4676bfbd46a 100644 (file)
@@ -1228,6 +1228,8 @@ minetest.register_node("default:chest_locked", {
                meta:set_string("owner", "")
                local inv = meta:get_inventory()
                inv:set_size("main", 8*4)
+               -- this is not really the intended usage but works for testing purposes:
+               meta:mark_as_private("owner")
        end,
        can_dig = function(pos,player)
                local meta = minetest.get_meta(pos);
index 5e98e1a80154a353de0d5afc113a8576637031af..6e0fb1738b17bfda95276340d4e4818c70843869 100644 (file)
@@ -502,10 +502,16 @@ minetest.register_craftitem("experimental:tester_tool_1", {
     on_use = function(itemstack, user, pointed_thing)
                --print(dump(pointed_thing))
                if pointed_thing.type == "node" then
-                       if minetest.get_node(pointed_thing.under).name == "experimental:tester_node_1" then
+                       local node = minetest.get_node(pointed_thing.under)
+                       if node.name == "experimental:tester_node_1" or node.name == "default:chest" then
                                local p = pointed_thing.under
                                minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p))
-                               minetest.dig_node(p)
+                               if node.name == "experimental:tester_node_1" then
+                                       minetest.dig_node(p)
+                               else
+                                       minetest.get_meta(p):mark_as_private({"infotext", "formspec"})
+                                       minetest.chat_send_player(user:get_player_name(), "Verify that chest is unusable now.")
+                               end
                        else
                                local p = pointed_thing.above
                                minetest.log("action", "Tester tool used at "..minetest.pos_to_string(p))
index 1a0b01f2b8bdc2480879d8eb5b266b61fe52d00d..ec10a49bb8c83a5346caca9dd385659eea995072 100644 (file)
@@ -611,7 +611,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
                Node metadata
        */
        std::ostringstream oss(std::ios_base::binary);
-       m_node_metadata.serialize(oss);
+       m_node_metadata.serialize(oss, version, disk);
        compressZlib(oss.str(), os);
 
        /*
@@ -669,11 +669,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
        u8 flags = readU8(is);
        is_underground = (flags & 0x01) ? true : false;
        m_day_night_differs = (flags & 0x02) ? true : false;
-       if (version < 27) {
+       if (version < 27)
                m_lighting_complete = 0xFFFF;
-       } else {
+       else
                m_lighting_complete = readU16(is);
-       }
        m_generated = (flags & 0x08) ? false : true;
 
        /*
index 9b60cf33e1a39d8d92f461b06528d8f9ba5b193b..0e8195c343e78badc4e62f3c403c65875dc25601 100644 (file)
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "inventory.h"
 #include "log.h"
 #include "util/serialize.h"
+#include "util/basic_macros.h"
 #include "constants.h" // MAP_BLOCKSIZE
 #include <sstream>
 
@@ -39,28 +40,38 @@ NodeMetadata::~NodeMetadata()
        delete m_inventory;
 }
 
-void NodeMetadata::serialize(std::ostream &os) const
+void NodeMetadata::serialize(std::ostream &os, u8 version, bool disk) const
 {
-       int num_vars = m_stringvars.size();
+       int num_vars = disk ? m_stringvars.size() : countNonPrivate();
        writeU32(os, num_vars);
        for (StringMap::const_iterator
                        it = m_stringvars.begin();
                        it != m_stringvars.end(); ++it) {
+               bool priv = isPrivate(it->first);
+               if (!disk && priv)
+                       continue;
+
                os << serializeString(it->first);
                os << serializeLongString(it->second);
+               if (version >= 2)
+                       writeU8(os, (priv) ? 1 : 0);
        }
 
        m_inventory->serialize(os);
 }
 
-void NodeMetadata::deSerialize(std::istream &is)
+void NodeMetadata::deSerialize(std::istream &is, u8 version)
 {
-       m_stringvars.clear();
+       clear();
        int num_vars = readU32(is);
        for(int i=0; i<num_vars; i++){
                std::string name = deSerializeString(is);
                std::string var = deSerializeLongString(is);
                m_stringvars[name] = var;
+               if (version >= 2) {
+                       if (readU8(is) == 1)
+                               markPrivate(name, true);
+               }
        }
 
        m_inventory->deSerialize(is);
@@ -69,6 +80,7 @@ void NodeMetadata::deSerialize(std::istream &is)
 void NodeMetadata::clear()
 {
        Metadata::clear();
+       m_privatevars.clear();
        m_inventory->clear();
 }
 
@@ -77,11 +89,34 @@ bool NodeMetadata::empty() const
        return Metadata::empty() && m_inventory->getLists().size() == 0;
 }
 
+
+void NodeMetadata::markPrivate(const std::string &name, bool set)
+{
+       if (set)
+               m_privatevars.insert(name);
+       else
+               m_privatevars.erase(name);
+}
+
+int NodeMetadata::countNonPrivate() const
+{
+       // m_privatevars can contain names not actually present
+       // DON'T: return m_stringvars.size() - m_privatevars.size();
+       int n = 0;
+       for (StringMap::const_iterator
+                       it = m_stringvars.begin();
+                       it != m_stringvars.end(); ++it) {
+               if (isPrivate(it->first) == false)
+                       n++;
+       }
+       return n;
+}
+
 /*
        NodeMetadataList
 */
 
-void NodeMetadataList::serialize(std::ostream &os) const
+void NodeMetadataList::serialize(std::ostream &os, u8 blockver, bool disk) const
 {
        /*
                Version 0 is a placeholder for "nothing to see here; go away."
@@ -93,7 +128,8 @@ void NodeMetadataList::serialize(std::ostream &os) const
                return;
        }
 
-       writeU8(os, 1); // version
+       u8 version = (blockver > 27) ? 2 : 1;
+       writeU8(os, version);
        writeU16(os, count);
 
        for(std::map<v3s16, NodeMetadata*>::const_iterator
@@ -108,7 +144,7 @@ void NodeMetadataList::serialize(std::ostream &os) const
                u16 p16 = p.Z * MAP_BLOCKSIZE * MAP_BLOCKSIZE + p.Y * MAP_BLOCKSIZE + p.X;
                writeU16(os, p16);
 
-               data->serialize(os);
+               data->serialize(os, version, disk);
        }
 }
 
@@ -123,7 +159,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
                return;
        }
 
-       if (version != 1) {
+       if (version > 2) {
                std::string err_str = std::string(FUNCTION_NAME)
                        + ": version " + itos(version) + " not supported";
                infostream << err_str << std::endl;
@@ -132,7 +168,7 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
 
        u16 count = readU16(is);
 
-       for (u16 i=0; i < count; i++) {
+       for (u16 i = 0; i < count; i++) {
                u16 p16 = readU16(is);
 
                v3s16 p;
@@ -143,15 +179,14 @@ void NodeMetadataList::deSerialize(std::istream &is, IItemDefManager *item_def_m
                p.X = p16;
 
                if (m_data.find(p) != m_data.end()) {
-                       warningstream<<"NodeMetadataList::deSerialize(): "
-                                       <<"already set data at position"
-                                       <<"("<<p.X<<","<<p.Y<<","<<p.Z<<"): Ignoring."
-                                       <<std::endl;
+                       warningstream << "NodeMetadataList::deSerialize(): "
+                                       << "already set data at position " << PP(p)
+                                       << ": Ignoring." << std::endl;
                        continue;
                }
 
                NodeMetadata *data = new NodeMetadata(item_def_mgr);
-               data->deSerialize(is);
+               data->deSerialize(is, version);
                m_data[p] = data;
        }
 }
index f46c0fe911037ee3e0120517df40741fa1467c0b..0d72485bcc8a0cca0399e987287596215440b29f 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define NODEMETADATA_HEADER
 
 #include "metadata.h"
+#include "util/cpp11_container.h"
 
 /*
        NodeMetadata stores arbitary amounts of data for special blocks.
@@ -40,8 +41,8 @@ public:
        NodeMetadata(IItemDefManager *item_def_mgr);
        ~NodeMetadata();
 
-       void serialize(std::ostream &os) const;
-       void deSerialize(std::istream &is);
+       void serialize(std::ostream &os, u8 version, bool disk=true) const;
+       void deSerialize(std::istream &is, u8 version);
 
        void clear();
        bool empty() const;
@@ -52,8 +53,17 @@ public:
                return m_inventory;
        }
 
+       inline bool isPrivate(const std::string &name) const
+       {
+               return m_privatevars.count(name) != 0;
+       }
+       void markPrivate(const std::string &name, bool set);
+
 private:
+       int countNonPrivate() const;
+
        Inventory *m_inventory;
+       UNORDERED_SET<std::string> m_privatevars;
 };
 
 
@@ -66,7 +76,7 @@ class NodeMetadataList
 public:
        ~NodeMetadataList();
 
-       void serialize(std::ostream &os) const;
+       void serialize(std::ostream &os, u8 blockver, bool disk=true) const;
        void deSerialize(std::istream &is, IItemDefManager *item_def_mgr);
 
        // Add all keys in this list to the vector keys
index 40a33a51da470010c3f4570dd53133d6ad1e10ce..d02d1cb3e8b861dabe5c66f2b29eff10487bf5d2 100644 (file)
@@ -44,7 +44,7 @@ RollbackNode::RollbackNode(Map *map, v3s16 p, IGameDef *gamedef)
        NodeMetadata *metap = map->getNodeMetadata(p);
        if (metap) {
                std::ostringstream os(std::ios::binary);
-               metap->serialize(os);
+               metap->serialize(os, 1); // FIXME: version bump??
                meta = os.str();
        }
 }
@@ -165,7 +165,7 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam
                                                }
                                        }
                                        std::istringstream is(n_old.meta, std::ios::binary);
-                                       meta->deSerialize(is);
+                                       meta->deSerialize(is, 1); // FIXME: version bump??
                                }
                                // Inform other things that the meta data has changed
                                v3s16 blockpos = getContainerPos(p, MAP_BLOCKSIZE);
index 6232112c5ca94b7ce20c3213f54fb65e92db3ab0..5dfa6d52e97928bd57f4b2e447db644deb657ab7 100644 (file)
@@ -94,6 +94,32 @@ int NodeMetaRef::l_get_inventory(lua_State *L)
        return 1;
 }
 
+// mark_as_private(self, <string> or {<string>, <string>, ...})
+int NodeMetaRef::l_mark_as_private(lua_State *L)
+{
+       MAP_LOCK_REQUIRED;
+
+       NodeMetaRef *ref = checkobject(L, 1);
+       NodeMetadata *meta = dynamic_cast<NodeMetadata*>(ref->getmeta(true));
+       assert(meta);
+
+       if (lua_istable(L, 2)) {
+               lua_pushnil(L);
+               while (lua_next(L, 2) != 0) {
+                       // key at index -2 and value at index -1
+                       luaL_checktype(L, -1, LUA_TSTRING);
+                       meta->markPrivate(lua_tostring(L, -1), true);
+                       // removes value, keeps key for next iteration
+                       lua_pop(L, 1);
+               }
+       } else if (lua_isstring(L, 2)) {
+               meta->markPrivate(lua_tostring(L, 2), true);
+       }
+       ref->reportMetadataChange();
+
+       return 0;
+}
+
 void NodeMetaRef::handleToTable(lua_State *L, Metadata *_meta)
 {
        // fields
@@ -229,6 +255,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = {
        luamethod(MetaDataRef, to_table),
        luamethod(MetaDataRef, from_table),
        luamethod(NodeMetaRef, get_inventory),
+       luamethod(NodeMetaRef, mark_as_private),
        luamethod(MetaDataRef, equals),
        {0,0}
 };
index 2ac028079aa62134aee8b27c6ede7a95dbdabc56..dd4260ff92979d42f3673c60a02351f123920d85 100644 (file)
@@ -73,6 +73,9 @@ private:
        // get_inventory(self)
        static int l_get_inventory(lua_State *L);
 
+       // mark_as_private(self, <string> or {<string>, <string>, ...})
+       static int l_mark_as_private(lua_State *L);
+
 public:
        NodeMetaRef(v3s16 p, ServerEnvironment *env);
        NodeMetaRef(Metadata *meta);
index 52c63098ee6df9efee2a96b55282b42ef97a6c71..c91c3241f5bd29261d52b60185aae305b988ae59 100644 (file)
@@ -63,13 +63,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        25: Improved node timer format
        26: Never written; read the same as 25
        27: Added light spreading flags to blocks
+       28: Added "private" flag to NodeMetadata
 */
 // This represents an uninitialized or invalid format
 #define SER_FMT_VER_INVALID 255
 // Highest supported serialization version
-#define SER_FMT_VER_HIGHEST_READ 27
+#define SER_FMT_VER_HIGHEST_READ 28
 // Saved on disk version
-#define SER_FMT_VER_HIGHEST_WRITE 27
+#define SER_FMT_VER_HIGHEST_WRITE 28
 // Lowest supported serialization version
 #define SER_FMT_VER_LOWEST_READ 0
 // Lowest serialization version for writing