From f2aa2c6a986dec47856c49ae5f54fbf3c688e027 Mon Sep 17 00:00:00 2001
From: rubenwardy <rubenwardy@gmail.com>
Date: Tue, 31 Jan 2017 19:49:01 +0000
Subject: Add ItemStack key-value meta storage

---
 src/script/lua_api/CMakeLists.txt      |   1 +
 src/script/lua_api/l_env.cpp           |   2 +-
 src/script/lua_api/l_item.cpp          |  38 +++++++++--
 src/script/lua_api/l_item.h            |   5 ++
 src/script/lua_api/l_itemstackmeta.cpp | 115 +++++++++++++++++++++++++++++++++
 src/script/lua_api/l_itemstackmeta.h   |  59 +++++++++++++++++
 6 files changed, 215 insertions(+), 5 deletions(-)
 create mode 100644 src/script/lua_api/l_itemstackmeta.cpp
 create mode 100644 src/script/lua_api/l_itemstackmeta.h

(limited to 'src/script/lua_api')

diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt
index efccce515..070234eba 100644
--- a/src/script/lua_api/CMakeLists.txt
+++ b/src/script/lua_api/CMakeLists.txt
@@ -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
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 3d9db7917..2722e35a4 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.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;
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index ff0baea14..f0293bed8 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -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),
diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h
index be919b701..1ba5d79e0 100644
--- a/src/script/lua_api/l_item.h
+++ b/src/script/lua_api/l_item.h
@@ -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);
 
diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp
new file mode 100644
index 000000000..304a7cdf3
--- /dev/null
+++ b/src/script/lua_api/l_itemstackmeta.cpp
@@ -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}
+};
diff --git a/src/script/lua_api/l_itemstackmeta.h b/src/script/lua_api/l_itemstackmeta.h
new file mode 100644
index 000000000..6f9b2016c
--- /dev/null
+++ b/src/script/lua_api/l_itemstackmeta.h
@@ -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
-- 
cgit v1.2.3