X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscriptapi.cpp;h=1a50e1e34e1571854c11323e229a2f5066d1a07b;hb=1c15f53318d49ccd148ec42b0a4345c4a8cd06bf;hp=83efef670e62631568f124107796f831fc1fdaad;hpb=d6b30dd3a5df4b84a287305f807442064f4cf68d;p=dragonfireclient.git diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 83efef670..1a50e1e34 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -107,6 +107,103 @@ class StackUnroller } }; +class ModNameStorer +{ +private: + lua_State *L; +public: + ModNameStorer(lua_State *L_, const std::string modname): + L(L_) + { + // Store current modname in registry + lua_pushstring(L, modname.c_str()); + lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname"); + } + ~ModNameStorer() + { + // Clear current modname in registry + lua_pushnil(L); + lua_setfield(L, LUA_REGISTRYINDEX, "minetest_current_modname"); + } +}; + +std::string get_current_modname(lua_State *L) +{ + lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname"); + std::string modname = ""; + if(lua_type(L, -1) == LUA_TSTRING) + modname = lua_tostring(L, -1); + lua_pop(L, 1); + return modname; +} + +void check_modname_prefix(lua_State *L, std::string &name) +{ + if(name.size() == 0) + throw LuaError(L, std::string("Name is empty")); + + if(name[0] == ':'){ + name = name.substr(1); + return; + } + + std::string modname = get_current_modname(L); + assert(modname != ""); + + // For __builtin, anything goes + if(modname == "__builtin") + return; + + if(name.substr(0, modname.size()+1) != modname + ":") + throw LuaError(L, std::string("Name \"")+name + +"\" does not follow naming conventions: " + +"\"modname:\" or \":\" prefix required)"); + + std::string subname = name.substr(modname.size()+1); + if(!string_allowed(subname, "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")) + throw LuaError(L, std::string("Name \"")+name + +"\" does not follow naming conventions: " + +"\"contains unallowed characters"); +} + +static void push_v3f(lua_State *L, v3f p) +{ + lua_newtable(L); + lua_pushnumber(L, p.X); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, p.Y); + lua_setfield(L, -2, "y"); + lua_pushnumber(L, p.Z); + lua_setfield(L, -2, "z"); +} + +static v2s16 read_v2s16(lua_State *L, int index) +{ + v2s16 p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; +} + +static v2f read_v2f(lua_State *L, int index) +{ + v2f p; + luaL_checktype(L, index, LUA_TTABLE); + lua_getfield(L, index, "x"); + p.X = lua_tonumber(L, -1); + lua_pop(L, 1); + lua_getfield(L, index, "y"); + p.Y = lua_tonumber(L, -1); + lua_pop(L, 1); + return p; +} + static v3f readFloatPos(lua_State *L, int index) { v3f pos; @@ -127,13 +224,7 @@ static v3f readFloatPos(lua_State *L, int index) static void pushFloatPos(lua_State *L, v3f p) { p /= BS; - lua_newtable(L); - lua_pushnumber(L, p.X); - lua_setfield(L, -2, "x"); - lua_pushnumber(L, p.Y); - lua_setfield(L, -2, "y"); - lua_pushnumber(L, p.Z); - lua_setfield(L, -2, "z"); + push_v3f(L, p); } static void pushpos(lua_State *L, v3s16 p) @@ -168,7 +259,7 @@ static void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef) static MapNode readnode(lua_State *L, int index, INodeDefManager *ndef) { lua_getfield(L, index, "name"); - const char *name = lua_tostring(L, -1); + const char *name = luaL_checkstring(L, -1); lua_pop(L, 1); u8 param1; lua_getfield(L, index, "param1"); @@ -233,32 +324,6 @@ static core::aabbox3d read_aabbox3df32(lua_State *L, int index, f32 scale) return box; } -static v2s16 read_v2s16(lua_State *L, int index) -{ - v2s16 p; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "x"); - p.X = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "y"); - p.Y = lua_tonumber(L, -1); - lua_pop(L, 1); - return p; -} - -static v2f read_v2f(lua_State *L, int index) -{ - v2f p; - luaL_checktype(L, index, LUA_TTABLE); - lua_getfield(L, index, "x"); - p.X = lua_tonumber(L, -1); - lua_pop(L, 1); - lua_getfield(L, index, "y"); - p.Y = lua_tonumber(L, -1); - lua_pop(L, 1); - return p; -} - static bool getstringfield(lua_State *L, int table, const char *fieldname, std::string &result) { @@ -386,6 +451,175 @@ static int getenumfield(lua_State *L, int table, return result; } +static void setfloatfield(lua_State *L, int table, + const char *fieldname, float value) +{ + lua_pushnumber(L, value); + if(table < 0) + table -= 1; + lua_setfield(L, table, fieldname); +} + +static void warn_if_field_exists(lua_State *L, int table, + const char *fieldname, const std::string &message) +{ + lua_getfield(L, table, fieldname); + if(!lua_isnil(L, -1)){ + infostream<deleteList(name); + return; + } + // Otherwise set list + std::list items; + luaL_checktype(L, tableindex, LUA_TTABLE); + int table = tableindex; + lua_pushnil(L); + while(lua_next(L, table) != 0){ + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + std::string itemstring = luaL_checkstring(L, -1); + items.push_back(itemstring); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + int listsize = (forcesize != -1) ? forcesize : items.size(); + InventoryList *invlist = inv->addList(name, listsize); + int index = 0; + for(std::list::const_iterator + i = items.begin(); i != items.end(); i++){ + if(forcesize != -1 && index == forcesize) + break; + const std::string &itemstring = *i; + InventoryItem *newitem = NULL; + if(itemstring != "") + newitem = InventoryItem::deSerialize(itemstring, + gamedef); + InventoryItem *olditem = invlist->changeItem(index, newitem); + delete olditem; + index++; + } + while(forcesize != -1 && index < forcesize){ + InventoryItem *olditem = invlist->changeItem(index, NULL); + delete olditem; + index++; + } +} + +static void inventory_get_list_to_lua(Inventory *inv, const char *name, + lua_State *L) +{ + InventoryList *invlist = inv->getList(name); + if(invlist == NULL){ + lua_pushnil(L); + return; + } + // Get the table insert function + lua_getglobal(L, "table"); + lua_getfield(L, -1, "insert"); + int table_insert = lua_gettop(L); + // Create and fill table + lua_newtable(L); + int table = lua_gettop(L); + for(u32 i=0; igetSize(); i++){ + InventoryItem *item = invlist->getItem(i); + lua_pushvalue(L, table_insert); + lua_pushvalue(L, table); + if(item == NULL){ + lua_pushstring(L, ""); + } else { + lua_pushstring(L, item->getItemString().c_str()); + } + if(lua_pcall(L, 2, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + } +} + +/* + ToolDiggingProperties +*/ + +static ToolDiggingProperties read_tool_digging_properties( + lua_State *L, int table) +{ + ToolDiggingProperties prop; + getfloatfield(L, table, "full_punch_interval", prop.full_punch_interval); + getfloatfield(L, table, "basetime", prop.basetime); + getfloatfield(L, table, "dt_weight", prop.dt_weight); + getfloatfield(L, table, "dt_crackiness", prop.dt_crackiness); + getfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness); + getfloatfield(L, table, "dt_cuttability", prop.dt_cuttability); + getfloatfield(L, table, "basedurability", prop.basedurability); + getfloatfield(L, table, "dd_weight", prop.dd_weight); + getfloatfield(L, table, "dd_crackiness", prop.dd_crackiness); + getfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness); + getfloatfield(L, table, "dd_cuttability", prop.dd_cuttability); + return prop; +} + +static void set_tool_digging_properties(lua_State *L, int table, + const ToolDiggingProperties &prop) +{ + setfloatfield(L, table, "full_punch_interval", prop.full_punch_interval); + setfloatfield(L, table, "basetime", prop.basetime); + setfloatfield(L, table, "dt_weight", prop.dt_weight); + setfloatfield(L, table, "dt_crackiness", prop.dt_crackiness); + setfloatfield(L, table, "dt_crumbliness", prop.dt_crumbliness); + setfloatfield(L, table, "dt_cuttability", prop.dt_cuttability); + setfloatfield(L, table, "basedurability", prop.basedurability); + setfloatfield(L, table, "dd_weight", prop.dd_weight); + setfloatfield(L, table, "dd_crackiness", prop.dd_crackiness); + setfloatfield(L, table, "dd_crumbliness", prop.dd_crumbliness); + setfloatfield(L, table, "dd_cuttability", prop.dd_cuttability); +} + +static void push_tool_digging_properties(lua_State *L, + const ToolDiggingProperties &prop) +{ + lua_newtable(L); + set_tool_digging_properties(L, -1, prop); +} + +/* + ToolDefinition +*/ + +static ToolDefinition read_tool_definition(lua_State *L, int table) +{ + ToolDefinition def; + getstringfield(L, table, "image", def.imagename); + def.properties = read_tool_digging_properties(L, table); + return def; +} + +static void push_tool_definition(lua_State *L, const ToolDefinition &def) +{ + lua_newtable(L); + lua_pushstring(L, def.imagename.c_str()); + lua_setfield(L, -2, "image"); + set_tool_digging_properties(L, -1, def.properties); +} + +/* + EnumString definitions +*/ + struct EnumString es_DrawType[] = { {NDT_NORMAL, "normal"}, @@ -454,8 +688,9 @@ static int l_register_nodedef_defaults(lua_State *L) // register_entity(name, prototype) static int l_register_entity(lua_State *L) { - const char *name = luaL_checkstring(L, 1); - infostream<<"register_entity: "< stack top // registered_entities[name] = object - lua_setfield(L, registered_entities, name); + lua_setfield(L, registered_entities, name.c_str()); // Get registered object to top of stack lua_pushvalue(L, 2); @@ -491,15 +726,18 @@ class LuaABM : public ActiveBlockModifier 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) { @@ -508,6 +746,10 @@ class LuaABM : public ActiveBlockModifier { return m_trigger_contents; } + virtual std::set getRequiredNeighbors() + { + return m_required_neighbors; + } virtual float getTriggerInterval() { return m_trigger_interval; @@ -546,14 +788,14 @@ class LuaABM : public ActiveBlockModifier 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\n", lua_tostring(L, -1)); + 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; - - getstringfield(L, table, "image", def.imagename); - getfloatfield(L, table, "basetime", def.properties.basetime); - getfloatfield(L, table, "dt_weight", def.properties.dt_weight); - getfloatfield(L, table, "dt_crackiness", def.properties.dt_crackiness); - getfloatfield(L, table, "dt_crumbliness", def.properties.dt_crumbliness); - getfloatfield(L, table, "dt_cuttability", def.properties.dt_cuttability); - getfloatfield(L, table, "basedurability", def.properties.basedurability); - getfloatfield(L, table, "dd_weight", def.properties.dd_weight); - getfloatfield(L, table, "dd_crackiness", def.properties.dd_crackiness); - getfloatfield(L, table, "dd_crumbliness", def.properties.dd_crumbliness); - getfloatfield(L, table, "dd_cuttability", def.properties.dd_cuttability); + ToolDefinition def = read_tool_definition(L, table); tooldef->registerTool(name, def); return 0; /* number of results */ @@ -620,8 +851,9 @@ static int l_register_tool(lua_State *L) // register_craftitem(name, {lots of stuff}) static int l_register_craftitem(lua_State *L) { - const char *name = luaL_checkstring(L, 1); - infostream<<"register_craftitem: "<registerCraftItem(name, def); lua_pushvalue(L, table); - scriptapi_add_craftitem(L, name); + scriptapi_add_craftitem(L, name.c_str()); return 0; /* number of results */ } @@ -669,8 +901,9 @@ static int l_register_craftitem(lua_State *L) // register_node(name, {lots of stuff}) static int l_register_node(lua_State *L) { - const char *name = luaL_checkstring(L, 1); - infostream<<"register_node: "<getWritableNodeDefManager(); + + nodedef->setAlias(name, convert_to); + + return 0; /* number of results */ +} + +// 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 server from registry + lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); + Server *server = (Server*)lua_touserdata(L, -1); + // And get the writable tool definition manager from the server + IWritableToolDefManager *tooldef = + server->getWritableToolDefManager(); + + tooldef->setAlias(name, convert_to); + + return 0; /* number of results */ +} + +// 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); + + // Get server from registry + lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server"); + Server *server = (Server*)lua_touserdata(L, -1); + // And get the writable CraftItem definition manager from the server + IWritableCraftItemDefManager *craftitemdef = + server->getWritableCraftItemDefManager(); + + craftitemdef->setAlias(name, convert_to); + + return 0; /* number of results */ +} + // register_craft({output=item, recipe={{item00,item10},{item01,item11}}) static int l_register_craft(lua_State *L) { - infostream<<"register_craft"<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; +} + +// 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; +} + static const struct luaL_Reg minetest_f [] = { {"register_nodedef_defaults", l_register_nodedef_defaults}, {"register_entity", l_register_entity}, @@ -1031,10 +1364,15 @@ static const struct luaL_Reg minetest_f [] = { {"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} }; @@ -1173,7 +1511,7 @@ class NodeMetaRef NodeMetadata *meta = getmeta(ref); if(meta == NULL) return 0; // Do it - std::string text = lua_tostring(L, 2); + std::string text = luaL_checkstring(L, 2); meta->setText(text); reportMetadataChange(ref); return 0; @@ -1213,7 +1551,7 @@ class NodeMetaRef NodeMetadata *meta = getmeta(ref); if(meta == NULL) return 0; // Do it - std::string text = lua_tostring(L, 2); + std::string text = luaL_checkstring(L, 2); meta->setInfoText(text); reportMetadataChange(ref); return 0; @@ -1227,41 +1565,9 @@ class NodeMetaRef if(meta == NULL) return 0; // Do it Inventory *inv = meta->getInventory(); - std::string name = lua_tostring(L, 2); - // If nil, delete list - if(lua_isnil(L, 3)){ - inv->deleteList(name); - return 0; - } - // Otherwise set list - std::list items; - luaL_checktype(L, 3, LUA_TTABLE); - int table = 3; - lua_pushnil(L); - infostream<<"items: "; - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - std::string itemstring = lua_tostring(L, -1); - infostream<<"\""<addList(name, items.size()); - int index = 0; - for(std::list::const_iterator - i = items.begin(); i != items.end(); i++){ - const std::string &itemstring = *i; - InventoryItem *newitem = NULL; - if(itemstring != "") - newitem = InventoryItem::deSerialize(itemstring, - ref->m_env->getGameDef()); - InventoryItem *olditem = invlist->changeItem(index, newitem); - delete olditem; - index++; - } + const char *name = luaL_checkstring(L, 2); + inventory_set_list_from_lua(inv, name, L, 3, + ref->m_env->getGameDef()); reportMetadataChange(ref); return 0; } @@ -1274,31 +1580,8 @@ class NodeMetaRef if(meta == NULL) return 0; // Do it Inventory *inv = meta->getInventory(); - std::string name = lua_tostring(L, 2); - InventoryList *invlist = inv->getList(name); - if(invlist == NULL){ - lua_pushnil(L); - return 1; - } - // Get the table insert function - lua_getglobal(L, "table"); - lua_getfield(L, -1, "insert"); - int table_insert = lua_gettop(L); - // Create and fill table - lua_newtable(L); - int table = lua_gettop(L); - for(u32 i=0; igetSize(); i++){ - InventoryItem *item = invlist->getItem(i); - lua_pushvalue(L, table_insert); - lua_pushvalue(L, table); - if(item == NULL){ - lua_pushnil(L); - } else { - lua_pushstring(L, item->getItemString().c_str()); - } - if(lua_pcall(L, 2, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); - } + const char *name = luaL_checkstring(L, 2); + inventory_get_list_to_lua(inv, name, L); return 1; } @@ -1309,7 +1592,7 @@ class NodeMetaRef NodeMetadata *meta = getmeta(ref); if(meta == NULL) return 0; // Do it - std::string text = lua_tostring(L, 2); + std::string text = luaL_checkstring(L, 2); meta->setInventoryDrawSpec(text); reportMetadataChange(ref); return 0; @@ -1407,7 +1690,7 @@ class NodeMetaRef NodeMetadata *meta = getmeta(ref); if(meta == NULL) return 0; // Do it - std::string name = lua_tostring(L, 2); + std::string name = luaL_checkstring(L, 2); size_t len = 0; const char *s = lua_tolstring(L, 3, &len); std::string str(s, len); @@ -1423,7 +1706,7 @@ class NodeMetaRef NodeMetadata *meta = getmeta(ref); if(meta == NULL) return 0; // Do it - std::string name = lua_tostring(L, 2); + std::string name = luaL_checkstring(L, 2); std::string str = meta->getString(name); lua_pushlstring(L, str.c_str(), str.size()); return 1; @@ -1503,243 +1786,13 @@ const luaL_reg NodeMetaRef::methods[] = { }; /* - EnvRef + ObjectRef */ -class EnvRef +class ObjectRef { private: - ServerEnvironment *m_env; - - static const char className[]; - static const luaL_reg methods[]; - - 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 - } - - // Exported functions - - // 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; - } - - // 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; - } - - // 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; - } - - // EnvRef:add_luaentity(pos, entityname) - // pos = {x=num, y=num, z=num} - static int l_add_luaentity(lua_State *L) - { - //infostream<<"EnvRef::l_add_luaentity()"<m_env; - if(env == NULL) return 0; - // pos - v3f pos = readFloatPos(L, 2); - // content - const char *name = lua_tostring(L, 3); - // Do it - ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, ""); - env->addActiveObject(obj); - return 0; - } - - // 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 = lua_tostring(L, 3); - // Do it - ServerActiveObject *obj = new ItemSAO(env, pos, inventorystring); - env->addActiveObject(obj); - return 0; - } - - // 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; - } - - // 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; - } - - // 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; - } - - static int gc_object(lua_State *L) { - EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1)); - delete o; - return 0; - } - -public: - EnvRef(ServerEnvironment *env): - m_env(env) - { - infostream<<"EnvRef created"<punch(co2); + return 0; + } + + // right_click(self, clicker); clicker = an another ObjectRef + static int l_right_click(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->rightClick(co2); + return 0; + } + + // get_wield_digging_properties(self) + static int l_get_wield_digging_properties(lua_State *L) + { + 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; + } + + // damage_wielded_item(self, amount) + static int l_damage_wielded_item(lua_State *L) + { + 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; + } + + // add_to_inventory(self, itemstring) + // returns: true if item was added, (false, "reason") otherwise + static int l_add_to_inventory(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + luaL_checkstring(L, 2); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // itemstring + const char *itemstring = luaL_checkstring(L, 2); + infostream<<"ObjectRef::l_add_to_inventory(): id="<getId() + <<" itemstring=\""<getEnv(); + assert(env); + IGameDef *gamedef = env->getGameDef(); + try{ + InventoryItem *item = InventoryItem::deSerialize(is, gamedef); + if(item->getCount() == 0) + item->setCount(1); + bool added = co->addToInventory(item); + // Return + lua_pushboolean(L, added); + if(!added) + lua_pushstring(L, "failed to add item"); + return 2; + } catch(SerializationError &e){ + // Return + lua_pushboolean(L, false); + lua_pushstring(L, (std::string("Invalid item: ") + + e.what()).c_str()); + return 2; + } + } + + // add_to_inventory_later(self, itemstring) + // returns: nil + static int l_add_to_inventory_later(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + luaL_checkstring(L, 2); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + // itemstring + const char *itemstring = luaL_checkstring(L, 2); + infostream<<"ObjectRef::l_add_to_inventory_later(): id="<getId() + <<" itemstring=\""<getEnv(); + assert(env); + IGameDef *gamedef = env->getGameDef(); + InventoryItem *item = InventoryItem::deSerialize(is, gamedef); + infostream<<"item="<addToInventoryLater(item); + // Return + return 0; + } + + // set_hp(self, hp) + // hp = number of hitpoints (2 * number of hearts) + // returns: nil + static int l_set_hp(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + luaL_checknumber(L, 2); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + int hp = lua_tonumber(L, 2); + infostream<<"ObjectRef::l_set_hp(): id="<getId() + <<" hp="<setHP(hp); + // Return + return 0; + } + + // get_hp(self) + // returns: number of hitpoints (2 * number of hearts) + // 0 if not applicable to this type of object + static int l_get_hp(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + if(co == NULL) return 0; + int hp = co->getHP(); + infostream<<"ObjectRef::l_get_hp(): id="<getId() + <<" hp="<setVelocity(pos); + return 0; + } + + // setacceleration(self, {x=num, y=num, z=num}) + static int l_setacceleration(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->setAcceleration(pos); + return 0; + } + + // getacceleration(self) + static int l_getacceleration(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + v3f v = co->getAcceleration(); + pushFloatPos(L, v); + return 1; + } + + // settexturemod(self, mod) + static int l_settexturemod(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + std::string mod = luaL_checkstring(L, 2); + co->setTextureMod(mod); + return 0; + } + + // 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) + { + ObjectRef *ref = checkobject(L, 1); + LuaEntitySAO *co = getluaobject(ref); + if(co == NULL) return 0; + // Do it + 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; + } + + /* Player-only */ + + // get_player_name(self) + static int l_get_player_name(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL){ + lua_pushnil(L); + return 1; + } + // Do it + lua_pushstring(L, player->getName()); + return 1; + } + + // inventory_set_list(self, name, {item1, item2, ...}) + static int l_inventory_set_list(lua_State *L) + { + 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) + { + 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; + } + + // get_wielded_itemstring(self) + static int l_get_wielded_itemstring(lua_State *L) + { + 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; + } + + // get_wielded_item(self) + static int l_get_wielded_item(lua_State *L) + { + ObjectRef *ref = checkobject(L, 1); + ServerRemotePlayer *player = getplayer(ref); + if(player == NULL) return 0; + // Do it + InventoryItem *item0 = player->getWieldedItem(); + if(item0 == NULL){ + lua_pushnil(L); + return 1; + } + if(std::string("MaterialItem") == item0->getName()){ + MaterialItem *item = (MaterialItem*)item0; + lua_newtable(L); + lua_pushstring(L, "NodeItem"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, item->getNodeName().c_str()); + lua_setfield(L, -2, "name"); + } + else if(std::string("CraftItem") == item0->getName()){ + CraftItem *item = (CraftItem*)item0; + lua_newtable(L); + lua_pushstring(L, "CraftItem"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, item->getSubName().c_str()); + lua_setfield(L, -2, "name"); + } + else if(std::string("ToolItem") == item0->getName()){ + ToolItem *item = (ToolItem*)item0; + lua_newtable(L); + lua_pushstring(L, "ToolItem"); + lua_setfield(L, -2, "type"); + lua_pushstring(L, item->getToolName().c_str()); + lua_setfield(L, -2, "name"); + lua_pushstring(L, itos(item->getWear()).c_str()); + lua_setfield(L, -2, "wear"); + } + else{ + errorstream<<"l_get_wielded_item: Unknown item name: \"" + <getName()<<"\""<getRadPitch(); + float yaw = player->getRadYaw(); + v3f v(cos(pitch)*cos(yaw), sin(pitch), cos(pitch)*sin(yaw)); + push_v3f(L, v); + return 1; + } + + // 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; + } + + // 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; + } + +public: + ObjectRef(ServerActiveObject *object): + m_object(object) + { + //infostream<<"ObjectRef created for id="<getId()<getId() == 0){ + ObjectRef::create(L, cobj); + } else { + objectref_get(L, cobj->getId()); + } +} + +/* + EnvRef +*/ + +class EnvRef +{ +private: + ServerEnvironment *m_env; + + static const char className[]; + static const luaL_reg methods[]; + + 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 + } + + // Exported functions + + // 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; + } + + // 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; + } + + // 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; + } + + // 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; + } + } + + // 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; + } + } + + // EnvRef:add_entity(pos, entityname) + // pos = {x=num, y=num, z=num} + static int l_add_entity(lua_State *L) + { + //infostream<<"EnvRef::l_add_entity()"<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; + } + + // 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; + } + + // 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 - co->setVelocity(pos); + ServerActiveObject *obj = new RatSAO(env, pos); + env->addActiveObject(obj); return 0; } - - // setacceleration(self, acceleration) - static int l_setacceleration(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); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; + infostream<<"EnvRef::l_add_firefly()"<m_env; + if(env == NULL) return 0; // pos v3f pos = readFloatPos(L, 2); // Do it - co->setAcceleration(pos); + ServerActiveObject *obj = new FireflySAO(env, pos); + env->addActiveObject(obj); return 0; } - - // getacceleration(self) - static int l_getacceleration(lua_State *L) + + // EnvRef:get_meta(pos) + static int l_get_meta(lua_State *L) { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; + //infostream<<"EnvRef::l_get_meta()"<m_env; + if(env == NULL) return 0; // Do it - v3f v = co->getAcceleration(); - pushFloatPos(L, v); + v3s16 p = readpos(L, 2); + NodeMetaRef::create(L, p, env); return 1; } - - // add_to_inventory(self, itemstring) - // returns: true if item was added, false otherwise - static int l_add_to_inventory(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_checkstring(L, 2); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; - // itemstring - const char *itemstring = lua_tostring(L, 2); - infostream<<"ObjectRef::l_add_to_inventory(): 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="<addToInventory(item); - // Return - lua_pushboolean(L, fits); + 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; } - // add_to_inventory_later(self, itemstring) - // returns: nil - static int l_add_to_inventory_later(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); - luaL_checkstring(L, 2); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; - // itemstring - const char *itemstring = lua_tostring(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; - } - - // get_hp(self) - // returns: number of hitpoints (2 * number of hearts) - // 0 if not applicable to this type of object - static int l_get_hp(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; - int hp = co->getHP(); - infostream<<"ObjectRef::l_get_hp(): id="<getId() - <<" hp="< 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; } - // set_hp(self, hp) - // hp = number of hitpoints (2 * number of hearts) - // returns: nil - static int l_set_hp(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - luaL_checknumber(L, 2); - ServerActiveObject *co = getobject(ref); - if(co == NULL) return 0; - int hp = lua_tonumber(L, 2); - infostream<<"ObjectRef::l_set_hp(): id="<getId() - <<" hp="<setHP(hp); - // Return + static int gc_object(lua_State *L) { + EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1)); + delete o; return 0; } - // settexturemod(self, mod) - static int l_settexturemod(lua_State *L) - { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; - // Do it - std::string mod = lua_tostring(L, 2); - co->setTextureMod(mod); - return 0; - } - - // 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) - { - ObjectRef *ref = checkobject(L, 1); - LuaEntitySAO *co = getluaobject(ref); - if(co == NULL) return 0; - // Do it - 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; - } - public: - ObjectRef(ServerActiveObject *object): - m_object(object) + EnvRef(ServerEnvironment *env): + m_env(env) { - //infostream<<"ObjectRef created for id="<getId()<getId() == 0){ - ObjectRef::create(L, cobj); - } else { - objectref_get(L, cobj->getId()); - } -} - /* Main export function */ @@ -2151,6 +2760,32 @@ void scriptapi_export(lua_State *L, Server *server) ObjectRef::Register(L); } +bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath, + const std::string &modname) +{ + ModNameStorer modnamestorer(L, modname); + + if(!string_allowed(modname, "abcdefghijklmnopqrstuvwxyz" + "0123456789_")){ + errorstream<<"Error loading mod \""< required_neighbors; + lua_getfield(L, current_abm, "neighbors"); + if(lua_istable(L, -1)){ + int table = lua_gettop(L); + lua_pushnil(L); + while(lua_next(L, table) != 0){ + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + required_neighbors.insert(lua_tostring(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } else if(lua_isstring(L, -1)){ + required_neighbors.insert(lua_tostring(L, -1)); } lua_pop(L, 1); @@ -2210,7 +2866,7 @@ void scriptapi_add_environment(lua_State *L, ServerEnvironment *env) getintfield(L, current_abm, "chance", trigger_chance); LuaABM *abm = new LuaABM(L, id, trigger_contents, - trigger_interval, trigger_chance); + required_neighbors, trigger_interval, trigger_chance); env->addActiveBlockModifier(abm); @@ -2231,7 +2887,7 @@ static void dump2(lua_State *L, const char *name) lua_pushvalue(L, -2); // Get previous stack top as first parameter lua_pushstring(L, name); if(lua_pcall(L, 2, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); } #endif @@ -2309,7 +2965,7 @@ bool scriptapi_on_chat_message(lua_State *L, const std::string &name, lua_pushstring(L, name.c_str()); lua_pushstring(L, message.c_str()); if(lua_pcall(L, 2, 1, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); bool ate = lua_toboolean(L, -1); lua_pop(L, 1); if(ate) @@ -2342,7 +2998,7 @@ void scriptapi_on_newplayer(lua_State *L, ServerActiveObject *player) // Call function objectref_get_or_create(L, player); if(lua_pcall(L, 1, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } } @@ -2367,7 +3023,7 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player) // Call function objectref_get_or_create(L, player); if(lua_pcall(L, 1, 1, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); bool positioning_handled = lua_toboolean(L, -1); lua_pop(L, 1); if(positioning_handled) @@ -2377,6 +3033,15 @@ bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player) return positioning_handled_by_some; } +void scriptapi_get_creative_inventory(lua_State *L, ServerRemotePlayer *player) +{ + lua_getglobal(L, "minetest"); + lua_getfield(L, -1, "creative_inventory"); + luaL_checktype(L, -1, LUA_TTABLE); + inventory_set_list_from_lua(&player->inventory, "main", L, -1, + player->getEnv()->getGameDef(), PLAYER_INVENTORY_SIZE); +} + /* craftitem */ @@ -2480,7 +3145,7 @@ bool scriptapi_craftitem_on_drop(lua_State *L, const char *name, objectref_get_or_create(L, dropper); pushFloatPos(L, pos); if(lua_pcall(L, 3, 1, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); result = lua_toboolean(L, -1); } return result; @@ -2504,7 +3169,7 @@ bool scriptapi_craftitem_on_place_on_ground(lua_State *L, const char *name, objectref_get_or_create(L, placer); pushFloatPos(L, pos); if(lua_pcall(L, 3, 1, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); result = lua_toboolean(L, -1); } return result; @@ -2528,7 +3193,7 @@ bool scriptapi_craftitem_on_use(lua_State *L, const char *name, objectref_get_or_create(L, user); pushPointedThing(L, pointed); if(lua_pcall(L, 3, 1, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); result = lua_toboolean(L, -1); } return result; @@ -2558,7 +3223,7 @@ void scriptapi_environment_step(lua_State *L, float dtime) // Call function lua_pushnumber(L, dtime); if(lua_pcall(L, 1, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } } @@ -2593,7 +3258,7 @@ void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode, pushnode(L, newnode, ndef); objectref_get_or_create(L, placer); if(lua_pcall(L, 3, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } } @@ -2628,7 +3293,7 @@ void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode, pushnode(L, oldnode, ndef); objectref_get_or_create(L, digger); if(lua_pcall(L, 3, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } } @@ -2663,7 +3328,7 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node, pushnode(L, node, ndef); objectref_get_or_create(L, puncher); if(lua_pcall(L, 3, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } } @@ -2689,7 +3354,7 @@ void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp) pushpos(L, minp); pushpos(L, maxp); if(lua_pcall(L, 2, 0, 0)) - script_error(L, "error: %s\n", lua_tostring(L, -1)); + script_error(L, "error: %s", lua_tostring(L, -1)); // value removed, keep key for next iteration } } @@ -2892,9 +3557,9 @@ void scriptapi_luaentity_step(lua_State *L, u16 id, float dtime) script_error(L, "error running function 'on_step': %s\n", lua_tostring(L, -1)); } -// Calls entity:on_punch(ObjectRef puncher) +// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch) void scriptapi_luaentity_punch(lua_State *L, u16 id, - ServerActiveObject *puncher) + ServerActiveObject *puncher, float time_from_last_punch) { realitycheck(L); assert(lua_checkstack(L, 20)); @@ -2912,8 +3577,9 @@ void scriptapi_luaentity_punch(lua_State *L, u16 id, luaL_checktype(L, -1, LUA_TFUNCTION); lua_pushvalue(L, object); // self objectref_get_or_create(L, puncher); // Clicker reference + lua_pushnumber(L, time_from_last_punch); // Call with 2 arguments, 0 results - if(lua_pcall(L, 2, 0, 0)) + if(lua_pcall(L, 3, 0, 0)) script_error(L, "error running function 'on_punch': %s\n", lua_tostring(L, -1)); }