*/
#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"
-#include "cpp_api/scriptapi.h"
+#include "common/c_packer.h"
+#include "itemdef.h"
+#include "nodedef.h"
#include "server.h"
-#include "common/c_internal.h"
+#include "inventory.h"
+#include "log.h"
+#include "script/cpp_api/s_base.h"
+#ifndef SERVER
+#include "client/client.h"
+#include "client/renderingengine.h"
+#include "client/shader.h"
+#endif
// garbage collector
int LuaItemStack::gc_object(lua_State *L)
return 0;
}
+// __tostring metamethod
+int LuaItemStack::mt_tostring(lua_State *L)
+{
+ LuaItemStack *o = checkobject(L, 1);
+ std::string itemstring = o->m_stack.getItemString(false);
+ lua_pushfstring(L, "ItemStack(\"%s\")", itemstring.c_str());
+ return 1;
+}
+
// is_empty(self) -> true/false
int LuaItemStack::l_is_empty(lua_State *L)
{
return 1;
}
+// set_name(self, name)
+int LuaItemStack::l_set_name(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+
+ bool status = true;
+ item.name = luaL_checkstring(L, 2);
+ if (item.name.empty() || item.empty()) {
+ item.clear();
+ status = false;
+ }
+
+ lua_pushboolean(L, status);
+ return 1;
+}
+
// get_count(self) -> number
int LuaItemStack::l_get_count(lua_State *L)
{
return 1;
}
+// set_count(self, number)
+int LuaItemStack::l_set_count(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+
+ bool status;
+ lua_Integer count = luaL_checkinteger(L, 2);
+ if (count > 0 && count <= 65535) {
+ item.count = count;
+ status = true;
+ } else {
+ item.clear();
+ status = false;
+ }
+
+ lua_pushboolean(L, status);
+ return 1;
+}
+
// get_wear(self) -> number
int LuaItemStack::l_get_wear(lua_State *L)
{
return 1;
}
+// set_wear(self, number)
+int LuaItemStack::l_set_wear(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+
+ bool status;
+ lua_Integer wear = luaL_checkinteger(L, 2);
+ if (wear <= 65535) {
+ item.wear = wear;
+ status = true;
+ } else {
+ item.clear();
+ status = false;
+ }
+
+ lua_pushboolean(L, status);
+ 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)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ ItemStack &item = o->m_stack;
+
+ size_t len = 0;
+ const char *ptr = luaL_checklstring(L, 2, &len);
+ item.metadata.setString("", std::string(ptr, len));
+
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// get_description(self)
+int LuaItemStack::l_get_description(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ std::string desc = o->m_stack.getDescription(getGameDef(L)->idef());
+ lua_pushstring(L, desc.c_str());
+ return 1;
+}
+
+// get_short_description(self)
+int LuaItemStack::l_get_short_description(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ LuaItemStack *o = checkobject(L, 1);
+ std::string desc = o->m_stack.getShortDescription(getGameDef(L)->idef());
+ lua_pushstring(L, desc.c_str());
return 1;
}
{
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
- o->m_stack = read_item(L,2,STACK_TO_SERVER(L));
+ o->m_stack = read_item(L, 2, getGameDef(L)->idef());
lua_pushboolean(L, true);
return 1;
}
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());
+
+ const std::string &metadata_str = item.metadata.getString("");
+ lua_pushlstring(L, metadata_str.c_str(), metadata_str.size());
lua_setfield(L, -2, "metadata");
+
+ lua_newtable(L);
+ const StringMap &fields = item.metadata.getStrings();
+ for (const auto &field : fields) {
+ const std::string &name = field.first;
+ if (name.empty())
+ continue;
+ const std::string &value = field.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, "meta");
}
return 1;
}
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.getStackMax(STACK_TO_SERVER(L)->idef()));
+ lua_pushinteger(L, item.getStackMax(getGameDef(L)->idef()));
return 1;
}
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- lua_pushinteger(L, item.freeSpace(STACK_TO_SERVER(L)->idef()));
+ lua_pushinteger(L, item.freeSpace(getGameDef(L)->idef()));
return 1;
}
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- bool is_known = item.isKnown(STACK_TO_SERVER(L)->idef());
+ bool is_known = item.isKnown(getGameDef(L)->idef());
lua_pushboolean(L, is_known);
return 1;
}
// get_definition(self) -> table
-// Returns the item definition table from minetest.registered_items,
+// Returns the item definition table from registered_items,
// or a fallback one (name="unknown")
int LuaItemStack::l_get_definition(lua_State *L)
{
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- // Get minetest.registered_items[name]
- lua_getglobal(L, "minetest");
+ // Get registered_items[name]
+ lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_items");
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, item.name.c_str());
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
const ToolCapabilities &prop =
- item.getToolCapabilities(STACK_TO_SERVER(L)->idef());
+ item.getToolCapabilities(getGameDef(L)->idef());
push_tool_capabilities(L, prop);
return 1;
}
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
int amount = lua_tointeger(L, 2);
- bool result = item.addWear(amount, STACK_TO_SERVER(L)->idef());
+ bool result = item.addWear(amount, getGameDef(L)->idef());
lua_pushboolean(L, result);
return 1;
}
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- ItemStack newitem = read_item(L,-1, STACK_TO_SERVER(L));
- ItemStack leftover = item.addItem(newitem, STACK_TO_SERVER(L)->idef());
+ ItemStack newitem = read_item(L, -1, getGameDef(L)->idef());
+ ItemStack leftover = item.addItem(newitem, getGameDef(L)->idef());
create(L, leftover);
return 1;
}
NO_MAP_LOCK_REQUIRED;
LuaItemStack *o = checkobject(L, 1);
ItemStack &item = o->m_stack;
- ItemStack newitem = read_item(L, 2 ,STACK_TO_SERVER(L));
+ ItemStack newitem = read_item(L, 2, getGameDef(L)->idef());
ItemStack restitem;
- bool fits = item.itemFits(newitem, &restitem, STACK_TO_SERVER(L)->idef());
+ bool fits = item.itemFits(newitem, &restitem, getGameDef(L)->idef());
lua_pushboolean(L, fits); // first return value
create(L, restitem); // second return value
return 2;
{
}
-LuaItemStack::~LuaItemStack()
-{
-}
-
const ItemStack& LuaItemStack::getItem() const
{
return m_stack;
int LuaItemStack::create_object(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- ItemStack item = read_item(L,1,STACK_TO_SERVER(L));
+ ItemStack item;
+ if (!lua_isnone(L, 1))
+ item = read_item(L, 1, getGameDef(L)->idef());
LuaItemStack *o = new LuaItemStack(item);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
return 1;
}
+
// Not callable from Lua
int LuaItemStack::create(lua_State *L, const ItemStack &item)
{
return 1;
}
-LuaItemStack* LuaItemStack::checkobject(lua_State *L, int narg)
+LuaItemStack *LuaItemStack::checkobject(lua_State *L, int narg)
+{
+ return *(LuaItemStack **)luaL_checkudata(L, narg, className);
+}
+
+void *LuaItemStack::packIn(lua_State *L, int idx)
+{
+ LuaItemStack *o = checkobject(L, idx);
+ return new ItemStack(o->getItem());
+}
+
+void LuaItemStack::packOut(lua_State *L, void *ptr)
{
- luaL_checktype(L, narg, LUA_TUSERDATA);
- void *ud = luaL_checkudata(L, narg, className);
- if(!ud) luaL_typerror(L, narg, className);
- return *(LuaItemStack**)ud; // unbox pointer
+ ItemStack *stack = reinterpret_cast<ItemStack*>(ptr);
+ if (L)
+ create(L, *stack);
+ delete stack;
}
void LuaItemStack::Register(lua_State *L)
luaL_newmetatable(L, className);
int metatable = lua_gettop(L);
+ // hide metatable from Lua getmetatable()
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+ lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
+ lua_pushliteral(L, "__tostring");
+ lua_pushcfunction(L, mt_tostring);
+ lua_settable(L, metatable);
+
lua_pop(L, 1); // drop metatable
- luaL_openlib(L, 0, methods, 0); // fill methodtable
+ luaL_register(L, nullptr, methods); // fill methodtable
lua_pop(L, 1); // drop methodtable
- // Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil))
+ // Can be created from Lua (ItemStack(itemstack or itemstring or table or nil))
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
const char LuaItemStack::className[] = "ItemStack";
-const luaL_reg LuaItemStack::methods[] = {
+const luaL_Reg LuaItemStack::methods[] = {
luamethod(LuaItemStack, is_empty),
luamethod(LuaItemStack, get_name),
+ luamethod(LuaItemStack, set_name),
luamethod(LuaItemStack, get_count),
+ 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, get_description),
+ luamethod(LuaItemStack, get_short_description),
luamethod(LuaItemStack, clear),
luamethod(LuaItemStack, replace),
luamethod(LuaItemStack, to_string),
{0,0}
};
-ModApiItemMod::ModApiItemMod() {
-}
-
/*
ItemDefinition
*/
luaL_checktype(L, 1, LUA_TTABLE);
int table = 1;
- ScriptApi* scriptIface = get_scriptapi(L);
-
// Get the writable item and node definition managers from the server
IWritableItemDefManager *idef =
- scriptIface->getServer()->getWritableItemDefManager();
- IWritableNodeDefManager *ndef =
- scriptIface->getServer()->getWritableNodeDefManager();
+ getGameDef(L)->getWritableItemDefManager();
+ NodeDefManager *ndef =
+ getGameDef(L)->getWritableNodeDefManager();
// Check if name is defined
std::string name;
lua_getfield(L, table, "name");
if(lua_isstring(L, -1)){
- name = lua_tostring(L, -1);
- verbosestream<<"register_item_raw: "<<name<<std::endl;
+ name = readParam<std::string>(L, -1);
} else {
- throw LuaError(L, "register_item_raw: name is not defined or not a string");
+ throw LuaError("register_item_raw: name is not defined or not a string");
}
// Check if on_use is defined
def.node_placement_prediction = "__default";
// Read the item definition
- def = read_item_definition(L, table, def);
+ read_item_definition(L, table, def, def);
// Default to having client-side placement prediction for nodes
// ("" in item definition sets it off)
idef->registerItem(def);
// Read the node definition (content features) and register it
- if(def.type == ITEM_NODE)
- {
- ContentFeatures f = read_content_features(L, table);
- ndef->set(f.name, f);
+ if (def.type == ITEM_NODE) {
+ ContentFeatures f;
+ read_content_features(L, f, table);
+ // when a mod reregisters ignore, only texture changes and such should
+ // be done
+ if (f.name == "ignore")
+ return 0;
+ // This would break everything
+ if (f.name.empty())
+ throw LuaError("Cannot register node with empty name");
+
+ content_t id = ndef->set(f.name, f);
+
+ if (id > MAX_REGISTERED_CONTENT) {
+ throw LuaError("Number of registerable nodes ("
+ + itos(MAX_REGISTERED_CONTENT+1)
+ + ") exceeded (" + name + ")");
+ }
+
+ }
+
+ return 0; /* number of results */
+}
+
+// unregister_item(name)
+int ModApiItemMod::l_unregister_item_raw(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ std::string name = luaL_checkstring(L, 1);
+
+ IWritableItemDefManager *idef =
+ getGameDef(L)->getWritableItemDefManager();
+
+ // Unregister the node
+ if (idef->get(name).type == ITEM_NODE) {
+ NodeDefManager *ndef =
+ getGameDef(L)->getWritableNodeDefManager();
+ ndef->removeNode(name);
}
+ idef->unregisterItem(name);
+
return 0; /* number of results */
}
// Get the writable item definition manager from the server
IWritableItemDefManager *idef =
- STACK_TO_SERVER(L)->getWritableItemDefManager();
+ getGameDef(L)->getWritableItemDefManager();
idef->registerAlias(name, convert_to);
return 0; /* number of results */
}
-bool ModApiItemMod::Initialize(lua_State *L,int top) {
+// get_content_id(name)
+int ModApiItemMod::l_get_content_id(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ std::string name = luaL_checkstring(L, 1);
+
+ const IItemDefManager *idef = getGameDef(L)->idef();
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
+
+ // If this is called at mod load time, NodeDefManager isn't aware of
+ // aliases yet, so we need to handle them manually
+ std::string alias_name = idef->getAlias(name);
+
+ content_t content_id;
+ if (alias_name != name) {
+ if (!ndef->getId(alias_name, content_id))
+ throw LuaError("Unknown node: " + alias_name +
+ " (from alias " + name + ")");
+ } else if (!ndef->getId(name, content_id)) {
+ throw LuaError("Unknown node: " + name);
+ }
+
+ lua_pushinteger(L, content_id);
+ return 1; /* number of results */
+}
- bool retval = true;
+// get_name_from_content_id(name)
+int ModApiItemMod::l_get_name_from_content_id(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ content_t c = luaL_checkint(L, 1);
- retval &= API_FCT(register_item_raw);
- retval &= API_FCT(register_alias_raw);
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
+ const char *name = ndef->get(c).name.c_str();
- LuaItemStack::Register(L);
+ lua_pushstring(L, name);
+ return 1; /* number of results */
+}
- return retval;
+void ModApiItemMod::Initialize(lua_State *L, int top)
+{
+ API_FCT(register_item_raw);
+ API_FCT(unregister_item_raw);
+ API_FCT(register_alias_raw);
+ API_FCT(get_content_id);
+ API_FCT(get_name_from_content_id);
}
-ModApiItemMod modapi_item_prototyp;
+void ModApiItemMod::InitializeAsync(lua_State *L, int top)
+{
+ // all read-only functions
+ API_FCT(get_content_id);
+ API_FCT(get_name_from_content_id);
+}