Add ItemStack key-value meta storage

This commit is contained in:
rubenwardy 2017-01-31 19:49:01 +00:00
parent c2e7b1f579
commit f2aa2c6a98
21 changed files with 459 additions and 123 deletions

@ -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 \
@ -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 \

@ -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:
@ -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
@ -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
@ -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)`
@ -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)`.

@ -415,6 +415,7 @@ set(common_SRCS
inventory.cpp
inventorymanager.cpp
itemdef.cpp
itemstackmetadata.cpp
light.cpp
log.cpp
map.cpp

@ -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);

@ -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;
}
@ -1126,4 +1126,3 @@ IWritableCraftDefManager* createCraftDefManager()
{
return new CCraftDefManager();
}

@ -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;
}
@ -137,7 +71,7 @@ void ItemStack::serialize(std::ostream &os) const
parts = 2;
if(wear != 0)
parts = 3;
if(metadata != "")
if (!metadata.empty())
parts = 4;
os<<serializeJsonStringIfNeeded(name);
@ -145,8 +79,10 @@ void ItemStack::serialize(std::ostream &os) const
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)
@ -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, ' ');
@ -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)
{
@ -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)
{

@ -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>
@ -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
@ -61,7 +62,7 @@ struct ItemStack
name = "";
count = 0;
wear = 0;
metadata = "";
metadata.clear();
}
void add(u16 n)
@ -166,7 +167,7 @@ struct ItemStack
std::string name;
u16 count;
u16 wear;
std::string metadata;
ItemStackMetadata metadata;
};
class InventoryList
@ -313,4 +314,3 @@ private:
};
#endif

43
src/itemstackmetadata.cpp Normal file

@ -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
src/itemstackmetadata.h Normal file

@ -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

@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gamedef.h"
#include "log.h"
#include <sstream>
#include "constants.h" // MAP_BLOCKSIZE
#include <sstream>
/*
Metadata

@ -25,35 +25,37 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <vector>
#include "util/string.h"
/*
NodeMetadata stores arbitary amounts of data for special blocks.
Used for furnaces, chests and signs.
There are two interaction methods: inventory menu and text input.
Only one can be used for a single metadata, thus only inventory OR
text input should exist in a metadata.
*/
class Inventory;
class IItemDefManager;
class Metadata
{
public:
void clear();
bool empty() const;
virtual ~Metadata() {}
// Generic key/value store
virtual void clear();
virtual bool empty() const;
bool operator==(const Metadata &other) const;
inline bool operator!=(const Metadata &other) const
{
return !(*this == other);
}
//
// Key-value related
//
size_t size() const;
bool contains(const std::string &name) const;
const std::string &getString(const std::string &name, u16 recursion = 0) const;
void setString(const std::string &name, const std::string &var);
// Support variable names in values
const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
const StringMap &getStrings() const
{
return m_stringvars;
}
private:
// Add support for variable names in values
const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
protected:
StringMap m_stringvars;
};
#endif

@ -824,11 +824,32 @@ ItemStack read_item(lua_State* L, int index,Server* srv)
std::string name = getstringfield_default(L, index, "name", "");
int count = getintfield_default(L, index, "count", 1);
int wear = getintfield_default(L, index, "wear", 0);
std::string metadata = getstringfield_default(L, index, "metadata", "");
return ItemStack(name, count, wear, metadata, idef);
}
else
{
ItemStack istack(name, count, wear, idef);
lua_getfield(L, index, "metadata");
// Support old metadata format by checking type
int fieldstable = lua_gettop(L);
if (lua_istable(L, fieldstable)) {
lua_pushnil(L);
while (lua_next(L, fieldstable) != 0) {
// key at index -2 and value at index -1
std::string key = lua_tostring(L, -2);
size_t value_len;
const char *value_cs = lua_tolstring(L, -1, &value_len);
std::string value(value_cs, value_len);
istack.metadata.setString(name, value);
lua_pop(L, 1); // removes value, keeps key for next iteration
}
} else {
// BACKWARDS COMPATIBLITY
std::string value = getstringfield_default(L, index, "metadata", "");
istack.metadata.setString("", value);
}
return istack;
} else {
throw LuaError("Expecting itemstack, itemstring, table or nil");
}
}

@ -5,6 +5,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_env.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_item.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_itemstackmeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mapgen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_metadata.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp

@ -284,7 +284,7 @@ int ModApiEnvMod::l_place_node(lua_State *L)
return 1;
}
// Create item to place
ItemStack item(ndef->get(n).name, 1, 0, "", idef);
ItemStack item(ndef->get(n).name, 1, 0, idef);
// Make pointed position
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "lua_api/l_item.h"
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
@ -137,16 +138,28 @@ int LuaItemStack::l_set_wear(lua_State *L)
return 1;
}
// get_meta(self) -> string
int LuaItemStack::l_get_meta(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStackMetaRef::create(L, &o->m_stack);
return 1;
}
// DEPRECATED
// get_metadata(self) -> string
int LuaItemStack::l_get_metadata(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
const std::string &value = item.metadata.getString("");
lua_pushlstring(L, value.c_str(), value.size());
return 1;
}
// DEPRECATED
// set_metadata(self, string)
int LuaItemStack::l_set_metadata(lua_State *L)
{
@ -156,7 +169,7 @@ int LuaItemStack::l_set_metadata(lua_State *L)
size_t len = 0;
const char *ptr = luaL_checklstring(L, 2, &len);
item.metadata.assign(ptr, len);
item.metadata.setString("", std::string(ptr, len));
lua_pushboolean(L, true);
return 1;
@ -211,8 +224,24 @@ int LuaItemStack::l_to_table(lua_State *L)
lua_setfield(L, -2, "count");
lua_pushinteger(L, item.wear);
lua_setfield(L, -2, "wear");
lua_pushlstring(L, item.metadata.c_str(), item.metadata.size());
lua_setfield(L, -2, "metadata");
if (item.metadata.size() == 1 && item.metadata.contains("")) {
const std::string &value = item.metadata.getString("");
lua_pushlstring(L, value.c_str(), value.size());
lua_setfield(L, -2, "metadata");
} else {
lua_newtable(L);
const StringMap &fields = item.metadata.getStrings();
for (StringMap::const_iterator it = fields.begin();
it != fields.end(); ++it) {
const std::string &name = it->first;
const std::string &value = it->second;
lua_pushlstring(L, name.c_str(), name.size());
lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3);
}
lua_setfield(L, -2, "metadata");
}
}
return 1;
}
@ -443,6 +472,7 @@ const luaL_reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, set_count),
luamethod(LuaItemStack, get_wear),
luamethod(LuaItemStack, set_wear),
luamethod(LuaItemStack, get_meta),
luamethod(LuaItemStack, get_metadata),
luamethod(LuaItemStack, set_metadata),
luamethod(LuaItemStack, clear),

@ -56,9 +56,14 @@ private:
// set_wear(self, number)
static int l_set_wear(lua_State *L);
// get_meta(self) -> string
static int l_get_meta(lua_State *L);
// DEPRECATED
// get_metadata(self) -> string
static int l_get_metadata(lua_State *L);
// DEPRECATED
// set_metadata(self, string)
static int l_set_metadata(lua_State *L);

@ -0,0 +1,115 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@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.
*/
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_internal.h"
#include "common/c_content.h"
/*
NodeMetaRef
*/
ItemStackMetaRef* ItemStackMetaRef::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
void *ud = luaL_checkudata(L, narg, className);
if (!ud)
luaL_typerror(L, narg, className);
return *(ItemStackMetaRef**)ud; // unbox pointer
}
Metadata* ItemStackMetaRef::getmeta(bool auto_create)
{
return &istack->metadata;
}
void ItemStackMetaRef::clearMeta()
{
istack->metadata.clear();
}
void ItemStackMetaRef::reportMetadataChange()
{
// TODO
}
// Exported functions
// garbage collector
int ItemStackMetaRef::gc_object(lua_State *L) {
ItemStackMetaRef *o = *(ItemStackMetaRef **)(lua_touserdata(L, 1));
delete o;
return 0;
}
// Creates an NodeMetaRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
void ItemStackMetaRef::create(lua_State *L, ItemStack *istack)
{
ItemStackMetaRef *o = new ItemStackMetaRef(istack);
//infostream<<"NodeMetaRef::create: o="<<o<<std::endl;
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
void ItemStackMetaRef::Register(lua_State *L)
{
lua_newtable(L);
int methodtable = lua_gettop(L);
luaL_newmetatable(L, className);
int metatable = lua_gettop(L);
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
lua_pushliteral(L, "metadata_class");
lua_pushlstring(L, className, strlen(className));
lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable);
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
lua_pop(L, 1); // drop metatable
luaL_openlib(L, 0, methods, 0); // fill methodtable
lua_pop(L, 1); // drop methodtable
// Cannot be created from Lua
//lua_register(L, className, create_object);
}
const char ItemStackMetaRef::className[] = "ItemStackMetaRef";
const luaL_reg ItemStackMetaRef::methods[] = {
luamethod(MetaDataRef, get_string),
luamethod(MetaDataRef, set_string),
luamethod(MetaDataRef, get_int),
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
{0,0}
};

@ -0,0 +1,59 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@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 L_ITEMSTACKMETA_H_
#define L_ITEMSTACKMETA_H_
#include "lua_api/l_base.h"
#include "lua_api/l_metadata.h"
#include "irrlichttypes_bloated.h"
#include "inventory.h"
class ItemStackMetaRef : public MetaDataRef
{
private:
ItemStack *istack;
static const char className[];
static const luaL_reg methods[];
static ItemStackMetaRef *checkobject(lua_State *L, int narg);
virtual Metadata* getmeta(bool auto_create);
virtual void clearMeta();
virtual void reportMetadataChange();
// Exported functions
// garbage collector
static int gc_object(lua_State *L);
public:
ItemStackMetaRef(ItemStack *istack): istack(istack) {}
~ItemStackMetaRef() {}
// Creates an ItemStackMetaRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, ItemStack *istack);
static void Register(lua_State *L);
};
#endif

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_env.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "lua_api/l_itemstackmeta.h"
#include "lua_api/l_mapgen.h"
#include "lua_api/l_nodemeta.h"
#include "lua_api/l_nodetimer.h"
@ -94,6 +95,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
// Register reference classes (userdata)
InvRef::Register(L);
ItemStackMetaRef::Register(L);
LuaAreaStore::Register(L);
LuaItemStack::Register(L);
LuaPerlinNoise::Register(L);

@ -354,6 +354,55 @@ std::string deSerializeJsonString(std::istream &is)
return os.str();
}
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;
}
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();
}
////
//// String/Struct conversions
////

@ -405,6 +405,13 @@ std::string serializeJsonString(const std::string &plain);
// Reads a string encoded in JSON format
std::string deSerializeJsonString(std::istream &is);
// If the string contains spaces, quotes or control characters, encodes as JSON.
// Else returns the string unmodified.
std::string serializeJsonStringIfNeeded(const std::string &s);
// Parses a string serialized by serializeJsonStringIfNeeded.
std::string deSerializeJsonStringIfNeeded(std::istream &is);
// Creates a string consisting of the hexadecimal representation of `data`
std::string serializeHexString(const std::string &data, bool insert_spaces=false);