From 6a76c226e10e92c3e3339096f07f8ab065e2098b Mon Sep 17 00:00:00 2001 From: Kahrl Date: Thu, 12 Jan 2012 06:10:39 +0100 Subject: The huge item definition and item namespace unification patch (itemdef), see http://c55.me/minetest/wiki/doku.php?id=changes:itemdef --- src/scriptapi.cpp | 2859 ++++++++++++++++++++++++++--------------------------- 1 file changed, 1429 insertions(+), 1430 deletions(-) (limited to 'src/scriptapi.cpp') diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index b617626a0..187d1a894 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -36,10 +36,9 @@ extern "C" { //#include "luna.h" #include "luaentity_common.h" #include "content_sao.h" // For LuaEntitySAO -#include "tooldef.h" +#include "itemdef.h" #include "nodedef.h" #include "craftdef.h" -#include "craftitemdef.h" #include "main.h" // For g_settings #include "settings.h" // For accessing g_settings #include "nodemetadata.h" @@ -127,243 +126,55 @@ public: } }; -std::string get_current_modname(lua_State *L) -{ - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname"); - std::string modname = ""; - if(lua_type(L, -1) == LUA_TSTRING) - modname = lua_tostring(L, -1); - lua_pop(L, 1); - return modname; -} - -void check_modname_prefix(lua_State *L, std::string &name) -{ - if(name.size() == 0) - throw LuaError(L, std::string("Name is empty")); - - if(name[0] == ':'){ - name = name.substr(1); - return; - } - - std::string modname = get_current_modname(L); - assert(modname != ""); - - // For __builtin, anything goes - if(modname == "__builtin") - return; - - if(name.substr(0, modname.size()+1) != modname + ":") - throw LuaError(L, std::string("Name \"")+name - +"\" does not follow naming conventions: " - +"\"modname:\" or \":\" prefix required)"); - - std::string subname = name.substr(modname.size()+1); - if(!string_allowed(subname, "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")) - throw LuaError(L, std::string("Name \"")+name - +"\" does not follow naming conventions: " - +"\"contains unallowed characters"); -} - -static void push_v3f(lua_State *L, v3f p) -{ - lua_newtable(L); - lua_pushnumber(L, p.X); - lua_setfield(L, -2, "x"); - lua_pushnumber(L, p.Y); - lua_setfield(L, -2, "y"); - lua_pushnumber(L, p.Z); - lua_setfield(L, -2, "z"); -} - -static v2s16 read_v2s16(lua_State *L, int index) -{ - v2s16 p; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "x"); - p.X = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "y"); - p.Y = lua_tonumber(L, -1); - lua_pop(L, 1); - return p; -} - -static v2f read_v2f(lua_State *L, int index) -{ - v2f p; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "x"); - p.X = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "y"); - p.Y = lua_tonumber(L, -1); - lua_pop(L, 1); - return p; -} +/* + Getters for stuff in main tables +*/ static Server* get_server(lua_State *L) { // Get server from registry lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - return (Server*)lua_touserdata(L, -1); + Server *server = (Server*)lua_touserdata(L, -1); + lua_pop(L, 1); + return server; } static ServerEnvironment* get_env(lua_State *L) { // Get environment from registry lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env"); - return (ServerEnvironment*)lua_touserdata(L, -1); -} - -static v3f read_v3f(lua_State *L, int index) -{ - v3f pos; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "x"); - pos.X = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "y"); - pos.Y = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "z"); - pos.Z = lua_tonumber(L, -1); - lua_pop(L, 1); - return pos; -} - -static v3f check_v3f(lua_State *L, int index) -{ - v3f pos; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "x"); - pos.X = luaL_checknumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "y"); - pos.Y = luaL_checknumber(L, -1); + ServerEnvironment *env = (ServerEnvironment*)lua_touserdata(L, -1); lua_pop(L, 1); - lua_getfield(L, index, "z"); - pos.Z = luaL_checknumber(L, -1); - lua_pop(L, 1); - return pos; -} - -static void pushFloatPos(lua_State *L, v3f p) -{ - p /= BS; - push_v3f(L, p); -} - -static v3f checkFloatPos(lua_State *L, int index) -{ - return check_v3f(L, index) * BS; -} - -static void push_v3s16(lua_State *L, v3s16 p) -{ - lua_newtable(L); - lua_pushnumber(L, p.X); - lua_setfield(L, -2, "x"); - lua_pushnumber(L, p.Y); - lua_setfield(L, -2, "y"); - lua_pushnumber(L, p.Z); - lua_setfield(L, -2, "z"); -} - -static v3s16 read_v3s16(lua_State *L, int index) -{ - // Correct rounding at <0 - v3f pf = read_v3f(L, index); - return floatToInt(pf, 1.0); -} - -static v3s16 check_v3s16(lua_State *L, int index) -{ - // Correct rounding at <0 - v3f pf = check_v3f(L, index); - return floatToInt(pf, 1.0); -} - -static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef) -{ - lua_newtable(L); - lua_pushstring(L, ndef->get(n).name.c_str()); - lua_setfield(L, -2, "name"); - lua_pushnumber(L, n.getParam1()); - lua_setfield(L, -2, "param1"); - lua_pushnumber(L, n.getParam2()); - lua_setfield(L, -2, "param2"); + return env; } -static MapNode readnode(lua_State *L, int index, INodeDefManager *ndef) +static void objectref_get(lua_State *L, u16 id) { - lua_getfield(L, index, "name"); - const char *name = luaL_checkstring(L, -1); - lua_pop(L, 1); - u8 param1; - lua_getfield(L, index, "param1"); - if(lua_isnil(L, -1)) - param1 = 0; - else - param1 = lua_tonumber(L, -1); - lua_pop(L, 1); - u8 param2; - lua_getfield(L, index, "param2"); - if(lua_isnil(L, -1)) - param2 = 0; - else - param2 = lua_tonumber(L, -1); - lua_pop(L, 1); - return MapNode(ndef, name, param1, param2); + // Get minetest.object_refs[i] + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "object_refs"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_pushnumber(L, id); + lua_gettable(L, -2); + lua_remove(L, -2); // object_refs + lua_remove(L, -2); // minetest } -static video::SColor readARGB8(lua_State *L, int index) +static void luaentity_get(lua_State *L, u16 id) { - video::SColor color; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "a"); - if(lua_isnumber(L, -1)) - color.setAlpha(lua_tonumber(L, -1)); - lua_pop(L, 1); - lua_getfield(L, index, "r"); - color.setRed(lua_tonumber(L, -1)); - lua_pop(L, 1); - lua_getfield(L, index, "g"); - color.setGreen(lua_tonumber(L, -1)); - lua_pop(L, 1); - lua_getfield(L, index, "b"); - color.setBlue(lua_tonumber(L, -1)); - lua_pop(L, 1); - return color; + // Get minetest.luaentities[i] + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "luaentities"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_pushnumber(L, id); + lua_gettable(L, -2); + lua_remove(L, -2); // luaentities + lua_remove(L, -2); // minetest } -static core::aabbox3d read_aabbox3df32(lua_State *L, int index, f32 scale) -{ - core::aabbox3d box; - if(lua_istable(L, -1)){ - lua_rawgeti(L, -1, 1); - box.MinEdge.X = lua_tonumber(L, -1) * scale; - lua_pop(L, 1); - lua_rawgeti(L, -1, 2); - box.MinEdge.Y = lua_tonumber(L, -1) * scale; - lua_pop(L, 1); - lua_rawgeti(L, -1, 3); - box.MinEdge.Z = lua_tonumber(L, -1) * scale; - lua_pop(L, 1); - lua_rawgeti(L, -1, 4); - box.MaxEdge.X = lua_tonumber(L, -1) * scale; - lua_pop(L, 1); - lua_rawgeti(L, -1, 5); - box.MaxEdge.Y = lua_tonumber(L, -1) * scale; - lua_pop(L, 1); - lua_rawgeti(L, -1, 6); - box.MaxEdge.Z = lua_tonumber(L, -1) * scale; - lua_pop(L, 1); - } - return box; -} +/* + Table field getters +*/ static bool getstringfield(lua_State *L, int table, const char *fieldname, std::string &result) @@ -371,7 +182,9 @@ static bool getstringfield(lua_State *L, int table, lua_getfield(L, table, fieldname); bool got = false; if(lua_isstring(L, -1)){ - result = lua_tostring(L, -1); + size_t len = 0; + const char *ptr = lua_tolstring(L, -1, &len); + result.assign(ptr, len); got = true; } lua_pop(L, 1); @@ -442,13 +255,13 @@ static int getintfield_default(lua_State *L, int table, return result; } -/*static float getfloatfield_default(lua_State *L, int table, +static float getfloatfield_default(lua_State *L, int table, const char *fieldname, float default_) { float result = default_; getfloatfield(L, table, fieldname, result); return result; -}*/ +} static bool getboolfield_default(lua_State *L, int table, const char *fieldname, bool default_) @@ -523,216 +336,19 @@ static void warn_if_field_exists(lua_State *L, int table, } /* - Inventory stuff + EnumString definitions */ -static void inventory_set_list_from_lua(Inventory *inv, const char *name, - lua_State *L, int tableindex, IGameDef *gamedef, int forcesize=-1) +struct EnumString es_ItemType[] = { - if(tableindex < 0) - tableindex = lua_gettop(L) + 1 + tableindex; - // If nil, delete list - if(lua_isnil(L, tableindex)){ - inv->deleteList(name); - return; - } - // Otherwise set list - std::list items; - luaL_checktype(L, tableindex, LUA_TTABLE); - int table = tableindex; - lua_pushnil(L); - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - std::string itemstring = luaL_checkstring(L, -1); - items.push_back(itemstring); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - int listsize = (forcesize != -1) ? forcesize : items.size(); - InventoryList *invlist = inv->addList(name, listsize); - int index = 0; - for(std::list::const_iterator - i = items.begin(); i != items.end(); i++){ - if(forcesize != -1 && index == forcesize) - break; - const std::string &itemstring = *i; - InventoryItem *newitem = NULL; - if(itemstring != "") - newitem = InventoryItem::deSerialize(itemstring, - gamedef); - InventoryItem *olditem = invlist->changeItem(index, newitem); - delete olditem; - index++; - } - while(forcesize != -1 && index < forcesize){ - InventoryItem *olditem = invlist->changeItem(index, NULL); - delete olditem; - index++; - } -} + {ITEM_NONE, "none"}, + {ITEM_NODE, "node"}, + {ITEM_CRAFT, "craft"}, + {ITEM_TOOL, "tool"}, + {0, NULL}, +}; -static void inventory_get_list_to_lua(Inventory *inv, const char *name, - lua_State *L) -{ - InventoryList *invlist = inv->getList(name); - if(invlist == NULL){ - lua_pushnil(L); - return; - } - // Get the table insert function - lua_getglobal(L, "table"); - lua_getfield(L, -1, "insert"); - int table_insert = lua_gettop(L); - // Create and fill table - lua_newtable(L); - int table = lua_gettop(L); - for(u32 i=0; igetSize(); i++){ - InventoryItem *item = invlist->getItem(i); - lua_pushvalue(L, table_insert); - lua_pushvalue(L, table); - if(item == NULL){ - lua_pushstring(L, ""); - } else { - lua_pushstring(L, item->getItemString().c_str()); - } - if(lua_pcall(L, 2, 0, 0)) - script_error(L, "error: %s", lua_tostring(L, -1)); - } -} - -static void push_stack_item(lua_State *L, InventoryItem *item0) -{ - if(item0 == NULL){ - lua_pushnil(L); - } - else if(std::string("MaterialItem") == item0->getName()){ - MaterialItem *item = (MaterialItem*)item0; - lua_newtable(L); - lua_pushstring(L, "node"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, item->getNodeName().c_str()); - lua_setfield(L, -2, "name"); - } - else if(std::string("CraftItem") == item0->getName()){ - CraftItem *item = (CraftItem*)item0; - lua_newtable(L); - lua_pushstring(L, "craft"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, item->getSubName().c_str()); - lua_setfield(L, -2, "name"); - } - else if(std::string("ToolItem") == item0->getName()){ - ToolItem *item = (ToolItem*)item0; - lua_newtable(L); - lua_pushstring(L, "tool"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, item->getToolName().c_str()); - lua_setfield(L, -2, "name"); - lua_pushstring(L, itos(item->getWear()).c_str()); - lua_setfield(L, -2, "wear"); - } - else{ - errorstream<<"push_stack_item: Unknown item name: \"" - <getName()<<"\""< Lua table converter functions */ -static void objectref_get(lua_State *L, u16 id) +static void push_v3f(lua_State *L, v3f p) { - // Get minetest.object_refs[i] - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "object_refs"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_pushnumber(L, id); - lua_gettable(L, -2); - lua_remove(L, -2); // object_refs - lua_remove(L, -2); // minetest + lua_newtable(L); + lua_pushnumber(L, p.X); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, p.Y); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, p.Z); + lua_setfield(L, -2, "z"); } -static void luaentity_get(lua_State *L, u16 id) +static v2s16 read_v2s16(lua_State *L, int index) { - // Get minetest.luaentities[i] - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "luaentities"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_pushnumber(L, id); - lua_gettable(L, -2); - lua_remove(L, -2); // luaentities - lua_remove(L, -2); // minetest + v2s16 p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; } -/* - Object wrappers -*/ +static v2f read_v2f(lua_State *L, int index) +{ + v2f p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; +} -#define method(class, name) {#name, class::l_##name} +static v3f read_v3f(lua_State *L, int index) +{ + v3f pos; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + pos.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + pos.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "z"); + pos.Z = lua_tonumber(L, -1); + lua_pop(L, 1); + return pos; +} -/* - ItemStack -*/ +static v3f check_v3f(lua_State *L, int index) +{ + v3f pos; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + pos.X = luaL_checknumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + pos.Y = luaL_checknumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "z"); + pos.Z = luaL_checknumber(L, -1); + lua_pop(L, 1); + return pos; +} + +static void pushFloatPos(lua_State *L, v3f p) +{ + p /= BS; + push_v3f(L, p); +} -class ItemStack +static v3f checkFloatPos(lua_State *L, int index) { -private: - InventoryItem *m_stack; + return check_v3f(L, index) * BS; +} - static const char className[]; - static const luaL_reg methods[]; +static void push_v3s16(lua_State *L, v3s16 p) +{ + lua_newtable(L); + lua_pushnumber(L, p.X); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, p.Y); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, p.Z); + lua_setfield(L, -2, "z"); +} - // Exported functions - - // garbage collector - static int gc_object(lua_State *L) { - ItemStack *o = *(ItemStack **)(lua_touserdata(L, 1)); - delete o; - return 0; +static v3s16 read_v3s16(lua_State *L, int index) +{ + // Correct rounding at <0 + v3f pf = read_v3f(L, index); + return floatToInt(pf, 1.0); +} + +static v3s16 check_v3s16(lua_State *L, int index) +{ + // Correct rounding at <0 + v3f pf = check_v3f(L, index); + return floatToInt(pf, 1.0); +} + +static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef) +{ + lua_newtable(L); + lua_pushstring(L, ndef->get(n).name.c_str()); + lua_setfield(L, -2, "name"); + lua_pushnumber(L, n.getParam1()); + lua_setfield(L, -2, "param1"); + lua_pushnumber(L, n.getParam2()); + lua_setfield(L, -2, "param2"); +} + +static MapNode readnode(lua_State *L, int index, INodeDefManager *ndef) +{ + lua_getfield(L, index, "name"); + const char *name = luaL_checkstring(L, -1); + lua_pop(L, 1); + u8 param1; + lua_getfield(L, index, "param1"); + if(lua_isnil(L, -1)) + param1 = 0; + else + param1 = lua_tonumber(L, -1); + lua_pop(L, 1); + u8 param2; + lua_getfield(L, index, "param2"); + if(lua_isnil(L, -1)) + param2 = 0; + else + param2 = lua_tonumber(L, -1); + lua_pop(L, 1); + return MapNode(ndef, name, param1, param2); +} + +static video::SColor readARGB8(lua_State *L, int index) +{ + video::SColor color; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "a"); + if(lua_isnumber(L, -1)) + color.setAlpha(lua_tonumber(L, -1)); + lua_pop(L, 1); + lua_getfield(L, index, "r"); + color.setRed(lua_tonumber(L, -1)); + lua_pop(L, 1); + lua_getfield(L, index, "g"); + color.setGreen(lua_tonumber(L, -1)); + lua_pop(L, 1); + lua_getfield(L, index, "b"); + color.setBlue(lua_tonumber(L, -1)); + lua_pop(L, 1); + return color; +} + +static core::aabbox3d read_aabbox3df32(lua_State *L, int index, f32 scale) +{ + core::aabbox3d box; + if(lua_istable(L, -1)){ + lua_rawgeti(L, -1, 1); + box.MinEdge.X = lua_tonumber(L, -1) * scale; + lua_pop(L, 1); + lua_rawgeti(L, -1, 2); + box.MinEdge.Y = lua_tonumber(L, -1) * scale; + lua_pop(L, 1); + lua_rawgeti(L, -1, 3); + box.MinEdge.Z = lua_tonumber(L, -1) * scale; + lua_pop(L, 1); + lua_rawgeti(L, -1, 4); + box.MaxEdge.X = lua_tonumber(L, -1) * scale; + lua_pop(L, 1); + lua_rawgeti(L, -1, 5); + box.MaxEdge.Y = lua_tonumber(L, -1) * scale; + lua_pop(L, 1); + lua_rawgeti(L, -1, 6); + box.MaxEdge.Z = lua_tonumber(L, -1) * scale; + lua_pop(L, 1); + } + return box; +} + +/* + ToolDiggingProperties +*/ + +static ToolDiggingProperties read_tool_digging_properties( + lua_State *L, int table) +{ + ToolDiggingProperties prop; + getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval); + getfloatfield(L, table, "basetime", prop.basetime); + getfloatfield(L, table, "dt_weight", prop.dt_weight); + getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness); + getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness); + getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability); + getfloatfield(L, table, "basedurability", prop.basedurability); + getfloatfield(L, table, "dd_weight", prop.dd_weight); + getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness); + getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness); + getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability); + return prop; +} + +static void set_tool_digging_properties(lua_State *L, int table, + const ToolDiggingProperties &prop) +{ + setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval); + setfloatfield(L, table, "basetime", prop.basetime); + setfloatfield(L, table, "dt_weight", prop.dt_weight); + setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness); + setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness); + setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability); + setfloatfield(L, table, "basedurability", prop.basedurability); + setfloatfield(L, table, "dd_weight", prop.dd_weight); + setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness); + setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness); + setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability); +} + +static void push_tool_digging_properties(lua_State *L, + const ToolDiggingProperties &prop) +{ + lua_newtable(L); + set_tool_digging_properties(L, -1, prop); +} + +/* + PointedThing +*/ + +static void push_pointed_thing(lua_State *L, const PointedThing& pointed) +{ + lua_newtable(L); + if(pointed.type == POINTEDTHING_NODE) + { + lua_pushstring(L, "node"); + lua_setfield(L, -2, "type"); + push_v3s16(L, pointed.node_undersurface); + lua_setfield(L, -2, "under"); + push_v3s16(L, pointed.node_abovesurface); + lua_setfield(L, -2, "above"); + } + else if(pointed.type == POINTEDTHING_OBJECT) + { + lua_pushstring(L, "object"); + lua_setfield(L, -2, "type"); + objectref_get(L, pointed.object_id); + lua_setfield(L, -2, "ref"); + } + else + { + lua_pushstring(L, "nothing"); + lua_setfield(L, -2, "type"); + } +} + +/* + ItemDefinition +*/ + +static ItemDefinition read_item_definition(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + // Read the item definition + ItemDefinition def; + + def.type = (ItemType)getenumfield(L, index, "type", + es_ItemType, ITEM_NONE); + getstringfield(L, index, "name", def.name); + getstringfield(L, index, "description", def.description); + getstringfield(L, index, "inventory_image", def.inventory_image); + getstringfield(L, index, "wield_image", def.wield_image); + + lua_getfield(L, index, "wield_scale"); + if(lua_istable(L, -1)){ + def.wield_scale = check_v3f(L, -1); + } + lua_pop(L, 1); + + def.stack_max = getintfield_default(L, index, "stack_max", def.stack_max); + if(def.stack_max == 0) + def.stack_max = 1; + + lua_getfield(L, index, "on_use"); + def.usable = lua_isfunction(L, -1); + lua_pop(L, 1); + + getboolfield(L, index, "liquids_pointable", def.liquids_pointable); + + lua_getfield(L, index, "tool_digging_properties"); + if(lua_istable(L, -1)){ + def.tool_digging_properties = new ToolDiggingProperties( + read_tool_digging_properties(L, -1)); + } + lua_pop(L, 1); + + // If name is "" (hand), ensure there are ToolDiggingProperties + // because it will be looked up there whenever any other item has + // no ToolDiggingProperties + if(def.name == "" && def.tool_digging_properties == NULL){ + def.tool_digging_properties = new ToolDiggingProperties(); + } + + return def; +} + +/* + ContentFeatures +*/ + +static ContentFeatures read_content_features(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + ContentFeatures f; + getstringfield(L, index, "name", f.name); + + /* Visual definition */ + + f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType, + NDT_NORMAL); + getfloatfield(L, index, "visual_scale", f.visual_scale); + + lua_getfield(L, index, "tile_images"); + if(lua_istable(L, -1)){ + int table = lua_gettop(L); + lua_pushnil(L); + int i = 0; + while(lua_next(L, table) != 0){ + // key at index -2 and value at index -1 + if(lua_isstring(L, -1)) + f.tname_tiles[i] = lua_tostring(L, -1); + else + f.tname_tiles[i] = ""; + // removes value, keeps key for next iteration + lua_pop(L, 1); + i++; + if(i==6){ + lua_pop(L, 1); + break; + } + } + // Copy last value to all remaining textures + if(i >= 1){ + std::string lastname = f.tname_tiles[i-1]; + while(i < 6){ + f.tname_tiles[i] = lastname; + i++; + } + } + } + lua_pop(L, 1); + + lua_getfield(L, index, "special_materials"); + if(lua_istable(L, -1)){ + int table = lua_gettop(L); + lua_pushnil(L); + int i = 0; + while(lua_next(L, table) != 0){ + // key at index -2 and value at index -1 + int smtable = lua_gettop(L); + std::string tname = getstringfield_default( + L, smtable, "image", ""); + bool backface_culling = getboolfield_default( + L, smtable, "backface_culling", true); + MaterialSpec mspec(tname, backface_culling); + f.mspec_special[i] = mspec; + // removes value, keeps key for next iteration + lua_pop(L, 1); + i++; + if(i==6){ + lua_pop(L, 1); + break; + } + } + } + lua_pop(L, 1); + + f.alpha = getintfield_default(L, index, "alpha", 255); + + /* Other stuff */ + + lua_getfield(L, index, "post_effect_color"); + if(!lua_isnil(L, -1)) + f.post_effect_color = readARGB8(L, -1); + lua_pop(L, 1); + + f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", + es_ContentParamType, CPT_NONE); + + // True for all ground-like things like stone and mud, false for eg. trees + getboolfield(L, index, "is_ground_content", f.is_ground_content); + f.light_propagates = (f.param_type == CPT_LIGHT); + warn_if_field_exists(L, index, "light_propagates", + "deprecated: determined from paramtype"); + getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); + // This is used for collision detection. + // Also for general solidness queries. + getboolfield(L, index, "walkable", f.walkable); + // Player can point to these + getboolfield(L, index, "pointable", f.pointable); + // Player can dig these + getboolfield(L, index, "diggable", f.diggable); + // Player can climb these + getboolfield(L, index, "climbable", f.climbable); + // Player can build on these + getboolfield(L, index, "buildable_to", f.buildable_to); + // If true, param2 is set to direction when placed. Used for torches. + // NOTE: the direction format is quite inefficient and should be changed + getboolfield(L, index, "wall_mounted", f.wall_mounted); + // Inventory item string as which the node appears in inventory when dug. + // Mineral overrides this. + getstringfield(L, index, "dug_item", f.dug_item); + // Extra dug item and its rarity + getstringfield(L, index, "extra_dug_item", f.extra_dug_item); + // Usual get interval for extra dug item + getintfield(L, index, "extra_dug_item_rarity", f.extra_dug_item_rarity); + // Metadata name of node (eg. "furnace") + getstringfield(L, index, "metadata_name", f.metadata_name); + // Whether the node is non-liquid, source liquid or flowing liquid + f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype", + es_LiquidType, LIQUID_NONE); + // If the content is liquid, this is the flowing version of the liquid. + getstringfield(L, index, "liquid_alternative_flowing", + f.liquid_alternative_flowing); + // If the content is liquid, this is the source version of the liquid. + getstringfield(L, index, "liquid_alternative_source", + f.liquid_alternative_source); + // Viscosity for fluid flow, ranging from 1 to 7, with + // 1 giving almost instantaneous propagation and 7 being + // the slowest possible + f.liquid_viscosity = getintfield_default(L, index, + "liquid_viscosity", f.liquid_viscosity); + // Amount of light the node emits + f.light_source = getintfield_default(L, index, + "light_source", f.light_source); + f.damage_per_second = getintfield_default(L, index, + "damage_per_second", f.damage_per_second); + + lua_getfield(L, index, "selection_box"); + if(lua_istable(L, -1)){ + f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type", + es_NodeBoxType, NODEBOX_REGULAR); + + lua_getfield(L, -1, "fixed"); + if(lua_istable(L, -1)) + f.selection_box.fixed = read_aabbox3df32(L, -1, BS); + lua_pop(L, 1); + + lua_getfield(L, -1, "wall_top"); + if(lua_istable(L, -1)) + f.selection_box.wall_top = read_aabbox3df32(L, -1, BS); + lua_pop(L, 1); + + lua_getfield(L, -1, "wall_bottom"); + if(lua_istable(L, -1)) + f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS); + lua_pop(L, 1); + + lua_getfield(L, -1, "wall_side"); + if(lua_istable(L, -1)) + f.selection_box.wall_side = read_aabbox3df32(L, -1, BS); + lua_pop(L, 1); + } + lua_pop(L, 1); + + lua_getfield(L, index, "material"); + if(lua_istable(L, -1)){ + f.material.diggability = (Diggability)getenumfield(L, -1, "diggability", + es_Diggability, DIGGABLE_NORMAL); + + getfloatfield(L, -1, "constant_time", f.material.constant_time); + getfloatfield(L, -1, "weight", f.material.weight); + getfloatfield(L, -1, "crackiness", f.material.crackiness); + getfloatfield(L, -1, "crumbliness", f.material.crumbliness); + getfloatfield(L, -1, "cuttability", f.material.cuttability); + getfloatfield(L, -1, "flammability", f.material.flammability); + } + lua_pop(L, 1); + + return f; +} + +/* + Inventory stuff +*/ + +static ItemStack read_item(lua_State *L, int index); + +static void inventory_set_list_from_lua(Inventory *inv, const char *name, + lua_State *L, int tableindex, int forcesize=-1) +{ + dstream<<"inventory_set_list_from_lua\n"; + if(tableindex < 0) + tableindex = lua_gettop(L) + 1 + tableindex; + // If nil, delete list + if(lua_isnil(L, tableindex)){ + inv->deleteList(name); + return; + } + // Otherwise set list + std::vector items; + luaL_checktype(L, tableindex, LUA_TTABLE); + lua_pushnil(L); + while(lua_next(L, tableindex) != 0){ + // key at index -2 and value at index -1 + items.push_back(read_item(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + int listsize = (forcesize != -1) ? forcesize : items.size(); + InventoryList *invlist = inv->addList(name, listsize); + int index = 0; + for(std::vector::const_iterator + i = items.begin(); i != items.end(); i++){ + if(forcesize != -1 && index == forcesize) + break; + invlist->changeItem(index, *i); + index++; + } + while(forcesize != -1 && index < forcesize){ + invlist->deleteItem(index); + index++; + } + dstream<<"inventory_set_list_from_lua done\n"; +} + +static void inventory_get_list_to_lua(Inventory *inv, const char *name, + lua_State *L) +{ + InventoryList *invlist = inv->getList(name); + if(invlist == NULL){ + lua_pushnil(L); + return; + } + // Get the table insert function + lua_getglobal(L, "table"); + lua_getfield(L, -1, "insert"); + int table_insert = lua_gettop(L); + // Create and fill table + lua_newtable(L); + int table = lua_gettop(L); + for(u32 i=0; igetSize(); i++){ + ItemStack item = invlist->getItem(i); + lua_pushvalue(L, table_insert); + lua_pushvalue(L, table); + lua_pushstring(L, item.getItemString().c_str()); + if(lua_pcall(L, 2, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + } +} + +/* + Helpful macros for userdata classes +*/ + +#define method(class, name) {#name, class::l_##name} + +/* + LuaItemStack +*/ + +class LuaItemStack +{ +private: + ItemStack m_stack; + + static const char className[]; + static const luaL_reg methods[]; + + // Exported functions + + // garbage collector + static int gc_object(lua_State *L) + { + LuaItemStack *o = *(LuaItemStack **)(lua_touserdata(L, 1)); + delete o; + return 0; + } + + // is_empty(self) -> true/false + static int l_is_empty(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushboolean(L, item.empty()); + return 1; + } + + // get_name(self) -> string + static int l_get_name(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushstring(L, item.name.c_str()); + return 1; + } + + // get_count(self) -> number + static int l_get_count(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushinteger(L, item.count); + return 1; + } + + // get_wear(self) -> number + static int l_get_wear(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushinteger(L, item.wear); + return 1; + } + + // get_metadata(self) -> string + static int l_get_metadata(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushlstring(L, item.metadata.c_str(), item.metadata.size()); + return 1; + } + + // clear(self) -> true + static int l_clear(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + o->m_stack.clear(); + lua_pushboolean(L, true); + return 1; + } + + // replace(self, itemstack or itemstring or table or nil) -> true + static int l_replace(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + o->m_stack = read_item(L, 2); + lua_pushboolean(L, true); + return 1; + } + + // to_string(self) -> string + static int l_to_string(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + std::string itemstring = o->m_stack.getItemString(); + lua_pushstring(L, itemstring.c_str()); + return 1; + } + + // to_table(self) -> table or nil + static int l_to_table(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + const ItemStack &item = o->m_stack; + if(item.empty()) + { + lua_pushnil(L); + } + else + { + lua_newtable(L); + lua_pushstring(L, item.name.c_str()); + lua_setfield(L, -2, "name"); + lua_pushinteger(L, item.count); + 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"); + } + return 1; + } + + // get_stack_max(self) -> number + static int l_get_stack_max(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushinteger(L, item.getStackMax(get_server(L)->idef())); + return 1; + } + + // get_free_space(self) -> number + static int l_get_free_space(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + lua_pushinteger(L, item.freeSpace(get_server(L)->idef())); + return 1; + } + + // is_known(self) -> true/false + // Checks if the item is defined. + static int l_is_known(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + bool is_known = item.isKnown(get_server(L)->idef()); + lua_pushboolean(L, is_known); + return 1; + } + + // get_definition(self) -> table + // Returns the item definition table from minetest.registered_items, + // or a fallback one (name="unknown") + static int 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"); + lua_getfield(L, -1, "registered_items"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, item.name.c_str()); + if(lua_isnil(L, -1)) + { + lua_pop(L, 1); + lua_getfield(L, -1, "unknown"); + } + return 1; } - // peek_item(self) - static int l_peek_item(lua_State *L) + // get_tool_digging_properties(self) -> table + // Returns the effective tool digging properties. + // Returns those of the hand ("") if this item has none associated. + static int l_get_tool_digging_properties(lua_State *L) { - ItemStack *o = checkobject(L, 1); - push_stack_item(L, o->m_stack); + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + const ToolDiggingProperties &prop = + item.getToolDiggingProperties(get_server(L)->idef()); + push_tool_digging_properties(L, prop); return 1; } - // take_item(self) - static int l_take_item(lua_State *L) + // add_wear(self, amount) -> true/false + // The range for "amount" is [0,65535]. Wear is only added if the item + // is a tool. Adding wear might destroy the item. + // Returns true if the item is (or was) a tool. + static int l_add_wear(lua_State *L) { - ItemStack *o = checkobject(L, 1); - push_stack_item(L, o->m_stack); - if(o->m_stack->getCount() <= 1){ - delete o->m_stack; - o->m_stack = NULL; - } else { - o->m_stack->remove(1); - } + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + int amount = lua_tointeger(L, 2); + bool result = item.addWear(amount, get_server(L)->idef()); + lua_pushboolean(L, result); return 1; } - // put_item(self, item) -> true/false - static int l_put_item(lua_State *L) + // add_item(self, itemstack or itemstring or table or nil) -> itemstack + // Returns leftover item stack + static int l_add_item(lua_State *L) { - ItemStack *o = checkobject(L, 1); - InventoryItem *item = check_stack_item(L, 2); - if(!item){ // nil can always be inserted - lua_pushboolean(L, true); - return 1; - } - if(!item->addableTo(o->m_stack)){ - lua_pushboolean(L, false); - return 1; - } - o->m_stack->add(1); - delete item; - lua_pushboolean(L, true); + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + ItemStack newitem = read_item(L, 2); + ItemStack leftover = item.addItem(newitem, get_server(L)->idef()); + create(L, leftover); return 1; } - // put_stackstring(self, stackstring) -> true/false - static int l_put_stackstring(lua_State *L) + // item_fits(self, itemstack or itemstring or table or nil) -> true/false, itemstack + // First return value is true iff the new item fits fully into the stack + // Second return value is the would-be-left-over item stack + static int l_item_fits(lua_State *L) { - ItemStack *o = checkobject(L, 1); - std::string stackstring = luaL_checkstring(L, 2); - try{ - InventoryItem *item = InventoryItem::deSerialize(stackstring, - get_server(L)); - if(!item->addableTo(o->m_stack)){ - lua_pushboolean(L, false); - return 1; - } - o->m_stack->add(1); - delete item; - lua_pushboolean(L, true); - return 1; - } - catch(SerializationError &e){ - lua_pushboolean(L, false); - return 1; - } + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + ItemStack newitem = read_item(L, 2); + ItemStack restitem; + bool fits = item.itemFits(newitem, &restitem, get_server(L)->idef()); + lua_pushboolean(L, fits); // first return value + create(L, restitem); // second return value + return 2; + } + + // take_item(self, takecount=1) -> itemstack + static int l_take_item(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + u32 takecount = 1; + if(!lua_isnone(L, 2)) + takecount = lua_tointeger(L, 2); + ItemStack taken = item.takeItem(takecount); + create(L, taken); + return 1; + } + + // peek_item(self, peekcount=1) -> itemstack + static int l_peek_item(lua_State *L) + { + LuaItemStack *o = checkobject(L, 1); + ItemStack &item = o->m_stack; + u32 peekcount = 1; + if(!lua_isnone(L, 2)) + peekcount = lua_tointeger(L, 2); + ItemStack peekaboo = item.peekItem(peekcount); + create(L, peekaboo); + return 1; } public: - ItemStack(InventoryItem *item=NULL): + LuaItemStack(const ItemStack &item): m_stack(item) { } - ~ItemStack() + ~LuaItemStack() { - delete m_stack; } - static ItemStack* checkobject(lua_State *L, int narg) + const ItemStack& getItem() const { - luaL_checktype(L, narg, LUA_TUSERDATA); - void *ud = luaL_checkudata(L, narg, className); - if(!ud) luaL_typerror(L, narg, className); - return *(ItemStack**)ud; // unbox pointer + return m_stack; } - - InventoryItem* getItemCopy() + ItemStack& getItem() { - if(!m_stack) - return NULL; - return m_stack->clone(); + return m_stack; } - // Creates an ItemStack and leaves it on top of stack + // LuaItemStack(itemstack or itemstring or table or nil) + // Creates an LuaItemStack and leaves it on top of stack static int create_object(lua_State *L) { - InventoryItem *item = NULL; - if(lua_isstring(L, 1)){ - std::string itemstring = lua_tostring(L, 1); - if(itemstring != ""){ - try{ - IGameDef *gdef = get_server(L); - item = InventoryItem::deSerialize(itemstring, gdef); - }catch(SerializationError &e){ - } - } - } - ItemStack *o = new ItemStack(item); + ItemStack item = read_item(L, 1); + 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 - static int create(lua_State *L, InventoryItem *item) + static int create(lua_State *L, const ItemStack &item) { - ItemStack *o = new ItemStack(item); + LuaItemStack *o = new LuaItemStack(item); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); return 1; } + static LuaItemStack* 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 *(LuaItemStack**)ud; // unbox pointer + } + static void Register(lua_State *L) { lua_newtable(L); @@ -981,19 +1286,83 @@ public: luaL_openlib(L, 0, methods, 0); // fill methodtable lua_pop(L, 1); // drop methodtable - // Can be created from Lua (ItemStack::create(itemstring)) + // Can be created from Lua (LuaItemStack(itemstack or itemstring or table or nil)) lua_register(L, className, create_object); } }; -const char ItemStack::className[] = "ItemStack"; -const luaL_reg ItemStack::methods[] = { - method(ItemStack, peek_item), - method(ItemStack, take_item), - method(ItemStack, put_item), - method(ItemStack, put_stackstring), +const char LuaItemStack::className[] = "ItemStack"; +const luaL_reg LuaItemStack::methods[] = { + method(LuaItemStack, is_empty), + method(LuaItemStack, get_name), + method(LuaItemStack, get_count), + method(LuaItemStack, get_wear), + method(LuaItemStack, get_metadata), + method(LuaItemStack, clear), + method(LuaItemStack, replace), + method(LuaItemStack, to_string), + method(LuaItemStack, to_table), + method(LuaItemStack, get_stack_max), + method(LuaItemStack, get_free_space), + method(LuaItemStack, is_known), + method(LuaItemStack, get_definition), + method(LuaItemStack, get_tool_digging_properties), + method(LuaItemStack, add_wear), + method(LuaItemStack, add_item), + method(LuaItemStack, item_fits), + method(LuaItemStack, take_item), + method(LuaItemStack, peek_item), {0,0} }; +static ItemStack read_item(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + if(lua_isnil(L, index)) + { + return ItemStack(); + } + else if(lua_isuserdata(L, index)) + { + // Convert from LuaItemStack + LuaItemStack *o = LuaItemStack::checkobject(L, index); + return o->getItem(); + } + else if(lua_isstring(L, index)) + { + // Convert from itemstring + std::string itemstring = lua_tostring(L, index); + IItemDefManager *idef = get_server(L)->idef(); + try + { + ItemStack item; + item.deSerialize(itemstring, idef); + return item; + } + catch(SerializationError &e) + { + infostream<<"WARNING: unable to create item from itemstring" + <<": "<idef(); + 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 + { + throw LuaError(L, "Expecting itemstack, itemstring, table or nil"); + } +} + /* InvRef */ @@ -1028,15 +1397,6 @@ private: return inv->getList(listname); } - static InventoryItem* getitem(lua_State *L, InvRef *ref, - const char *listname, int i) - { - InventoryList *list = getlist(L, ref, listname); - if(!list) - return NULL; - return list->getItem(i); - } - static void reportInventoryChange(lua_State *L, InvRef *ref) { // Inform other things that the inventory has changed @@ -1088,39 +1448,35 @@ private: return 0; } - // get_stack(self, listname, i) + // get_stack(self, listname, i) -> itemstack static int l_get_stack(lua_State *L) { InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); int i = luaL_checknumber(L, 3) - 1; - InventoryItem *item = getitem(L, ref, listname, i); - if(!item){ - ItemStack::create(L, NULL); - return 1; - } - ItemStack::create(L, item->clone()); + InventoryList *list = getlist(L, ref, listname); + ItemStack item; + if(list != NULL && i >= 0 && i < (int) list->getSize()) + item = list->getItem(i); + LuaItemStack::create(L, item); return 1; } - // set_stack(self, listname, i, stack) + // set_stack(self, listname, i, stack) -> true/false static int l_set_stack(lua_State *L) { InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); int i = luaL_checknumber(L, 3) - 1; - ItemStack *stack = ItemStack::checkobject(L, 4); + ItemStack newitem = read_item(L, 4); InventoryList *list = getlist(L, ref, listname); - if(!list){ + if(list != NULL && i >= 0 && i < (int) list->getSize()){ + list->changeItem(i, newitem); + reportInventoryChange(L, ref); + lua_pushboolean(L, true); + } else { lua_pushboolean(L, false); - return 1; } - InventoryItem *newitem = stack->getItemCopy(); - InventoryItem *olditem = list->changeItem(i, newitem); - bool success = (olditem != newitem); - delete olditem; - lua_pushboolean(L, success); - reportInventoryChange(L, ref); return 1; } @@ -1143,57 +1499,79 @@ private: InventoryList *list = inv->getList(listname); if(list) inventory_set_list_from_lua(inv, listname, L, 3, - get_server(L), list->getSize()); + list->getSize()); else - inventory_set_list_from_lua(inv, listname, L, 3, - get_server(L)); + inventory_set_list_from_lua(inv, listname, L, 3); reportInventoryChange(L, ref); return 0; } - // autoinsert_stack(self, listname, stack) - static int l_autoinsert_stack(lua_State *L) + // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack + // Returns the leftover stack + static int l_add_item(lua_State *L) { InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); - ItemStack *stack = ItemStack::checkobject(L, 3); + ItemStack item = read_item(L, 3); InventoryList *list = getlist(L, ref, listname); - if(!list){ - lua_pushboolean(L, false); - return 1; + if(list){ + ItemStack leftover = list->addItem(item); + if(leftover.count != item.count) + reportInventoryChange(L, ref); + LuaItemStack::create(L, leftover); + } else { + LuaItemStack::create(L, item); } - InventoryItem *item = stack->getItemCopy(); - if(list->roomForItem(item)){ - delete list->addItem(item); - lua_pushboolean(L, true); - reportInventoryChange(L, ref); + return 1; + } + + // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false + // Returns true if the item completely fits into the list + static int l_room_for_item(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + ItemStack item = read_item(L, 3); + InventoryList *list = getlist(L, ref, listname); + if(list){ + lua_pushboolean(L, list->roomForItem(item)); } else { - delete item; lua_pushboolean(L, false); } return 1; } - // autoinsert_stackstring(self, listname, stackstring) - static int l_autoinsert_stackstring(lua_State *L) + // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false + // Returns true if the list contains the given count of the given item name + static int l_contains_item(lua_State *L) { InvRef *ref = checkobject(L, 1); const char *listname = luaL_checkstring(L, 2); - const char *stackstring = luaL_checkstring(L, 3); + ItemStack item = read_item(L, 3); InventoryList *list = getlist(L, ref, listname); - if(!list){ + if(list){ + lua_pushboolean(L, list->containsItem(item)); + } else { lua_pushboolean(L, false); - return 1; } - InventoryItem *item = InventoryItem::deSerialize(stackstring, - get_server(L)); - if(list->roomForItem(item)){ - delete list->addItem(item); - lua_pushboolean(L, true); - reportInventoryChange(L, ref); + return 1; + } + + // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack + // Returns the items that were actually removed + static int l_remove_item(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + ItemStack item = read_item(L, 3); + InventoryList *list = getlist(L, ref, listname); + if(list){ + ItemStack removed = list->removeItem(item); + if(!removed.empty()) + reportInventoryChange(L, ref); + LuaItemStack::create(L, removed); } else { - delete item; - lua_pushboolean(L, false); + LuaItemStack::create(L, ItemStack()); } return 1; } @@ -1266,8 +1644,10 @@ const luaL_reg InvRef::methods[] = { method(InvRef, set_stack), method(InvRef, get_list), method(InvRef, set_list), - method(InvRef, autoinsert_stack), - method(InvRef, autoinsert_stackstring), + method(InvRef, add_item), + method(InvRef, room_for_item), + method(InvRef, contains_item), + method(InvRef, remove_item), {0,0} }; @@ -1420,36 +1800,6 @@ private: return 1; } - // deprecated: inventory_set_list(self, name, {item1, item2, ...}) - static int l_inventory_set_list(lua_State *L) - { - infostream<<"Deprecated: inventory_set_list"<getInventory(); - const char *name = luaL_checkstring(L, 2); - inventory_set_list_from_lua(inv, name, L, 3, - ref->m_env->getGameDef()); - reportMetadataChange(ref); - return 0; - } - - // deprecated: inventory_get_list(self, name) - static int l_inventory_get_list(lua_State *L) - { - infostream<<"Deprecated: inventory_get_list"<getInventory(); - const char *name = luaL_checkstring(L, 2); - inventory_get_list_to_lua(inv, name, L); - return 1; - } - // set_inventory_draw_spec(self, text) static int l_set_inventory_draw_spec(lua_State *L) { @@ -1636,8 +1986,6 @@ const luaL_reg NodeMetaRef::methods[] = { method(NodeMetaRef, get_owner), method(NodeMetaRef, set_infotext), method(NodeMetaRef, get_inventory), - method(NodeMetaRef, inventory_set_list), // deprecated - method(NodeMetaRef, inventory_get_list), // deprecated method(NodeMetaRef, set_inventory_draw_spec), method(NodeMetaRef, set_allow_text_input), method(NodeMetaRef, set_allow_removal), @@ -1798,122 +2146,98 @@ private: return 0; } - // get_wield_digging_properties(self) - static int l_get_wield_digging_properties(lua_State *L) + // set_hp(self, hp) + // hp = number of hitpoints (2 * number of hearts) + // returns: nil + static int l_set_hp(lua_State *L) { ObjectRef *ref = checkobject(L, 1); + luaL_checknumber(L, 2); ServerActiveObject *co = getobject(ref); if(co == NULL) return 0; + int hp = lua_tonumber(L, 2); + infostream<<"ObjectRef::l_set_hp(): id="<getId() + <<" hp="<getWieldDiggingProperties(&prop); - push_tool_digging_properties(L, prop); + co->setHP(hp); + // Return + return 0; + } + + // get_hp(self) + // returns: number of hitpoints (2 * number of hearts) + // 0 if not applicable to this type of object + static int l_get_hp(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + int hp = co->getHP(); + infostream<<"ObjectRef::l_get_hp(): id="<getId() + <<" hp="<damageWieldedItem(amount); - return 0; + InventoryLocation loc = co->getInventoryLocation(); + if(get_server(L)->getInventory(loc) != NULL) + InvRef::create(L, loc); + else + lua_pushnil(L); + return 1; } - // add_to_inventory(self, itemstring) - // returns: true if item was added, (false, "reason") otherwise - static int l_add_to_inventory(lua_State *L) + // get_wield_list(self) + static int l_get_wield_list(lua_State *L) { ObjectRef *ref = checkobject(L, 1); - luaL_checkstring(L, 2); ServerActiveObject *co = getobject(ref); if(co == NULL) return 0; - // itemstring - const char *itemstring = luaL_checkstring(L, 2); - infostream<<"ObjectRef::l_add_to_inventory(): id="<getId() - <<" itemstring=\""<getEnv(); - assert(env); - IGameDef *gamedef = env->getGameDef(); - try{ - InventoryItem *item = InventoryItem::deSerialize(is, gamedef); - if(item->getCount() == 0) - item->setCount(1); - bool added = co->addToInventory(item); - // Return - lua_pushboolean(L, added); - if(!added) - lua_pushstring(L, "failed to add item"); - return 2; - } catch(SerializationError &e){ - // Return - lua_pushboolean(L, false); - lua_pushstring(L, (std::string("Invalid item: ") - + e.what()).c_str()); - return 2; - } + lua_pushstring(L, co->getWieldList().c_str()); + return 1; } - // add_to_inventory_later(self, itemstring) - // returns: nil - static int l_add_to_inventory_later(lua_State *L) + // get_wield_index(self) + static int l_get_wield_index(lua_State *L) { ObjectRef *ref = checkobject(L, 1); - luaL_checkstring(L, 2); ServerActiveObject *co = getobject(ref); if(co == NULL) return 0; - // itemstring - const char *itemstring = luaL_checkstring(L, 2); - infostream<<"ObjectRef::l_add_to_inventory_later(): id="<getId() - <<" itemstring=\""<getEnv(); - assert(env); - IGameDef *gamedef = env->getGameDef(); - InventoryItem *item = InventoryItem::deSerialize(is, gamedef); - infostream<<"item="<addToInventoryLater(item); - // Return - return 0; + lua_pushinteger(L, co->getWieldIndex() + 1); + return 1; } - // set_hp(self, hp) - // hp = number of hitpoints (2 * number of hearts) - // returns: nil - static int l_set_hp(lua_State *L) + // get_wielded_item(self) + static int l_get_wielded_item(lua_State *L) { ObjectRef *ref = checkobject(L, 1); - luaL_checknumber(L, 2); ServerActiveObject *co = getobject(ref); if(co == NULL) return 0; - int hp = lua_tonumber(L, 2); - infostream<<"ObjectRef::l_set_hp(): id="<getId() - <<" hp="<setHP(hp); - // Return - return 0; + LuaItemStack::create(L, co->getWieldedItem()); + return 1; } - // get_hp(self) - // returns: number of hitpoints (2 * number of hearts) - // 0 if not applicable to this type of object - static int l_get_hp(lua_State *L) + // set_wielded_item(self, itemstack or itemstring or table or nil) + static int l_set_wielded_item(lua_State *L) { ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); if(co == NULL) return 0; - int hp = co->getHP(); - infostream<<"ObjectRef::l_get_hp(): id="<getId() - <<" hp="<setWieldedItem(item); + lua_pushboolean(L, success); return 1; } @@ -2031,112 +2355,45 @@ private: } // DEPRECATED - // get_entity_name(self) - static int l_get_entity_name(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; - // Do it - std::string name = co->getName(); - lua_pushstring(L, name.c_str()); - return 1; - } - - // get_luaentity(self) - static int l_get_luaentity(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; - // Do it - luaentity_get(L, co->getId()); - return 1; - } - - /* Player-only */ - - // get_player_name(self) - static int l_get_player_name(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL){ - lua_pushnil(L); - return 1; - } - // Do it - lua_pushstring(L, player->getName()); - return 1; - } - - // get_inventory(self) - static int l_get_inventory(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - // Do it - InvRef::createPlayer(L, player); - return 1; - } - - // deprecated: inventory_set_list(self, name, {item1, item2, ...}) - static int l_inventory_set_list(lua_State *L) - { - infostream<<"Deprecated: inventory_set_list"<inventory, name, L, 3, - player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE); - player->m_inventory_not_sent = true; - return 0; - } - - // deprecated: inventory_get_list(self, name) - static int l_inventory_get_list(lua_State *L) + // get_entity_name(self) + static int l_get_entity_name(lua_State *L) { - infostream<<"Deprecated: inventory_get_list"<inventory, name, L); + std::string name = co->getName(); + lua_pushstring(L, name.c_str()); return 1; } - - // get_wielded_itemstring(self) - static int l_get_wielded_itemstring(lua_State *L) + + // get_luaentity(self) + static int l_get_luaentity(lua_State *L) { ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; // Do it - InventoryItem *item = player->getWieldedItem(); - if(item == NULL){ - lua_pushnil(L); - return 1; - } - lua_pushstring(L, item->getItemString().c_str()); + luaentity_get(L, co->getId()); return 1; } - - // get_wielded_item(self) - static int l_get_wielded_item(lua_State *L) + + /* Player-only */ + + // get_player_name(self) + static int l_get_player_name(lua_State *L) { ObjectRef *ref = checkobject(L, 1); ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; + if(player == NULL){ + lua_pushnil(L); + return 1; + } // Do it - InventoryItem *item0 = player->getWieldedItem(); - push_stack_item(L, item0); + lua_pushstring(L, player->getName()); return 1; } - + // get_look_dir(self) static int l_get_look_dir(lua_State *L) { @@ -2243,12 +2500,13 @@ const luaL_reg ObjectRef::methods[] = { method(ObjectRef, moveto), method(ObjectRef, punch), method(ObjectRef, right_click), - method(ObjectRef, get_wield_digging_properties), - method(ObjectRef, damage_wielded_item), - method(ObjectRef, add_to_inventory), - method(ObjectRef, add_to_inventory_later), method(ObjectRef, set_hp), method(ObjectRef, get_hp), + method(ObjectRef, get_inventory), + method(ObjectRef, get_wield_list), + method(ObjectRef, get_wield_index), + method(ObjectRef, get_wielded_item), + method(ObjectRef, set_wielded_item), // LuaEntitySAO-only method(ObjectRef, setvelocity), method(ObjectRef, getvelocity), @@ -2262,11 +2520,6 @@ const luaL_reg ObjectRef::methods[] = { method(ObjectRef, get_luaentity), // Player-only method(ObjectRef, get_player_name), - method(ObjectRef, get_inventory), - method(ObjectRef, inventory_set_list), // deprecated - method(ObjectRef, inventory_get_list), // deprecated - method(ObjectRef, get_wielded_itemstring), - method(ObjectRef, get_wielded_item), method(ObjectRef, get_look_dir), method(ObjectRef, get_look_pitch), method(ObjectRef, get_look_yaw), @@ -2408,7 +2661,7 @@ private: } } - // EnvRef:add_entity(pos, entityname) + // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil // pos = {x=num, y=num, z=num} static int l_add_entity(lua_State *L) { @@ -2431,22 +2684,29 @@ private: return 1; } - // EnvRef:add_item(pos, inventorystring) + // EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil // pos = {x=num, y=num, z=num} static int l_add_item(lua_State *L) { - infostream<<"EnvRef::l_add_item()"<m_env; if(env == NULL) return 0; // pos v3f pos = checkFloatPos(L, 2); - // inventorystring - const char *inventorystring = luaL_checkstring(L, 3); + // item + ItemStack item = read_item(L, 3); + if(item.empty() || !item.isKnown(get_server(L)->idef())) + return 0; // Do it - ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring); - env->addActiveObject(obj); - return 0; + ServerActiveObject *obj = new ItemSAO(env, pos, item.getItemString()); + int objectid = env->addActiveObject(obj); + // If failed to add, return nothing (reads as nil) + if(objectid == 0) + return 0; + // Return ObjectRef + objectref_get_or_create(L, obj); + return 1; } // EnvRef:add_rat(pos) @@ -2627,55 +2887,6 @@ const luaL_reg EnvRef::methods[] = { Global functions */ -static int l_register_nodedef_defaults(lua_State *L) -{ - luaL_checktype(L, 1, LUA_TTABLE); - - lua_pushvalue(L, 1); // Explicitly put parameter 1 on top of stack - lua_setfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default"); - - return 0; -} - -// Register new object prototype -// register_entity(name, prototype) -static int l_register_entity(lua_State *L) -{ - std::string name = luaL_checkstring(L, 1); - check_modname_prefix(L, name); - //infostream<<"register_entity: "< stack top - // registered_entities[name] = object - lua_setfield(L, registered_entities, name.c_str()); - - // Get registered object to top of stack - lua_pushvalue(L, 2); - - // Set name field - lua_pushvalue(L, 1); - lua_setfield(L, -2, "name"); - - // Set __index to point to itself - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - - // Set metatable.__index = metatable - luaL_getmetatable(L, "minetest.entity"); - lua_pushvalue(L, -1); // duplicate metatable - lua_setfield(L, -2, "__index"); - // Set object metatable - lua_setmetatable(L, -2); - - return 0; /* number of results */ -} - class LuaABM : public ActiveBlockModifier { private: @@ -2738,465 +2949,329 @@ public: // Call action luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - push_v3s16(L, p); - pushnode(L, n, env->getGameDef()->ndef()); - lua_pushnumber(L, active_object_count); - lua_pushnumber(L, active_object_count_wider); - if(lua_pcall(L, 4, 0, 0)) - script_error(L, "error: %s", lua_tostring(L, -1)); - } -}; - -// register_abm({...}) -static int l_register_abm(lua_State *L) -{ - //infostream<<"register_abm"<getWritableToolDefManager(); - - ToolDefinition def = read_tool_definition(L, table); - - tooldef->registerTool(name, def); - return 0; /* number of results */ -} - -// register_craftitem(name, {lots of stuff}) -static int l_register_craftitem(lua_State *L) -{ - std::string name = luaL_checkstring(L, 1); - check_modname_prefix(L, name); - //infostream<<"register_craftitem: "<getWritableCraftItemDefManager(); - - // Check if on_drop is defined - lua_getfield(L, table, "on_drop"); - bool got_on_drop = !lua_isnil(L, -1); - lua_pop(L, 1); - - // Check if on_use is defined - lua_getfield(L, table, "on_use"); - bool got_on_use = !lua_isnil(L, -1); - lua_pop(L, 1); - - CraftItemDefinition def; - - getstringfield(L, table, "image", def.imagename); - getstringfield(L, table, "cookresult_itemstring", def.cookresult_item); - getfloatfield(L, table, "furnace_cooktime", def.furnace_cooktime); - getfloatfield(L, table, "furnace_burntime", def.furnace_burntime); - def.usable = getboolfield_default(L, table, "usable", got_on_use); - getboolfield(L, table, "liquids_pointable", def.liquids_pointable); - def.dropcount = getintfield_default(L, table, "dropcount", def.dropcount); - def.stack_max = getintfield_default(L, table, "stack_max", def.stack_max); - - // If an on_drop callback is defined, force dropcount to 1 - if (got_on_drop) - def.dropcount = 1; - - // Register it - craftitemdef->registerCraftItem(name, def); - - lua_pushvalue(L, table); - scriptapi_add_craftitem(L, name.c_str()); - - return 0; /* number of results */ -} - -// register_node(name, {lots of stuff}) -static int l_register_node(lua_State *L) -{ - std::string name = luaL_checkstring(L, 1); - check_modname_prefix(L, name); - //infostream<<"register_node: "<getWritableNodeDefManager(); - - // Get default node definition from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default"); - int nodedef_default = lua_gettop(L); - - /* - Add to minetest.registered_nodes with default as metatable - */ - - // Get the node definition table given as parameter - lua_pushvalue(L, nodedef_table); - - // Set __index to point to itself - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - - // Set nodedef_default as metatable for the definition - lua_pushvalue(L, nodedef_default); - lua_setmetatable(L, nodedef_table); - - // minetest.registered_nodes[name] = nodedef - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_nodes"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_pushstring(L, name.c_str()); - lua_pushvalue(L, nodedef_table); - lua_settable(L, -3); - - /* - Create definition - */ - - ContentFeatures f; - - // Default to getting the corresponding NodeItem when dug - f.dug_item = std::string("NodeItem \"")+name+"\" 1"; - - // Default to unknown_block.png as all textures - f.setAllTextures("unknown_block.png"); - - /* - Read definiton from Lua - */ - - f.name = name; - - /* Visual definition */ - - f.drawtype = (NodeDrawType)getenumfield(L, nodedef_table, "drawtype", es_DrawType, - NDT_NORMAL); - getfloatfield(L, nodedef_table, "visual_scale", f.visual_scale); - - lua_getfield(L, nodedef_table, "tile_images"); - if(lua_istable(L, -1)){ - int table = lua_gettop(L); - lua_pushnil(L); - int i = 0; - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - if(lua_isstring(L, -1)) - f.tname_tiles[i] = lua_tostring(L, -1); - else - f.tname_tiles[i] = ""; - // removes value, keeps key for next iteration - lua_pop(L, 1); - i++; - if(i==6){ - lua_pop(L, 1); - break; - } - } - // Copy last value to all remaining textures - if(i >= 1){ - std::string lastname = f.tname_tiles[i-1]; - while(i < 6){ - f.tname_tiles[i] = lastname; - i++; - } - } - } - lua_pop(L, 1); - - getstringfield(L, nodedef_table, "inventory_image", f.tname_inventory); - - lua_getfield(L, nodedef_table, "special_materials"); - if(lua_istable(L, -1)){ - int table = lua_gettop(L); - lua_pushnil(L); - int i = 0; - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - int smtable = lua_gettop(L); - std::string tname = getstringfield_default( - L, smtable, "image", ""); - bool backface_culling = getboolfield_default( - L, smtable, "backface_culling", true); - MaterialSpec mspec(tname, backface_culling); - f.setSpecialMaterial(i, mspec); - // removes value, keeps key for next iteration - lua_pop(L, 1); - i++; - if(i==6){ - lua_pop(L, 1); - break; - } - } - } - lua_pop(L, 1); - - f.alpha = getintfield_default(L, nodedef_table, "alpha", 255); - - /* Other stuff */ - - lua_getfield(L, nodedef_table, "post_effect_color"); - if(!lua_isnil(L, -1)) - f.post_effect_color = readARGB8(L, -1); - lua_pop(L, 1); - - f.param_type = (ContentParamType)getenumfield(L, nodedef_table, "paramtype", - es_ContentParamType, CPT_NONE); - - // True for all ground-like things like stone and mud, false for eg. trees - getboolfield(L, nodedef_table, "is_ground_content", f.is_ground_content); - f.light_propagates = (f.param_type == CPT_LIGHT); - warn_if_field_exists(L, nodedef_table, "light_propagates", - "deprecated: determined from paramtype"); - getboolfield(L, nodedef_table, "sunlight_propagates", f.sunlight_propagates); - // This is used for collision detection. - // Also for general solidness queries. - getboolfield(L, nodedef_table, "walkable", f.walkable); - // Player can point to these - getboolfield(L, nodedef_table, "pointable", f.pointable); - // Player can dig these - getboolfield(L, nodedef_table, "diggable", f.diggable); - // Player can climb these - getboolfield(L, nodedef_table, "climbable", f.climbable); - // Player can build on these - getboolfield(L, nodedef_table, "buildable_to", f.buildable_to); - // If true, param2 is set to direction when placed. Used for torches. - // NOTE: the direction format is quite inefficient and should be changed - getboolfield(L, nodedef_table, "wall_mounted", f.wall_mounted); - // Whether this content type often contains mineral. - // Used for texture atlas creation. - // Currently only enabled for CONTENT_STONE. - getboolfield(L, nodedef_table, "often_contains_mineral", f.often_contains_mineral); - // Inventory item string as which the node appears in inventory when dug. - // Mineral overrides this. - getstringfield(L, nodedef_table, "dug_item", f.dug_item); - // Extra dug item and its rarity - getstringfield(L, nodedef_table, "extra_dug_item", f.extra_dug_item); - // Usual get interval for extra dug item - getintfield(L, nodedef_table, "extra_dug_item_rarity", f.extra_dug_item_rarity); - // Metadata name of node (eg. "furnace") - getstringfield(L, nodedef_table, "metadata_name", f.metadata_name); - // Whether the node is non-liquid, source liquid or flowing liquid - f.liquid_type = (LiquidType)getenumfield(L, nodedef_table, "liquidtype", - es_LiquidType, LIQUID_NONE); - // If the content is liquid, this is the flowing version of the liquid. - getstringfield(L, nodedef_table, "liquid_alternative_flowing", - f.liquid_alternative_flowing); - // If the content is liquid, this is the source version of the liquid. - getstringfield(L, nodedef_table, "liquid_alternative_source", - f.liquid_alternative_source); - // Viscosity for fluid flow, ranging from 1 to 7, with - // 1 giving almost instantaneous propagation and 7 being - // the slowest possible - f.liquid_viscosity = getintfield_default(L, nodedef_table, - "liquid_viscosity", f.liquid_viscosity); - // Amount of light the node emits - f.light_source = getintfield_default(L, nodedef_table, - "light_source", f.light_source); - f.damage_per_second = getintfield_default(L, nodedef_table, - "damage_per_second", f.damage_per_second); - - lua_getfield(L, nodedef_table, "selection_box"); - if(lua_istable(L, -1)){ - f.selection_box.type = (NodeBoxType)getenumfield(L, -1, "type", - es_NodeBoxType, NODEBOX_REGULAR); + lua_getfield(L, -1, "action"); + luaL_checktype(L, -1, LUA_TFUNCTION); + push_v3s16(L, p); + pushnode(L, n, env->getGameDef()->ndef()); + lua_pushnumber(L, active_object_count); + lua_pushnumber(L, active_object_count_wider); + if(lua_pcall(L, 4, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + } +}; - lua_getfield(L, -1, "fixed"); - if(lua_istable(L, -1)) - f.selection_box.fixed = read_aabbox3df32(L, -1, BS); - lua_pop(L, 1); +// debug(text) +// Writes a line to dstream +static int l_debug(lua_State *L) +{ + std::string text = lua_tostring(L, 1); + dstream << text << std::endl; + return 0; +} - lua_getfield(L, -1, "wall_top"); - if(lua_istable(L, -1)) - f.selection_box.wall_top = read_aabbox3df32(L, -1, BS); - lua_pop(L, 1); +// log([level,] text) +// Writes a line to the logger. +// The one-argument version logs to infostream. +// The two-argument version accept a log level: error, action, info, or verbose. +static int l_log(lua_State *L) +{ + std::string text; + LogMessageLevel level = LMT_INFO; + if(lua_isnone(L, 2)) + { + text = lua_tostring(L, 1); + } + else + { + std::string levelname = lua_tostring(L, 1); + text = lua_tostring(L, 2); + if(levelname == "error") + level = LMT_ERROR; + else if(levelname == "action") + level = LMT_ACTION; + else if(levelname == "verbose") + level = LMT_VERBOSE; + } + log_printline(level, text); + return 0; +} - lua_getfield(L, -1, "wall_bottom"); - if(lua_istable(L, -1)) - f.selection_box.wall_bottom = read_aabbox3df32(L, -1, BS); - lua_pop(L, 1); +// register_item_raw({lots of stuff}) +static int l_register_item_raw(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + int table = 1; - lua_getfield(L, -1, "wall_side"); - if(lua_istable(L, -1)) - f.selection_box.wall_side = read_aabbox3df32(L, -1, BS); - lua_pop(L, 1); + // Get the writable item and node definition managers from the server + IWritableItemDefManager *idef = + get_server(L)->getWritableItemDefManager(); + IWritableNodeDefManager *ndef = + get_server(L)->getWritableNodeDefManager(); + + // Check if name is defined + lua_getfield(L, table, "name"); + if(lua_isstring(L, -1)){ + std::string name = lua_tostring(L, -1); + infostream<<"register_item_raw: "<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); } - lua_pop(L, 1); - getstringfield(L, nodedef_table, "cookresult_itemstring", f.cookresult_item); - getfloatfield(L, nodedef_table, "furnace_cooktime", f.furnace_cooktime); - getfloatfield(L, nodedef_table, "furnace_burntime", f.furnace_burntime); - - /* - Register it - */ - - nodedef->set(name, f); - return 0; /* number of results */ } -// alias_node(name, convert_to_name) -static int l_alias_node(lua_State *L) +// register_alias_raw(name, convert_to_name) +static int l_register_alias_raw(lua_State *L) { std::string name = luaL_checkstring(L, 1); std::string convert_to = luaL_checkstring(L, 2); - // Get the writable node definition manager from the server - IWritableNodeDefManager *nodedef = - get_server(L)->getWritableNodeDefManager(); + // Get the writable item definition manager from the server + IWritableItemDefManager *idef = + get_server(L)->getWritableItemDefManager(); - nodedef->setAlias(name, convert_to); + idef->registerAlias(name, convert_to); return 0; /* number of results */ } -// alias_tool(name, convert_to_name) -static int l_alias_tool(lua_State *L) +// helper for register_craft +static bool read_craft_recipe_shaped(lua_State *L, int index, + int &width, std::vector &recipe) { - std::string name = luaL_checkstring(L, 1); - std::string convert_to = luaL_checkstring(L, 2); + if(index < 0) + index = lua_gettop(L) + 1 + index; - // Get the writable tool definition manager from the server - IWritableToolDefManager *tooldef = - get_server(L)->getWritableToolDefManager(); - - tooldef->setAlias(name, convert_to); + if(!lua_istable(L, index)) + return false; - return 0; /* number of results */ + lua_pushnil(L); + int rowcount = 0; + while(lua_next(L, index) != 0){ + int colcount = 0; + // key at index -2 and value at index -1 + if(!lua_istable(L, -1)) + return false; + int table2 = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table2) != 0){ + // key at index -2 and value at index -1 + if(!lua_isstring(L, -1)) + return false; + recipe.push_back(lua_tostring(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + colcount++; + } + if(rowcount == 0){ + width = colcount; + } else { + if(colcount != width) + return false; + } + // removes value, keeps key for next iteration + lua_pop(L, 1); + rowcount++; + } + return width != 0; } -// alias_craftitem(name, convert_to_name) -static int l_alias_craftitem(lua_State *L) +// helper for register_craft +static bool read_craft_recipe_shapeless(lua_State *L, int index, + std::vector &recipe) { - std::string name = luaL_checkstring(L, 1); - std::string convert_to = luaL_checkstring(L, 2); + if(index < 0) + index = lua_gettop(L) + 1 + index; - // Get the writable CraftItem definition manager from the server - IWritableCraftItemDefManager *craftitemdef = - get_server(L)->getWritableCraftItemDefManager(); - - craftitemdef->setAlias(name, convert_to); + if(!lua_istable(L, index)) + return false; - return 0; /* number of results */ + lua_pushnil(L); + while(lua_next(L, index) != 0){ + // key at index -2 and value at index -1 + if(!lua_isstring(L, -1)) + return false; + recipe.push_back(lua_tostring(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + return true; } +// helper for register_craft +static bool read_craft_replacements(lua_State *L, int index, + CraftReplacements &replacements) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + if(!lua_istable(L, index)) + return false; + + lua_pushnil(L); + while(lua_next(L, index) != 0){ + // key at index -2 and value at index -1 + if(!lua_istable(L, -1)) + return false; + lua_rawgeti(L, -1, 1); + if(!lua_isstring(L, -1)) + return false; + std::string replace_from = lua_tostring(L, -1); + lua_pop(L, 1); + lua_rawgeti(L, -1, 2); + if(!lua_isstring(L, -1)) + return false; + std::string replace_to = lua_tostring(L, -1); + lua_pop(L, 1); + replacements.pairs.push_back( + std::make_pair(replace_from, replace_to)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + return true; +} // register_craft({output=item, recipe={{item00,item10},{item01,item11}}) static int l_register_craft(lua_State *L) { //infostream<<"register_craft"<getWritableCraftDefManager(); - std::string output; - int width = 0; - std::vector input; - - lua_getfield(L, table0, "output"); - luaL_checktype(L, -1, LUA_TSTRING); - if(lua_isstring(L, -1)) - output = lua_tostring(L, -1); - lua_pop(L, 1); + std::string type = getstringfield_default(L, table, "type", "shaped"); - lua_getfield(L, table0, "recipe"); - luaL_checktype(L, -1, LUA_TTABLE); - if(lua_istable(L, -1)){ - int table1 = lua_gettop(L); - lua_pushnil(L); - int rowcount = 0; - while(lua_next(L, table1) != 0){ - int colcount = 0; - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TTABLE); - if(lua_istable(L, -1)){ - int table2 = lua_gettop(L); - lua_pushnil(L); - while(lua_next(L, table2) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - input.push_back(lua_tostring(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - colcount++; - } - } - if(rowcount == 0){ - width = colcount; - } else { - if(colcount != width){ - std::string error; - error += "Invalid crafting recipe (output=\"" - + output + "\")"; - throw LuaError(L, error); - } - } - // removes value, keeps key for next iteration - lua_pop(L, 1); - rowcount++; + /* + CraftDefinitionShaped + */ + if(type == "shaped"){ + std::string output = getstringfield_default(L, table, "output", ""); + if(output == "") + throw LuaError(L, "Crafting definition is missing an output"); + + int width = 0; + std::vector recipe; + lua_getfield(L, table, "recipe"); + if(lua_isnil(L, -1)) + throw LuaError(L, "Crafting definition is missing a recipe" + " (output=\"" + output + "\")"); + if(!read_craft_recipe_shaped(L, -1, width, recipe)) + throw LuaError(L, "Invalid crafting recipe" + " (output=\"" + output + "\")"); + + CraftReplacements replacements; + lua_getfield(L, table, "replacements"); + if(!lua_isnil(L, -1)) + { + if(!read_craft_replacements(L, -1, replacements)) + throw LuaError(L, "Invalid replacements" + " (output=\"" + output + "\")"); } + + CraftDefinition *def = new CraftDefinitionShaped( + output, width, recipe, replacements); + craftdef->registerCraft(def); } - lua_pop(L, 1); + /* + CraftDefinitionShapeless + */ + else if(type == "shapeless"){ + std::string output = getstringfield_default(L, table, "output", ""); + if(output == "") + throw LuaError(L, "Crafting definition (shapeless)" + " is missing an output"); + + std::vector recipe; + lua_getfield(L, table, "recipe"); + if(lua_isnil(L, -1)) + throw LuaError(L, "Crafting definition (shapeless)" + " is missing a recipe" + " (output=\"" + output + "\")"); + if(!read_craft_recipe_shapeless(L, -1, recipe)) + throw LuaError(L, "Invalid crafting recipe" + " (output=\"" + output + "\")"); + + CraftReplacements replacements; + lua_getfield(L, table, "replacements"); + if(!lua_isnil(L, -1)) + { + if(!read_craft_replacements(L, -1, replacements)) + throw LuaError(L, "Invalid replacements" + " (output=\"" + output + "\")"); + } + + CraftDefinition *def = new CraftDefinitionShapeless( + output, recipe, replacements); + craftdef->registerCraft(def); + } + /* + CraftDefinitionToolRepair + */ + else if(type == "toolrepair"){ + float additional_wear = getfloatfield_default(L, table, + "additional_wear", 0.0); + + CraftDefinition *def = new CraftDefinitionToolRepair( + additional_wear); + craftdef->registerCraft(def); + } + /* + CraftDefinitionCooking + */ + else if(type == "cooking"){ + std::string output = getstringfield_default(L, table, "output", ""); + if(output == "") + throw LuaError(L, "Crafting definition (cooking)" + " is missing an output"); + + std::string recipe = getstringfield_default(L, table, "recipe", ""); + if(recipe == "") + throw LuaError(L, "Crafting definition (cooking)" + " is missing a recipe" + " (output=\"" + output + "\")"); + + float cooktime = getfloatfield_default(L, table, "cooktime", 3.0); + + CraftDefinition *def = new CraftDefinitionCooking( + output, recipe, cooktime); + craftdef->registerCraft(def); + } + /* + CraftDefinitionFuel + */ + else if(type == "fuel"){ + std::string recipe = getstringfield_default(L, table, "recipe", ""); + if(recipe == "") + throw LuaError(L, "Crafting definition (fuel)" + " is missing a recipe"); + + float burntime = getfloatfield_default(L, table, "burntime", 1.0); - CraftDefinition def(output, width, input); - craftdef->registerCraft(def); + CraftDefinition *def = new CraftDefinitionFuel( + recipe, burntime); + craftdef->registerCraft(def); + } + else + { + throw LuaError(L, "Unknown crafting definition type: \"" + type + "\""); + } + lua_pop(L, 1); return 0; /* number of results */ } @@ -3294,15 +3369,19 @@ static int l_get_inventory(lua_State *L) return 1; } +// get_current_modname() +static int l_get_current_modname(lua_State *L) +{ + lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname"); + return 1; +} + // get_modpath(modname) static int l_get_modpath(lua_State *L) { const char *modname = luaL_checkstring(L, 1); - // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); - Server *server = (Server*)lua_touserdata(L, -1); // Do it - const ModSpec *mod = server->getModSpec(modname); + const ModSpec *mod = get_server(L)->getModSpec(modname); if(!mod){ lua_pushnil(L); return 1; @@ -3312,34 +3391,22 @@ static int l_get_modpath(lua_State *L) } static const struct luaL_Reg minetest_f [] = { - {"register_nodedef_defaults", l_register_nodedef_defaults}, - {"register_entity", l_register_entity}, - {"register_tool", l_register_tool}, - {"register_craftitem", l_register_craftitem}, - {"register_node", l_register_node}, + {"debug", l_debug}, + {"log", l_log}, + {"register_item_raw", l_register_item_raw}, + {"register_alias_raw", l_register_alias_raw}, {"register_craft", l_register_craft}, - {"register_abm", l_register_abm}, - {"alias_node", l_alias_node}, - {"alias_tool", l_alias_tool}, - {"alias_craftitem", l_alias_craftitem}, {"setting_get", l_setting_get}, {"setting_getbool", l_setting_getbool}, {"chat_send_all", l_chat_send_all}, {"chat_send_player", l_chat_send_player}, {"get_player_privs", l_get_player_privs}, {"get_inventory", l_get_inventory}, + {"get_current_modname", l_get_current_modname}, {"get_modpath", l_get_modpath}, {NULL, NULL} }; -/* - LuaEntity functions -*/ - -static const struct luaL_Reg minetest_entity_m [] = { - {NULL, NULL} -}; - /* Main export function */ @@ -3355,10 +3422,6 @@ void scriptapi_export(lua_State *L, Server *server) lua_pushlightuserdata(L, server); lua_setfield(L, LUA_REGISTRYINDEX, "minetest_server"); - // Store nil as minetest_nodedef_defaults in registry - lua_pushnil(L); - lua_setfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default"); - // Register global functions in table minetest lua_newtable(L); luaL_register(L, NULL, minetest_f); @@ -3369,31 +3432,13 @@ void scriptapi_export(lua_State *L, Server *server) // Add tables to minetest - lua_newtable(L); - lua_setfield(L, -2, "registered_nodes"); - lua_newtable(L); - lua_setfield(L, -2, "registered_entities"); - lua_newtable(L); - lua_setfield(L, -2, "registered_craftitems"); - lua_newtable(L); - lua_setfield(L, -2, "registered_abms"); - lua_newtable(L); lua_setfield(L, -2, "object_refs"); lua_newtable(L); lua_setfield(L, -2, "luaentities"); - // Create entity prototype - luaL_newmetatable(L, "minetest.entity"); - // metatable.__index = metatable - lua_pushvalue(L, -1); // Duplicate metatable - lua_setfield(L, -2, "__index"); - // Put functions in metatable - luaL_register(L, NULL, minetest_entity_m); - // Put other stuff in metatable - // Register wrappers - ItemStack::Register(L); + LuaItemStack::Register(L); InvRef::Register(L); NodeMetaRef::Register(L); ObjectRef::Register(L); @@ -3705,62 +3750,22 @@ void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player) lua_getfield(L, -1, "creative_inventory"); luaL_checktype(L, -1, LUA_TTABLE); inventory_set_list_from_lua(&player->inventory, "main", L, -1, - player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE); + PLAYER_INVENTORY_SIZE); } /* - craftitem + item callbacks */ -static void pushPointedThing(lua_State *L, const PointedThing& pointed) -{ - lua_newtable(L); - if(pointed.type == POINTEDTHING_NODE) - { - lua_pushstring(L, "node"); - lua_setfield(L, -2, "type"); - push_v3s16(L, pointed.node_undersurface); - lua_setfield(L, -2, "under"); - push_v3s16(L, pointed.node_abovesurface); - lua_setfield(L, -2, "above"); - } - else if(pointed.type == POINTEDTHING_OBJECT) - { - lua_pushstring(L, "object"); - lua_setfield(L, -2, "type"); - objectref_get(L, pointed.object_id); - lua_setfield(L, -2, "ref"); - } - else - { - lua_pushstring(L, "nothing"); - lua_setfield(L, -2, "type"); - } -} - -void scriptapi_add_craftitem(lua_State *L, const char *name) -{ - StackUnroller stack_unroller(L); - assert(lua_gettop(L) > 0); - - // Set minetest.registered_craftitems[name] = table on top of stack - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_craftitems"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_pushvalue(L, -3); // push another reference to the table to be registered - lua_setfield(L, -2, name); // set minetest.registered_craftitems[name] -} - -static bool get_craftitem_callback(lua_State *L, const char *name, - const char *callbackname) +// Retrieves minetest.registered_items[name][callbackname] +// If that is nil or on error, return false and stack is unchanged +// If that is a function, returns true and pushes the +// function onto the stack +static bool get_item_callback(lua_State *L, + const char *name, const char *callbackname) { - // Get minetest.registered_craftitems[name][callbackname] - // If that is nil or on error, return false and stack is unchanged - // If that is a function, returns true and pushes the - // function onto the stack - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_craftitems"); + lua_getfield(L, -1, "registered_items"); lua_remove(L, -2); luaL_checktype(L, -1, LUA_TTABLE); lua_getfield(L, -1, name); @@ -3768,7 +3773,7 @@ static bool get_craftitem_callback(lua_State *L, const char *name, // Should be a table if(lua_type(L, -1) != LUA_TTABLE) { - errorstream<<"CraftItem name \""< Date: Sat, 21 Jan 2012 00:11:44 +0100 Subject: Node placement / mineral / serialization / iron freq / node_dig callback - Node placement code moved to Lua - Mineral system removed (added default:stone_with_coal and default:stone_with_iron). - MapBlock and MapNode serialization updated. - Mapgen: Frequency of iron increased. - node_dig callback and related changes. --- data/builtin.lua | 265 +++++++++- data/mods/default/init.lua | 99 ++-- .../mods/default/textures/default_mineral_coal.png | Bin 0 -> 952 bytes .../mods/default/textures/default_mineral_iron.png | Bin 0 -> 1614 bytes data/mods/legacy/init.lua | 2 + data/mods/legacy/textures/mineral_coal.png | Bin 952 -> 0 bytes data/mods/legacy/textures/mineral_iron.png | Bin 1614 -> 0 bytes src/CMakeLists.txt | 1 - src/client.cpp | 7 +- src/content_mapblock.cpp | 20 +- src/content_mapnode.cpp | 2 +- src/environment.cpp | 13 +- src/game.cpp | 11 +- src/gamedef.h | 1 - src/light.h | 17 +- src/main.cpp | 31 -- src/map.cpp | 23 +- src/map.h | 2 +- src/mapblock.cpp | 537 +++++++++++++++------ src/mapblock.h | 31 +- src/mapblock_mesh.cpp | 83 ++-- src/mapgen.cpp | 300 ++++++------ src/mapnode.cpp | 420 +++++++++------- src/mapnode.h | 112 ++--- src/materials.cpp | 15 +- src/materials.h | 8 +- src/mineral.cpp | 62 --- src/mineral.h | 47 -- src/nameidmapping.h | 3 + src/nodedef.cpp | 33 +- src/nodedef.h | 33 +- src/scriptapi.cpp | 314 +++++++----- src/scriptapi.h | 15 +- src/serialization.h | 3 +- src/server.cpp | 353 +------------- src/servermain.cpp | 5 - src/test.cpp | 3 - src/tile.cpp | 13 +- 38 files changed, 1520 insertions(+), 1364 deletions(-) create mode 100644 data/mods/default/textures/default_mineral_coal.png create mode 100644 data/mods/default/textures/default_mineral_iron.png delete mode 100644 data/mods/legacy/textures/mineral_coal.png delete mode 100644 data/mods/legacy/textures/mineral_iron.png delete mode 100644 src/mineral.cpp delete mode 100644 src/mineral.h (limited to 'src/scriptapi.cpp') diff --git a/data/builtin.lua b/data/builtin.lua index 1926d88b4..2e31c43b8 100644 --- a/data/builtin.lua +++ b/data/builtin.lua @@ -83,7 +83,7 @@ end -- Item definition helpers -- -minetest.inventorycube = function(img1, img2, img3) +function minetest.inventorycube(img1, img2, img3) img2 = img2 or img1 img3 = img3 or img1 return "[inventorycube" @@ -92,7 +92,11 @@ minetest.inventorycube = function(img1, img2, img3) .. "{" .. img3:gsub("%^", "&") end -minetest.get_pointed_thing_position = function(pointed_thing, above) +function minetest.pos_to_string(pos) + return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")" +end + +function minetest.get_pointed_thing_position(pointed_thing, above) if pointed_thing.type == "node" then if above then -- The position where a node would be placed @@ -113,31 +117,240 @@ minetest.get_pointed_thing_position = function(pointed_thing, above) end end -function minetest.item_place(itemstack, placer, pointed_thing) - pos = minetest.get_pointed_thing_position(pointed_thing, true) - if pos ~= nil then - item = itemstack:take_item() - if item ~= nil then - minetest.env:add_item(pos, item) +function minetest.dir_to_facedir(dir) + if math.abs(dir.x) > math.abs(dir.z) then + if dir.x < 0 then + return 3 + else + return 1 + end + else + if dir.z < 0 then + return 2 + else + return 0 + end + end +end + +function minetest.dir_to_wallmounted(dir) + if math.abs(dir.y) > math.max(math.abs(dir.x), math.abs(dir.z)) then + if dir.y < 0 then + return 1 + else + return 0 + end + elseif math.abs(dir.x) > math.abs(dir.z) then + if dir.x < 0 then + return 3 + else + return 2 + end + else + if dir.z < 0 then + return 5 + else + return 4 + end + end +end + +function minetest.get_node_drops(nodename, toolname) + local drop = ItemStack({name=nodename}):get_definition().drop + if drop == nil then + -- default drop + print("default drop: " .. nodename) + return {ItemStack({name=nodename})} + elseif type(drop) == "string" then + -- itemstring drop + return {ItemStack(drop)} + elseif drop.items == nil then + -- drop = {} to disable default drop + return {} + end + + -- Extended drop table + local got_items = {} + local got_count = 0 + local _, item, tool + for _, item in ipairs(drop.items) do + local good_rarity = true + local good_tool = true + if item.rarity ~= nil then + good_rarity = item.rarity < 1 or math.random(item.rarity) == 1 + end + if item.tools ~= nil then + good_tool = false + for _, tool in ipairs(item.tools) do + if tool:sub(1, 1) == '~' then + good_tool = toolname:find(tool:sub(2)) ~= nil + else + good_tool = toolname == tool + end + if good_tool then + break + end + end + end + if good_rarity and good_tool then + got_count = got_count + 1 + for _, add_item in ipairs(item.items) do + got_items[#got_items+1] = add_item + end + if drop.max_items ~= nil and got_count == drop.max_items then + break + end end end + return got_items +end + +function minetest.item_place_node(itemstack, placer, pointed_thing) + local item = itemstack:peek_item() + local def = itemstack:get_definition() + if def.type == "node" and pointed_thing.type == "node" then + local pos = pointed_thing.above + local oldnode = minetest.env:get_node(pos) + local olddef = ItemStack({name=oldnode.name}):get_definition() + + if not olddef.buildable_to then + minetest.log("info", placer:get_player_name() .. " tried to place" + .. " node in invalid position " .. minetest.pos_to_string(pos) + .. ", replacing " .. oldnode.name) + return + end + + minetest.log("action", placer:get_player_name() .. " places node " + .. def.name .. " at " .. minetest.pos_to_string(pos)) + + local newnode = {name = def.name, param1 = 0, param2 = 0} + + -- Calculate direction for wall mounted stuff like torches and signs + if def.paramtype2 == 'wallmounted' then + local under = pointed_thing.under + local above = pointed_thing.above + local dir = {x = under.x - above.x, y = under.y - above.y, z = under.z - above.z} + newnode.param2 = minetest.dir_to_wallmounted(dir) + -- Calculate the direction for furnaces and chests and stuff + elseif def.paramtype2 == 'facedir' then + local playerpos = placer:getpos() + local dir = {x = pos.x - playerpos.x, y = pos.y - playerpos.y, z = pos.z - playerpos.z} + newnode.param2 = minetest.dir_to_facedir(dir) + minetest.log("action", "facedir: " .. newnode.param2) + end + + -- Add node and update + minetest.env:add_node(pos, newnode) + + -- Set metadata owner + if def.metadata_name ~= "" then + minetest.env:get_meta(pos):set_owner(placer:get_player_name()) + end + + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_placenodes) do + callback(pos, newnode, placer) + end + + itemstack:take_item() + end + return itemstack +end + +function minetest.item_place_object(itemstack, placer, pointed_thing) + local pos = minetest.get_pointed_thing_position(pointed_thing, true) + if pos ~= nil then + local item = itemstack:take_item() + minetest.env:add_item(pos, item) + end return itemstack end +function minetest.item_place(itemstack, placer, pointed_thing) + if itemstack:get_definition().type == "node" then + return minetest.item_place_node(itemstack, placer, pointed_thing) + else + return minetest.item_place_object(itemstack, placer, pointed_thing) + end +end + function minetest.item_drop(itemstack, dropper, pos) minetest.env:add_item(pos, itemstack) return "" end -function minetest.item_eat(hp_change) +function minetest.item_eat(hp_change, replace_with_item) return function(itemstack, user, pointed_thing) -- closure if itemstack:take_item() ~= nil then user:set_hp(user:get_hp() + hp_change) + itemstack:add_item(replace_with_item) -- note: replace_with_item is optional end return itemstack end end +function minetest.node_punch(pos, node, puncher) + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_punchnodes) do + callback(pos, node, puncher) + end + +end + +function minetest.node_dig(pos, node, digger) + minetest.debug("node_dig") + + local def = ItemStack({name=node.name}):get_definition() + if not def.diggable then + minetest.debug("not diggable") + minetest.log("info", digger:get_player_name() .. " tried to dig " + .. node.name .. " which is not diggable " + .. minetest.pos_to_string(pos)) + return + end + + local meta = minetest.env:get_meta(pos) + if meta ~= nil and not meta:get_allow_removal() then + minetest.debug("dig prevented by metadata") + minetest.log("info", digger:get_player_name() .. " tried to dig " + .. node.name .. ", but removal is disabled by metadata " + .. minetest.pos_to_string(pos)) + return + end + + minetest.log('action', digger:get_player_name() .. " digs " + .. node.name .. " at " .. minetest.pos_to_string(pos)) + + if not minetest.setting_getbool("creative_mode") then + local wielded = digger:get_wielded_item() + local drops = minetest.get_node_drops(node.name, wielded:get_name()) + + -- Wear out tool + mp = def.material + tp = wielded:get_tool_digging_properties() + dp = minetest.get_digging_properties(mp, tp) + wielded:add_wear(dp.wear) + digger:set_wielded_item(wielded) + + -- Add dropped items + local _, dropped_item + for _, dropped_item in ipairs(drops) do + digger:get_inventory():add_item("main", dropped_item) + end + end + + -- Remove node and update + minetest.env:remove_node(pos) + + -- Run script hook + local _, callback + for _, callback in ipairs(minetest.registered_on_dignodes) do + callback(pos, node, digger) + end +end + -- -- Item definition defaults -- @@ -151,16 +364,18 @@ minetest.nodedef_default = { wield_image = "", wield_scale = {x=1,y=1,z=1}, stack_max = 99, - dropcount = -1, usable = false, liquids_pointable = false, tool_digging_properties = nil, -- Interaction callbacks - on_place = nil, -- let C handle node placement for now + on_place = minetest.item_place, on_drop = minetest.item_drop, on_use = nil, + on_punch = minetest.node_punch, + on_dig = minetest.node_dig, + -- Node properties drawtype = "normal", visual_scale = 1.0, @@ -172,6 +387,7 @@ minetest.nodedef_default = { alpha = 255, post_effect_color = {a=0, r=0, g=0, b=0}, paramtype = "none", + paramtype2 = "none", is_ground_content = false, sunlight_propagates = false, walkable = true, @@ -179,10 +395,6 @@ minetest.nodedef_default = { diggable = true, climbable = false, buildable_to = false, - wall_mounted = false, - --dug_item intentionally not defined here - extra_dug_item = "", - extra_dug_item_rarity = 2, metadata_name = "", liquidtype = "none", liquid_alternative_flowing = "", @@ -199,6 +411,8 @@ minetest.nodedef_default = { cuttability = 0, flammability = 0, }, + legacy_facedir_simple = false, + legacy_wallmounted = false, } minetest.craftitemdef_default = { @@ -369,12 +583,12 @@ function minetest.register_item(name, itemdef) error("Unable to register item: Type is invalid: " .. dump(itemdef)) end - -- Default dug item - if itemdef.type == "node" and itemdef.dug_item == nil then - itemdef.dug_item = ItemStack({name=itemdef.name}):to_string() + -- Flowing liquid uses param2 + if itemdef.type == "node" and itemdef.liquidtype == "flowing" then + itemdef.paramtype2 = "flowingliquid" end - -- Legacy stuff + -- BEGIN Legacy stuff if itemdef.cookresult_itemstring ~= nil and itemdef.cookresult_itemstring ~= "" then minetest.register_craft({ type="cooking", @@ -390,6 +604,7 @@ function minetest.register_item(name, itemdef) burntime=itemdef.furnace_burntime }) end + -- END Legacy stuff -- Disable all further modifications getmetatable(itemdef).__newindex = {} @@ -408,10 +623,11 @@ end function minetest.register_craftitem(name, craftitemdef) craftitemdef.type = "craft" - -- Legacy stuff + -- BEGIN Legacy stuff if craftitemdef.inventory_image == nil and craftitemdef.image ~= nil then craftitemdef.inventory_image = craftitemdef.image end + -- END Legacy stuff minetest.register_item(name, craftitemdef) end @@ -420,7 +636,7 @@ function minetest.register_tool(name, tooldef) tooldef.type = "tool" tooldef.stack_max = 1 - -- Legacy stuff + -- BEGIN Legacy stuff if tooldef.inventory_image == nil and tooldef.image ~= nil then tooldef.inventory_image = tooldef.image end @@ -450,6 +666,7 @@ function minetest.register_tool(name, tooldef) dd_cuttability = tooldef.dd_cuttability, } end + -- END Legacy stuff minetest.register_item(name, tooldef) end @@ -643,4 +860,10 @@ minetest.registered_on_newplayers, minetest.register_on_newplayer = make_registr minetest.registered_on_dieplayers, minetest.register_on_dieplayer = make_registration() minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make_registration() +-- +-- Set random seed +-- + +math.randomseed(os.time()) + -- END diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index 8093e99d5..7c6cccd44 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -176,6 +176,7 @@ -- - set_text(text) -- eg. set the text of a sign -- - get_text() -- - get_owner() +-- - set_owner(string) -- Generic node metadata specific: -- - set_infotext(infotext) -- - get_inventory() -> InvRef @@ -302,7 +303,7 @@ -- myvariable = whatever, -- } -- --- Item definition: +-- Item definition options (register_node, register_craftitem, register_tool) -- { -- description = "Steel Axe", -- inventory_image = "default_tool_steelaxe.png", @@ -328,9 +329,9 @@ -- on_use = func(item, user, pointed_thing), -- } -- --- Node definition options: +-- Node definition options (register_node): -- { --- , +-- , -- drawtype = "normal", -- visual_scale = 1.0, -- tile_images = {"default_unknown_block.png"}, @@ -341,6 +342,7 @@ -- alpha = 255, -- post_effect_color = {a=0, r=0, g=0, b=0}, -- paramtype = "none", +-- paramtype2 = "none", -- is_ground_content = false, -- sunlight_propagates = false, -- walkable = true, @@ -348,10 +350,8 @@ -- diggable = true, -- climbable = false, -- buildable_to = false, --- wall_mounted = false, --- dug_item = "", --- extra_dug_item = "", --- extra_dug_item_rarity = 2, +-- drop = "", +-- -- alternatively drop = { max_items = ..., items = { ... } } -- metadata_name = "", -- liquidtype = "none", -- liquid_alternative_flowing = "", @@ -368,23 +368,10 @@ -- cuttability = 0, -- flammability = 0, -- }, --- on_drop = func(item, dropper), --- on_place = func(item, placer, pointed_thing), --- on_use = func(item, user, pointed_thing), +-- legacy_facedir_simple = false, -- Support maps made in and before January 2012 +-- legacy_wallmounted = false, -- Support maps made in and before January 2012 -- } -- --- Craftitem definition options: --- { --- description = , --- inventory_image = "default_unknown_block.png", --- wield_image = "", --- stack_max = , --- liquids_pointable = , --- on_drop = func(item, dropper), --- on_place = func(item, placer, pointed_thing), --- on_use = func(item, user, pointed_thing), --- } --- -- Recipe: -- { -- output = 'default:pick_stone', @@ -1111,10 +1098,26 @@ minetest.register_craft({ minetest.register_node("default:stone", { description = "Stone", tile_images = {"default_stone.png"}, - paramtype = "mineral", is_ground_content = true, material = minetest.digprop_stonelike(1.0), - dug_item = 'node "default:cobble" 1', + drop = 'default:cobble', + legacy_mineral = true, +}) + +minetest.register_node("default:stone_with_coal", { + description = "Stone with coal", + tile_images = {"default_stone.png^default_mineral_coal.png"}, + is_ground_content = true, + material = minetest.digprop_stonelike(1.0), + drop = 'default:coal_lump', +}) + +minetest.register_node("default:stone_with_iron", { + description = "Stone with iron", + tile_images = {"default_stone.png^default_mineral_iron.png"}, + is_ground_content = true, + material = minetest.digprop_stonelike(1.0), + drop = 'default:iron_lump', }) minetest.register_node("default:dirt_with_grass", { @@ -1122,7 +1125,7 @@ minetest.register_node("default:dirt_with_grass", { tile_images = {"default_grass.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, is_ground_content = true, material = minetest.digprop_dirtlike(1.0), - dug_item = 'node "default:dirt" 1', + drop = 'default:dirt', }) minetest.register_node("default:dirt_with_grass_footsteps", { @@ -1130,7 +1133,7 @@ minetest.register_node("default:dirt_with_grass_footsteps", { tile_images = {"default_grass_footsteps.png", "default_dirt.png", "default_dirt.png^default_grass_side.png"}, is_ground_content = true, material = minetest.digprop_dirtlike(1.0), - dug_item = 'node "default:dirt" 1', + drop = 'default:dirt', }) minetest.register_node("default:dirt", { @@ -1159,7 +1162,7 @@ minetest.register_node("default:sandstone", { tile_images = {"default_sandstone.png"}, is_ground_content = true, material = minetest.digprop_dirtlike(1.0), -- FIXME should this be stonelike? - dug_item = 'node "default:sand" 1', -- FIXME is this intentional? + drop = 'default:sand', }) minetest.register_node("default:clay", { @@ -1167,7 +1170,7 @@ minetest.register_node("default:clay", { tile_images = {"default_clay.png"}, is_ground_content = true, material = minetest.digprop_dirtlike(1.0), - dug_item = 'craft "default:clay_lump" 4', + drop = 'default:clay_lump 4', }) minetest.register_node("default:brick", { @@ -1175,7 +1178,7 @@ minetest.register_node("default:brick", { tile_images = {"default_brick.png"}, is_ground_content = true, material = minetest.digprop_stonelike(1.0), - dug_item = 'craft "default:clay_brick" 4', + drop = 'default:clay_brick 4', }) minetest.register_node("default:tree", { @@ -1211,8 +1214,21 @@ minetest.register_node("default:leaves", { tile_images = {"default_leaves.png"}, paramtype = "light", material = minetest.digprop_leaveslike(1.0), - extra_dug_item = 'node "default:sapling" 1', - extra_dug_item_rarity = 20, + drop = { + max_items = 1, + items = { + { + -- player will get sapling with 1/20 chance + items = {'default:sapling'}, + rarity = 20, + }, + { + -- player will get leaves only if he get no saplings, + -- this is because max_items is 1 + items = {'default:leaves'}, + } + } + }, }) minetest.register_node("default:cactus", { @@ -1290,8 +1306,8 @@ minetest.register_node("default:ladder", { inventory_image = "default_ladder.png", wield_image = "default_ladder.png", paramtype = "light", + paramtype2 = "wallmounted", is_ground_content = true, - wall_mounted = true, walkable = false, climbable = true, selection_box = { @@ -1301,6 +1317,7 @@ minetest.register_node("default:ladder", { --wall_side = = }, material = minetest.digprop_woodlike(0.5), + legacy_wallmounted = true, }) minetest.register_node("default:wood", { @@ -1420,9 +1437,9 @@ minetest.register_node("default:torch", { inventory_image = "default_torch_on_floor.png", wield_image = "default_torch_on_floor.png", paramtype = "light", + paramtype2 = "wallmounted", sunlight_propagates = true, walkable = false, - wall_mounted = true, light_source = LIGHT_MAX-1, selection_box = { type = "wallmounted", @@ -1431,6 +1448,7 @@ minetest.register_node("default:torch", { wall_side = {-0.5, -0.3, -0.1, -0.5+0.3, 0.3, 0.1}, }, material = minetest.digprop_constanttime(0.0), + legacy_wallmounted = true, }) minetest.register_node("default:sign_wall", { @@ -1440,9 +1458,9 @@ minetest.register_node("default:sign_wall", { inventory_image = "default_sign_wall.png", wield_image = "default_sign_wall.png", paramtype = "light", + paramtype2 = "wallmounted", sunlight_propagates = true, walkable = false, - wall_mounted = true, metadata_name = "sign", selection_box = { type = "wallmounted", @@ -1451,33 +1469,37 @@ minetest.register_node("default:sign_wall", { --wall_side = }, material = minetest.digprop_constanttime(0.5), + legacy_wallmounted = true, }) minetest.register_node("default:chest", { description = "Chest", tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png", "default_chest_side.png", "default_chest_side.png", "default_chest_front.png"}, - paramtype = "facedir_simple", + paramtype2 = "facedir", metadata_name = "chest", material = minetest.digprop_woodlike(1.0), + legacy_facedir_simple = true, }) minetest.register_node("default:chest_locked", { description = "Locked Chest", tile_images = {"default_chest_top.png", "default_chest_top.png", "default_chest_side.png", "default_chest_side.png", "default_chest_side.png", "default_chest_lock.png"}, - paramtype = "facedir_simple", + paramtype2 = "facedir", metadata_name = "locked_chest", material = minetest.digprop_woodlike(1.0), + legacy_facedir_simple = true, }) minetest.register_node("default:furnace", { description = "Furnace", tile_images = {"default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png", "default_furnace_side.png", "default_furnace_front.png"}, - paramtype = "facedir_simple", + paramtype2 = "facedir", metadata_name = "furnace", material = minetest.digprop_stonelike(3.0), + legacy_facedir_simple = true, }) minetest.register_node("default:cobble", { @@ -1506,8 +1528,9 @@ minetest.register_node("default:nyancat", { tile_images = {"default_nc_side.png", "default_nc_side.png", "default_nc_side.png", "default_nc_side.png", "default_nc_back.png", "default_nc_front.png"}, inventory_image = "default_nc_front.png", - paramtype = "facedir_simple", + paramtype2 = "facedir", material = minetest.digprop_stonelike(3.0), + legacy_facedir_simple = true, }) minetest.register_node("default:nyancat_rainbow", { diff --git a/data/mods/default/textures/default_mineral_coal.png b/data/mods/default/textures/default_mineral_coal.png new file mode 100644 index 000000000..3ff9692fb Binary files /dev/null and b/data/mods/default/textures/default_mineral_coal.png differ diff --git a/data/mods/default/textures/default_mineral_iron.png b/data/mods/default/textures/default_mineral_iron.png new file mode 100644 index 000000000..51b15d95d Binary files /dev/null and b/data/mods/default/textures/default_mineral_iron.png differ diff --git a/data/mods/legacy/init.lua b/data/mods/legacy/init.lua index 127b0e17f..7f9088ce0 100644 --- a/data/mods/legacy/init.lua +++ b/data/mods/legacy/init.lua @@ -6,6 +6,8 @@ -- minetest.register_alias("stone", "default:stone") +minetest.register_alias("stone_with_coal", "default:stone_with_coal") +minetest.register_alias("stone_with_iron", "default:stone_with_iron") minetest.register_alias("dirt_with_grass", "default:dirt_with_grass") minetest.register_alias("dirt_with_grass_footsteps", "default:dirt_with_grass_footsteps") minetest.register_alias("dirt", "default:dirt") diff --git a/data/mods/legacy/textures/mineral_coal.png b/data/mods/legacy/textures/mineral_coal.png deleted file mode 100644 index 3ff9692fb..000000000 Binary files a/data/mods/legacy/textures/mineral_coal.png and /dev/null differ diff --git a/data/mods/legacy/textures/mineral_iron.png b/data/mods/legacy/textures/mineral_iron.png deleted file mode 100644 index 51b15d95d..000000000 Binary files a/data/mods/legacy/textures/mineral_iron.png and /dev/null differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e82e26dc7..ee02d66f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,7 +115,6 @@ set(common_SRCS nodemetadata.cpp serverobject.cpp noise.cpp - mineral.cpp porting.cpp materials.cpp defaultsettings.cpp diff --git a/src/client.cpp b/src/client.cpp index feb8a3a1e..602f0cf84 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -899,7 +899,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) Update an existing block */ //infostream<<"Updating"<deSerialize(istr, ser_version); + block->deSerialize(istr, ser_version, false); } else { @@ -908,7 +908,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) */ //infostream<<"Creating new"<deSerialize(istr, ser_version); + block->deSerialize(istr, ser_version, false); sector->insertBlock(block); } @@ -1816,8 +1816,7 @@ void Client::addNode(v3s16 p, MapNode n) try { //TimeTaker timer3("Client::addNode(): addNodeAndUpdate"); - std::string st = std::string(""); - m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st); + m_env.getMap().addNodeAndUpdate(p, n, modified_blocks); } catch(InvalidPositionException &e) {} diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 79f49cbf8..dc1e1daed 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -85,15 +85,15 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box, video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]), video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]), // back - video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[16],txc[17]), - video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[18],txc[17]), - video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[18],txc[19]), - video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[16],txc[19]), + video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]), + video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]), + video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]), + video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]), // front - video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[20],txc[21]), - video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[22],txc[21]), - video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[22],txc[23]), - video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[20],txc[23]), + video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]), + video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]), + video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]), + video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]), }; for(s32 j=0; j<24; j++) @@ -602,7 +602,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, break; case NDT_TORCHLIKE: { - v3s16 dir = unpackDir(n.param2); + v3s16 dir = n.getWallMountedDir(nodedef); AtlasPointer ap(0); if(dir == v3s16(0,-1,0)){ @@ -694,7 +694,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, ap.x0(), ap.y1()), }; - v3s16 dir = unpackDir(n.param2); + v3s16 dir = n.getWallMountedDir(nodedef); for(s32 i=0; i<4; i++) { diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index 4701736cf..ce7ee593f 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Ranges: 0x000...0x07f (0...127): param2 is fully usable 126 and 127 are reserved (CONTENT_AIR and CONTENT_IGNORE). - 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable + 0x800...0xfff (2048...4095): higher 4 bits of param2 are not usable */ #define CONTENT_STONE 0 #define CONTENT_WATER 2 diff --git a/src/environment.cpp b/src/environment.cpp index 3a294086c..7c2aef272 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2057,7 +2057,9 @@ void ClientEnvironment::step(float dtime) MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); } - catch(InvalidPositionException &e) {} + catch(InvalidPositionException &e){ + light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); + } player->updateLight(light); /* @@ -2104,7 +2106,6 @@ void ClientEnvironment::step(float dtime) if(m_active_object_light_update_interval.step(dtime, 0.21)) { // Update lighting - //u8 light = LIGHT_MAX; u8 light = 0; try{ // Get node at head @@ -2112,7 +2113,9 @@ void ClientEnvironment::step(float dtime) MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); } - catch(InvalidPositionException &e) {} + catch(InvalidPositionException &e){ + light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); + } obj->updateLight(light); } } @@ -2203,7 +2206,9 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object) MapNode n = m_map->getNode(p); light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); } - catch(InvalidPositionException &e) {} + catch(InvalidPositionException &e){ + light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); + } object->updateLight(light); } return object->getId(); diff --git a/src/game.cpp b/src/game.cpp index 7bd5d9587..055320a8e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -303,6 +303,8 @@ PointedThing getPointedThing(Client *client, v3f player_position, should_show_hilightbox = false; selected_object = NULL; + INodeDefManager *nodedef = client->getNodeDefManager(); + // First try to find a pointed at active object if(look_for_object) { @@ -378,7 +380,7 @@ PointedThing getPointedThing(Client *client, v3f player_position, v3s16(-1,0,0), // left }; - const ContentFeatures &f = client->getNodeDefManager()->get(n); + const ContentFeatures &f = nodedef->get(n); if(f.selection_box.type == NODEBOX_FIXED) { @@ -447,7 +449,7 @@ PointedThing getPointedThing(Client *client, v3f player_position, } else if(f.selection_box.type == NODEBOX_WALLMOUNTED) { - v3s16 dir = unpackDir(n.param2); + v3s16 dir = n.getWallMountedDir(nodedef); v3f dir_f = v3f(dir.X, dir.Y, dir.Z); dir_f *= BS/2 - BS/6 - BS/20; v3f cpf = npf + dir_f; @@ -1827,11 +1829,10 @@ void the_game( MapNode n = client.getNode(nodepos); // Get digging properties for material and tool - content_t material = n.getContent(); + MaterialProperties mp = nodedef->get(n.getContent()).material; ToolDiggingProperties tp = playeritem.getToolDiggingProperties(itemdef); - DiggingProperties prop = - getDiggingProperties(material, &tp, nodedef); + DiggingProperties prop = getDiggingProperties(&mp, &tp); float dig_time_complete = 0.0; diff --git a/src/gamedef.h b/src/gamedef.h index 8df6988ad..10ab0b0bc 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc., class IItemDefManager; class INodeDefManager; class ICraftDefManager; -// Mineral too? class ITextureSource; /* diff --git a/src/light.h b/src/light.h index c1af7fa62..238acce43 100644 --- a/src/light.h +++ b/src/light.h @@ -75,16 +75,27 @@ inline u8 undiminish_light(u8 light) extern u8 light_decode_table[LIGHT_MAX+1]; +// 0 <= light <= LIGHT_SUN +// 0 <= return value <= 255 inline u8 decode_light(u8 light) { - if(light == LIGHT_SUN) - return light_decode_table[LIGHT_MAX]; - if(light > LIGHT_MAX) light = LIGHT_MAX; return light_decode_table[light]; } +// 0 <= daylight_factor <= 1000 +// 0 <= lightday, lightnight <= LIGHT_SUN +// 0 <= return value <= LIGHT_SUN +inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight) +{ + u32 c = 1000; + u32 l = ((daylight_factor * lightday + (c-daylight_factor) * lightnight))/c; + if(l > LIGHT_SUN) + l = LIGHT_SUN; + return l; +} + #endif diff --git a/src/main.cpp b/src/main.cpp index b7c3ceffe..6cb9cf984 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,24 +54,6 @@ A list of "active blocks" in which stuff happens. (+=done) + This was left to be done by the old system and it sends only the nearest ones. -Vim conversion regexpes for moving to extended content type storage: -%s/\(\.\|->\)d \([!=]=\)/\1getContent() \2/g -%s/content_features(\([^.]*\)\.d)/content_features(\1)/g -%s/\(\.\|->\)d = \([^;]*\);/\1setContent(\2);/g -%s/\(getNodeNoExNoEmerge([^)]*)\)\.d/\1.getContent()/g -%s/\(getNodeNoExNoEmerge(.*)\)\.d/\1.getContent()/g -%s/\.d;/.getContent();/g -%s/\(content_liquid\|content_flowing_liquid\|make_liquid_flowing\|content_pointable\)(\([^.]*\).d)/\1(\2.getContent())/g -Other things to note: -- node.d = node.param0 (only in raw serialization; use getContent() otherwise) -- node.param = node.param1 -- node.dir = node.param2 -- content_walkable(node.d) etc should be changed to - content_features(node).walkable etc -- Also check for lines that store the result of getContent to a 8-bit - variable and fix them (result of getContent() must be stored in - content_t, which is 16-bit) - NOTE: Seeds in 1260:6c77e7dbfd29: 5721858502589302589: Spawns you on a small sand island with a surface dungeon @@ -351,8 +333,6 @@ TODO: Block cube placement around player's head TODO: Protocol version field TODO: Think about using same bits for material for fences and doors, for example -TODO: Move mineral to param2, increment map serialization version, add - conversion SUGG: Restart irrlicht completely when coming back to main menu from game. - This gets rid of everything that is stored in irrlicht's caches. @@ -419,7 +399,6 @@ Doing currently: #include "filesys.h" #include "config.h" #include "guiMainMenu.h" -#include "mineral.h" #include "materials.h" #include "game.h" #include "keycode.h" @@ -1260,16 +1239,6 @@ int main(int argc, char *argv[]) srand(time(0)); mysrand(time(0)); - /* - Pre-initialize some stuff with a dummy irrlicht wrapper. - - These are needed for unit tests at least. - */ - - // Must be called before texturesource is created - // (for texture atlas making) - init_mineral(); - /* Run unit tests */ diff --git a/src/map.cpp b/src/map.cpp index 8bdc2ad4c..31c0c958b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -915,7 +915,7 @@ void Map::updateLighting(core::map & a_blocks, /* */ void Map::addNodeAndUpdate(v3s16 p, MapNode n, - core::map &modified_blocks, std::string &player_name) + core::map &modified_blocks) { INodeDefManager *nodemgr = m_gamedef->ndef(); @@ -1010,9 +1010,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, if(!meta){ errorstream<<"Failed to create node metadata \"" <setOwner(player_name); - setNodeMetadata(p, meta); } } @@ -1291,8 +1288,7 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n) bool succeeded = true; try{ core::map modified_blocks; - std::string st = std::string(""); - addNodeAndUpdate(p, n, modified_blocks, st); + addNodeAndUpdate(p, n, modified_blocks); // Copy modified_blocks to event for(core::map::Iterator @@ -3271,10 +3267,7 @@ void ServerMap::saveBlock(MapBlock *block) o.write((char*)&version, 1); // Write basic data - block->serialize(o, version); - - // Write extra data stored on disk - block->serializeDiskExtra(o, version); + block->serialize(o, version, true); // Write block to database @@ -3336,11 +3329,8 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto } // Read basic data - block->deSerialize(is, version); + block->deSerialize(is, version, true); - // Read extra data stored on disk - block->deSerializeDiskExtra(is, version); - // If it's a new block, insert it to the map if(created_new) sector->insertBlock(block); @@ -3406,10 +3396,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool } // Read basic data - block->deSerialize(is, version); - - // Read extra data stored on disk - block->deSerializeDiskExtra(is, version); + block->deSerialize(is, version, true); // If it's a new block, insert it to the map if(created_new) diff --git a/src/map.h b/src/map.h index 2bd2c0eb8..90255c1d9 100644 --- a/src/map.h +++ b/src/map.h @@ -212,7 +212,7 @@ public: These handle lighting but not faces. */ void addNodeAndUpdate(v3s16 p, MapNode n, - core::map &modified_blocks, std::string &player_name); + core::map &modified_blocks); void removeNodeAndUpdate(v3s16 p, core::map &modified_blocks); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 73c13caca..fb3bbf7a7 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -507,25 +507,41 @@ s16 MapBlock::getGroundLevel(v2s16 p2d) /* Serialization */ - // List relevant id-name pairs for ids in the block using nodedef -static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block, +// Renumbers the content IDs (starting at 0 and incrementing +static void getBlockNodeIdMapping(NameIdMapping *nimap, MapNode *nodes, INodeDefManager *nodedef) { + std::map mapping; std::set unknown_contents; - for(s16 z0=0; z0getNode(p); - content_t id = n.getContent(); - const ContentFeatures &f = nodedef->get(id); - const std::string &name = f.name; - if(name == "") - unknown_contents.insert(id); + content_t global_id = nodes[i].getContent(); + content_t id = CONTENT_IGNORE; + + // Try to find an existing mapping + std::map::iterator j = mapping.find(global_id); + if(j != mapping.end()) + { + id = j->second; + } else - nimap->set(id, name); + { + // We have to assign a new mapping + id = id_counter++; + mapping.insert(std::make_pair(global_id, id)); + + const ContentFeatures &f = nodedef->get(global_id); + const std::string &name = f.name; + if(name == "") + unknown_contents.insert(global_id); + else + nimap->set(id, name); + } + + // Update the MapNode + nodes[i].setContent(id); } for(std::set::const_iterator i = unknown_contents.begin(); @@ -537,7 +553,7 @@ static void getBlockNodeIdMapping(NameIdMapping *nimap, MapBlock *block, // Correct ids in the block to match nodedef based on names. // Unknown ones are added to nodedef. // Will not update itself to match id-name pairs in nodedef. -void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, +static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, IGameDef *gamedef) { INodeDefManager *nodedef = gamedef->ndef(); @@ -547,13 +563,9 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, // correct ids. std::set unnamed_contents; std::set unallocatable_contents; - for(s16 z0=0; z0getNode(p); - content_t local_id = n.getContent(); + content_t local_id = nodes[i].getContent(); std::string name; bool found = nimap->getName(local_id, name); if(!found){ @@ -569,8 +581,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, continue; } } - n.setContent(global_id); - block->setNode(p, n); + nodes[i].setContent(global_id); } for(std::set::const_iterator i = unnamed_contents.begin(); @@ -588,7 +599,7 @@ void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, } } -void MapBlock::serialize(std::ostream &os, u8 version) +void MapBlock::serialize(std::ostream &os, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); @@ -598,22 +609,226 @@ void MapBlock::serialize(std::ostream &os, u8 version) throw SerializationError("ERROR: Not writing dummy block."); } - // These have no compression - if(version <= 3 || version == 5 || version == 6) + if(version <= 21) { - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; - - u32 buflen = 1 + nodecount * MapNode::serializedLength(version); - SharedBuffer dest(buflen); + serialize_pre22(os, version, disk); + return; + } - dest[0] = is_underground; + // First byte + u8 flags = 0; + if(is_underground) + flags |= 0x01; + if(m_day_night_differs) + flags |= 0x02; + if(m_lighting_expired) + flags |= 0x04; + if(m_generated == false) + flags |= 0x08; + writeU8(os, flags); + + /* + Bulk node data + */ + NameIdMapping nimap; + u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; + if(disk) + { + MapNode *tmp_nodes = new MapNode[nodecount]; for(u32 i=0; indef()); + + u8 content_width = 1; + /*u8 content_width = (nimap.size() <= 255) ? 1 : 2;*/ + u8 params_width = 2; + writeU8(os, content_width); + writeU8(os, params_width); + MapNode::serializeBulk(os, version, tmp_nodes, nodecount, + content_width, params_width, true); + delete[] tmp_nodes; + } + else + { + u8 content_width = 1; + /*u8 content_width = 2;*/ + u8 params_width = 2; + writeU8(os, content_width); + writeU8(os, params_width); + MapNode::serializeBulk(os, version, data, nodecount, + content_width, params_width, true); + } + + /* + Node metadata + */ + std::ostringstream oss(std::ios_base::binary); + m_node_metadata->serialize(oss); + compressZlib(oss.str(), os); + + /* + Data that goes to disk, but not the network + */ + if(disk) + { + // Static objects + m_static_objects.serialize(os); + + // Timestamp + writeU32(os, getTimestamp()); + + // Write block-specific node definition id mapping + nimap.serialize(os); + } +} + + +void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) +{ + if(!ser_ver_supported(version)) + throw VersionMismatchException("ERROR: MapBlock format not supported"); + + if(version <= 21) + { + deSerialize_pre22(is, version, disk); + return; + } + + u8 flags = readU8(is); + is_underground = (flags & 0x01) ? true : false; + m_day_night_differs = (flags & 0x02) ? true : false; + m_lighting_expired = (flags & 0x04) ? true : false; + m_generated = (flags & 0x08) ? false : true; + + /* + Bulk node data + */ + u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; + u8 content_width = readU8(is); + u8 params_width = readU8(is); + if(content_width != 1) + throw SerializationError("MapBlock::deSerialize(): invalid content_width"); + if(params_width != 2) + throw SerializationError("MapBlock::deSerialize(): invalid params_width"); + MapNode::deSerializeBulk(is, version, data, nodecount, + content_width, params_width, true); + + /* + NodeMetadata + */ + // Ignore errors + try{ + std::ostringstream oss(std::ios_base::binary); + decompressZlib(is, oss); + std::istringstream iss(oss.str(), std::ios_base::binary); + m_node_metadata->deSerialize(iss, m_gamedef); + } + catch(SerializationError &e) + { + errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" + <<" while deserializing node metadata"< unknown_contents; + for(u32 i=0; iget(id); + const std::string &name = f.name; + if(name == "") + unknown_contents.insert(id); + else + nimap->set(id, name); + } + for(std::set::const_iterator + i = unknown_contents.begin(); + i != unknown_contents.end(); i++){ + errorstream<<"getBlockNodeIdMapping_pre22(): IGNORING ERROR: " + <<"Name for node id "<<(*i)<<" not known"<ndef(); + for(u32 i=0; iget(tmp_data[i].getContent()); + // Mineral + if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent()) + { + tmp_data[i].setContent(nodedef->getId("default:stone")); + tmp_data[i].setParam1(1); // MINERAL_COAL + } + else if(nodedef->getId("default:stone_with_iron") == tmp_data[i].getContent()) + { + tmp_data[i].setContent(nodedef->getId("default:stone")); + tmp_data[i].setParam1(2); // MINERAL_IRON + } + // facedir_simple + if(f.legacy_facedir_simple) { - u32 s = 1 + i * MapNode::serializedLength(version); - data[i].serialize(&dest[s], version); + tmp_data[i].setParam1(tmp_data[i].getParam2()); + tmp_data[i].setParam2(0); } + // wall_mounted + if(f.legacy_wallmounted) + { + u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0}; + u8 dir_new_format = tmp_data[i].getParam2() & 7; // lowest 3 bits + u8 dir_old_format = wallmounted_new_to_old[dir_new_format]; + tmp_data[i].setParam2(dir_old_format); + } + } + + // Serialize nodes + u32 ser_length = MapNode::serializedLength(version); + SharedBuffer databuf_nodelist(nodecount * ser_length); + for(u32 i=0; i materialdata(nodecount); for(u32 i=0; i lightdata(nodecount); for(u32 i=0; i param2data(nodecount); for(u32 i=0; i databuf_nodelist(nodecount*3); - for(u32 i=0; i databuf(nodecount*3); for(u32 i=0; i= 9) + { + // count=0 + writeU16(os, 0); + } - // These have no "generated" field - if(version < 18) - { - m_generated = true; + // Versions up from 15 have static objects. + if(version >= 15) + { + m_static_objects.serialize(os); + } + + // Timestamp + if(version >= 17) + { + writeU32(os, getTimestamp()); + } + + // Scan and write node definition id mapping + if(version >= 21) + { + NameIdMapping nimap; + getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef()); + nimap.serialize(os); + } } +} + +void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk) +{ + u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; + + // Initialize default flags + is_underground = false; + m_day_night_differs = false; + m_lighting_expired = false; + m_generated = true; + + // Make a temporary buffer + u32 ser_length = MapNode::serializedLength(version); + SharedBuffer databuf_nodelist(nodecount * ser_length); // These have no compression if(version <= 3 || version == 5 || version == 6) { - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; char tmp; is.read(&tmp, 1); if(is.gcount() != 1) throw SerializationError ("MapBlock::deSerialize: no enough input data"); is_underground = tmp; - for(u32 i=0; i d(len); - is.read((char*)*d, len); - if(is.gcount() != len) - throw SerializationError - ("MapBlock::deSerialize: no enough input data"); - data[i].deSerialize(*d, version); - } + is.read((char*)*databuf_nodelist, nodecount * ser_length); + if(is.gcount() != nodecount * ser_length) + throw SerializationError + ("MapBlock::deSerialize: no enough input data"); } else if(version <= 10) { - u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; - u8 t8; is.read((char*)&t8, 1); is_underground = t8; @@ -786,7 +1009,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version) ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i= 9) + // Deserialize node data + for(u32 i=0; i= 15) - { - m_static_objects.serialize(os); + data[i].deSerialize(&databuf_nodelist[i*ser_length], version); } - // Timestamp - if(version >= 17) + if(disk) { - writeU32(os, getTimestamp()); - } + /* + Versions up from 9 have block objects. (DEPRECATED) + */ + if(version >= 9){ + u16 count = readU16(is); + // Not supported and length not known if count is not 0 + if(count != 0){ + errorstream<<"WARNING: MapBlock::deSerialize_pre22(): " + <<"Ignoring stuff coming at and after MBOs"<= 15) + m_static_objects.deSerialize(is); + + // Timestamp + if(version >= 17){ + setTimestamp(readU32(is)); + m_disk_timestamp = m_timestamp; + } else { + setTimestamp(BLOCK_TIMESTAMP_UNDEFINED); + } - // Scan and write node definition id mapping - if(version >= 21){ + // Dynamically re-set ids based on node names NameIdMapping nimap; - getBlockNodeIdMapping(&nimap, this, m_gamedef->ndef()); - nimap.serialize(os); + // If supported, read node definition id mapping + if(version >= 21){ + nimap.deSerialize(is); + // Else set the legacy mapping + } else { + content_mapnode_get_name_id_mapping(&nimap); + } + correctBlockNodeIds(&nimap, data, m_gamedef); } -} -void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version) -{ - /* - Versions up from 9 have block objects. (DEPRECATED) - */ - if(version >= 9){ - u16 count = readU16(is); - // Not supported and length not known if count is not 0 - if(count != 0){ - errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): " - <<"Ignoring stuff coming at and after MBOs"<ndef(); + for(u32 i=0; iget(data[i].getContent()); + // Mineral + if(nodedef->getId("default:stone") == data[i].getContent() + && data[i].getParam1() == 1) + { + //dstream << "legacy coal\n"; + data[i].setContent(nodedef->getId("default:stone_with_coal")); + data[i].setParam1(0); + } + else if(nodedef->getId("default:stone") == data[i].getContent() + && data[i].getParam1() == 2) + { + //dstream << "legacy iron\n"; + data[i].setContent(nodedef->getId("default:stone_with_iron")); + data[i].setParam1(0); + } + // facedir_simple + if(f.legacy_facedir_simple) + { + dstream << "legacy_facedir_simple\n"; + data[i].setParam2(data[i].getParam1()); + data[i].setParam1(0); + } + // wall_mounted + if(f.legacy_wallmounted) + { + dstream << "legacy_wallmounted\n"; + u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0}; + u8 dir_old_format = data[i].getParam2(); + u8 dir_new_format = 0; + for(u8 j=0; j<8; j++) + { + if((dir_old_format & wallmounted_new_to_old[j]) != 0) + { + dir_new_format = j; + break; + } + } + data[i].setParam2(dir_new_format); } } - /* - Versions up from 15 have static objects. - */ - if(version >= 15) - m_static_objects.deSerialize(is); - - // Timestamp - if(version >= 17){ - setTimestamp(readU32(is)); - m_disk_timestamp = m_timestamp; - } else { - setTimestamp(BLOCK_TIMESTAMP_UNDEFINED); - } - - // Dynamically re-set ids based on node names - NameIdMapping nimap; - // If supported, read node definition id mapping - if(version >= 21){ - nimap.deSerialize(is); - // Else set the legacy mapping - } else { - content_mapnode_get_name_id_mapping(&nimap); - } - correctBlockNodeIds(&nimap, this, m_gamedef); } /* diff --git a/src/mapblock.h b/src/mapblock.h index f2d94753c..c9ff36679 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -363,17 +363,8 @@ public: Graphics-related methods */ - /*// A quick version with nodes passed as parameters - u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, - v3s16 face_dir);*/ - /*// A more convenient version - u8 getFaceLight(u32 daynight_ratio, v3s16 p, v3s16 face_dir) - { - return getFaceLight(daynight_ratio, - getNodeParentNoEx(p), - getNodeParentNoEx(p + face_dir), - face_dir); - }*/ +#ifndef SERVER // Only on client + u8 getFaceLight2(u32 daynight_ratio, v3s16 p, v3s16 face_dir, INodeDefManager *nodemgr) { @@ -383,8 +374,6 @@ public: face_dir, nodemgr); } -#ifndef SERVER // Only on client - #if 1 /* Thread-safely updates the whole mesh of the mapblock. @@ -524,20 +513,20 @@ public: */ // These don't write or read version by itself - void serialize(std::ostream &os, u8 version); - void deSerialize(std::istream &is, u8 version); - - // Used after the basic ones when writing on disk (serverside) - void serializeDiskExtra(std::ostream &os, u8 version); - // In addition to doing other things, will add unknown blocks from - // id-name mapping to wndef - void deSerializeDiskExtra(std::istream &is, u8 version); + // Set disk to true for on-disk format, false for over-the-network format + void serialize(std::ostream &os, u8 version, bool disk); + // If disk == true: In addition to doing other things, will add + // unknown blocks from id-name mapping to wndef + void deSerialize(std::istream &is, u8 version, bool disk); private: /* Private methods */ + void serialize_pre22(std::ostream &os, u8 version, bool disk); + void deSerialize_pre22(std::istream &is, u8 version, bool disk); + /* Used only internally, because changes can't be tracked */ diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index db9057e19..b843448c4 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "gamedef.h" #include "content_mapblock.h" -#include "mineral.h" // For mineral_block_texture void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block) { @@ -282,59 +281,37 @@ static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p, dest.push_back(face); } -static TileSpec getTile(const MapNode &node, v3s16 dir, - ITextureSource *tsrc, INodeDefManager *nodemgr) +static TileSpec getTile(const MapNode &node, v3s16 dir, INodeDefManager *nodemgr) { - const ContentFeatures &f = nodemgr->get(node); + // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0), + // (0,0,1), (0,0,-1) or (0,0,0) + assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1); + + // Convert direction to single integer for table lookup + // 0 = (0,0,0) + // 1 = (1,0,0) + // 2 = (0,1,0) + // 3 = (0,0,1) + // 4 = invalid, treat as (0,0,0) + // 5 = (0,0,-1) + // 6 = (0,-1,0) + // 7 = (-1,0,0) + u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7; + + // Get rotation for things like chests + u8 facedir = node.getFaceDir(nodemgr); + assert(facedir <= 3); - if(f.param_type == CPT_FACEDIR_SIMPLE) - dir = facedir_rotate(node.param1, dir); - - TileSpec spec; - - s32 dir_i = -1; - - if(dir == v3s16(0,0,0)) - dir_i = -1; - else if(dir == v3s16(0,1,0)) - dir_i = 0; - else if(dir == v3s16(0,-1,0)) - dir_i = 1; - else if(dir == v3s16(1,0,0)) - dir_i = 2; - else if(dir == v3s16(-1,0,0)) - dir_i = 3; - else if(dir == v3s16(0,0,1)) - dir_i = 4; - else if(dir == v3s16(0,0,-1)) - dir_i = 5; - - if(dir_i == -1) - // Non-directional - spec = f.tiles[0]; - else - spec = f.tiles[dir_i]; - - /* - If it contains some mineral, change texture id - */ - if(f.param_type == CPT_MINERAL && tsrc) + static const u8 dir_to_tile[4 * 8] = { - u8 mineral = node.getMineral(nodemgr); - std::string mineral_texture_name = mineral_block_texture(mineral); - if(mineral_texture_name != "") - { - u32 orig_id = spec.texture.id; - std::string texture_name = tsrc->getTextureName(orig_id); - //texture_name += "^blit:"; - texture_name += "^"; - texture_name += mineral_texture_name; - u32 new_id = tsrc->getTextureId(texture_name); - spec.texture = tsrc->getTexture(new_id); - } - } - - return spec; + // 0 +X +Y +Z 0 -Z -Y -X + 0, 2, 0, 4, 0, 5, 1, 3, // facedir = 0 + 0, 4, 0, 3, 0, 2, 1, 5, // facedir = 1 + 0, 3, 0, 5, 0, 4, 1, 2, // facedir = 2 + 0, 5, 0, 2, 0, 3, 1, 4, // facedir = 3 + }; + + return nodemgr->get(node).tiles[dir_to_tile[facedir*8 + dir_i]]; } /* @@ -345,7 +322,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, NodeModMap *temp_mods, ITextureSource *tsrc, INodeDefManager *ndef) { TileSpec spec; - spec = getTile(mn, face_dir, tsrc, ndef); + spec = getTile(mn, face_dir, ndef); /* Check temporary modifications on this node @@ -363,7 +340,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, if(mod.type == NODEMOD_CHANGECONTENT) { MapNode mn2(mod.param); - spec = getTile(mn2, face_dir, tsrc, ndef); + spec = getTile(mn2, face_dir, ndef); } #endif if(mod.type == NODEMOD_CRACK) diff --git a/src/mapgen.cpp b/src/mapgen.cpp index c2256cedb..fe2ce13f5 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -22,7 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "noise.h" #include "mapblock.h" #include "map.h" -#include "mineral.h" //#include "serverobject.h" #include "content_sao.h" #include "nodedef.h" @@ -1652,15 +1651,20 @@ void make_block(BlockMakeData *data) MapNode n_##name(c_##name); CONTENT_VARIABLE(ndef, stone); - CONTENT_VARIABLE(ndef, water_source); CONTENT_VARIABLE(ndef, air); + CONTENT_VARIABLE(ndef, water_source); CONTENT_VARIABLE(ndef, dirt); CONTENT_VARIABLE(ndef, sand); CONTENT_VARIABLE(ndef, gravel); + CONTENT_VARIABLE(ndef, clay); CONTENT_VARIABLE(ndef, lava_source); CONTENT_VARIABLE(ndef, cobble); CONTENT_VARIABLE(ndef, mossycobble); CONTENT_VARIABLE(ndef, dirt_with_grass); + CONTENT_VARIABLE(ndef, junglegrass); + CONTENT_VARIABLE(ndef, stone_with_coal); + CONTENT_VARIABLE(ndef, stone_with_iron); + CONTENT_VARIABLE(ndef, mese); /* Make base ground level @@ -1702,139 +1706,6 @@ void make_block(BlockMakeData *data) } } - /* - Add minerals - */ - - { - PseudoRandom mineralrandom(blockseed); - - /* - Add meseblocks - */ - for(s16 i=0; i 0.0) - new_content = MapNode(LEGN(ndef, "CONTENT_STONE"), MINERAL_IRON); - /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD")); - else - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND"));*/ - } - /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1) - { - }*/ - - if(new_content.getContent() != CONTENT_IGNORE) - { - for(u16 i=0; i<27; i++) - { - v3s16 p = v3s16(x,y,z) + g_27dirs[i]; - u32 vi = vmanip.m_area.index(p); - if(vmanip.m_data[vi].getContent() == base_content) - { - if(mineralrandom.next()%sparseness == 0) - vmanip.m_data[vi] = new_content; - } - } - } - } - } - /* - Add coal - */ - //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++) - //for(s16 i=0; i<50; i++) - u16 coal_amount = 30; - u16 coal_rareness = 60 / coal_amount; - if(coal_rareness == 0) - coal_rareness = 1; - if(mineralrandom.next()%coal_rareness == 0) - { - u16 a = mineralrandom.next() % 16; - u16 amount = coal_amount * a*a*a / 1000; - for(s16 i=0; i 1.2) - vmanip.m_data[i].setContent(LEGN(ndef, "CONTENT_MUD")); + vmanip.m_data[i].setContent(c_dirt); }*/ data->vmanip->m_area.add_y(em, i, -1); } @@ -2077,23 +1948,23 @@ void make_block(BlockMakeData *data) ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1)) ); if (have_clay) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_CLAY")); + vmanip.m_data[i] = MapNode(c_clay); else - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_SAND")); + vmanip.m_data[i] = MapNode(c_sand); } #if 1 else if(current_depth==0 && !water_detected && y >= WATER_LEVEL && air_detected) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_GRASS")); + vmanip.m_data[i] = MapNode(c_dirt_with_grass); #endif else - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_MUD")); + vmanip.m_data[i] = MapNode(c_dirt); } else { - if(vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_MUD") - || vmanip.m_data[i].getContent() == LEGN(ndef, "CONTENT_GRASS")) - vmanip.m_data[i] = MapNode(LEGN(ndef, "CONTENT_STONE")); + if(vmanip.m_data[i].getContent() == c_dirt + || vmanip.m_data[i].getContent() == c_dirt_with_grass) + vmanip.m_data[i] = MapNode(c_stone); } current_depth++; @@ -2171,7 +2042,7 @@ void make_block(BlockMakeData *data) make_papyrus(vmanip, p, ndef); } // Trees grow only on mud and grass, on land - else if((n->getContent() == c_dirt || n->getContent() == LEGN(ndef, "CONTENT_GRASS")) && y > WATER_LEVEL + 2) + else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2) { p.Y++; //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5) @@ -2238,10 +2109,10 @@ void make_block(BlockMakeData *data) continue; /*p.Y--; if(vmanip.m_area.contains(p)) - vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_MUD"); + vmanip.m_data[vmanip.m_area.index(p)] = c_dirt; p.Y++;*/ if(vmanip.m_area.contains(p)) - vmanip.m_data[vmanip.m_area.index(p)] = LEGN(ndef, "CONTENT_JUNGLEGRASS"); + vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass; } } @@ -2269,7 +2140,7 @@ void make_block(BlockMakeData *data) /*{ u32 i = data->vmanip->m_area.index(v3s16(p)); MapNode *n = &data->vmanip->m_data[i]; - if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS")) + if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass) continue; }*/ // Will be placed one higher @@ -2304,7 +2175,7 @@ void make_block(BlockMakeData *data) /*{ u32 i = data->vmanip->m_area.index(v3s16(p)); MapNode *n = &data->vmanip->m_data[i]; - if(n->getContent() != LEGN(ndef, "CONTENT_MUD") && n->getContent() != LEGN(ndef, "CONTENT_GRASS")) + if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass) continue; }*/ // Will be placed one lower @@ -2315,6 +2186,139 @@ void make_block(BlockMakeData *data) #endif } + /* + Add minerals + */ + + { + PseudoRandom mineralrandom(blockseed); + + /* + Add meseblocks + */ + for(s16 i=0; i 0.0) + new_content = MapNode(c_stone_with_iron); + /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0) + vmanip.m_data[i] = MapNode(c_dirt); + else + vmanip.m_data[i] = MapNode(c_sand);*/ + } + /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1) + { + }*/ + + if(new_content.getContent() != CONTENT_IGNORE) + { + for(u16 i=0; i<27; i++) + { + v3s16 p = v3s16(x,y,z) + g_27dirs[i]; + u32 vi = vmanip.m_area.index(p); + if(vmanip.m_data[vi].getContent() == base_content) + { + if(mineralrandom.next()%sparseness == 0) + vmanip.m_data[vi] = new_content; + } + } + } + } + } + /* + Add coal + */ + //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++) + //for(s16 i=0; i<50; i++) + u16 coal_amount = 30; + u16 coal_rareness = 60 / coal_amount; + if(coal_rareness == 0) + coal_rareness = 1; + if(mineralrandom.next()%coal_rareness == 0) + { + u16 a = mineralrandom.next() % 16; + u16 amount = coal_amount * a*a*a / 1000; + for(s16 i=0; i -#include "mineral.h" #include "main.h" // For g_settings #include "nodedef.h" #include "content_mapnode.h" // For mapnode_translate_*_internal #include "serialization.h" // For ser_ver_supported -#ifndef SERVER -/* - Nodes make a face if contents differ and solidness differs. - Return value: - 0: No face - 1: Face uses m1's content - 2: Face uses m2's content - equivalent: Whether the blocks share the same face (eg. water and glass) - - TODO: Add 3: Both faces drawn with backface culling, remove equivalent -*/ -u8 face_contents(content_t m1, content_t m2, bool *equivalent, - INodeDefManager *nodemgr) -{ - *equivalent = false; - - if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE) - return 0; - - bool contents_differ = (m1 != m2); - - const ContentFeatures &f1 = nodemgr->get(m1); - const ContentFeatures &f2 = nodemgr->get(m2); - - // Contents don't differ for different forms of same liquid - if(f1.sameLiquid(f2)) - contents_differ = false; - - u8 c1 = f1.solidness; - u8 c2 = f2.solidness; - - bool solidness_differs = (c1 != c2); - bool makes_face = contents_differ && solidness_differs; - - if(makes_face == false) - return 0; - - if(c1 == 0) - c1 = f1.visual_solidness; - if(c2 == 0) - c2 = f2.visual_solidness; - - if(c1 == c2){ - *equivalent = true; - // If same solidness, liquid takes precense - if(f1.isLiquid()) - return 1; - if(f2.isLiquid()) - return 2; - } - - if(c1 > c2) - return 1; - else - return 2; -} -#endif - -v3s16 facedir_rotate(u8 facedir, v3s16 dir) -{ - /* - Face 2 (normally Z-) direction: - facedir=0: Z- - facedir=1: X- - facedir=2: Z+ - facedir=3: X+ - */ - v3s16 newdir; - if(facedir==0) // Same - newdir = v3s16(dir.X, dir.Y, dir.Z); - else if(facedir == 1) // Face is taken from rotXZccv(-90) - newdir = v3s16(-dir.Z, dir.Y, dir.X); - else if(facedir == 2) // Face is taken from rotXZccv(180) - newdir = v3s16(-dir.X, dir.Y, -dir.Z); - else if(facedir == 3) // Face is taken from rotXZccv(90) - newdir = v3s16(dir.Z, dir.Y, -dir.X); - else - newdir = dir; - return newdir; -} - -u8 packDir(v3s16 dir) -{ - u8 b = 0; - - if(dir.X > 0) - b |= (1<<0); - else if(dir.X < 0) - b |= (1<<1); - - if(dir.Y > 0) - b |= (1<<2); - else if(dir.Y < 0) - b |= (1<<3); - - if(dir.Z > 0) - b |= (1<<4); - else if(dir.Z < 0) - b |= (1<<5); - - return b; -} -v3s16 unpackDir(u8 b) -{ - v3s16 d(0,0,0); - - if(b & (1<<0)) - d.X = 1; - else if(b & (1<<1)) - d.X = -1; - - if(b & (1<<2)) - d.Y = 1; - else if(b & (1<<3)) - d.Y = -1; - - if(b & (1<<4)) - d.Z = 1; - else if(b & (1<<5)) - d.Z = -1; - - return d; -} - /* MapNode */ @@ -191,8 +66,9 @@ void MapNode::setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const { // Select the brightest of [light source, propagated light] + const ContentFeatures &f = nodemgr->get(*this); u8 light = 0; - if(nodemgr->get(*this).param_type == CPT_LIGHT) + if(f.param_type == CPT_LIGHT) { if(bank == LIGHTBANK_DAY) light = param1 & 0x0f; @@ -201,38 +77,63 @@ u8 MapNode::getLight(enum LightBank bank, INodeDefManager *nodemgr) const else assert(0); } - if(nodemgr->get(*this).light_source > light) - light = nodemgr->get(*this).light_source; + if(f.light_source > light) + light = f.light_source; return light; } -u8 MapNode::getLightBanksWithSource(INodeDefManager *nodemgr) const +bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const { // Select the brightest of [light source, propagated light] - u8 lightday = 0; - u8 lightnight = 0; - if(nodemgr->get(*this).param_type == CPT_LIGHT) + const ContentFeatures &f = nodemgr->get(*this); + if(f.param_type == CPT_LIGHT) { lightday = param1 & 0x0f; lightnight = (param1>>4)&0x0f; } - if(nodemgr->get(*this).light_source > lightday) - lightday = nodemgr->get(*this).light_source; - if(nodemgr->get(*this).light_source > lightnight) - lightnight = nodemgr->get(*this).light_source; - return (lightday&0x0f) | ((lightnight<<4)&0xf0); + else + { + lightday = 0; + lightnight = 0; + } + if(f.light_source > lightday) + lightday = f.light_source; + if(f.light_source > lightnight) + lightnight = f.light_source; + return f.param_type == CPT_LIGHT || f.light_source != 0; } -u8 MapNode::getMineral(INodeDefManager *nodemgr) const +u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const { - if(nodemgr->get(*this).param_type == CPT_MINERAL) + const ContentFeatures &f = nodemgr->get(*this); + if(f.param_type_2 == CPT2_FACEDIR) + return getParam2() & 0x03; + return 0; +} + +u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const +{ + const ContentFeatures &f = nodemgr->get(*this); + if(f.param_type_2 == CPT2_WALLMOUNTED) + return getParam2() & 0x07; + return 0; +} + +v3s16 MapNode::getWallMountedDir(INodeDefManager *nodemgr) const +{ + switch(getWallMounted(nodemgr)) { - return param1 & 0x0f; + case 0: default: return v3s16(0,1,0); + case 1: return v3s16(0,-1,0); + case 2: return v3s16(1,0,0); + case 3: return v3s16(-1,0,0); + case 4: return v3s16(0,0,1); + case 5: return v3s16(0,0,-1); } - - return MINERAL_NONE; } + + u32 MapNode::serializedLength(u8 version) { if(!ser_ver_supported(version)) @@ -246,52 +147,182 @@ u32 MapNode::serializedLength(u8 version) return 3; } void MapNode::serialize(u8 *dest, u8 version) +{ + if(!ser_ver_supported(version)) + throw VersionMismatchException("ERROR: MapNode format not supported"); + + if(version <= 21) + { + serialize_pre22(dest, version); + return; + } + + writeU8(dest+0, param0); + writeU8(dest+1, param1); + writeU8(dest+2, param2); +} +void MapNode::deSerialize(u8 *source, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); + if(version <= 21) + { + deSerialize_pre22(source, version); + return; + } + + param0 = readU8(source+0); + param1 = readU8(source+1); + param2 = readU8(source+2); +} +void MapNode::serializeBulk(std::ostream &os, int version, + const MapNode *nodes, u32 nodecount, + u8 content_width, u8 params_width, bool compressed) +{ + if(!ser_ver_supported(version)) + throw VersionMismatchException("ERROR: MapNode format not supported"); + + assert(version >= 22); + assert(content_width == 1); + assert(params_width == 2); + + SharedBuffer databuf(nodecount * (content_width + params_width)); + + // Serialize content + if(content_width == 1) + { + for(u32 i=0; i= 22); + assert(content_width == 1); + assert(params_width == 2); + + // Uncompress or read data + u32 len = nodecount * (content_width + params_width); + SharedBuffer databuf(len); + if(compressed) + { + std::ostringstream os(std::ios_base::binary); + decompressZlib(is, os); + std::string s = os.str(); + if(s.size() != len) + throw SerializationError("deSerializeBulkNodes: " + "decompress resulted in invalid size"); + memcpy(&databuf[0], s.c_str(), len); + } + else + { + is.read((char*) &databuf[0], len); + if(is.eof() || is.fail()) + throw SerializationError("deSerializeBulkNodes: " + "failed to read bulk node data"); + } + + // Deserialize content + if(content_width == 1) + { + for(u32 i=0; iget(m1); + const ContentFeatures &f2 = nodemgr->get(m2); + + // Contents don't differ for different forms of same liquid + if(f1.sameLiquid(f2)) + contents_differ = false; + + u8 c1 = f1.solidness; + u8 c2 = f2.solidness; + + bool solidness_differs = (c1 != c2); + bool makes_face = contents_differ && solidness_differs; + + if(makes_face == false) + return 0; + + if(c1 == 0) + c1 = f1.visual_solidness; + if(c2 == 0) + c2 = f2.visual_solidness; + + if(c1 == c2){ + *equivalent = true; + // If same solidness, liquid takes precense + if(f1.isLiquid()) + return 1; + if(f2.isLiquid()) + return 2; + } + + if(c1 > c2) + return 1; + else + return 2; +} + /* Gets lighting value at face of node @@ -380,4 +463,5 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, } } +#endif diff --git a/src/mapnode.h b/src/mapnode.h index 65fc3b3e2..1c75f39c5 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -32,8 +32,8 @@ class INodeDefManager; - Tile = TileSpec at some side of a node of some content type Content ranges: - 0x000...0x07f: param2 is fully usable - 0x800...0xfff: param2 lower 4 bytes are free + 0x000...0x07f: param2 is fully usable + 0x800...0xfff: param2 lower 4 bits are free */ typedef u16 content_t; #define MAX_CONTENT 0xfff @@ -56,36 +56,6 @@ typedef u16 content_t; */ #define CONTENT_AIR 126 -#ifndef SERVER -/* - Nodes make a face if contents differ and solidness differs. - Return value: - 0: No face - 1: Face uses m1's content - 2: Face uses m2's content - equivalent: Whether the blocks share the same face (eg. water and glass) -*/ -u8 face_contents(content_t m1, content_t m2, bool *equivalent, - INodeDefManager *nodemgr); -#endif - -/* - Packs directions like (1,0,0), (1,-1,0) in six bits. - NOTE: This wastes way too much space for most purposes. -*/ -u8 packDir(v3s16 dir); -v3s16 unpackDir(u8 b); - -/* - facedir: CPT_FACEDIR_SIMPLE param1 value - dir: The face for which stuff is wanted - return value: The face from which the stuff is actually found - - NOTE: Currently this uses 2 bits for Z-,X-,Z+,X+, should there be Y+ - and Y- too? -*/ -v3s16 facedir_rotate(u8 facedir, v3s16 dir); - enum LightBank { LIGHTBANK_DAY, @@ -122,7 +92,6 @@ struct MapNode stored logarithmically from 0 to LIGHT_MAX. Sunlight is LIGHT_SUN, which is LIGHT_MAX+1. - Contains 2 values, day- and night lighting. Each takes 4 bits. - - Mineral content (should be removed from here) - Uhh... well, most blocks have light or nothing in here. */ u8 param1; @@ -143,7 +112,7 @@ struct MapNode { param1 = a_param1; param2 = a_param2; - // Set content (param0 and (param2&0xf0)) after other params + // Set content (param0 and param2&0xf0)) after other params // because this needs to override part of param2 setContent(content); } @@ -210,40 +179,22 @@ struct MapNode void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr); u8 getLight(enum LightBank bank, INodeDefManager *nodemgr) const; - u8 getLightBanksWithSource(INodeDefManager *nodemgr) const; + bool getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const; // 0 <= daylight_factor <= 1000 // 0 <= return value <= LIGHT_SUN u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const { - u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY, nodemgr) - + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT, nodemgr)) - )/1000; - u8 max = LIGHT_MAX; - if(getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN) - max = LIGHT_SUN; - if(l > max) - l = max; - return l; + u8 lightday = 0; + u8 lightnight = 0; + getLightBanks(lightday, lightnight, nodemgr); + return blend_light(daylight_factor, lightday, lightnight); } - /*// 0 <= daylight_factor <= 1000 - // 0 <= return value <= 255 - u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) - { - u8 daylight = decode_light(getLight(LIGHTBANK_DAY, nodemgr)); - u8 nightlight = decode_light(getLight(LIGHTBANK_NIGHT, nodemgr)); - u8 mix = ((daylight_factor * daylight - + (1000-daylight_factor) * nightlight) - )/1000; - return mix; - }*/ - /* - Gets mineral content of node, if there is any. - MINERAL_NONE if doesn't contain or isn't able to contain mineral. - */ - u8 getMineral(INodeDefManager *nodemgr) const; - + u8 getFaceDir(INodeDefManager *nodemgr) const; + u8 getWallMounted(INodeDefManager *nodemgr) const; + v3s16 getWallMountedDir(INodeDefManager *nodemgr) const; + /* Serialization functions */ @@ -252,8 +203,44 @@ struct MapNode void serialize(u8 *dest, u8 version); void deSerialize(u8 *source, u8 version); + // Serializes or deserializes a list of nodes in bulk format (first the + // content of all nodes, then the param1 of all nodes, then the param2 + // of all nodes). + // version = serialization version. Must be >= 22 + // content_width = the number of bytes of content per node + // params_width = the number of bytes of params per node + // compressed = true to zlib-compress output + static void serializeBulk(std::ostream &os, int version, + const MapNode *nodes, u32 nodecount, + u8 content_width, u8 params_width, bool compressed); + static void deSerializeBulk(std::istream &is, int version, + MapNode *nodes, u32 nodecount, + u8 content_width, u8 params_width, bool compressed); + +private: + // Deprecated serialization methods + void serialize_pre22(u8 *dest, u8 version); + void deSerialize_pre22(u8 *source, u8 version); }; + +/* + MapNode helpers for mesh making stuff +*/ + +#ifndef SERVER + +/* + Nodes make a face if contents differ and solidness differs. + Return value: + 0: No face + 1: Face uses m1's content + 2: Face uses m2's content + equivalent: Whether the blocks share the same face (eg. water and glass) +*/ +u8 face_contents(content_t m1, content_t m2, bool *equivalent, + INodeDefManager *nodemgr); + /* Gets lighting value at face of node @@ -275,3 +262,6 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, #endif + +#endif + diff --git a/src/materials.cpp b/src/materials.cpp index 146209d58..c37b7c505 100644 --- a/src/materials.cpp +++ b/src/materials.cpp @@ -18,8 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "materials.h" -#include "mapnode.h" -#include "nodedef.h" #include "utility.h" void MaterialProperties::serialize(std::ostream &os) @@ -139,13 +137,6 @@ DiggingProperties getDiggingProperties(const MaterialProperties *mp, return getDiggingProperties(mp, tp, 1000000); } -DiggingProperties getDiggingProperties(u16 content, - const ToolDiggingProperties *tp, INodeDefManager *nodemgr) -{ - const MaterialProperties &mp = nodemgr->get(content).material; - return getDiggingProperties(&mp, tp); -} - HittingProperties getHittingProperties(const MaterialProperties *mp, const ToolDiggingProperties *tp, float time_from_last_punch) { @@ -160,3 +151,9 @@ HittingProperties getHittingProperties(const MaterialProperties *mp, return HittingProperties(hp, wear); } +HittingProperties getHittingProperties(const MaterialProperties *mp, + const ToolDiggingProperties *tp) +{ + return getHittingProperties(mp, tp, 1000000); +} + diff --git a/src/materials.h b/src/materials.h index face7d5df..058b2ab85 100644 --- a/src/materials.h +++ b/src/materials.h @@ -110,17 +110,12 @@ struct DiggingProperties {} }; -class INodeDefManager; - DiggingProperties getDiggingProperties(const MaterialProperties *mp, const ToolDiggingProperties *tp, float time_from_last_punch); DiggingProperties getDiggingProperties(const MaterialProperties *mp, const ToolDiggingProperties *tp); -DiggingProperties getDiggingProperties(u16 content, - const ToolDiggingProperties *tp, INodeDefManager *nodemgr); - struct HittingProperties { s16 hp; @@ -135,5 +130,8 @@ struct HittingProperties HittingProperties getHittingProperties(const MaterialProperties *mp, const ToolDiggingProperties *tp, float time_from_last_punch); +HittingProperties getHittingProperties(const MaterialProperties *mp, + const ToolDiggingProperties *tp); + #endif diff --git a/src/mineral.cpp b/src/mineral.cpp deleted file mode 100644 index 4e495fce6..000000000 --- a/src/mineral.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 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 General Public License for more details. - -You should have received a copy of the GNU 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 "mineral.h" -#include "gamedef.h" - - -const char *mineral_filenames[MINERAL_COUNT] = -{ - NULL, - "mineral_coal.png", - "mineral_iron.png" -}; - -std::string mineral_textures[MINERAL_COUNT]; - -void init_mineral() -{ - for(u32 i=0; i= MINERAL_COUNT) - return ""; - - return mineral_textures[mineral]; -} - -ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef) -{ - if(mineral == MINERAL_COAL) - return ItemStack("default:coal_lump", 1, 0, "", gamedef->idef()); - else if(mineral == MINERAL_IRON) - return ItemStack("default:iron_lump", 1, 0, "", gamedef->idef()); - else - return ItemStack(); -} - - - diff --git a/src/mineral.h b/src/mineral.h deleted file mode 100644 index a945d0e02..000000000 --- a/src/mineral.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -Minetest-c55 -Copyright (C) 2010 celeron55, Perttu Ahola - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 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 General Public License for more details. - -You should have received a copy of the GNU 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 MINERAL_HEADER -#define MINERAL_HEADER - -#include "inventory.h" - -/* - Minerals - - Value is stored in the lowest 5 bits of a MapNode's CPT_MINERAL - type param. -*/ - -// Caches textures -void init_mineral(); - -#define MINERAL_NONE 0 -#define MINERAL_COAL 1 -#define MINERAL_IRON 2 - -#define MINERAL_COUNT 3 - -class IGameDef; - -std::string mineral_block_texture(u8 mineral); -ItemStack getDiggedMineralItem(u8 mineral, IGameDef *gamedef); - -#endif - diff --git a/src/nameidmapping.h b/src/nameidmapping.h index 071599e10..238deb451 100644 --- a/src/nameidmapping.h +++ b/src/nameidmapping.h @@ -70,6 +70,9 @@ public: result = i->second; return true; } + u16 size() const{ + return m_id_to_name.size(); + } private: std::map m_id_to_name; std::map m_name_to_id; diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 87469bfb5..3d85bdbd9 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -127,6 +127,7 @@ void ContentFeatures::reset() alpha = 255; post_effect_color = video::SColor(0, 0, 0, 0); param_type = CPT_NONE; + param_type_2 = CPT2_NONE; is_ground_content = false; light_propagates = false; sunlight_propagates = false; @@ -135,10 +136,6 @@ void ContentFeatures::reset() diggable = true; climbable = false; buildable_to = false; - wall_mounted = false; - dug_item = ""; - extra_dug_item = ""; - extra_dug_item_rarity = 2; metadata_name = ""; liquid_type = LIQUID_NONE; liquid_alternative_flowing = ""; @@ -151,6 +148,8 @@ void ContentFeatures::reset() // Make unknown blocks diggable material.diggability = DIGGABLE_CONSTANT; material.constant_time = 0.5; + legacy_facedir_simple = false; + legacy_wallmounted = false; } void ContentFeatures::serialize(std::ostream &os) @@ -172,6 +171,7 @@ void ContentFeatures::serialize(std::ostream &os) writeU8(os, post_effect_color.getGreen()); writeU8(os, post_effect_color.getBlue()); writeU8(os, param_type); + writeU8(os, param_type_2); writeU8(os, is_ground_content); writeU8(os, light_propagates); writeU8(os, sunlight_propagates); @@ -180,10 +180,6 @@ void ContentFeatures::serialize(std::ostream &os) writeU8(os, diggable); writeU8(os, climbable); writeU8(os, buildable_to); - writeU8(os, wall_mounted); - os< read_aabbox3df32(lua_State *L, int index, f32 scale) return box; } +/* + MaterialProperties +*/ + +static MaterialProperties read_material_properties( + lua_State *L, int table) +{ + MaterialProperties prop; + prop.diggability = (Diggability)getenumfield(L, -1, "diggability", + es_Diggability, DIGGABLE_NORMAL); + getfloatfield(L, -1, "constant_time", prop.constant_time); + getfloatfield(L, -1, "weight", prop.weight); + getfloatfield(L, -1, "crackiness", prop.crackiness); + getfloatfield(L, -1, "crumbliness", prop.crumbliness); + getfloatfield(L, -1, "cuttability", prop.cuttability); + getfloatfield(L, -1, "flammability", prop.flammability); + return prop; +} + /* ToolDiggingProperties */ @@ -631,6 +676,43 @@ static void push_tool_digging_properties(lua_State *L, set_tool_digging_properties(L, -1, prop); } +/* + DiggingProperties +*/ + +static void set_digging_properties(lua_State *L, int table, + const DiggingProperties &prop) +{ + setboolfield(L, table, "diggable", prop.diggable); + setfloatfield(L, table, "time", prop.time); + setintfield(L, table, "wear", prop.wear); +} + +static void push_digging_properties(lua_State *L, + const DiggingProperties &prop) +{ + lua_newtable(L); + set_digging_properties(L, -1, prop); +} + +/* + HittingProperties +*/ + +static void set_hitting_properties(lua_State *L, int table, + const HittingProperties &prop) +{ + setintfield(L, table, "hp", prop.hp); + setintfield(L, table, "wear", prop.wear); +} + +static void push_hitting_properties(lua_State *L, + const HittingProperties &prop) +{ + lua_newtable(L); + set_hitting_properties(L, -1, prop); +} + /* PointedThing */ @@ -797,12 +879,24 @@ static ContentFeatures read_content_features(lua_State *L, int index) f.param_type = (ContentParamType)getenumfield(L, index, "paramtype", es_ContentParamType, CPT_NONE); + f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2", + es_ContentParamType2, CPT2_NONE); + + // Warn about some deprecated fields + warn_if_field_exists(L, index, "wall_mounted", + "deprecated: use paramtype2 = 'wallmounted'"); + warn_if_field_exists(L, index, "light_propagates", + "deprecated: determined from paramtype"); + warn_if_field_exists(L, index, "dug_item", + "deprecated: use 'drops' field"); + warn_if_field_exists(L, index, "extra_dug_item", + "deprecated: use 'drops' field"); + warn_if_field_exists(L, index, "extra_dug_item_rarity", + "deprecated: use 'drops' field"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); f.light_propagates = (f.param_type == CPT_LIGHT); - warn_if_field_exists(L, index, "light_propagates", - "deprecated: determined from paramtype"); getboolfield(L, index, "sunlight_propagates", f.sunlight_propagates); // This is used for collision detection. // Also for general solidness queries. @@ -815,16 +909,6 @@ static ContentFeatures read_content_features(lua_State *L, int index) getboolfield(L, index, "climbable", f.climbable); // Player can build on these getboolfield(L, index, "buildable_to", f.buildable_to); - // If true, param2 is set to direction when placed. Used for torches. - // NOTE: the direction format is quite inefficient and should be changed - getboolfield(L, index, "wall_mounted", f.wall_mounted); - // Inventory item string as which the node appears in inventory when dug. - // Mineral overrides this. - getstringfield(L, index, "dug_item", f.dug_item); - // Extra dug item and its rarity - getstringfield(L, index, "extra_dug_item", f.extra_dug_item); - // Usual get interval for extra dug item - getintfield(L, index, "extra_dug_item_rarity", f.extra_dug_item_rarity); // Metadata name of node (eg. "furnace") getstringfield(L, index, "metadata_name", f.metadata_name); // Whether the node is non-liquid, source liquid or flowing liquid @@ -876,18 +960,15 @@ static ContentFeatures read_content_features(lua_State *L, int index) lua_getfield(L, index, "material"); if(lua_istable(L, -1)){ - f.material.diggability = (Diggability)getenumfield(L, -1, "diggability", - es_Diggability, DIGGABLE_NORMAL); - - getfloatfield(L, -1, "constant_time", f.material.constant_time); - getfloatfield(L, -1, "weight", f.material.weight); - getfloatfield(L, -1, "crackiness", f.material.crackiness); - getfloatfield(L, -1, "crumbliness", f.material.crumbliness); - getfloatfield(L, -1, "cuttability", f.material.cuttability); - getfloatfield(L, -1, "flammability", f.material.flammability); + f.material = read_material_properties(L, -1); } lua_pop(L, 1); + // Set to true if paramtype used to be 'facedir_simple' + getboolfield(L, index, "legacy_facedir_simple", f.legacy_facedir_simple); + // Set to true if wall_mounted used to be set to true + getboolfield(L, index, "legacy_wallmounted", f.legacy_wallmounted); + return f; } @@ -1774,6 +1855,33 @@ private: return 1; } + // set_owner(self, string) + static int l_set_owner(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string owner = luaL_checkstring(L, 2); + meta->setOwner(owner); + reportMetadataChange(ref); + return 1; + } + + // get_allow_removal(self) + static int l_get_allow_removal(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL){ + lua_pushboolean(L, true); + return 1; + } + // Do it + lua_pushboolean(L, !meta->nodeRemovalDisabled()); + return 1; + } + /* IGenericNodeMetadata interface */ // set_infotext(self, text) @@ -1984,6 +2092,8 @@ const luaL_reg NodeMetaRef::methods[] = { method(NodeMetaRef, set_text), method(NodeMetaRef, get_text), method(NodeMetaRef, get_owner), + method(NodeMetaRef, set_owner), + method(NodeMetaRef, get_allow_removal), method(NodeMetaRef, set_infotext), method(NodeMetaRef, get_inventory), method(NodeMetaRef, set_inventory_draw_spec), @@ -3369,6 +3479,32 @@ static int l_get_inventory(lua_State *L) return 1; } +// get_digging_properties(material_properties, tool_digging_properties[, time_from_last_punch]) +static int l_get_digging_properties(lua_State *L) +{ + MaterialProperties mp = read_material_properties(L, 1); + ToolDiggingProperties tp = read_tool_digging_properties(L, 2); + if(lua_isnoneornil(L, 3)) + push_digging_properties(L, getDiggingProperties(&mp, &tp)); + else + push_digging_properties(L, getDiggingProperties(&mp, &tp, + luaL_checknumber(L, 3))); + return 1; +} + +// get_hitting_properties(material_properties, tool_digging_properties[, time_from_last_punch]) +static int l_get_hitting_properties(lua_State *L) +{ + MaterialProperties mp = read_material_properties(L, 1); + ToolDiggingProperties tp = read_tool_digging_properties(L, 2); + if(lua_isnoneornil(L, 3)) + push_hitting_properties(L, getHittingProperties(&mp, &tp)); + else + push_hitting_properties(L, getHittingProperties(&mp, &tp, + luaL_checknumber(L, 3))); + return 1; +} + // get_current_modname() static int l_get_current_modname(lua_State *L) { @@ -3402,6 +3538,8 @@ static const struct luaL_Reg minetest_f [] = { {"chat_send_player", l_chat_send_player}, {"get_player_privs", l_get_player_privs}, {"get_inventory", l_get_inventory}, + {"get_digging_properties", l_get_digging_properties}, + {"get_hitting_properties", l_get_hitting_properties}, {"get_current_modname", l_get_current_modname}, {"get_modpath", l_get_modpath}, {NULL, NULL} @@ -3719,6 +3857,8 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player) assert(lua_checkstack(L, 20)); StackUnroller stack_unroller(L); + dstream<<"player: "<getId()<ndef(); -void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode, - ServerActiveObject *placer) -{ - realitycheck(L); - assert(lua_checkstack(L, 20)); - //infostream<<"scriptapi_environment_on_placenode"<get(node).name.c_str(), "on_punch")) + return false; - // Get the writable node definition manager from the server - IWritableNodeDefManager *ndef = - get_server(L)->getWritableNodeDefManager(); - - // Get minetest.registered_on_placenodes - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_on_placenodes"); - luaL_checktype(L, -1, LUA_TTABLE); - int table = lua_gettop(L); - // Foreach - lua_pushnil(L); - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TFUNCTION); - // Call function - push_v3s16(L, p); - pushnode(L, newnode, ndef); - objectref_get_or_create(L, placer); - if(lua_pcall(L, 3, 0, 0)) - script_error(L, "error: %s", lua_tostring(L, -1)); - // value removed, keep key for next iteration - } + // Call function + push_v3s16(L, pos); + pushnode(L, node, ndef); + objectref_get_or_create(L, puncher); + if(lua_pcall(L, 3, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + return true; } -void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode, +bool scriptapi_node_on_dig(lua_State *L, v3s16 pos, MapNode node, ServerActiveObject *digger) { realitycheck(L); assert(lua_checkstack(L, 20)); - //infostream<<"scriptapi_environment_on_dignode"<getWritableNodeDefManager(); - - // Get minetest.registered_on_dignodes - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_on_dignodes"); - luaL_checktype(L, -1, LUA_TTABLE); - int table = lua_gettop(L); - // Foreach - lua_pushnil(L); - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TFUNCTION); - // Call function - push_v3s16(L, p); - pushnode(L, oldnode, ndef); - objectref_get_or_create(L, digger); - if(lua_pcall(L, 3, 0, 0)) - script_error(L, "error: %s", lua_tostring(L, -1)); - // value removed, keep key for next iteration - } + INodeDefManager *ndef = get_server(L)->ndef(); + + // Push callback function on stack + if(!get_item_callback(L, ndef->get(node).name.c_str(), "on_dig")) + return false; + + // Call function + push_v3s16(L, pos); + pushnode(L, node, ndef); + objectref_get_or_create(L, digger); + if(lua_pcall(L, 3, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + return true; } -void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, - ServerActiveObject *puncher) +/* + environment +*/ + +void scriptapi_environment_step(lua_State *L, float dtime) { realitycheck(L); assert(lua_checkstack(L, 20)); - //infostream<<"scriptapi_environment_on_punchnode"<getWritableNodeDefManager(); - - // Get minetest.registered_on_punchnodes + // Get minetest.registered_globalsteps lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_on_punchnodes"); + lua_getfield(L, -1, "registered_globalsteps"); luaL_checktype(L, -1, LUA_TTABLE); int table = lua_gettop(L); // Foreach @@ -3980,10 +4070,8 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TFUNCTION); // Call function - push_v3s16(L, p); - pushnode(L, node, ndef); - objectref_get_or_create(L, puncher); - if(lua_pcall(L, 3, 0, 0)) + lua_pushnumber(L, dtime); + if(lua_pcall(L, 1, 0, 0)) script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } diff --git a/src/scriptapi.h b/src/scriptapi.h index 198f60525..500a9ab99 100644 --- a/src/scriptapi.h +++ b/src/scriptapi.h @@ -49,15 +49,6 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name, /* environment */ // On environment step void scriptapi_environment_step(lua_State *L, float dtime); -// After adding node -void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode, - ServerActiveObject *placer); -// After removing node -void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode, - ServerActiveObject *digger); -// When punching node -void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, - ServerActiveObject *puncher); // After generating a piece of map void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp); @@ -75,6 +66,12 @@ bool scriptapi_item_on_place(lua_State *L, ItemStack &item, bool scriptapi_item_on_use(lua_State *L, ItemStack &item, ServerActiveObject *user, const PointedThing &pointed); +/* node callbacks */ +bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node, + ServerActiveObject *puncher); +bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node, + ServerActiveObject *digger); + /* luaentity */ // Returns true if succesfully added into Lua; false otherwise. bool scriptapi_luaentity_add(lua_State *L, u16 id, const char *name, diff --git a/src/serialization.h b/src/serialization.h index cc4381155..bcfea451a 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -57,11 +57,12 @@ with this program; if not, write to the Free Software Foundation, Inc., 19: new content type handling 20: many existing content types translated to extended ones 21: dynamic content type allocation + 22: full 16-bit content types, minerals removed, facedir & wallmounted changed */ // This represents an uninitialized or invalid format #define SER_FMT_VER_INVALID 255 // Highest supported serialization version -#define SER_FMT_VER_HIGHEST 21 +#define SER_FMT_VER_HIGHEST 22 // Lowest supported serialization version #define SER_FMT_VER_LOWEST 0 diff --git a/src/server.cpp b/src/server.cpp index 3c0cab2a9..9f3db34d9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "voxel.h" #include "materials.h" -#include "mineral.h" #include "config.h" #include "servercommand.h" #include "filesys.h" @@ -2899,13 +2898,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) /* Make sure the player is allowed to do it */ - bool interact_priv = (getPlayerPrivs(player) & PRIV_INTERACT) != 0; - if(!interact_priv) + if((getPlayerPrivs(player) & PRIV_INTERACT) == 0) { infostream<<"Ignoring interaction from player "<getName() <<" because privileges are "<getMap().getNode(p_under); @@ -2934,22 +2929,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) <m_removed) return; @@ -2977,190 +2962,24 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) else if(action == 2) { // Only complete digging of nodes - if(pointed.type != POINTEDTHING_NODE) - return; - - // Mandatory parameter; actually used for nothing - core::map modified_blocks; - - content_t material = CONTENT_IGNORE; - u8 mineral = MINERAL_NONE; - - bool cannot_remove_node = !interact_priv; - - MapNode n(CONTENT_IGNORE); - try - { - n = m_env->getMap().getNode(p_under); - // Get mineral - mineral = n.getMineral(m_nodedef); - // Get material at position - material = n.getContent(); - // If not yet cancelled - if(cannot_remove_node == false) - { - // If it's not diggable, do nothing - if(m_nodedef->get(material).diggable == false) - { - infostream<<"Server: Not finishing digging: " - <<"Node not diggable" - <getMap().getNodeMetadata(p_under); - if(meta && meta->nodeRemovalDisabled() == true) - { - infostream<<"Server: Not finishing digging: " - <<"Node metadata disables removal" - <SetBlockNotSent(blockpos); - - return; - } - - actionstream<getName()<<" digs "< far_players; - sendRemoveNode(p_under, peer_id, &far_players, 30); - - /* - Update and send inventory - */ - - if(g_settings->getBool("creative_mode") == false) + if(pointed.type == POINTEDTHING_NODE) { - /* - Wear out tool - */ - InventoryList *mlist = player->inventory.getList("main"); - if(mlist != NULL) - { - ItemStack &item = mlist->getItem(item_i); - - // Get digging properties for material and tool - ToolDiggingProperties tp = - item.getToolDiggingProperties(m_itemdef); - DiggingProperties prop = - getDiggingProperties(material, &tp, m_nodedef); - item.addWear(prop.wear, m_itemdef); - srp->m_inventory_not_sent = true; - } - - /* - Add dug item to inventory - */ - - ItemStack item; - - if(mineral != MINERAL_NONE) - item = getDiggedMineralItem(mineral, this); - - // If not mineral - if(item.empty()) - { - const std::string &dug_s = m_nodedef->get(material).dug_item; - if(dug_s != "") - { - item.deSerialize(dug_s, m_itemdef); - } - } - - if(!item.empty()) - { - // Add a item to inventory - player->inventory.addItem("main", item); - srp->m_inventory_not_sent = true; - } - - item.clear(); - + MapNode n(CONTENT_IGNORE); + try { - const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item; - s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity; - if(extra_dug_s != "" && extra_rarity != 0 - && myrand() % extra_rarity == 0) - { - item.deSerialize(extra_dug_s, m_itemdef); - } + n = m_env->getMap().getNode(p_under); } - - if(!item.empty()) + catch(InvalidPositionException &e) { - // Add a item to inventory - player->inventory.addItem("main", item); - srp->m_inventory_not_sent = true; + infostream<<"Server: Not finishing digging: Node not found." + <<" Adding block to emerge queue." + <getMap().removeNodeAndUpdate(p_under, modified_blocks); - } - /* - Set blocks not sent to far players - */ - for(core::list::Iterator - i = far_players.begin(); - i != far_players.end(); i++) - { - u16 peer_id = *i; - RemoteClient *client = getClient(peer_id); - if(client==NULL) - continue; - client->SetBlocksNotSent(modified_blocks); - } - - /* - Run script hook - */ - scriptapi_environment_on_dignode(m_lua, p_under, n, srp); } // action == 2 /* @@ -3168,16 +2987,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ else if(action == 3) { - if(!interact_priv) - { - infostream<<"Not allowing player " - <getName()<<" to place item: " - <<"no interact privileges"<getWieldedItem(); + // Reset build time counter + if(pointed.type == POINTEDTHING_NODE && + item.getDefinition(m_itemdef).type == ITEM_NODE) + getClient(peer_id)->m_time_from_building = 0.0; + if(pointed.type == POINTEDTHING_OBJECT) { // Right click object @@ -3201,123 +3017,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(g_settings->getBool("creative_mode") == false) srp->setWieldedItem(item); } - else if(pointed.type == POINTEDTHING_NODE && - item.getDefinition(m_itemdef).type == ITEM_NODE) - { - bool cannot_place_node = !interact_priv; - - try{ - // Don't add a node if this is not a free space - MapNode n2 = m_env->getMap().getNode(p_above); - if(m_nodedef->get(n2).buildable_to == false) - { - infostream<<"Client "<SetBlockNotSent(blockpos); - return; - } - - // Reset build time counter - getClient(peer_id)->m_time_from_building = 0.0; - - // Create node data - MapNode n(m_nodedef, item.name, 0, 0); - - actionstream<getName()<<" places material " - <get(n).wall_mounted) - n.param2 = packDir(p_under - p_above); - - // Calculate the direction for furnaces and chests and stuff - if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE) - { - v3f playerpos = player->getPosition(); - v3f blockpos = intToFloat(p_above, BS) - playerpos; - blockpos = blockpos.normalize(); - n.param1 = 0; - if (fabs(blockpos.X) > fabs(blockpos.Z)) { - if (blockpos.X < 0) - n.param1 = 3; - else - n.param1 = 1; - } else { - if (blockpos.Z < 0) - n.param1 = 2; - else - n.param1 = 0; - } - } - - /* - Send to all close-by players - */ - core::list far_players; - sendAddNode(p_above, n, 0, &far_players, 30); - - /* - Handle inventory - */ - if(g_settings->getBool("creative_mode") == false) - { - // Remove from inventory and send inventory - item.remove(1); - srp->setWieldedItem(item); - } - - /* - Add node. - - This takes some time so it is done after the quick stuff - */ - core::map modified_blocks; - { - MapEditEventIgnorer ign(&m_ignore_map_edit_events); - - std::string p_name = std::string(player->getName()); - m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name); - } - /* - Set blocks not sent to far players - */ - for(core::list::Iterator - i = far_players.begin(); - i != far_players.end(); i++) - { - u16 peer_id = *i; - RemoteClient *client = getClient(peer_id); - if(client==NULL) - continue; - client->SetBlocksNotSent(modified_blocks); - } - - /* - Run script hook - */ - scriptapi_environment_on_placenode(m_lua, p_above, n, srp); - } } // action == 3 @@ -3326,14 +3025,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) */ else if(action == 4) { - // Requires interact privs - if(!interact_priv) - { - infostream<<"Not allowing player to use item: " - "no interact privileges"<getWieldedItem(); actionstream<getName()<<" uses "<serialize(os, ver); + block->serialize(os, ver, false); std::string s = os.str(); SharedBuffer blockdata((u8*)s.c_str(), s.size()); diff --git a/src/servermain.cpp b/src/servermain.cpp index e8a54512e..3ef1d9479 100644 --- a/src/servermain.cpp +++ b/src/servermain.cpp @@ -68,7 +68,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "materials.h" #include "config.h" -#include "mineral.h" #include "filesys.h" #include "defaultsettings.h" #include "settings.h" @@ -301,10 +300,6 @@ int main(int argc, char *argv[]) srand(time(0)); mysrand(time(0)); - // Initialize stuff - - init_mineral(); - /* Run unit tests */ diff --git a/src/test.cpp b/src/test.cpp index caf31d1af..2d5c86e64 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -76,9 +76,7 @@ void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *n f.name = itemdef.name; for(int i = 0; i < 6; i++) f.tname_tiles[i] = "default_stone.png"; - f.param_type = CPT_MINERAL; f.is_ground_content = true; - f.dug_item = itemdef.name; f.material.diggability = DIGGABLE_NORMAL; f.material.weight = 5.0; f.material.crackiness = 1.0; @@ -106,7 +104,6 @@ void define_some_nodes(IWritableItemDefManager *idef, IWritableNodeDefManager *n for(int i = 2; i < 6; i++) f.tname_tiles[i] = "default_dirt.png^default_grass_side.png"; f.is_ground_content = true; - f.dug_item = itemdef.name; f.material.diggability = DIGGABLE_NORMAL; f.material.weight = 1.2; f.material.crackiness = 0.0; diff --git a/src/tile.cpp b/src/tile.cpp index 1d5f4d833..bc4c49cb1 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "log.h" #include "mapnode.h" // For texture atlas making -#include "mineral.h" // For texture atlas making #include "nodedef.h" // For texture atlas making #include "gamedef.h" @@ -299,8 +298,8 @@ public: Example names: "stone.png" "stone.png^crack2" - "stone.png^blit:mineral_coal.png" - "stone.png^blit:mineral_coal.png^crack1" + "stone.png^mineral_coal.png" + "stone.png^mineral_coal.png^crack1" - If texture specified by name is found from cache, return the cached id. @@ -824,14 +823,6 @@ void TextureSource::buildMainAtlas(class IGameDef *gamedef) { std::string name = f.tname_tiles[i]; sourcelist[name] = true; - - if(f.param_type == CPT_MINERAL){ - for(int k=1; k Date: Sun, 22 Jan 2012 15:57:49 +0100 Subject: Fix give_initial_stuff mod; experimental mod: dug_item -> drop; scriptapi.cpp: drops -> drop --- data/mods/experimental/init.lua | 2 +- data/mods/give_initial_stuff/init.lua | 10 +++++----- src/scriptapi.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/scriptapi.cpp') diff --git a/data/mods/experimental/init.lua b/data/mods/experimental/init.lua index a58d8f08d..368295ea7 100644 --- a/data/mods/experimental/init.lua +++ b/data/mods/experimental/init.lua @@ -271,7 +271,7 @@ minetest.register_node("experimental:tnt", { "default_tnt_side.png", "default_tnt_side.png"}, inventory_image = minetest.inventorycube("default_tnt_top.png", "default_tnt_side.png", "default_tnt_side.png"), - dug_item = '', -- Get nothing + drop = '', -- Get nothing material = { diggability = "not", }, diff --git a/data/mods/give_initial_stuff/init.lua b/data/mods/give_initial_stuff/init.lua index e52784d64..9cf6b51b5 100644 --- a/data/mods/give_initial_stuff/init.lua +++ b/data/mods/give_initial_stuff/init.lua @@ -2,11 +2,11 @@ minetest.register_on_newplayer(function(player) print("on_newplayer") if minetest.setting_getbool("give_initial_stuff") then print("giving give_initial_stuff to player") - player:add_to_inventory('tool "SteelPick" 0') - player:add_to_inventory('node "torch" 99') - player:add_to_inventory('tool "SteelAxe" 0') - player:add_to_inventory('tool "SteelShovel" 0') - player:add_to_inventory('node "cobble" 99') + player:get_inventory():add_item('main', 'default:pick_steel') + player:get_inventory():add_item('main', 'default:torch 99') + player:get_inventory():add_item('main', 'default:axe_steel') + player:get_inventory():add_item('main', 'default:shovel_steel') + player:get_inventory():add_item('main', 'default:cobble 99') end end) diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 173e5a827..5d68793e2 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -888,11 +888,11 @@ static ContentFeatures read_content_features(lua_State *L, int index) warn_if_field_exists(L, index, "light_propagates", "deprecated: determined from paramtype"); warn_if_field_exists(L, index, "dug_item", - "deprecated: use 'drops' field"); + "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item", - "deprecated: use 'drops' field"); + "deprecated: use 'drop' field"); warn_if_field_exists(L, index, "extra_dug_item_rarity", - "deprecated: use 'drops' field"); + "deprecated: use 'drop' field"); // True for all ground-like things like stone and mud, false for eg. trees getboolfield(L, index, "is_ground_content", f.is_ground_content); -- cgit v1.2.3 From 2e8e9ee7f5c0fa638e5a427f34b6823892c84f7c Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 24 Jan 2012 12:01:59 +0200 Subject: Add EnvRef:set_timeofday(0...1) and EnvRef:get_timeofday() --- data/mods/default/init.lua | 6 ++++-- data/mods/experimental/init.lua | 22 ++++++++++++++++++++++ src/scriptapi.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) (limited to 'src/scriptapi.cpp') diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua index 7c6cccd44..f0e6b6dc2 100644 --- a/data/mods/default/init.lua +++ b/data/mods/default/init.lua @@ -114,10 +114,10 @@ -- minetest.chat_send_player(name, text) -- minetest.get_player_privs(name) -> set of privs -- minetest.get_inventory(location) -> InvRef --- minetest.get_current_modname() -> string --- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname" -- ^ location = eg. {type="player", name="celeron55"} -- {type="node", pos={x=, y=, z=}} +-- minetest.get_current_modname() -> string +-- minetest.get_modpath(modname) -> eg. "/home/user/.minetest/usermods/modname" -- -- minetest.debug(line) -- ^ Goes to dstream @@ -169,6 +169,8 @@ -- - get_meta(pos) -- Get a NodeMetaRef at that position -- - get_player_by_name(name) -- Get an ObjectRef to a player -- - get_objects_inside_radius(pos, radius) +-- - set_timeofday(val): val: 0...1; 0 = midnight, 0.5 = midday +-- - get_timeofday() -- -- NodeMetaRef (this stuff is subject to change in a future version) -- - get_type() diff --git a/data/mods/experimental/init.lua b/data/mods/experimental/init.lua index 368295ea7..9a8f8868d 100644 --- a/data/mods/experimental/init.lua +++ b/data/mods/experimental/init.lua @@ -4,6 +4,8 @@ -- For testing random stuff +experimental = {} + function on_step(dtime) -- print("experimental on_step") --[[ @@ -20,6 +22,26 @@ function on_step(dtime) end end --]] + --[[ + if experimental.t1 == nil then + experimental.t1 = 0 + end + experimental.t1 = experimental.t1 + dtime + if experimental.t1 >= 2 then + experimental.t1 = experimental.t1 - 2 + minetest.log("time of day is "..minetest.env:get_timeofday()) + if experimental.day then + minetest.log("forcing day->night") + experimental.day = false + minetest.env:set_timeofday(0.0) + else + minetest.log("forcing night->day") + experimental.day = true + minetest.env:set_timeofday(0.5) + end + minetest.log("time of day is "..minetest.env:get_timeofday()) + end + --]] end minetest.register_globalstep(on_step) diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 5d68793e2..a064cd688 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -2913,6 +2913,38 @@ private: return 1; } + // EnvRef:set_timeofday(val) + // val = 0...1 + static int l_set_timeofday(lua_State *L) + { + EnvRef *o = checkobject(L, 1); + ServerEnvironment *env = o->m_env; + if(env == NULL) return 0; + // Do it + float timeofday_f = luaL_checknumber(L, 2); + assert(timeofday_f >= 0.0 && timeofday_f <= 1.0); + int timeofday_mh = (int)(timeofday_f * 24000.0); + // This should be set directly in the environment but currently + // such changes aren't immediately sent to the clients, so call + // the server instead. + //env->setTimeOfDay(timeofday_mh); + get_server(L)->setTimeOfDay(timeofday_mh); + return 0; + } + + // EnvRef:get_timeofday() -> 0...1 + static int l_get_timeofday(lua_State *L) + { + EnvRef *o = checkobject(L, 1); + ServerEnvironment *env = o->m_env; + if(env == NULL) return 0; + // Do it + int timeofday_mh = env->getTimeOfDay(); + float timeofday_f = (float)timeofday_mh / 24000.0; + lua_pushnumber(L, timeofday_f); + return 1; + } + static int gc_object(lua_State *L) { EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1)); delete o; @@ -2990,6 +3022,8 @@ const luaL_reg EnvRef::methods[] = { method(EnvRef, get_meta), method(EnvRef, get_player_by_name), method(EnvRef, get_objects_inside_radius), + method(EnvRef, set_timeofday), + method(EnvRef, get_timeofday), {0,0} }; -- cgit v1.2.3