Skip to content

Commit

Permalink
Add ItemStack key-value meta storage
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenwardy committed Feb 4, 2017
1 parent c2e7b1f commit f2aa2c6
Show file tree
Hide file tree
Showing 21 changed files with 459 additions and 123 deletions.
2 changes: 2 additions & 0 deletions build/android/jni/Android.mk
Expand Up @@ -164,6 +164,7 @@ LOCAL_SRC_FILES := \
jni/src/inventory.cpp \
jni/src/inventorymanager.cpp \
jni/src/itemdef.cpp \
jni/src/itemstackmetadata.cpp \
jni/src/keycode.cpp \
jni/src/light.cpp \
jni/src/localplayer.cpp \
Expand Down Expand Up @@ -305,6 +306,7 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_env.cpp \
jni/src/script/lua_api/l_inventory.cpp \
jni/src/script/lua_api/l_item.cpp \
jni/src/script/lua_api/l_itemstackmeta.cpp\
jni/src/script/lua_api/l_mainmenu.cpp \
jni/src/script/lua_api/l_mapgen.cpp \
jni/src/script/lua_api/l_metadata.cpp \
Expand Down
45 changes: 36 additions & 9 deletions doc/lua_api.txt
Expand Up @@ -1411,7 +1411,7 @@ the entity itself.
* `direction` is a unit vector, pointing from the source of the punch to
the punched object.
* `damage` damage that will be done to entity
Return value of this function will determin if damage is done by this function
Return value of this function will determin if damage is done by this function
(retval true) or shall be done by engine (retval false)

To punch an entity/object in Lua, call:
Expand All @@ -1427,9 +1427,9 @@ Node Metadata
-------------
The instance of a node in the world normally only contains the three values
mentioned in "Nodes". However, it is possible to insert extra data into a
node. It is called "node metadata"; See "`NodeMetaRef`".
node. It is called "node metadata"; See `NodeMetaRef`.

Metadata contains two things:
Node metadata contains two things:

* A key-value store
* An inventory
Expand Down Expand Up @@ -1467,6 +1467,18 @@ Example stuff:
}
})

Item Metadata
-------------
Item stacks can store metadata too. See `ItemStackMetaRef`.

Item metadata only contains a key-value store.

Example stuff:

local meta = stack:get_meta()
meta:set_string("key", "value")
print(dump(meta:to_table()))

Formspec
--------
Formspec defines a menu. Currently not much else than inventories are
Expand Down Expand Up @@ -2774,9 +2786,8 @@ These functions return the leftover itemstack.
Class reference
---------------

### `NodeMetaRef`
Node metadata: reference extra data and functionality stored in a node.
Can be gotten via `minetest.get_meta(pos)`.
### `MetaDataRef`
See `NodeMetaRef` and `ItemStackMetaRef`.

#### Methods
* `set_string(name, value)`
Expand All @@ -2785,13 +2796,29 @@ Can be gotten via `minetest.get_meta(pos)`.
* `get_int(name)`
* `set_float(name, value)`
* `get_float(name)`
* `get_inventory()`: returns `InvRef`
* `to_table()`: returns `nil` or `{fields = {...}, inventory = {list1 = {}, ...}}`
* `to_table()`: returns `nil` or a table with keys:
* `fields`: key-value storage
* `inventory`: `{list1 = {}, ...}}` (NodeMetaRef only)
* `from_table(nil or {})`
* Any non-table value will clear the metadata
* See "Node Metadata"
* See "Node Metadata" for an example
* returns `true` on success

### `NodeMetaRef`
Node metadata: reference extra data and functionality stored in a node.
Can be gotten via `minetest.get_meta(pos)`.

#### Methods
* All methods in MetaDataRef
* `get_inventory()`: returns `InvRef`

### `ItemStackMetaRef`
ItemStack metadata: reference extra data and functionality stored in a stack.
Can be gotten via `item:get_meta()`.

#### Methods
* All methods in MetaDataRef

### `NodeTimerRef`
Node Timers: a high resolution persistent per-node timer.
Can be gotten via `minetest.get_node_timer(pos)`.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -415,6 +415,7 @@ set(common_SRCS
inventory.cpp
inventorymanager.cpp
itemdef.cpp
itemstackmetadata.cpp
light.cpp
log.cpp
map.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/content_cao.cpp
Expand Up @@ -938,7 +938,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr,
if(m_prop.textures.size() >= 1){
infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
IItemDefManager *idef = m_client->idef();
ItemStack item(m_prop.textures[0], 1, 0, "", idef);
ItemStack item(m_prop.textures[0], 1, 0, idef);

m_wield_meshnode = new WieldMeshSceneNode(
smgr->getRootSceneNode(), smgr, -1);
Expand Down
3 changes: 1 addition & 2 deletions src/craftdef.cpp
Expand Up @@ -139,7 +139,7 @@ static std::vector<ItemStack> craftGetItems(
for (std::vector<std::string>::size_type i = 0;
i < items.size(); i++) {
result.push_back(ItemStack(std::string(items[i]), (u16)1,
(u16)0, "", gamedef->getItemDefManager()));
(u16)0, gamedef->getItemDefManager()));
}
return result;
}
Expand Down Expand Up @@ -1126,4 +1126,3 @@ IWritableCraftDefManager* createCraftDefManager()
{
return new CCraftDefManager();
}

88 changes: 12 additions & 76 deletions src/inventory.cpp
Expand Up @@ -45,82 +45,16 @@ static content_t content_translate_from_19_to_internal(content_t c_from)
return c_from;
}

// If the string contains spaces, quotes or control characters, encodes as JSON.
// Else returns the string unmodified.
static std::string serializeJsonStringIfNeeded(const std::string &s)
{
for(size_t i = 0; i < s.size(); ++i)
{
if(s[i] <= 0x1f || s[i] >= 0x7f || s[i] == ' ' || s[i] == '\"')
return serializeJsonString(s);
}
return s;
}

// Parses a string serialized by serializeJsonStringIfNeeded.
static std::string deSerializeJsonStringIfNeeded(std::istream &is)
{
std::ostringstream tmp_os;
bool expect_initial_quote = true;
bool is_json = false;
bool was_backslash = false;
for(;;)
{
char c = is.get();
if(is.eof())
break;
if(expect_initial_quote && c == '"')
{
tmp_os << c;
is_json = true;
}
else if(is_json)
{
tmp_os << c;
if(was_backslash)
was_backslash = false;
else if(c == '\\')
was_backslash = true;
else if(c == '"')
break; // Found end of string
}
else
{
if(c == ' ')
{
// Found end of word
is.unget();
break;
}
else
{
tmp_os << c;
}
}
expect_initial_quote = false;
}
if(is_json)
{
std::istringstream tmp_is(tmp_os.str(), std::ios::binary);
return deSerializeJsonString(tmp_is);
}
else
return tmp_os.str();
}


ItemStack::ItemStack(std::string name_, u16 count_,
u16 wear_, std::string metadata_,
IItemDefManager *itemdef)
ItemStack::ItemStack(const std::string &name_, u16 count_,
u16 wear_, IItemDefManager *itemdef)
{
name = itemdef->getAlias(name_);
count = count_;
wear = wear_;
metadata = metadata_;

if(name.empty() || count == 0)
if (name.empty() || count == 0)
clear();
else if(itemdef->get(name).type == ITEM_TOOL)
else if (itemdef->get(name).type == ITEM_TOOL)
count = 1;
}

Expand All @@ -137,16 +71,18 @@ void ItemStack::serialize(std::ostream &os) const
parts = 2;
if(wear != 0)
parts = 3;
if(metadata != "")
if (!metadata.empty())
parts = 4;

os<<serializeJsonStringIfNeeded(name);
if(parts >= 2)
os<<" "<<count;
if(parts >= 3)
os<<" "<<wear;
if(parts >= 4)
os<<" "<<serializeJsonStringIfNeeded(metadata);
if (parts >= 4) {
os << " ";
metadata.serialize(os);
}
}

void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
Expand Down Expand Up @@ -289,7 +225,7 @@ void ItemStack::deSerialize(std::istream &is, IItemDefManager *itemdef)
wear = stoi(wear_str);

// Read metadata
metadata = deSerializeJsonStringIfNeeded(is);
metadata.deSerialize(is);

// In case fields are added after metadata, skip space here:
//std::getline(is, tmp, ' ');
Expand Down Expand Up @@ -335,7 +271,7 @@ ItemStack ItemStack::addItem(const ItemStack &newitem_,
*this = newitem;
newitem.clear();
}
// If item name or metadata differs, bail out
// If item name or metadata differs, bail out
else if (name != newitem.name
|| metadata != newitem.metadata)
{
Expand Down Expand Up @@ -375,7 +311,7 @@ bool ItemStack::itemFits(const ItemStack &newitem_,
{
newitem.clear();
}
// If item name or metadata differs, bail out
// If item name or metadata differs, bail out
else if (name != newitem.name
|| metadata != newitem.metadata)
{
Expand Down
14 changes: 7 additions & 7 deletions src/inventory.h
Expand Up @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "debug.h"
#include "itemdef.h"
#include "irrlichttypes.h"
#include "itemstackmetadata.h"
#include <istream>
#include <ostream>
#include <string>
Expand All @@ -32,10 +33,10 @@ struct ToolCapabilities;

struct ItemStack
{
ItemStack(): name(""), count(0), wear(0), metadata("") {}
ItemStack(std::string name_, u16 count_,
u16 wear, std::string metadata_,
IItemDefManager *itemdef);
ItemStack(): name(""), count(0), wear(0) {}
ItemStack(const std::string &name_, u16 count_,
u16 wear, IItemDefManager *itemdef);

~ItemStack() {}

// Serialization
Expand All @@ -61,7 +62,7 @@ struct ItemStack
name = "";
count = 0;
wear = 0;
metadata = "";
metadata.clear();
}

void add(u16 n)
Expand Down Expand Up @@ -166,7 +167,7 @@ struct ItemStack
std::string name;
u16 count;
u16 wear;
std::string metadata;
ItemStackMetadata metadata;
};

class InventoryList
Expand Down Expand Up @@ -313,4 +314,3 @@ class Inventory
};

#endif

43 changes: 43 additions & 0 deletions src/itemstackmetadata.cpp
@@ -0,0 +1,43 @@
#include "itemstackmetadata.h"
#include "util/serialize.h"
#include "util/strfnd.h"

#define DESERIALIZE_START '\x01'
#define DESERIALIZE_KV_DELIM '\x02'
#define DESERIALIZE_PAIR_DELIM '\x03'
#define DESERIALIZE_START_STR "\x01"
#define DESERIALIZE_KV_DELIM_STR "\x02"
#define DESERIALIZE_PAIR_DELIM_STR "\x03"

void ItemStackMetadata::serialize(std::ostream &os) const
{
std::ostringstream os2;
os2 << DESERIALIZE_START;
for (StringMap::const_iterator
it = m_stringvars.begin();
it != m_stringvars.end(); ++it) {
os2 << it->first << DESERIALIZE_KV_DELIM
<< it->second << DESERIALIZE_PAIR_DELIM;
}
os << serializeJsonStringIfNeeded(os2.str());
}

void ItemStackMetadata::deSerialize(std::istream &is)
{
std::string in = deSerializeJsonStringIfNeeded(is);

m_stringvars.clear();

if (!in.empty() && in[0] == DESERIALIZE_START) {
Strfnd fnd(in);
fnd.to(1);
while (!fnd.at_end()) {
std::string name = fnd.next(DESERIALIZE_KV_DELIM_STR);
std::string var = fnd.next(DESERIALIZE_PAIR_DELIM_STR);
m_stringvars[name] = var;
}
} else {
// BACKWARDS COMPATIBILITY
m_stringvars[""] = in;
}
}
35 changes: 35 additions & 0 deletions src/itemstackmetadata.h
@@ -0,0 +1,35 @@
/*
Minetest
Copyright (C) 2010-2013 rubenwardy <rubenwardy@gmail.com>
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef ITEMSTACKMETADATA_HEADER
#define ITEMSTACKMETADATA_HEADER

#include "metadata.h"

class Inventory;
class IItemDefManager;

class ItemStackMetadata : public Metadata
{
public:
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
};

#endif

0 comments on commit f2aa2c6

Please sign in to comment.