From e0b4890794497c4b801e901fa233bbb2589e0503 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Tue, 6 Dec 2011 15:55:05 +0200 Subject: [PATCH] Add minetest.get_inventory(location), untested --- src/scriptapi.cpp | 3788 +++++++++++++++++++++++---------------------- 1 file changed, 1931 insertions(+), 1857 deletions(-) diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 8a4e0b0d9..f30aab41c 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -218,7 +218,7 @@ static ServerEnvironment* get_env(lua_State *L) return (ServerEnvironment*)lua_touserdata(L, -1); } -static v3f readFloatPos(lua_State *L, int index) +static v3f read_v3f(lua_State *L, int index) { v3f pos; luaL_checktype(L, index, LUA_TTABLE); @@ -231,7 +231,22 @@ static v3f readFloatPos(lua_State *L, int index) lua_getfield(L, index, "z"); pos.Z = lua_tonumber(L, -1); lua_pop(L, 1); - pos *= BS; // Scale to internal format + 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); + lua_pop(L, 1); + lua_getfield(L, index, "z"); + pos.Z = luaL_checknumber(L, -1); + lua_pop(L, 1); return pos; } @@ -241,7 +256,12 @@ static void pushFloatPos(lua_State *L, v3f p) push_v3f(L, p); } -static void pushpos(lua_State *L, v3s16 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); @@ -252,11 +272,18 @@ static void pushpos(lua_State *L, v3s16 p) lua_setfield(L, -2, "z"); } -static v3s16 readpos(lua_State *L, int index) +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 = readFloatPos(L, index); - return floatToInt(pf, BS); + v3f pf = check_v3f(L, index); + return floatToInt(pf, 1.0); } static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef) @@ -390,6 +417,15 @@ static bool getboolfield(lua_State *L, int table, return got; } +static std::string checkstringfield(lua_State *L, int table, + const char *fieldname) +{ + lua_getfield(L, table, fieldname); + std::string s = luaL_checkstring(L, -1); + lua_pop(L, 1); + return s; +} + static std::string getstringfield_default(lua_State *L, int table, const char *fieldname, const std::string &default_) { @@ -747,837 +783,694 @@ struct EnumString es_Diggability[] = }; /* - Global functions + Getters for stuff in main tables */ -static int l_register_nodedef_defaults(lua_State *L) +static void objectref_get(lua_State *L, u16 id) { - 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; + // 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 } -// Register new object prototype -// register_entity(name, prototype) -static int l_register_entity(lua_State *L) +static void luaentity_get(lua_State *L, u16 id) { - 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 __index to point to itself - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); + lua_pushnumber(L, id); + lua_gettable(L, -2); + lua_remove(L, -2); // luaentities + lua_remove(L, -2); // minetest +} - // 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); +/* + Object wrappers +*/ - return 0; /* number of results */ -} +#define method(class, name) {#name, class::l_##name} -class LuaABM : public ActiveBlockModifier +/* + ItemStack +*/ + +class ItemStack { private: - lua_State *m_lua; - int m_id; + InventoryItem *m_stack; - std::set m_trigger_contents; - std::set m_required_neighbors; - float m_trigger_interval; - u32 m_trigger_chance; -public: - LuaABM(lua_State *L, int id, - const std::set &trigger_contents, - const std::set &required_neighbors, - float trigger_interval, u32 trigger_chance): - m_lua(L), - m_id(id), - m_trigger_contents(trigger_contents), - m_required_neighbors(required_neighbors), - m_trigger_interval(trigger_interval), - m_trigger_chance(trigger_chance) + static const char className[]; + static const luaL_reg methods[]; + + // Exported functions + + // garbage collector + static int gc_object(lua_State *L) { + ItemStack *o = *(ItemStack **)(lua_touserdata(L, 1)); + delete o; + return 0; + } + + // take_item(self) + static int l_take_item(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); + } + return 1; } - virtual std::set getTriggerContents() + + // put_item(self, item) -> true/false + static int l_put_item(lua_State *L) { - return m_trigger_contents; + 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); + return 1; } - virtual std::set getRequiredNeighbors() + +public: + ItemStack(InventoryItem *item=NULL): + m_stack(item) { - return m_required_neighbors; } - virtual float getTriggerInterval() + + ~ItemStack() { - return m_trigger_interval; + delete m_stack; } - virtual u32 getTriggerChance() + + static ItemStack* checkobject(lua_State *L, int narg) { - return m_trigger_chance; + 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 } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, - u32 active_object_count, u32 active_object_count_wider) + + InventoryItem* getItemCopy() { - lua_State *L = m_lua; + if(!m_stack) + return NULL; + return m_stack->clone(); + } - realitycheck(L); - assert(lua_checkstack(L, 20)); - StackUnroller stack_unroller(L); + // Creates an ItemStack 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); + *(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) + { + ItemStack *o = new ItemStack(item); + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + return 1; + } - // Get minetest.registered_abms - lua_getglobal(L, "minetest"); - lua_getfield(L, -1, "registered_abms"); - luaL_checktype(L, -1, LUA_TTABLE); - int registered_abms = lua_gettop(L); + static void Register(lua_State *L) + { + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); - // Get minetest.registered_abms[m_id] - lua_pushnumber(L, m_id); - lua_gettable(L, registered_abms); - if(lua_isnil(L, -1)) - assert(0); - - // Call action - luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - pushpos(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_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() -// register_abm({...}) -static int l_register_abm(lua_State *L) -{ - //infostream<<"register_abm"<getWritableToolDefManager(); + static const char className[]; + static const luaL_reg methods[]; + + static InvRef *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 *(InvRef**)ud; // unbox pointer + } - ToolDefinition def = read_tool_definition(L, table); + static Inventory* getinv(lua_State *L, InvRef *ref) + { + return get_server(L)->getInventory(ref->m_loc); + } - tooldef->registerTool(name, def); - return 0; /* number of results */ -} + static InventoryList* getlist(lua_State *L, InvRef *ref, + const char *listname) + { + Inventory *inv = getinv(L, ref); + if(!inv) + return NULL; + return inv->getList(listname); + } -// 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: "<getItem(i); + } - // Get the writable CraftItem definition manager from the server - IWritableCraftItemDefManager *craftitemdef = - get_server(L)->getWritableCraftItemDefManager(); + static void reportInventoryChange(lua_State *L, InvRef *ref) + { + // Inform other things that the inventory has changed + get_server(L)->setInventoryModified(ref->m_loc); + } - // 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; + // Exported functions - 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); + // garbage collector + static int gc_object(lua_State *L) { + InvRef *o = *(InvRef **)(lua_touserdata(L, 1)); + delete o; + return 0; + } - // If an on_drop callback is defined, force dropcount to 1 - if (got_on_drop) - def.dropcount = 1; + // get_size(self, listname) + static int l_get_size(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + InventoryList *list = getlist(L, ref, listname); + if(list){ + lua_pushinteger(L, list->getSize()); + } else { + lua_pushinteger(L, 0); + } + return 1; + } - // Register it - craftitemdef->registerCraftItem(name, def); + // set_size(self, listname, size) + static int l_set_size(lua_State *L) + { + InvRef *ref = checkobject(L, 1); + const char *listname = luaL_checkstring(L, 2); + int newsize = luaL_checknumber(L, 3); + Inventory *inv = getinv(L, ref); + if(newsize == 0){ + inv->deleteList(listname); + return 0; + } + InventoryList *list = inv->getList(listname); + if(list){ + list->setSize(newsize); + } else { + list = inv->addList(listname, newsize); + } + return 0; + } - lua_pushvalue(L, table); - scriptapi_add_craftitem(L, name.c_str()); + // get_stack(self, listname, i) + 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); + InventoryItem *item = getitem(L, ref, listname, i); + if(!item){ + ItemStack::create(L, NULL); + return 1; + } + ItemStack::create(L, item->clone()); + return 1; + } - return 0; /* number of results */ -} + // set_stack(self, listname, i, stack) + 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); + ItemStack *stack = ItemStack::checkobject(L, 4); + InventoryList *list = getlist(L, ref, listname); + if(!list){ + 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); + return 1; + } -// 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); + ~InvRef() + { + } - /* - Add to minetest.registered_nodes with default as metatable - */ - - // Get the node definition table given as parameter - lua_pushvalue(L, nodedef_table); + // Creates an InvRef and leaves it on top of stack + // Not callable from Lua; all references are created on the C side. + static void create(lua_State *L, const InventoryLocation &loc) + { + InvRef *o = new InvRef(loc); + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + } + static void createPlayer(lua_State *L, Player *player) + { + InventoryLocation loc; + loc.setPlayer(player->getName()); + create(L, loc); + } + static void createNodeMeta(lua_State *L, v3s16 p) + { + InventoryLocation loc; + loc.setNodeMeta(p); + create(L, loc); + } - // Set __index to point to itself - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); + static void Register(lua_State *L) + { + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); - // 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; + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() - // 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"); + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); - /* - Read definiton from Lua - */ + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); - f.name = name; - - /* Visual definition */ + lua_pop(L, 1); // drop metatable - f.drawtype = (NodeDrawType)getenumfield(L, nodedef_table, "drawtype", es_DrawType, - NDT_NORMAL); - getfloatfield(L, nodedef_table, "visual_scale", f.visual_scale); + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable - 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++; - } - } + // Cannot be created from Lua + //lua_register(L, className, create_object); } - lua_pop(L, 1); +}; +const char InvRef::className[] = "InvRef"; +const luaL_reg InvRef::methods[] = { + method(InvRef, get_size), + method(InvRef, set_size), + method(InvRef, get_stack), + method(InvRef, set_stack), + {0,0} +}; - getstringfield(L, nodedef_table, "inventory_image", f.tname_inventory); +/* + NodeMetaRef +*/ - 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); +class NodeMetaRef +{ +private: + v3s16 m_p; + ServerEnvironment *m_env; - f.alpha = getintfield_default(L, nodedef_table, "alpha", 255); + static const char className[]; + static const luaL_reg methods[]; - /* Other stuff */ + static NodeMetaRef *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 *(NodeMetaRef**)ud; // unbox pointer + } - lua_getfield(L, nodedef_table, "post_effect_color"); - if(!lua_isnil(L, -1)) - f.post_effect_color = readARGB8(L, -1); - lua_pop(L, 1); + static NodeMetadata* getmeta(NodeMetaRef *ref) + { + NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); + return meta; + } - f.param_type = (ContentParamType)getenumfield(L, nodedef_table, "paramtype", - es_ContentParamType, CPT_NONE); + /*static IGenericNodeMetadata* getgenericmeta(NodeMetaRef *ref) + { + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) + return NULL; + if(meta->typeId() != NODEMETA_GENERIC) + return NULL; + return (IGenericNodeMetadata*)meta; + }*/ + + static void reportMetadataChange(NodeMetaRef *ref) + { + // Inform other things that the metadata has changed + v3s16 blockpos = getNodeBlockPos(ref->m_p); + MapEditEvent event; + event.type = MEET_BLOCK_NODE_METADATA_CHANGED; + event.p = blockpos; + ref->m_env->getMap().dispatchEvent(&event); + // Set the block to be saved + MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos); + if(block) + block->raiseModified(MOD_STATE_WRITE_NEEDED, + "NodeMetaRef::reportMetadataChange"); + } - // 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); + // Exported functions - 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, "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); + // garbage collector + static int gc_object(lua_State *L) { + NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1)); + delete o; + return 0; + } - 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_type(self) + static int l_get_type(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL){ + lua_pushnil(L); + return 1; + } + // Do it + lua_pushstring(L, meta->typeName()); + return 1; } - lua_pop(L, 1); - lua_getfield(L, nodedef_table, "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); + // allows_text_input(self) + static int l_allows_text_input(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + lua_pushboolean(L, meta->allowsTextInput()); + return 1; } - 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) -{ - std::string name = luaL_checkstring(L, 1); - std::string convert_to = luaL_checkstring(L, 2); + // set_text(self, text) + static int l_set_text(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string text = luaL_checkstring(L, 2); + meta->setText(text); + reportMetadataChange(ref); + return 0; + } - // Get the writable node definition manager from the server - IWritableNodeDefManager *nodedef = - get_server(L)->getWritableNodeDefManager(); - - nodedef->setAlias(name, convert_to); - - return 0; /* number of results */ -} + // get_text(self) + static int l_get_text(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string text = meta->getText(); + lua_pushstring(L, text.c_str()); + return 1; + } -// alias_tool(name, convert_to_name) -static int l_alias_tool(lua_State *L) -{ - std::string name = luaL_checkstring(L, 1); - std::string convert_to = luaL_checkstring(L, 2); + // get_owner(self) + static int l_get_owner(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string owner = meta->getOwner(); + lua_pushstring(L, owner.c_str()); + return 1; + } - // Get the writable tool definition manager from the server - IWritableToolDefManager *tooldef = - get_server(L)->getWritableToolDefManager(); + /* IGenericNodeMetadata interface */ - tooldef->setAlias(name, convert_to); - - return 0; /* number of results */ -} + // set_infotext(self, text) + static int l_set_infotext(lua_State *L) + { + infostream<<__FUNCTION_NAME<setInfoText(text); + reportMetadataChange(ref); + return 0; + } -// alias_craftitem(name, convert_to_name) -static int l_alias_craftitem(lua_State *L) -{ - std::string name = luaL_checkstring(L, 1); - std::string convert_to = luaL_checkstring(L, 2); + // inventory_set_list(self, name, {item1, item2, ...}) + static int l_inventory_set_list(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + Inventory *inv = meta->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; + } - // Get the writable CraftItem definition manager from the server - IWritableCraftItemDefManager *craftitemdef = - get_server(L)->getWritableCraftItemDefManager(); - - craftitemdef->setAlias(name, convert_to); + // inventory_get_list(self, name) + static int l_inventory_get_list(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + Inventory *inv = meta->getInventory(); + const char *name = luaL_checkstring(L, 2); + inventory_get_list_to_lua(inv, name, L); + return 1; + } - return 0; /* number of results */ -} + // set_inventory_draw_spec(self, text) + static int l_set_inventory_draw_spec(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string text = luaL_checkstring(L, 2); + meta->setInventoryDrawSpec(text); + reportMetadataChange(ref); + return 0; + } -// register_craft({output=item, recipe={{item00,item10},{item01,item11}}) -static int l_register_craft(lua_State *L) -{ - //infostream<<"register_craft"<setAllowTextInput(b); + reportMetadataChange(ref); + return 0; + } - // Get the writable craft definition manager from the server - IWritableCraftDefManager *craftdef = - get_server(L)->getWritableCraftDefManager(); - - std::string output; - int width = 0; - std::vector input; + // set_allow_removal(self, text) + static int l_set_allow_removal(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + bool b = lua_toboolean(L, 2); + meta->setRemovalDisabled(!b); + reportMetadataChange(ref); + return 0; + } - 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); + // set_enforce_owner(self, text) + static int l_set_enforce_owner(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + bool b = lua_toboolean(L, 2); + meta->setEnforceOwner(b); + reportMetadataChange(ref); + return 0; + } - 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++; - } + // is_inventory_modified(self) + static int l_is_inventory_modified(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + lua_pushboolean(L, meta->isInventoryModified()); + return 1; } - lua_pop(L, 1); - CraftDefinition def(output, width, input); - craftdef->registerCraft(def); - - return 0; /* number of results */ -} - -// setting_get(name) -static int l_setting_get(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - try{ - std::string value = g_settings->get(name); - lua_pushstring(L, value.c_str()); - } catch(SettingNotFoundException &e){ - lua_pushnil(L); - } - return 1; -} - -// setting_getbool(name) -static int l_setting_getbool(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - try{ - bool value = g_settings->getBool(name); - lua_pushboolean(L, value); - } catch(SettingNotFoundException &e){ - lua_pushnil(L); - } - return 1; -} - -// chat_send_all(text) -static int l_chat_send_all(lua_State *L) -{ - const char *text = luaL_checkstring(L, 1); - // Get server from registry - Server *server = get_server(L); - // Send - server->notifyPlayers(narrow_to_wide(text)); - return 0; -} - -// chat_send_player(name, text) -static int l_chat_send_player(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - const char *text = luaL_checkstring(L, 2); - // Get server from registry - Server *server = get_server(L); - // Send - server->notifyPlayer(name, narrow_to_wide(text)); - return 0; -} - -// get_player_privs(name, text) -static int l_get_player_privs(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - // Get server from registry - Server *server = get_server(L); - // Do it - lua_newtable(L); - int table = lua_gettop(L); - u64 privs_i = server->getPlayerAuthPrivs(name); - // Special case for the "name" setting (local player / server owner) - if(name == g_settings->get("name")) - privs_i = PRIV_ALL; - std::set privs_s = privsToSet(privs_i); - for(std::set::const_iterator - i = privs_s.begin(); i != privs_s.end(); i++){ - lua_pushboolean(L, true); - lua_setfield(L, table, i->c_str()); + // reset_inventory_modified(self) + static int l_reset_inventory_modified(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + meta->resetInventoryModified(); + reportMetadataChange(ref); + return 0; } - lua_pushvalue(L, table); - 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); - if(!mod){ - lua_pushnil(L); + // is_text_modified(self) + static int l_is_text_modified(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + lua_pushboolean(L, meta->isTextModified()); return 1; } - lua_pushstring(L, mod->path.c_str()); - return 1; -} - -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}, - {"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_modpath", l_get_modpath}, - {NULL, NULL} -}; - -/* - LuaEntity functions -*/ - -static const struct luaL_Reg minetest_entity_m [] = { - {NULL, NULL} -}; - -/* - Getters for stuff in main tables -*/ - -static void objectref_get(lua_State *L, u16 id) -{ - // 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 void luaentity_get(lua_State *L, u16 id) -{ - // 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 -} - -/* - Object wrappers -*/ - -#define method(class, name) {#name, class::l_##name} - -/* - ItemStack -*/ - -class ItemStack -{ -private: - InventoryItem *m_stack; - - static const char className[]; - static const luaL_reg methods[]; - // Exported functions - - // garbage collector - static int gc_object(lua_State *L) { - ItemStack *o = *(ItemStack **)(lua_touserdata(L, 1)); - delete o; + // reset_text_modified(self) + static int l_reset_text_modified(lua_State *L) + { + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + meta->resetTextModified(); + reportMetadataChange(ref); return 0; } - // take_item(self) - static int l_take_item(lua_State *L) + // set_string(self, name, var) + static int l_set_string(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); - } - return 1; + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string name = luaL_checkstring(L, 2); + size_t len = 0; + const char *s = lua_tolstring(L, 3, &len); + std::string str(s, len); + meta->setString(name, str); + reportMetadataChange(ref); + return 0; } - // put_item(self, item) -> true/false - static int l_put_item(lua_State *L) + // get_string(self, name) + static int l_get_string(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); + NodeMetaRef *ref = checkobject(L, 1); + NodeMetadata *meta = getmeta(ref); + if(meta == NULL) return 0; + // Do it + std::string name = luaL_checkstring(L, 2); + std::string str = meta->getString(name); + lua_pushlstring(L, str.c_str(), str.size()); return 1; } public: - ItemStack(InventoryItem *item=NULL): - m_stack(item) + NodeMetaRef(v3s16 p, ServerEnvironment *env): + m_p(p), + m_env(env) { } - ~ItemStack() + ~NodeMetaRef() { - delete m_stack; } - static ItemStack* checkobject(lua_State *L, int narg) + // Creates an NodeMetaRef and leaves it on top of stack + // Not callable from Lua; all references are created on the C side. + static void create(lua_State *L, v3s16 p, ServerEnvironment *env) { - 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 - } - - InventoryItem* getItemCopy() - { - if(!m_stack) - return NULL; - return m_stack->clone(); - } - - // Creates an ItemStack 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); - *(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) - { - ItemStack *o = new ItemStack(item); + NodeMetaRef *o = new NodeMetaRef(p, env); + //infostream<<"NodeMetaRef::create: o="<getInventory(ref->m_loc); + ServerActiveObject *co = ref->m_object; + return co; } - - static InventoryList* getlist(lua_State *L, InvRef *ref, - const char *listname) + + static LuaEntitySAO* getluaobject(ObjectRef *ref) { - Inventory *inv = getinv(L, ref); - if(!inv) + ServerActiveObject *obj = getobject(ref); + if(obj == NULL) return NULL; - 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) + if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY) return NULL; - return list->getItem(i); + return (LuaEntitySAO*)obj; } - - static void reportInventoryChange(lua_State *L, InvRef *ref) + + static ServerRemotePlayer* getplayer(ObjectRef *ref) { - // Inform other things that the inventory has changed - get_server(L)->setInventoryModified(ref->m_loc); + ServerActiveObject *obj = getobject(ref); + if(obj == NULL) + return NULL; + if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER) + return NULL; + return static_cast(obj); } // Exported functions // garbage collector static int gc_object(lua_State *L) { - InvRef *o = *(InvRef **)(lua_touserdata(L, 1)); + ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1)); + //infostream<<"ObjectRef::gc_object: o="<deleteList(listname); - return 0; - } - InventoryList *list = inv->getList(listname); - if(list){ - list->setSize(newsize); - } else { - list = inv->addList(listname, newsize); - } + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + infostream<<"ObjectRef::l_remove(): id="<getId()<m_removed = true; return 0; } - - // get_stack(self, listname, i) - static int l_get_stack(lua_State *L) + + // getpos(self) + // returns: {x=num, y=num, z=num} + static int l_getpos(lua_State *L) { - InvRef *ref = checkobject(L, 1); - const char *listname = luaL_checkstring(L, 2); - int i = luaL_checknumber(L, 3); - InventoryItem *item = getitem(L, ref, listname, i); - if(!item){ - ItemStack::create(L, NULL); - return 1; - } - ItemStack::create(L, item->clone()); + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + v3f pos = co->getBasePosition() / BS; + lua_newtable(L); + lua_pushnumber(L, pos.X); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, pos.Y); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, pos.Z); + lua_setfield(L, -2, "z"); return 1; } - - // set_stack(self, listname, i, stack) - static int l_set_stack(lua_State *L) + + // setpos(self, pos) + static int l_setpos(lua_State *L) { - InvRef *ref = checkobject(L, 1); - const char *listname = luaL_checkstring(L, 2); - int i = luaL_checknumber(L, 3); - ItemStack *stack = ItemStack::checkobject(L, 4); - InventoryList *list = getlist(L, ref, listname); - if(!list){ - 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); - return 1; + ObjectRef *ref = checkobject(L, 1); + //LuaEntitySAO *co = getluaobject(ref); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); + // Do it + co->setPos(pos); + return 0; } - -public: - InvRef(const InventoryLocation &loc): - m_loc(loc) + + // moveto(self, pos, continuous=false) + static int l_moveto(lua_State *L) { + ObjectRef *ref = checkobject(L, 1); + //LuaEntitySAO *co = getluaobject(ref); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); + // continuous + bool continuous = lua_toboolean(L, 3); + // Do it + co->moveTo(pos, continuous); + return 0; } - ~InvRef() + // punch(self, puncher); puncher = an another ObjectRef + static int l_punch(lua_State *L) { + ObjectRef *ref = checkobject(L, 1); + ObjectRef *ref2 = checkobject(L, 2); + ServerActiveObject *co = getobject(ref); + ServerActiveObject *co2 = getobject(ref2); + if(co == NULL) return 0; + if(co2 == NULL) return 0; + // Do it + co->punch(co2); + return 0; } - // Creates an InvRef and leaves it on top of stack - // Not callable from Lua; all references are created on the C side. - static void create(lua_State *L, const InventoryLocation &loc) - { - InvRef *o = new InvRef(loc); - *(void **)(lua_newuserdata(L, sizeof(void *))) = o; - luaL_getmetatable(L, className); - lua_setmetatable(L, -2); - } - static void createPlayer(lua_State *L, Player *player) - { - InventoryLocation loc; - loc.setPlayer(player->getName()); - create(L, loc); - } - static void createNodeMeta(lua_State *L, v3s16 p) + // right_click(self, clicker); clicker = an another ObjectRef + static int l_right_click(lua_State *L) { - InventoryLocation loc; - loc.setNodeMeta(p); - create(L, loc); + ObjectRef *ref = checkobject(L, 1); + ObjectRef *ref2 = checkobject(L, 2); + ServerActiveObject *co = getobject(ref); + ServerActiveObject *co2 = getobject(ref2); + if(co == NULL) return 0; + if(co2 == NULL) return 0; + // Do it + co->rightClick(co2); + return 0; } - static void Register(lua_State *L) - { - lua_newtable(L); - int methodtable = lua_gettop(L); - luaL_newmetatable(L, className); - int metatable = lua_gettop(L); - - lua_pushliteral(L, "__metatable"); - lua_pushvalue(L, methodtable); - lua_settable(L, metatable); // hide metatable from Lua getmetatable() - - lua_pushliteral(L, "__index"); - lua_pushvalue(L, methodtable); - lua_settable(L, metatable); - - lua_pushliteral(L, "__gc"); - lua_pushcfunction(L, gc_object); - lua_settable(L, metatable); - - lua_pop(L, 1); // drop metatable - - luaL_openlib(L, 0, methods, 0); // fill methodtable - lua_pop(L, 1); // drop methodtable - - // Cannot be created from Lua - //lua_register(L, className, create_object); - } -}; -const char InvRef::className[] = "InvRef"; -const luaL_reg InvRef::methods[] = { - method(InvRef, set_size), - method(InvRef, get_stack), - method(InvRef, set_stack), - {0,0} -}; - -/* - NodeMetaRef -*/ - -class NodeMetaRef -{ -private: - v3s16 m_p; - ServerEnvironment *m_env; - - static const char className[]; - static const luaL_reg methods[]; - - static NodeMetaRef *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 *(NodeMetaRef**)ud; // unbox pointer - } - - static NodeMetadata* getmeta(NodeMetaRef *ref) + // get_wield_digging_properties(self) + static int l_get_wield_digging_properties(lua_State *L) { - NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); - return meta; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + ToolDiggingProperties prop; + co->getWieldDiggingProperties(&prop); + push_tool_digging_properties(L, prop); + return 1; } - /*static IGenericNodeMetadata* getgenericmeta(NodeMetaRef *ref) - { - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) - return NULL; - if(meta->typeId() != NODEMETA_GENERIC) - return NULL; - return (IGenericNodeMetadata*)meta; - }*/ - - static void reportMetadataChange(NodeMetaRef *ref) + // damage_wielded_item(self, amount) + static int l_damage_wielded_item(lua_State *L) { - // Inform other things that the metadata has changed - v3s16 blockpos = getNodeBlockPos(ref->m_p); - MapEditEvent event; - event.type = MEET_BLOCK_NODE_METADATA_CHANGED; - event.p = blockpos; - ref->m_env->getMap().dispatchEvent(&event); - // Set the block to be saved - MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos); - if(block) - block->raiseModified(MOD_STATE_WRITE_NEEDED, - "NodeMetaRef::reportMetadataChange"); - } - - // Exported functions - - // garbage collector - static int gc_object(lua_State *L) { - NodeMetaRef *o = *(NodeMetaRef **)(lua_touserdata(L, 1)); - delete o; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // Do it + int amount = lua_tonumber(L, 2); + co->damageWieldedItem(amount); return 0; } - // get_type(self) - static int l_get_type(lua_State *L) + // add_to_inventory(self, itemstring) + // returns: true if item was added, (false, "reason") otherwise + static int l_add_to_inventory(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL){ - lua_pushnil(L); - return 1; - } + 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=\""<typeName()); - return 1; + std::istringstream is(itemstring, std::ios::binary); + ServerEnvironment *env = co->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; + } } - // allows_text_input(self) - static int l_allows_text_input(lua_State *L) + // add_to_inventory_later(self, itemstring) + // returns: nil + static int l_add_to_inventory_later(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + 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=\""<allowsTextInput()); - return 1; + std::istringstream is(itemstring, std::ios::binary); + ServerEnvironment *env = co->getEnv(); + assert(env); + IGameDef *gamedef = env->getGameDef(); + InventoryItem *item = InventoryItem::deSerialize(is, gamedef); + infostream<<"item="<addToInventoryLater(item); + // Return + return 0; } - // set_text(self, text) - static int l_set_text(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) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + 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="<setText(text); - reportMetadataChange(ref); + co->setHP(hp); + // Return return 0; } - // get_text(self) - static int l_get_text(lua_State *L) + // 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) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; - // Do it - std::string text = meta->getText(); - lua_pushstring(L, text.c_str()); + 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="<getOwner(); - lua_pushstring(L, owner.c_str()); - return 1; + co->setVelocity(pos); + return 0; } - - /* IGenericNodeMetadata interface */ - // set_infotext(self, text) - static int l_set_infotext(lua_State *L) + // setacceleration(self, {x=num, y=num, z=num}) + static int l_setacceleration(lua_State *L) { - infostream<<__FUNCTION_NAME<setInfoText(text); - reportMetadataChange(ref); + co->setAcceleration(pos); return 0; } - - // inventory_set_list(self, name, {item1, item2, ...}) - static int l_inventory_set_list(lua_State *L) - { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; - // Do it - Inventory *inv = meta->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; - } - - // inventory_get_list(self, name) - static int l_inventory_get_list(lua_State *L) + + // getacceleration(self) + static int l_getacceleration(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; // Do it - Inventory *inv = meta->getInventory(); - const char *name = luaL_checkstring(L, 2); - inventory_get_list_to_lua(inv, name, L); + v3f v = co->getAcceleration(); + pushFloatPos(L, v); return 1; } - - // set_inventory_draw_spec(self, text) - static int l_set_inventory_draw_spec(lua_State *L) + + // settexturemod(self, mod) + static int l_settexturemod(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; // Do it - std::string text = luaL_checkstring(L, 2); - meta->setInventoryDrawSpec(text); - reportMetadataChange(ref); + std::string mod = luaL_checkstring(L, 2); + co->setTextureMod(mod); return 0; } - - // set_allow_text_input(self, text) - static int l_set_allow_text_input(lua_State *L) + + // setsprite(self, p={x=0,y=0}, num_frames=1, framelength=0.2, + // select_horiz_by_yawpitch=false) + static int l_setsprite(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; // Do it - bool b = lua_toboolean(L, 2); - meta->setAllowTextInput(b); - reportMetadataChange(ref); + v2s16 p(0,0); + if(!lua_isnil(L, 2)) + p = read_v2s16(L, 2); + int num_frames = 1; + if(!lua_isnil(L, 3)) + num_frames = lua_tonumber(L, 3); + float framelength = 0.2; + if(!lua_isnil(L, 4)) + framelength = lua_tonumber(L, 4); + bool select_horiz_by_yawpitch = false; + if(!lua_isnil(L, 5)) + select_horiz_by_yawpitch = lua_toboolean(L, 5); + co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch); return 0; } - // set_allow_removal(self, text) - static int l_set_allow_removal(lua_State *L) + /* Player-only */ + + // get_player_name(self) + static int l_get_player_name(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL){ + lua_pushnil(L); + return 1; + } // Do it - bool b = lua_toboolean(L, 2); - meta->setRemovalDisabled(!b); - reportMetadataChange(ref); - return 0; + lua_pushstring(L, player->getName()); + return 1; } - - // set_enforce_owner(self, text) - static int l_set_enforce_owner(lua_State *L) + + // inventory_set_list(self, name, {item1, item2, ...}) + static int l_inventory_set_list(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; + const char *name = luaL_checkstring(L, 2); // Do it - bool b = lua_toboolean(L, 2); - meta->setEnforceOwner(b); - reportMetadataChange(ref); + inventory_set_list_from_lua(&player->inventory, name, L, 3, + player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE); + player->m_inventory_not_sent = true; return 0; } - // is_inventory_modified(self) - static int l_is_inventory_modified(lua_State *L) + // inventory_get_list(self, name) + static int l_inventory_get_list(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; + const char *name = luaL_checkstring(L, 2); // Do it - lua_pushboolean(L, meta->isInventoryModified()); + inventory_get_list_to_lua(&player->inventory, name, L); return 1; } - // reset_inventory_modified(self) - static int l_reset_inventory_modified(lua_State *L) + // get_wielded_itemstring(self) + static int l_get_wielded_itemstring(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; // Do it - meta->resetInventoryModified(); - reportMetadataChange(ref); - return 0; + InventoryItem *item = player->getWieldedItem(); + if(item == NULL){ + lua_pushnil(L); + return 1; + } + lua_pushstring(L, item->getItemString().c_str()); + return 1; } - // is_text_modified(self) - static int l_is_text_modified(lua_State *L) + // get_wielded_item(self) + static int l_get_wielded_item(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; // Do it - lua_pushboolean(L, meta->isTextModified()); + InventoryItem *item0 = player->getWieldedItem(); + push_stack_item(L, item0); return 1; } - // reset_text_modified(self) - static int l_reset_text_modified(lua_State *L) + // get_look_dir(self) + static int l_get_look_dir(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; // Do it - meta->resetTextModified(); - reportMetadataChange(ref); - return 0; + float pitch = player->getRadPitch(); + float yaw = player->getRadYaw(); + v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw)); + push_v3f(L, v); + return 1; } - // set_string(self, name, var) - static int l_set_string(lua_State *L) + // get_look_pitch(self) + static int l_get_look_pitch(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; // Do it - std::string name = luaL_checkstring(L, 2); - size_t len = 0; - const char *s = lua_tolstring(L, 3, &len); - std::string str(s, len); - meta->setString(name, str); - reportMetadataChange(ref); - return 0; + lua_pushnumber(L, player->getRadPitch()); + return 1; } - // get_string(self, name) - static int l_get_string(lua_State *L) + // get_look_yaw(self) + static int l_get_look_yaw(lua_State *L) { - NodeMetaRef *ref = checkobject(L, 1); - NodeMetadata *meta = getmeta(ref); - if(meta == NULL) return 0; + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; // Do it - std::string name = luaL_checkstring(L, 2); - std::string str = meta->getString(name); - lua_pushlstring(L, str.c_str(), str.size()); + lua_pushnumber(L, player->getRadYaw()); return 1; } public: - NodeMetaRef(v3s16 p, ServerEnvironment *env): - m_p(p), - m_env(env) + ObjectRef(ServerActiveObject *object): + m_object(object) { + //infostream<<"ObjectRef created for id="<getId()<getId() == 0){ + ObjectRef::create(L, cobj); + } else { + objectref_get(L, cobj->getId()); + } +} + /* - ObjectRef + EnvRef */ -class ObjectRef +class EnvRef { private: - ServerActiveObject *m_object; + ServerEnvironment *m_env; static const char className[]; static const luaL_reg methods[]; - static ObjectRef *checkobject(lua_State *L, int narg) + static EnvRef *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 *(ObjectRef**)ud; // unbox pointer - } - - static ServerActiveObject* getobject(ObjectRef *ref) - { - ServerActiveObject *co = ref->m_object; - return co; - } - - static LuaEntitySAO* getluaobject(ObjectRef *ref) - { - ServerActiveObject *obj = getobject(ref); - if(obj == NULL) - return NULL; - if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY) - return NULL; - return (LuaEntitySAO*)obj; - } - - static ServerRemotePlayer* getplayer(ObjectRef *ref) - { - ServerActiveObject *obj = getobject(ref); - if(obj == NULL) - return NULL; - if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER) - return NULL; - return static_cast(obj); + return *(EnvRef**)ud; // unbox pointer } // Exported functions - - // garbage collector - static int gc_object(lua_State *L) { - ObjectRef *o = *(ObjectRef **)(lua_touserdata(L, 1)); - //infostream<<"ObjectRef::gc_object: o="<m_env; + if(env == NULL) return 0; + // pos + v3s16 pos = read_v3s16(L, 2); + // content + MapNode n = readnode(L, 3, env->getGameDef()->ndef()); + // Do it + bool succeeded = env->getMap().addNodeWithEvent(pos, n); + lua_pushboolean(L, succeeded); + return 1; } - - // getpos(self) - // returns: {x=num, y=num, z=num} - static int l_getpos(lua_State *L) + + // EnvRef:remove_node(pos) + // pos = {x=num, y=num, z=num} + static int l_remove_node(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; - v3f pos = co->getBasePosition() / BS; - lua_newtable(L); - lua_pushnumber(L, pos.X); - lua_setfield(L, -2, "x"); - lua_pushnumber(L, pos.Y); - lua_setfield(L, -2, "y"); - lua_pushnumber(L, pos.Z); - lua_setfield(L, -2, "z"); + //infostream<<"EnvRef::l_remove_node()"<m_env; + if(env == NULL) return 0; + // pos + v3s16 pos = read_v3s16(L, 2); + // Do it + bool succeeded = env->getMap().removeNodeWithEvent(pos); + lua_pushboolean(L, succeeded); return 1; } - - // setpos(self, pos) - static int l_setpos(lua_State *L) + + // EnvRef:get_node(pos) + // pos = {x=num, y=num, z=num} + static int l_get_node(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - //LuaEntitySAO *co = getluaobject(ref); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; + //infostream<<"EnvRef::l_get_node()"<m_env; + if(env == NULL) return 0; // pos - v3f pos = readFloatPos(L, 2); + v3s16 pos = read_v3s16(L, 2); // Do it - co->setPos(pos); - return 0; + MapNode n = env->getMap().getNodeNoEx(pos); + // Return node + pushnode(L, n, env->getGameDef()->ndef()); + return 1; } - - // moveto(self, pos, continuous=false) - static int l_moveto(lua_State *L) + + // EnvRef:get_node_or_nil(pos) + // pos = {x=num, y=num, z=num} + static int l_get_node_or_nil(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - //LuaEntitySAO *co = getluaobject(ref); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; + //infostream<<"EnvRef::l_get_node()"<m_env; + if(env == NULL) return 0; // pos - v3f pos = readFloatPos(L, 2); - // continuous - bool continuous = lua_toboolean(L, 3); + v3s16 pos = read_v3s16(L, 2); // Do it - co->moveTo(pos, continuous); - return 0; + try{ + MapNode n = env->getMap().getNode(pos); + // Return node + pushnode(L, n, env->getGameDef()->ndef()); + return 1; + } catch(InvalidPositionException &e) + { + lua_pushnil(L); + return 1; + } } - // punch(self, puncher); puncher = an another ObjectRef - static int l_punch(lua_State *L) + // EnvRef:get_node_light(pos, timeofday) + // pos = {x=num, y=num, z=num} + // timeofday: nil = current time, 0 = night, 0.5 = day + static int l_get_node_light(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - ObjectRef *ref2 = checkobject(L, 2); - ServerActiveObject *co = getobject(ref); - ServerActiveObject *co2 = getobject(ref2); - if(co == NULL) return 0; - if(co2 == NULL) return 0; + EnvRef *o = checkobject(L, 1); + ServerEnvironment *env = o->m_env; + if(env == NULL) return 0; // Do it - co->punch(co2); - return 0; + v3s16 pos = read_v3s16(L, 2); + u32 time_of_day = env->getTimeOfDay(); + if(lua_isnumber(L, 3)) + time_of_day = 24000.0 * lua_tonumber(L, 3); + time_of_day %= 24000; + u32 dnr = time_to_daynight_ratio(time_of_day); + MapNode n = env->getMap().getNodeNoEx(pos); + try{ + MapNode n = env->getMap().getNode(pos); + INodeDefManager *ndef = env->getGameDef()->ndef(); + lua_pushinteger(L, n.getLightBlend(dnr, ndef)); + return 1; + } catch(InvalidPositionException &e) + { + lua_pushnil(L); + return 1; + } } - // right_click(self, clicker); clicker = an another ObjectRef - static int l_right_click(lua_State *L) + // EnvRef:add_entity(pos, entityname) + // pos = {x=num, y=num, z=num} + static int l_add_entity(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - ObjectRef *ref2 = checkobject(L, 2); - ServerActiveObject *co = getobject(ref); - ServerActiveObject *co2 = getobject(ref2); - if(co == NULL) return 0; - if(co2 == NULL) return 0; + //infostream<<"EnvRef::l_add_entity()"<m_env; + if(env == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); + // content + const char *name = luaL_checkstring(L, 3); // Do it - co->rightClick(co2); + ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, ""); + env->addActiveObject(obj); return 0; } - // get_wield_digging_properties(self) - static int l_get_wield_digging_properties(lua_State *L) + // EnvRef:add_item(pos, inventorystring) + // pos = {x=num, y=num, z=num} + static int l_add_item(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; + 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); // Do it - ToolDiggingProperties prop; - co->getWieldDiggingProperties(&prop); - push_tool_digging_properties(L, prop); - return 1; + ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring); + env->addActiveObject(obj); + return 0; } - // damage_wielded_item(self, amount) - static int l_damage_wielded_item(lua_State *L) + // EnvRef:add_rat(pos) + // pos = {x=num, y=num, z=num} + static int l_add_rat(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; + infostream<<"EnvRef::l_add_rat()"<m_env; + if(env == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); // Do it - int amount = lua_tonumber(L, 2); - co->damageWieldedItem(amount); + ServerActiveObject *obj = new RatSAO(env, pos); + env->addActiveObject(obj); return 0; } - // add_to_inventory(self, itemstring) - // returns: true if item was added, (false, "reason") otherwise - static int l_add_to_inventory(lua_State *L) + // EnvRef:add_firefly(pos) + // pos = {x=num, y=num, z=num} + static int l_add_firefly(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=\""<m_env; + if(env == NULL) return 0; + // pos + v3f pos = checkFloatPos(L, 2); // Do it - std::istringstream is(itemstring, std::ios::binary); - ServerEnvironment *env = co->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; - } + ServerActiveObject *obj = new FireflySAO(env, pos); + env->addActiveObject(obj); + return 0; } - // add_to_inventory_later(self, itemstring) - // returns: nil - static int l_add_to_inventory_later(lua_State *L) + // EnvRef:get_meta(pos) + static int l_get_meta(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=\""<m_env; + if(env == NULL) return 0; // Do it - std::istringstream is(itemstring, std::ios::binary); - ServerEnvironment *env = co->getEnv(); - assert(env); - IGameDef *gamedef = env->getGameDef(); - InventoryItem *item = InventoryItem::deSerialize(is, gamedef); - infostream<<"item="<addToInventoryLater(item); - // Return - return 0; + v3s16 p = read_v3s16(L, 2); + NodeMetaRef::create(L, p, env); + return 1; } - // set_hp(self, hp) - // hp = number of hitpoints (2 * number of hearts) - // returns: nil - static int l_set_hp(lua_State *L) + // EnvRef:get_player_by_name(name) + static int l_get_player_by_name(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="<m_env; + if(env == NULL) return 0; // Do it - co->setHP(hp); - // Return - return 0; + const char *name = luaL_checkstring(L, 2); + ServerRemotePlayer *player = + static_cast(env->getPlayer(name)); + if(player == NULL){ + lua_pushnil(L); + return 1; + } + // Put player on stack + objectref_get_or_create(L, player); + 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) + // EnvRef:get_objects_inside_radius(pos, radius) + static int l_get_objects_inside_radius(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="<m_env; + if(env == NULL) return 0; + // Do it + v3f pos = checkFloatPos(L, 2); + float radius = luaL_checknumber(L, 3) * BS; + std::set ids = env->getObjectsInsideRadius(pos, radius); + lua_newtable(L); + int table = lua_gettop(L); + for(std::set::const_iterator + i = ids.begin(); i != ids.end(); i++){ + ServerActiveObject *obj = env->getActiveObject(*i); + // Insert object reference into table + lua_pushvalue(L, table_insert); + lua_pushvalue(L, table); + objectref_get_or_create(L, obj); + if(lua_pcall(L, 2, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + } return 1; } - /* LuaEntitySAO-only */ - - // setvelocity(self, {x=num, y=num, z=num}) - static int l_setvelocity(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; - // pos - v3f pos = readFloatPos(L, 2); - // Do it - co->setVelocity(pos); + static int gc_object(lua_State *L) { + EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1)); + delete o; return 0; } - - // setacceleration(self, {x=num, y=num, z=num}) - static int l_setacceleration(lua_State *L) + +public: + EnvRef(ServerEnvironment *env): + m_env(env) { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; - // pos - v3f pos = readFloatPos(L, 2); - // Do it - co->setAcceleration(pos); - return 0; + infostream<<"EnvRef created"<getAcceleration(); - pushFloatPos(L, v); - return 1; + infostream<<"EnvRef destructing"<setTextureMod(mod); - return 0; + EnvRef *o = new EnvRef(env); + //infostream<<"EnvRef::create: o="<setSprite(p, num_frames, framelength, select_horiz_by_yawpitch); - return 0; + EnvRef *o = checkobject(L, -1); + o->m_env = NULL; } - - /* Player-only */ - // get_player_name(self) - static int l_get_player_name(lua_State *L) + static void Register(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; + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pop(L, 1); // drop metatable + + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable + + // Cannot be created from Lua + //lua_register(L, className, create_object); } +}; +const char EnvRef::className[] = "EnvRef"; +const luaL_reg EnvRef::methods[] = { + method(EnvRef, add_node), + method(EnvRef, remove_node), + method(EnvRef, get_node), + method(EnvRef, get_node_or_nil), + method(EnvRef, get_node_light), + method(EnvRef, add_entity), + method(EnvRef, add_item), + method(EnvRef, add_rat), + method(EnvRef, add_firefly), + method(EnvRef, get_meta), + method(EnvRef, get_player_by_name), + method(EnvRef, get_objects_inside_radius), + {0,0} +}; + +/* + 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()); - // inventory_set_list(self, name, {item1, item2, ...}) - static int l_inventory_set_list(lua_State *L) + // Get registered object to top of stack + lua_pushvalue(L, 2); + + // 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: + lua_State *m_lua; + int m_id; + + std::set m_trigger_contents; + std::set m_required_neighbors; + float m_trigger_interval; + u32 m_trigger_chance; +public: + LuaABM(lua_State *L, int id, + const std::set &trigger_contents, + const std::set &required_neighbors, + float trigger_interval, u32 trigger_chance): + m_lua(L), + m_id(id), + m_trigger_contents(trigger_contents), + m_required_neighbors(required_neighbors), + m_trigger_interval(trigger_interval), + m_trigger_chance(trigger_chance) { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - const char *name = luaL_checkstring(L, 2); - // Do it - inventory_set_list_from_lua(&player->inventory, name, L, 3, - player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE); - player->m_inventory_not_sent = true; - return 0; } - - // inventory_get_list(self, name) - static int l_inventory_get_list(lua_State *L) + virtual std::set getTriggerContents() { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - const char *name = luaL_checkstring(L, 2); - // Do it - inventory_get_list_to_lua(&player->inventory, name, L); - return 1; + return m_trigger_contents; } - - // get_wielded_itemstring(self) - static int l_get_wielded_itemstring(lua_State *L) + virtual std::set getRequiredNeighbors() { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - // Do it - InventoryItem *item = player->getWieldedItem(); - if(item == NULL){ - lua_pushnil(L); - return 1; - } - lua_pushstring(L, item->getItemString().c_str()); - return 1; + return m_required_neighbors; } - - // get_wielded_item(self) - static int l_get_wielded_item(lua_State *L) + virtual float getTriggerInterval() { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - // Do it - InventoryItem *item0 = player->getWieldedItem(); - push_stack_item(L, item0); - return 1; + return m_trigger_interval; } - - // get_look_dir(self) - static int l_get_look_dir(lua_State *L) + virtual u32 getTriggerChance() { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - // Do it - float pitch = player->getRadPitch(); - float yaw = player->getRadYaw(); - v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw)); - push_v3f(L, v); - return 1; + return m_trigger_chance; } + virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider) + { + lua_State *L = m_lua; + + realitycheck(L); + assert(lua_checkstack(L, 20)); + StackUnroller stack_unroller(L); + + // Get minetest.registered_abms + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "registered_abms"); + luaL_checktype(L, -1, LUA_TTABLE); + int registered_abms = lua_gettop(L); + + // Get minetest.registered_abms[m_id] + lua_pushnumber(L, m_id); + lua_gettable(L, registered_abms); + if(lua_isnil(L, -1)) + assert(0); + + // 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 */ - // get_look_pitch(self) - static int l_get_look_pitch(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - // Do it - lua_pushnumber(L, player->getRadPitch()); - return 1; - } + f.drawtype = (NodeDrawType)getenumfield(L, nodedef_table, "drawtype", es_DrawType, + NDT_NORMAL); + getfloatfield(L, nodedef_table, "visual_scale", f.visual_scale); - // get_look_yaw(self) - static int l_get_look_yaw(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - ServerRemotePlayer *player = getplayer(ref); - if(player == NULL) return 0; - // Do it - lua_pushnumber(L, player->getRadYaw()); - return 1; + 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); -public: - ObjectRef(ServerActiveObject *object): - m_object(object) - { - //infostream<<"ObjectRef created for id="<getId()<m_object = NULL; - } + /* Other stuff */ - static void Register(lua_State *L) - { - lua_newtable(L); - int methodtable = lua_gettop(L); - luaL_newmetatable(L, className); - int metatable = lua_gettop(L); - - lua_pushliteral(L, "__metatable"); - lua_pushvalue(L, methodtable); - lua_settable(L, metatable); // hide metatable from Lua getmetatable() + lua_getfield(L, nodedef_table, "post_effect_color"); + if(!lua_isnil(L, -1)) + f.post_effect_color = readARGB8(L, -1); + lua_pop(L, 1); - lua_pushliteral(L, "__index"); - lua_pushvalue(L, methodtable); - lua_settable(L, metatable); + 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_pushliteral(L, "__gc"); - lua_pushcfunction(L, gc_object); - lua_settable(L, metatable); + lua_getfield(L, -1, "fixed"); + if(lua_istable(L, -1)) + f.selection_box.fixed = read_aabbox3df32(L, -1, BS); + lua_pop(L, 1); - lua_pop(L, 1); // drop metatable + 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); - luaL_openlib(L, 0, methods, 0); // fill methodtable - lua_pop(L, 1); // drop methodtable + 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); - // Cannot be created from Lua - //lua_register(L, className, create_object); + 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); } -}; -const char ObjectRef::className[] = "ObjectRef"; -const luaL_reg ObjectRef::methods[] = { - // ServerActiveObject - method(ObjectRef, remove), - method(ObjectRef, getpos), - method(ObjectRef, setpos), - 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), - // LuaEntitySAO-only - method(ObjectRef, setvelocity), - method(ObjectRef, setacceleration), - method(ObjectRef, getacceleration), - method(ObjectRef, settexturemod), - method(ObjectRef, setsprite), - // Player-only - method(ObjectRef, get_player_name), - method(ObjectRef, inventory_set_list), - method(ObjectRef, inventory_get_list), - 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), - {0,0} -}; + lua_pop(L, 1); -// Creates a new anonymous reference if id=0 -static void objectref_get_or_create(lua_State *L, - ServerActiveObject *cobj) -{ - if(cobj->getId() == 0){ - ObjectRef::create(L, cobj); - } else { - objectref_get(L, cobj->getId()); + lua_getfield(L, nodedef_table, "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); -/* - EnvRef -*/ + 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 */ +} -class EnvRef +// alias_node(name, convert_to_name) +static int l_alias_node(lua_State *L) { -private: - ServerEnvironment *m_env; + std::string name = luaL_checkstring(L, 1); + std::string convert_to = luaL_checkstring(L, 2); - static const char className[]; - static const luaL_reg methods[]; + // Get the writable node definition manager from the server + IWritableNodeDefManager *nodedef = + get_server(L)->getWritableNodeDefManager(); + + nodedef->setAlias(name, convert_to); + + return 0; /* number of results */ +} - static EnvRef *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 *(EnvRef**)ud; // unbox pointer - } +// alias_tool(name, convert_to_name) +static int l_alias_tool(lua_State *L) +{ + std::string name = luaL_checkstring(L, 1); + std::string convert_to = luaL_checkstring(L, 2); + + // Get the writable tool definition manager from the server + IWritableToolDefManager *tooldef = + get_server(L)->getWritableToolDefManager(); - // Exported functions + tooldef->setAlias(name, convert_to); - // EnvRef:add_node(pos, node) - // pos = {x=num, y=num, z=num} - static int l_add_node(lua_State *L) - { - //infostream<<"EnvRef::l_add_node()"<m_env; - if(env == NULL) return 0; - // pos - v3s16 pos = readpos(L, 2); - // content - MapNode n = readnode(L, 3, env->getGameDef()->ndef()); - // Do it - bool succeeded = env->getMap().addNodeWithEvent(pos, n); - lua_pushboolean(L, succeeded); - return 1; - } + return 0; /* number of results */ +} - // EnvRef:remove_node(pos) - // pos = {x=num, y=num, z=num} - static int l_remove_node(lua_State *L) - { - //infostream<<"EnvRef::l_remove_node()"<m_env; - if(env == NULL) return 0; - // pos - v3s16 pos = readpos(L, 2); - // Do it - bool succeeded = env->getMap().removeNodeWithEvent(pos); - lua_pushboolean(L, succeeded); - return 1; - } +// alias_craftitem(name, convert_to_name) +static int l_alias_craftitem(lua_State *L) +{ + std::string name = luaL_checkstring(L, 1); + std::string convert_to = luaL_checkstring(L, 2); - // EnvRef:get_node(pos) - // pos = {x=num, y=num, z=num} - static int l_get_node(lua_State *L) - { - //infostream<<"EnvRef::l_get_node()"<m_env; - if(env == NULL) return 0; - // pos - v3s16 pos = readpos(L, 2); - // Do it - MapNode n = env->getMap().getNodeNoEx(pos); - // Return node - pushnode(L, n, env->getGameDef()->ndef()); - return 1; - } + // Get the writable CraftItem definition manager from the server + IWritableCraftItemDefManager *craftitemdef = + get_server(L)->getWritableCraftItemDefManager(); + + craftitemdef->setAlias(name, convert_to); - // EnvRef:get_node_or_nil(pos) - // pos = {x=num, y=num, z=num} - static int l_get_node_or_nil(lua_State *L) - { - //infostream<<"EnvRef::l_get_node()"<m_env; - if(env == NULL) return 0; - // pos - v3s16 pos = readpos(L, 2); - // Do it - try{ - MapNode n = env->getMap().getNode(pos); - // Return node - pushnode(L, n, env->getGameDef()->ndef()); - return 1; - } catch(InvalidPositionException &e) - { - lua_pushnil(L); - return 1; - } - } + return 0; /* number of results */ +} - // EnvRef:get_node_light(pos, timeofday) - // pos = {x=num, y=num, z=num} - // timeofday: nil = current time, 0 = night, 0.5 = day - static int l_get_node_light(lua_State *L) - { - EnvRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - // Do it - v3s16 pos = readpos(L, 2); - u32 time_of_day = env->getTimeOfDay(); - if(lua_isnumber(L, 3)) - time_of_day = 24000.0 * lua_tonumber(L, 3); - time_of_day %= 24000; - u32 dnr = time_to_daynight_ratio(time_of_day); - MapNode n = env->getMap().getNodeNoEx(pos); - try{ - MapNode n = env->getMap().getNode(pos); - INodeDefManager *ndef = env->getGameDef()->ndef(); - lua_pushinteger(L, n.getLightBlend(dnr, ndef)); - return 1; - } catch(InvalidPositionException &e) - { - lua_pushnil(L); - return 1; - } - } +// register_craft({output=item, recipe={{item00,item10},{item01,item11}}) +static int l_register_craft(lua_State *L) +{ + //infostream<<"register_craft"<m_env; - if(env == NULL) return 0; - // pos - v3f pos = readFloatPos(L, 2); - // content - const char *name = luaL_checkstring(L, 3); - // Do it - ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, ""); - env->addActiveObject(obj); - return 0; - } + // Get the writable craft definition manager from the server + IWritableCraftDefManager *craftdef = + get_server(L)->getWritableCraftDefManager(); + + std::string output; + int width = 0; + std::vector input; - // EnvRef:add_item(pos, inventorystring) - // 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 = readFloatPos(L, 2); - // inventorystring - const char *inventorystring = luaL_checkstring(L, 3); - // Do it - ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring); - env->addActiveObject(obj); - return 0; - } + 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); - // EnvRef:add_rat(pos) - // pos = {x=num, y=num, z=num} - static int l_add_rat(lua_State *L) - { - infostream<<"EnvRef::l_add_rat()"<m_env; - if(env == NULL) return 0; - // pos - v3f pos = readFloatPos(L, 2); - // Do it - ServerActiveObject *obj = new RatSAO(env, pos); - env->addActiveObject(obj); - return 0; + 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++; + } } + lua_pop(L, 1); - // EnvRef:add_firefly(pos) - // pos = {x=num, y=num, z=num} - static int l_add_firefly(lua_State *L) - { - infostream<<"EnvRef::l_add_firefly()"<m_env; - if(env == NULL) return 0; - // pos - v3f pos = readFloatPos(L, 2); - // Do it - ServerActiveObject *obj = new FireflySAO(env, pos); - env->addActiveObject(obj); - return 0; - } + CraftDefinition def(output, width, input); + craftdef->registerCraft(def); - // EnvRef:get_meta(pos) - static int l_get_meta(lua_State *L) - { - //infostream<<"EnvRef::l_get_meta()"<m_env; - if(env == NULL) return 0; - // Do it - v3s16 p = readpos(L, 2); - NodeMetaRef::create(L, p, env); - return 1; - } + return 0; /* number of results */ +} - // EnvRef:get_player_by_name(name) - static int l_get_player_by_name(lua_State *L) - { - EnvRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - // Do it - const char *name = luaL_checkstring(L, 2); - ServerRemotePlayer *player = - static_cast(env->getPlayer(name)); - if(player == NULL){ - lua_pushnil(L); - return 1; - } - // Put player on stack - objectref_get_or_create(L, player); - return 1; +// setting_get(name) +static int l_setting_get(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + try{ + std::string value = g_settings->get(name); + lua_pushstring(L, value.c_str()); + } catch(SettingNotFoundException &e){ + lua_pushnil(L); } + return 1; +} - // EnvRef:get_objects_inside_radius(pos, radius) - static int l_get_objects_inside_radius(lua_State *L) - { - // Get the table insert function - lua_getglobal(L, "table"); - lua_getfield(L, -1, "insert"); - int table_insert = lua_gettop(L); - // Get environemnt - EnvRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - // Do it - v3f pos = readFloatPos(L, 2); - float radius = luaL_checknumber(L, 3) * BS; - std::set ids = env->getObjectsInsideRadius(pos, radius); - lua_newtable(L); - int table = lua_gettop(L); - for(std::set::const_iterator - i = ids.begin(); i != ids.end(); i++){ - ServerActiveObject *obj = env->getActiveObject(*i); - // Insert object reference into table - lua_pushvalue(L, table_insert); - lua_pushvalue(L, table); - objectref_get_or_create(L, obj); - if(lua_pcall(L, 2, 0, 0)) - script_error(L, "error: %s", lua_tostring(L, -1)); - } - return 1; +// setting_getbool(name) +static int l_setting_getbool(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + try{ + bool value = g_settings->getBool(name); + lua_pushboolean(L, value); + } catch(SettingNotFoundException &e){ + lua_pushnil(L); } + return 1; +} - static int gc_object(lua_State *L) { - EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1)); - delete o; - return 0; - } +// chat_send_all(text) +static int l_chat_send_all(lua_State *L) +{ + const char *text = luaL_checkstring(L, 1); + // Get server from registry + Server *server = get_server(L); + // Send + server->notifyPlayers(narrow_to_wide(text)); + return 0; +} -public: - EnvRef(ServerEnvironment *env): - m_env(env) - { - infostream<<"EnvRef created"<notifyPlayer(name, narrow_to_wide(text)); + return 0; +} - ~EnvRef() - { - infostream<<"EnvRef destructing"<getPlayerAuthPrivs(name); + // Special case for the "name" setting (local player / server owner) + if(name == g_settings->get("name")) + privs_i = PRIV_ALL; + std::set privs_s = privsToSet(privs_i); + for(std::set::const_iterator + i = privs_s.begin(); i != privs_s.end(); i++){ + lua_pushboolean(L, true); + lua_setfield(L, table, i->c_str()); } + lua_pushvalue(L, table); + return 1; +} - // Creates an EnvRef and leaves it on top of stack - // Not callable from Lua; all references are created on the C side. - static void create(lua_State *L, ServerEnvironment *env) - { - EnvRef *o = new EnvRef(env); - //infostream<<"EnvRef::create: o="<m_env = NULL; + std::string type = checkstringfield(L, 1, "type"); + if(type == "player"){ + std::string name = checkstringfield(L, 1, "name"); + loc.setPlayer(name); + } else if(type == "node"){ + lua_getfield(L, 1, "pos"); + v3s16 pos = check_v3s16(L, -1); + loc.setNodeMeta(pos); } - static void Register(lua_State *L) - { - lua_newtable(L); - int methodtable = lua_gettop(L); - luaL_newmetatable(L, className); - int metatable = lua_gettop(L); - - lua_pushliteral(L, "__metatable"); - lua_pushvalue(L, methodtable); - lua_settable(L, metatable); // hide metatable from Lua getmetatable() - - lua_pushliteral(L, "__index"); - lua_pushvalue(L, methodtable); - lua_settable(L, metatable); + if(get_server(L)->getInventory(loc) != NULL) + InvRef::create(L, loc); + else + lua_pushnil(L); + return 1; +} - lua_pushliteral(L, "__gc"); - lua_pushcfunction(L, gc_object); - lua_settable(L, metatable); +// 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); + if(!mod){ + lua_pushnil(L); + return 1; + } + lua_pushstring(L, mod->path.c_str()); + return 1; +} - lua_pop(L, 1); // drop metatable +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}, + {"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_modpath", l_get_modpath}, + {NULL, NULL} +}; - luaL_openlib(L, 0, methods, 0); // fill methodtable - lua_pop(L, 1); // drop methodtable +/* + LuaEntity functions +*/ - // Cannot be created from Lua - //lua_register(L, className, create_object); - } -}; -const char EnvRef::className[] = "EnvRef"; -const luaL_reg EnvRef::methods[] = { - method(EnvRef, add_node), - method(EnvRef, remove_node), - method(EnvRef, get_node), - method(EnvRef, get_node_or_nil), - method(EnvRef, get_node_light), - method(EnvRef, add_entity), - method(EnvRef, add_item), - method(EnvRef, add_rat), - method(EnvRef, add_firefly), - method(EnvRef, get_meta), - method(EnvRef, get_player_by_name), - method(EnvRef, get_objects_inside_radius), - {0,0} +static const struct luaL_Reg minetest_entity_m [] = { + {NULL, NULL} }; /* @@ -3397,9 +3471,9 @@ static void pushPointedThing(lua_State *L, const PointedThing& pointed) { lua_pushstring(L, "node"); lua_setfield(L, -2, "type"); - pushpos(L, pointed.node_undersurface); + push_v3s16(L, pointed.node_undersurface); lua_setfield(L, -2, "under"); - pushpos(L, pointed.node_abovesurface); + push_v3s16(L, pointed.node_abovesurface); lua_setfield(L, -2, "above"); } else if(pointed.type == POINTEDTHING_OBJECT) @@ -3595,7 +3669,7 @@ void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode, // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TFUNCTION); // Call function - pushpos(L, p); + push_v3s16(L, p); pushnode(L, newnode, ndef); objectref_get_or_create(L, placer); if(lua_pcall(L, 3, 0, 0)) @@ -3627,7 +3701,7 @@ void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode, // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TFUNCTION); // Call function - pushpos(L, p); + push_v3s16(L, p); pushnode(L, oldnode, ndef); objectref_get_or_create(L, digger); if(lua_pcall(L, 3, 0, 0)) @@ -3659,7 +3733,7 @@ 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 - pushpos(L, p); + push_v3s16(L, p); pushnode(L, node, ndef); objectref_get_or_create(L, puncher); if(lua_pcall(L, 3, 0, 0)) @@ -3686,8 +3760,8 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp) // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TFUNCTION); // Call function - pushpos(L, minp); - pushpos(L, maxp); + push_v3s16(L, minp); + push_v3s16(L, maxp); if(lua_pcall(L, 2, 0, 0)) script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration -- 2.25.1