diff options
Diffstat (limited to 'src/script')
33 files changed, 427 insertions, 115 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 793485e25..cb0253c32 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_types.h" #include "nodedef.h" #include "object_properties.h" +#include "content_sao.h" #include "cpp_api/s_node.h" #include "lua_api/l_object.h" #include "lua_api/l_item.h" @@ -163,11 +164,7 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i) lua_pushboolean(L, i.liquids_pointable); lua_setfield(L, -2, "liquids_pointable"); if (i.type == ITEM_TOOL) { - push_tool_capabilities(L, ToolCapabilities( - i.tool_capabilities->full_punch_interval, - i.tool_capabilities->max_drop_level, - i.tool_capabilities->groupcaps, - i.tool_capabilities->damageGroups)); + push_tool_capabilities(L, *i.tool_capabilities); lua_setfield(L, -2, "tool_capabilities"); } push_groups(L, i.groups); @@ -182,7 +179,7 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i) /******************************************************************************/ void read_object_properties(lua_State *L, int index, - ObjectProperties *prop, IItemDefManager *idef) + ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef) { if(index < 0) index = lua_gettop(L) + 1 + index; @@ -190,10 +187,24 @@ void read_object_properties(lua_State *L, int index, return; int hp_max = 0; - if (getintfield(L, -1, "hp_max", hp_max)) + if (getintfield(L, -1, "hp_max", hp_max)) { prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX); - getintfield(L, -1, "breath_max", prop->breath_max); + if (prop->hp_max < sao->getHP()) { + PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP); + sao->setHP(prop->hp_max, reason); + if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) + sao->getEnv()->getGameDef()->SendPlayerHPOrDie((PlayerSAO *)sao, reason); + } + } + + if (getintfield(L, -1, "breath_max", prop->breath_max)) { + if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) { + PlayerSAO *player = (PlayerSAO *)sao; + if (prop->breath_max < player->getBreath()) + player->setBreath(prop->breath_max); + } + } getboolfield(L, -1, "physical", prop->physical); getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects); @@ -1093,7 +1104,7 @@ MapNode readnode(lua_State *L, int index, const NodeDefManager *ndef) lua_getfield(L, index, "name"); if (!lua_isstring(L, -1)) throw LuaError("Node name is not set or is not a string!"); - const char *name = lua_tostring(L, -1); + std::string name = lua_tostring(L, -1); lua_pop(L, 1); u8 param1 = 0; @@ -1108,7 +1119,11 @@ MapNode readnode(lua_State *L, int index, const NodeDefManager *ndef) param2 = lua_tonumber(L, -1); lua_pop(L, 1); - return {ndef, name, param1, param2}; + content_t id = CONTENT_IGNORE; + if (!ndef->getId(name, id)) + throw LuaError("\"" + name + "\" is not a registered node!"); + + return {id, param1, param2}; } /******************************************************************************/ @@ -1234,7 +1249,8 @@ void push_tool_capabilities(lua_State *L, { lua_newtable(L); setfloatfield(L, -1, "full_punch_interval", toolcap.full_punch_interval); - setintfield(L, -1, "max_drop_level", toolcap.max_drop_level); + setintfield(L, -1, "max_drop_level", toolcap.max_drop_level); + setintfield(L, -1, "punch_attack_uses", toolcap.punch_attack_uses); // Create groupcaps table lua_newtable(L); // For each groupcap @@ -1356,6 +1372,7 @@ ToolCapabilities read_tool_capabilities( ToolCapabilities toolcap; getfloatfield(L, table, "full_punch_interval", toolcap.full_punch_interval); getintfield(L, table, "max_drop_level", toolcap.max_drop_level); + getintfield(L, table, "punch_attack_uses", toolcap.punch_attack_uses); lua_getfield(L, table, "groupcaps"); if(lua_istable(L, -1)){ int table_groupcaps = lua_gettop(L); @@ -1510,13 +1527,15 @@ void read_groups(lua_State *L, int index, ItemGroupList &result) return; result.clear(); lua_pushnil(L); - if(index < 0) + if (index < 0) index -= 1; - while(lua_next(L, index) != 0){ + while (lua_next(L, index) != 0) { // key at index -2 and value at index -1 std::string name = luaL_checkstring(L, -2); int rating = luaL_checkinteger(L, -1); - result[name] = rating; + // zero rating indicates not in the group + if (rating != 0) + result[name] = rating; // removes value, keeps key for next iteration lua_pop(L, 1); } diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index f3a653682..9e755682f 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -62,6 +62,7 @@ struct HitParams; struct EnumString; struct NoiseParams; class Schematic; +class ServerActiveObject; ContentFeatures read_content_features (lua_State *L, int index); @@ -107,6 +108,7 @@ void push_item_definition_full (lua_State *L, const ItemDefinition &i); void read_object_properties (lua_State *L, int index, + ServerActiveObject *sao, ObjectProperties *prop, IItemDefManager *idef); void push_object_properties (lua_State *L, diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index dfd3f5cea..b9d6f0494 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -540,9 +540,9 @@ v3s16 getv3s16field_default(lua_State *L, int table, } void setstringfield(lua_State *L, int table, - const char *fieldname, const char *value) + const char *fieldname, const std::string &value) { - lua_pushstring(L, value); + lua_pushlstring(L, value.c_str(), value.length()); if(table < 0) table -= 1; lua_setfield(L, table, fieldname); diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h index 87bc35ac6..f84494c8d 100644 --- a/src/script/common/c_converter.h +++ b/src/script/common/c_converter.h @@ -91,7 +91,7 @@ std::string checkstringfield(lua_State *L, int table, const char *fieldname); void setstringfield(lua_State *L, int table, - const char *fieldname, const char *value); + const char *fieldname, const std::string &value); void setintfield(lua_State *L, int table, const char *fieldname, int value); void setfloatfield(lua_State *L, int table, diff --git a/src/script/common/helper.cpp b/src/script/common/helper.cpp index 59bde57ab..f53a2b7e8 100644 --- a/src/script/common/helper.cpp +++ b/src/script/common/helper.cpp @@ -107,9 +107,10 @@ template <> v2f LuaHelper::readParam(lua_State *L, int index) template <> std::string LuaHelper::readParam(lua_State *L, int index) { + size_t length; std::string result; - const char *str = luaL_checkstring(L, index); - result.append(str); + const char *str = luaL_checklstring(L, index, &length); + result.assign(str, length); return result; } diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index a8ed902dd..caa335d76 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -232,6 +232,13 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name) void ScriptApiBase::runCallbacksRaw(int nargs, RunCallbacksMode mode, const char *fxn) { +#ifndef SERVER + // Hard fail for bad guarded callbacks + // Only run callbacks when the scripting enviroment is loaded + FATAL_ERROR_IF(m_type == ScriptingType::Client && + !getClient()->modsLoaded(), fxn); +#endif + #ifdef SCRIPTAPI_LOCK_DEBUG assert(m_lock_recursion_count > 0); #endif @@ -404,6 +411,10 @@ void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeR objectrefGetOrCreate(L, reason.object); lua_setfield(L, -2, "object"); } + if (!reason.node.empty()) { + lua_pushstring(L, reason.node.c_str()); + lua_setfield(L, -2, "node"); + } } Server* ScriptApiBase::getServer() diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp index 8af9f9bf6..26c7e8cd4 100644 --- a/src/script/cpp_api/s_entity.cpp +++ b/src/script/cpp_api/s_entity.cpp @@ -157,7 +157,7 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id) } void ScriptApiEntity::luaentity_GetProperties(u16 id, - ObjectProperties *prop) + ServerActiveObject *self, ObjectProperties *prop) { SCRIPTAPI_PRECHECKHEADER @@ -170,11 +170,11 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id, prop->hp_max = 10; // Deprecated: read object properties directly - read_object_properties(L, -1, prop, getServer()->idef()); + read_object_properties(L, -1, self, prop, getServer()->idef()); // Read initial_properties lua_getfield(L, -1, "initial_properties"); - read_object_properties(L, -1, prop, getServer()->idef()); + read_object_properties(L, -1, self, prop, getServer()->idef()); lua_pop(L, 1); } diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h index 966c2745e..cc08c46e8 100644 --- a/src/script/cpp_api/s_entity.h +++ b/src/script/cpp_api/s_entity.h @@ -35,7 +35,7 @@ public: void luaentity_Remove(u16 id); std::string luaentity_GetStaticdata(u16 id); void luaentity_GetProperties(u16 id, - ObjectProperties *prop); + ServerActiveObject *self, ObjectProperties *prop); void luaentity_Step(u16 id, float dtime); bool luaentity_Punch(u16 id, ServerActiveObject *puncher, float time_from_last_punch, diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index f8cef98b7..ab3b5fe46 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -151,6 +151,10 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) bool simple_catch_up = true; getboolfield(L, current_abm, "catch_up", simple_catch_up); + lua_getfield(L, current_abm, "action"); + luaL_checktype(L, current_abm + 1, LUA_TFUNCTION); + lua_pop(L, 1); + LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors, trigger_interval, trigger_chance, simple_catch_up); @@ -200,6 +204,10 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) bool run_at_every_load = getboolfield_default(L, current_lbm, "run_at_every_load", false); + lua_getfield(L, current_lbm, "action"); + luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION); + lua_pop(L, 1); + LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name, run_at_every_load); diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp index 719f53a6b..d93a4c3ad 100644 --- a/src/script/cpp_api/s_node.cpp +++ b/src/script/cpp_api/s_node.cpp @@ -246,7 +246,7 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p, const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(p); + MapNode node = getEnv()->getMap().getNode(p); if (node.getContent() == CONTENT_IGNORE) return; diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp index b49bb8170..c081e9fc4 100644 --- a/src/script/cpp_api/s_nodemeta.cpp +++ b/src/script/cpp_api/s_nodemeta.cpp @@ -38,7 +38,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove( const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(ma.to_inv.p); + MapNode node = getEnv()->getMap().getNode(ma.to_inv.p); if (node.getContent() == CONTENT_IGNORE) return 0; @@ -76,7 +76,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut( const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(ma.to_inv.p); + MapNode node = getEnv()->getMap().getNode(ma.to_inv.p); if (node.getContent() == CONTENT_IGNORE) return 0; @@ -112,7 +112,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake( const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(ma.from_inv.p); + MapNode node = getEnv()->getMap().getNode(ma.from_inv.p); if (node.getContent() == CONTENT_IGNORE) return 0; @@ -148,7 +148,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove( const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(ma.from_inv.p); + MapNode node = getEnv()->getMap().getNode(ma.from_inv.p); if (node.getContent() == CONTENT_IGNORE) return; @@ -181,7 +181,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut( const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(ma.to_inv.p); + MapNode node = getEnv()->getMap().getNode(ma.to_inv.p); if (node.getContent() == CONTENT_IGNORE) return; @@ -212,7 +212,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake( const NodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call - MapNode node = getEnv()->getMap().getNodeNoEx(ma.from_inv.p); + MapNode node = getEnv()->getMap().getNode(ma.from_inv.p); if (node.getContent() == CONTENT_IGNORE) return; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index e9067a54c..b90b3aa2c 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -113,7 +113,6 @@ void ScriptApiSecurity::initializeSecurity() "setupvalue", "setmetatable", "upvalueid", - "upvaluejoin", "sethook", "debug", "setlocal", @@ -244,6 +243,7 @@ void ScriptApiSecurity::initializeSecurityClient() "rawset", "select", "setfenv", + // getmetatable can be used to escape the sandbox "setmetatable", "tonumber", "tostring", @@ -265,6 +265,7 @@ void ScriptApiSecurity::initializeSecurityClient() }; static const char *debug_whitelist[] = { "getinfo", + "traceback" }; #if USE_LUAJIT diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp index 3b461a2a3..1ce2f9d45 100644 --- a/src/script/cpp_api/s_server.cpp +++ b/src/script/cpp_api/s_server.cpp @@ -168,3 +168,25 @@ void ScriptApiServer::on_shutdown() runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); } +std::string ScriptApiServer::formatChatMessage(const std::string &name, + const std::string &message) +{ + SCRIPTAPI_PRECHECKHEADER + + // Push function onto stack + lua_getglobal(L, "core"); + lua_getfield(L, -1, "format_chat_message"); + + // Push arguments onto stack + lua_pushstring(L, name.c_str()); + lua_pushstring(L, message.c_str()); + + // Actually call the function + lua_call(L, 2, 1); + + // Fetch return value + std::string ret = lua_tostring(L, -1); + lua_pop(L, 1); + + return ret; +} diff --git a/src/script/cpp_api/s_server.h b/src/script/cpp_api/s_server.h index 769939d3f..a4cede84d 100644 --- a/src/script/cpp_api/s_server.h +++ b/src/script/cpp_api/s_server.h @@ -36,14 +36,18 @@ public: // Calls on_shutdown handlers void on_shutdown(); + // Calls core.format_chat_message + std::string formatChatMessage(const std::string &name, + const std::string &message); + /* auth */ bool getAuth(const std::string &playername, - std::string *dst_password, - std::set<std::string> *dst_privs); + std::string *dst_password, + std::set<std::string> *dst_privs); void createAuth(const std::string &playername, - const std::string &password); + const std::string &password); bool setPassword(const std::string &playername, - const std::string &password); + const std::string &password); private: void getAuthHandler(); void readPrivileges(int index, std::set<std::string> &result); diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp index d53d74aa8..908c766b0 100644 --- a/src/script/lua_api/l_areastore.cpp +++ b/src/script/lua_api/l_areastore.cpp @@ -185,6 +185,7 @@ int LuaAreaStore::l_insert_area(lua_State *L) if (lua_isnumber(L, 5)) a.id = lua_tonumber(L, 5); + // Insert & assign a new ID if necessary if (!ast->insertArea(&a)) return 0; diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp index 462006777..80071b3b8 100644 --- a/src/script/lua_api/l_camera.cpp +++ b/src/script/lua_api/l_camera.cpp @@ -31,19 +31,24 @@ LuaCamera::LuaCamera(Camera *m) : m_camera(m) void LuaCamera::create(lua_State *L, Camera *m) { + lua_getglobal(L, "core"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + lua_getfield(L, -1, "camera"); + + // Duplication check + if (lua_type(L, -1) == LUA_TUSERDATA) { + lua_pop(L, 1); + return; + } + LuaCamera *o = new LuaCamera(m); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); - int camera_object = lua_gettop(L); - - lua_getglobal(L, "core"); - luaL_checktype(L, -1, LUA_TTABLE); - int coretable = lua_gettop(L); - - lua_pushvalue(L, camera_object); - lua_setfield(L, coretable, "camera"); + lua_pushvalue(L, lua_gettop(L)); + lua_setfield(L, objectstable, "camera"); } int LuaCamera::l_set_camera_mode(lua_State *L) diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index 6d9d832b7..6345fc75f 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -210,17 +210,13 @@ int ModApiClient::l_get_language(lua_State *L) int ModApiClient::l_get_wielded_item(lua_State *L) { Client *client = getClient(L); + LocalPlayer *player = client->getEnv().getLocalPlayer(); + if (!player) + return 0; - Inventory local_inventory(client->idef()); - client->getLocalInventory(local_inventory); - - InventoryList *mlist = local_inventory.getList("main"); - - if (mlist && client->getPlayerItem() < mlist->getSize()) { - LuaItemStack::create(L, mlist->getItem(client->getPlayerItem())); - } else { - LuaItemStack::create(L, ItemStack()); - } + ItemStack selected_item; + player->getWieldedItem(&selected_item, nullptr); + LuaItemStack::create(L, selected_item); return 1; } diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp index 0899b945e..18622ee00 100644 --- a/src/script/lua_api/l_craft.cpp +++ b/src/script/lua_api/l_craft.cpp @@ -294,7 +294,7 @@ int ModApiCraft::l_clear_craft(lua_State *L) std::string type = getstringfield_default(L, table, "type", "shaped"); CraftOutput c_output(output, 0); if (!output.empty()) { - if (craftdef->clearCraftRecipesByOutput(c_output, getServer(L))) { + if (craftdef->clearCraftsByOutput(c_output, getServer(L))) { lua_pushboolean(L, true); return 1; } @@ -351,7 +351,13 @@ int ModApiCraft::l_clear_craft(lua_State *L) throw LuaError("Unknown crafting definition type: \"" + type + "\""); } - if (!craftdef->clearCraftRecipesByInput(method, width, recipe, getServer(L))) { + std::vector<ItemStack> items; + items.reserve(recipe.size()); + for (const auto &item : recipe) + items.emplace_back(item, 1, 0, getServer(L)->idef()); + CraftInput input(method, width, items); + + if (!craftdef->clearCraftsByInput(input, getServer(L))) { warningstream << "No craft recipe matches input" << std::endl; lua_pushboolean(L, false); return 1; diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 711bd3fdd..a56b1cb0b 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -350,7 +350,7 @@ int ModApiEnvMod::l_get_node(lua_State *L) // pos v3s16 pos = read_v3s16(L, 1); // Do it - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); // Return node pushnode(L, n, env->getGameDef()->ndef()); return 1; @@ -366,7 +366,7 @@ int ModApiEnvMod::l_get_node_or_nil(lua_State *L) v3s16 pos = read_v3s16(L, 1); // Do it bool pos_ok; - MapNode n = env->getMap().getNodeNoEx(pos, &pos_ok); + MapNode n = env->getMap().getNode(pos, &pos_ok); if (pos_ok) { // Return node pushnode(L, n, env->getGameDef()->ndef()); @@ -392,7 +392,7 @@ int ModApiEnvMod::l_get_node_light(lua_State *L) u32 dnr = time_to_daynight_ratio(time_of_day, true); bool is_position_ok; - MapNode n = env->getMap().getNodeNoEx(pos, &is_position_ok); + MapNode n = env->getMap().getNode(pos, &is_position_ok); if (is_position_ok) { const NodeDefManager *ndef = env->getGameDef()->ndef(); lua_pushinteger(L, n.getLightBlend(dnr, ndef)); @@ -417,7 +417,7 @@ int ModApiEnvMod::l_place_node(lua_State *L) MapNode n = readnode(L, 2, ndef); // Don't attempt to load non-loaded area as of now - MapNode n_old = env->getMap().getNodeNoEx(pos); + MapNode n_old = env->getMap().getNode(pos); if(n_old.getContent() == CONTENT_IGNORE){ lua_pushboolean(L, false); return 1; @@ -446,7 +446,7 @@ int ModApiEnvMod::l_dig_node(lua_State *L) v3s16 pos = read_v3s16(L, 1); // Don't attempt to load non-loaded area as of now - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); if(n.getContent() == CONTENT_IGNORE){ lua_pushboolean(L, false); return 1; @@ -469,7 +469,7 @@ int ModApiEnvMod::l_punch_node(lua_State *L) v3s16 pos = read_v3s16(L, 1); // Don't attempt to load non-loaded area as of now - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); if(n.getContent() == CONTENT_IGNORE){ lua_pushboolean(L, false); return 1; @@ -491,7 +491,7 @@ int ModApiEnvMod::l_get_node_max_level(lua_State *L) } v3s16 pos = read_v3s16(L, 1); - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef())); return 1; } @@ -506,7 +506,7 @@ int ModApiEnvMod::l_get_node_level(lua_State *L) } v3s16 pos = read_v3s16(L, 1); - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef())); return 1; } @@ -522,7 +522,7 @@ int ModApiEnvMod::l_set_node_level(lua_State *L) u8 level = 1; if(lua_isnumber(L, 2)) level = lua_tonumber(L, 2); - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); lua_pushnumber(L, n.setLevel(env->getGameDef()->ndef(), level)); env->setNode(pos, n); return 1; @@ -539,7 +539,7 @@ int ModApiEnvMod::l_add_node_level(lua_State *L) u8 level = 1; if(lua_isnumber(L, 2)) level = lua_tonumber(L, 2); - MapNode n = env->getMap().getNodeNoEx(pos); + MapNode n = env->getMap().getNode(pos); lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level)); env->setNode(pos, n); return 1; @@ -780,7 +780,7 @@ int ModApiEnvMod::l_find_node_near(lua_State *L) std::vector<v3s16> list = FacePositionCache::getFacePositions(d); for (const v3s16 &i : list) { v3s16 p = pos + i; - content_t c = env->getMap().getNodeNoEx(p).getContent(); + content_t c = env->getMap().getNode(p).getContent(); if (CONTAINS(filter, c)) { push_v3s16(L, p); return 1; @@ -832,7 +832,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) for (s16 y = minp.Y; y <= maxp.Y; y++) for (s16 z = minp.Z; z <= maxp.Z; z++) { v3s16 p(x, y, z); - content_t c = env->getMap().getNodeNoEx(p).getContent(); + content_t c = env->getMap().getNode(p).getContent(); std::vector<content_t>::iterator it = std::find(filter.begin(), filter.end(), c); if (it != filter.end()) { @@ -898,10 +898,10 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) for (s16 z = minp.Z; z <= maxp.Z; z++) { s16 y = minp.Y; v3s16 p(x, y, z); - content_t c = env->getMap().getNodeNoEx(p).getContent(); + content_t c = env->getMap().getNode(p).getContent(); for (; y <= maxp.Y; y++) { v3s16 psurf(x, y + 1, z); - content_t csurf = env->getMap().getNodeNoEx(psurf).getContent(); + content_t csurf = env->getMap().getNode(psurf).getContent(); if (c != CONTENT_AIR && csurf == CONTENT_AIR && CONTAINS(filter, c)) { push_v3s16(L, v3s16(x, y, z)); @@ -1035,7 +1035,7 @@ int ModApiEnvMod::l_fix_light(lua_State *L) for (auto &modified_block : modified_blocks) event.modified_blocks.insert(modified_block.first); - map.dispatchEvent(&event); + map.dispatchEvent(event); } lua_pushboolean(L, success); @@ -1144,7 +1144,7 @@ int ModApiEnvMod::l_delete_area(lua_State *L) } } - map.dispatchEvent(&event); + map.dispatchEvent(event); lua_pushboolean(L, success); return 1; } diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp index ac261cd60..2ff651cb5 100644 --- a/src/script/lua_api/l_http.cpp +++ b/src/script/lua_api/l_http.cpp @@ -53,9 +53,8 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req) lua_getfield(L, 1, "post_data"); if (lua_istable(L, 2)) { lua_pushnil(L); - while (lua_next(L, 2) != 0) - { - req.post_fields[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1); + while (lua_next(L, 2) != 0) { + req.post_fields[readParam<std::string>(L, -2)] = readParam<std::string>(L, -1); lua_pop(L, 1); } } else if (lua_isstring(L, 2)) { @@ -66,10 +65,8 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req) lua_getfield(L, 1, "extra_headers"); if (lua_istable(L, 2)) { lua_pushnil(L); - while (lua_next(L, 2) != 0) - { - const char *header = luaL_checkstring(L, -1); - req.extra_headers.emplace_back(header); + while (lua_next(L, 2) != 0) { + req.extra_headers.emplace_back(readParam<std::string>(L, -1)); lua_pop(L, 1); } } @@ -83,7 +80,7 @@ void ModApiHttp::push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool setboolfield(L, -1, "timeout", res.timeout); setboolfield(L, -1, "completed", completed); setintfield(L, -1, "code", res.response_code); - setstringfield(L, -1, "data", res.data.c_str()); + setstringfield(L, -1, "data", res.data); } // http_api.fetch_async(HTTPRequest definition) @@ -94,7 +91,7 @@ int ModApiHttp::l_http_fetch_async(lua_State *L) HTTPFetchRequest req; read_http_fetch_request(L, req); - actionstream << "Mod performs HTTP request with URL " << req.url << std::endl; + infostream << "Mod performs HTTP request with URL " << req.url << std::endl; httpfetch_async(req); // Convert handle to hex string since lua can't handle 64-bit integers diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index e41d23fd1..f9708b560 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -175,6 +175,16 @@ int LuaItemStack::l_set_metadata(lua_State *L) return 1; } +// get_description(self) +int LuaItemStack::l_get_description(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + LuaItemStack *o = checkobject(L, 1); + std::string desc = o->m_stack.getDescription(getGameDef(L)->idef()); + lua_pushstring(L, desc.c_str()); + return 1; +} + // clear(self) -> true int LuaItemStack::l_clear(lua_State *L) { @@ -470,6 +480,7 @@ const luaL_Reg LuaItemStack::methods[] = { luamethod(LuaItemStack, get_meta), luamethod(LuaItemStack, get_metadata), luamethod(LuaItemStack, set_metadata), + luamethod(LuaItemStack, get_description), luamethod(LuaItemStack, clear), luamethod(LuaItemStack, replace), luamethod(LuaItemStack, to_string), diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h index 5ff715b2a..6fab58045 100644 --- a/src/script/lua_api/l_item.h +++ b/src/script/lua_api/l_item.h @@ -66,6 +66,9 @@ private: // set_metadata(self, string) static int l_set_metadata(lua_State *L); + // get_description(self) + static int l_get_description(lua_State *L); + // clear(self) -> true static int l_clear(lua_State *L); diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index 7444d0e88..3e14e48e4 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -30,20 +30,24 @@ LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m) void LuaLocalPlayer::create(lua_State *L, LocalPlayer *m) { + lua_getglobal(L, "core"); + luaL_checktype(L, -1, LUA_TTABLE); + int objectstable = lua_gettop(L); + lua_getfield(L, -1, "localplayer"); + + // Duplication check + if (lua_type(L, -1) == LUA_TUSERDATA) { + lua_pop(L, 1); + return; + } + LuaLocalPlayer *o = new LuaLocalPlayer(m); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); - // Keep localplayer object stack id - int localplayer_object = lua_gettop(L); - - lua_getglobal(L, "core"); - luaL_checktype(L, -1, LUA_TTABLE); - int coretable = lua_gettop(L); - - lua_pushvalue(L, localplayer_object); - lua_setfield(L, coretable, "localplayer"); + lua_pushvalue(L, lua_gettop(L)); + lua_setfield(L, objectstable, "localplayer"); } int LuaLocalPlayer::l_get_velocity(lua_State *L) diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 2557f448a..76db7ed13 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -107,6 +107,21 @@ int ModApiMainMenu::l_update_formspec(lua_State *L) } /******************************************************************************/ +int ModApiMainMenu::l_set_formspec_prepend(lua_State *L) +{ + GUIEngine *engine = getGuiEngine(L); + sanity_check(engine != NULL); + + if (engine->m_startgame) + return 0; + + std::string formspec(luaL_checkstring(L, 1)); + engine->setFormspecPrepend(formspec); + + return 0; +} + +/******************************************************************************/ int ModApiMainMenu::l_start(lua_State *L) { GUIEngine* engine = getGuiEngine(L); @@ -867,6 +882,16 @@ bool ModApiMainMenu::mayModifyPath(const std::string &path) return false; } + +/******************************************************************************/ +int ModApiMainMenu::l_may_modify_path(lua_State *L) +{ + const char *target = luaL_checkstring(L, 1); + std::string absolute_destination = fs::RemoveRelativePathComponents(target); + lua_pushboolean(L, ModApiMainMenu::mayModifyPath(absolute_destination)); + return 1; +} + /******************************************************************************/ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L) { @@ -1031,6 +1056,7 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L) void ModApiMainMenu::Initialize(lua_State *L, int top) { API_FCT(update_formspec); + API_FCT(set_formspec_prepend); API_FCT(set_clouds); API_FCT(get_textlist_index); API_FCT(get_table_index); @@ -1057,6 +1083,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(delete_dir); API_FCT(copy_dir); API_FCT(extract_zip); + API_FCT(may_modify_path); API_FCT(get_mainmenu_path); API_FCT(show_path_select_dialog); API_FCT(download_file); @@ -1086,6 +1113,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top) API_FCT(delete_dir); API_FCT(copy_dir); //API_FCT(extract_zip); //TODO remove dependency to GuiEngine + API_FCT(may_modify_path); API_FCT(download_file); //API_FCT(gettext); (gettext lib isn't threadsafe) } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 4a664359a..b2ca49320 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -104,6 +104,8 @@ private: static int l_update_formspec(lua_State *L); + static int l_set_formspec_prepend(lua_State *L); + static int l_get_screen_info(lua_State *L); //filesystem @@ -130,6 +132,8 @@ private: static int l_extract_zip(lua_State *L); + static int l_may_modify_path(lua_State *L); + static int l_download_file(lua_State *L); static int l_get_video_drivers(lua_State *L); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 92ed4377e..2e0cba8dd 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -405,7 +405,16 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef) nn.push_back(getstringfield_default(L, index, "node_river_water", "")); nn.push_back(getstringfield_default(L, index, "node_riverbed", "")); nn.push_back(getstringfield_default(L, index, "node_dust", "")); - nn.push_back(getstringfield_default(L, index, "node_cave_liquid", "")); + + size_t nnames = getstringlistfield(L, index, "node_cave_liquid", &nn); + // If no cave liquids defined, set list to "ignore" to trigger old hardcoded + // cave liquid behaviour. + if (nnames == 0) { + nn.emplace_back("ignore"); + nnames = 1; + } + b->m_nnlistsizes.push_back(nnames); + nn.push_back(getstringfield_default(L, index, "node_dungeon", "")); nn.push_back(getstringfield_default(L, index, "node_dungeon_alt", "")); nn.push_back(getstringfield_default(L, index, "node_dungeon_stair", "")); @@ -1745,6 +1754,83 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) return 1; } +// read_schematic(schematic, options={...}) +int ModApiMapgen::l_read_schematic(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + + //// Read options + std::string write_yslice = getstringfield_default(L, 2, "write_yslice_prob", "all"); + + //// Get schematic + bool was_loaded = false; + Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr); + if (!schem) { + schem = load_schematic(L, 1, NULL, NULL); + was_loaded = true; + } + if (!schem) { + errorstream << "read_schematic: failed to get schematic" << std::endl; + return 0; + } + lua_pop(L, 2); + + //// Create the Lua table + u32 numnodes = schem->size.X * schem->size.Y * schem->size.Z; + const std::vector<std::string> &names = schem->m_nodenames; + + lua_createtable(L, 0, (write_yslice == "none") ? 2 : 3); + + // Create the size field + push_v3s16(L, schem->size); + lua_setfield(L, 1, "size"); + + // Create the yslice_prob field + if (write_yslice != "none") { + lua_createtable(L, schem->size.Y, 0); + for (u16 y = 0; y != schem->size.Y; ++y) { + u8 probability = schem->slice_probs[y] & MTSCHEM_PROB_MASK; + if (probability < MTSCHEM_PROB_ALWAYS || write_yslice != "low") { + lua_createtable(L, 0, 2); + lua_pushinteger(L, y); + lua_setfield(L, 3, "ypos"); + lua_pushinteger(L, probability * 2); + lua_setfield(L, 3, "prob"); + lua_rawseti(L, 2, y + 1); + } + } + lua_setfield(L, 1, "yslice_prob"); + } + + // Create the data field + lua_createtable(L, numnodes, 0); // data table + for (u32 i = 0; i < numnodes; ++i) { + MapNode node = schem->schemdata[i]; + u8 probability = node.param1 & MTSCHEM_PROB_MASK; + bool force_place = node.param1 & MTSCHEM_FORCE_PLACE; + lua_createtable(L, 0, force_place ? 4 : 3); + lua_pushstring(L, names[schem->schemdata[i].getContent()].c_str()); + lua_setfield(L, 3, "name"); + lua_pushinteger(L, probability * 2); + lua_setfield(L, 3, "prob"); + lua_pushinteger(L, node.param2); + lua_setfield(L, 3, "param2"); + if (force_place) { + lua_pushboolean(L, 1); + lua_setfield(L, 3, "force_place"); + } + lua_rawseti(L, 2, i + 1); + } + lua_setfield(L, 1, "data"); + + if (was_loaded) + delete schem; + + return 1; +} + void ModApiMapgen::Initialize(lua_State *L, int top) { @@ -1784,4 +1870,5 @@ void ModApiMapgen::Initialize(lua_State *L, int top) API_FCT(place_schematic); API_FCT(place_schematic_on_vmanip); API_FCT(serialize_schematic); + API_FCT(read_schematic); } diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index 1339791f3..4a6a9ccf4 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -131,6 +131,9 @@ private: // serialize_schematic(schematic, format, options={...}) static int l_serialize_schematic(lua_State *L); + // read_schematic(schematic, options={...}) + static int l_read_schematic(lua_State *L); + public: static void Initialize(lua_State *L, int top); diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 22fc61782..229ce73db 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -68,7 +68,7 @@ void NodeMetaRef::reportMetadataChange(const std::string *name) event.type = MEET_BLOCK_NODE_METADATA_CHANGED; event.p = m_p; event.is_private_change = name && meta && meta->isPrivate(*name); - m_env->getMap().dispatchEvent(&event); + m_env->getMap().dispatchEvent(event); } // Exported functions diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index b3ed39c7c..efdb345c9 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -170,8 +170,8 @@ int ObjectRef::l_punch(lua_State *L) ObjectRef *puncher_ref = checkobject(L, 2); ServerActiveObject *co = getobject(ref); ServerActiveObject *puncher = getobject(puncher_ref); - if (co == NULL) return 0; - if (puncher == NULL) return 0; + if (!co || !puncher) + return 0; v3f dir; if (lua_type(L, 5) != LUA_TTABLE) dir = co->getBasePosition() - puncher->getBasePosition(); @@ -187,12 +187,14 @@ int ObjectRef::l_punch(lua_State *L) u16 dst_origin_hp = puncher->getHP(); // Do it - co->punch(dir, &toolcap, puncher, time_from_last_punch); + u16 wear = co->punch(dir, &toolcap, puncher, time_from_last_punch); + lua_pushnumber(L, wear); // If the punched is a player, and its HP changed if (src_original_hp != co->getHP() && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher)); + getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, + PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher)); } // If the puncher is a player, and its HP changed @@ -201,7 +203,7 @@ int ObjectRef::l_punch(lua_State *L) getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher, PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, co)); } - return 0; + return 1; } // right_click(self, clicker); clicker = an another ObjectRef @@ -307,8 +309,9 @@ int ObjectRef::l_get_wield_list(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; - // Do it + if (!co) + return 0; + lua_pushstring(L, co->getWieldList().c_str()); return 1; } @@ -319,8 +322,9 @@ int ObjectRef::l_get_wield_index(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; - // Do it + if (!co) + return 0; + lua_pushinteger(L, co->getWieldIndex() + 1); return 1; } @@ -331,13 +335,15 @@ int ObjectRef::l_get_wielded_item(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) { + if (!co) { // Empty ItemStack LuaItemStack::create(L, ItemStack()); return 1; } - // Do it - LuaItemStack::create(L, co->getWieldedItem()); + + ItemStack selected_item; + co->getWieldedItem(&selected_item, nullptr); + LuaItemStack::create(L, selected_item); return 1; } @@ -352,7 +358,7 @@ int ObjectRef::l_set_wielded_item(lua_State *L) ItemStack item = read_item(L, 2, getServer(L)->idef()); bool success = co->setWieldedItem(item); if (success && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendInventory(((PlayerSAO*)co)); + getServer(L)->SendInventory((PlayerSAO *)co, true); } lua_pushboolean(L, success); return 1; @@ -583,6 +589,24 @@ int ObjectRef::l_get_eye_offset(lua_State *L) return 2; } +// send_mapblock(self, pos) +int ObjectRef::l_send_mapblock(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + v3s16 p = read_v3s16(L, 2); + + session_t peer_id = player->getPeerId(); + bool r = getServer(L)->SendBlock(peer_id, p); + + lua_pushboolean(L, r); + return 1; +} + // set_animation_frame_speed(self, frame_speed) int ObjectRef::l_set_animation_frame_speed(lua_State *L) { @@ -731,17 +755,14 @@ int ObjectRef::l_set_properties(lua_State *L) NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); - if (co == NULL) return 0; + if (!co) + return 0; + ObjectProperties *prop = co->accessObjectProperties(); if (!prop) return 0; - read_object_properties(L, 2, prop, getServer(L)->idef()); - if (prop->hp_max < co->getHP()) { - PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP); - co->setHP(prop->hp_max, reason); - if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason); - } + + read_object_properties(L, 2, co, prop, getServer(L)->idef()); co->notifyObjectPropertiesModified(); return 0; } @@ -1074,6 +1095,27 @@ int ObjectRef::l_get_player_velocity(lua_State *L) return 1; } +// add_player_velocity(self, {x=num, y=num, z=num}) +int ObjectRef::l_add_player_velocity(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + v3f vel = checkFloatPos(L, 2); + + RemotePlayer *player = getplayer(ref); + PlayerSAO *co = getplayersao(ref); + if (!player || !co) + return 0; + + session_t peer_id = player->getPeerId(); + if (peer_id == PEER_ID_INEXISTENT) + return 0; + // Do it + co->setMaxSpeedOverride(vel); + getServer(L)->SendPlayerSpeed(peer_id, vel); + return 0; +} + // get_look_dir(self) int ObjectRef::l_get_look_dir(lua_State *L) { @@ -1210,6 +1252,37 @@ int ObjectRef::l_set_look_yaw(lua_State *L) return 1; } +// set_fov(self, degrees[, is_multiplier]) +int ObjectRef::l_set_fov(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + + player->setFov({ static_cast<f32>(luaL_checknumber(L, 2)), readParam<bool>(L, 3) }); + getServer(L)->SendPlayerFov(player->getPeerId()); + + return 0; +} + +// get_fov(self) +int ObjectRef::l_get_fov(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + + PlayerFovSpec fov_spec = player->getFov(); + lua_pushnumber(L, fov_spec.fov); + lua_pushboolean(L, fov_spec.is_multiplier); + + return 2; +} + // set_breath(self, breath) int ObjectRef::l_set_breath(lua_State *L) { @@ -1239,6 +1312,9 @@ int ObjectRef::l_get_breath(lua_State *L) // set_attribute(self, attribute, value) int ObjectRef::l_set_attribute(lua_State *L) { + log_deprecated(L, + "Deprecated call to set_attribute, use MetaDataRef methods instead."); + ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); if (co == NULL) @@ -1257,6 +1333,9 @@ int ObjectRef::l_set_attribute(lua_State *L) // get_attribute(self, attribute) int ObjectRef::l_get_attribute(lua_State *L) { + log_deprecated(L, + "Deprecated call to get_attribute, use MetaDataRef methods instead."); + ObjectRef *ref = checkobject(L, 1); PlayerSAO* co = getplayersao(ref); if (co == NULL) @@ -1907,6 +1986,7 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, is_player_connected), luamethod(ObjectRef, get_player_name), luamethod(ObjectRef, get_player_velocity), + luamethod(ObjectRef, add_player_velocity), luamethod(ObjectRef, get_look_dir), luamethod(ObjectRef, get_look_pitch), luamethod(ObjectRef, get_look_yaw), @@ -1916,6 +1996,8 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, set_look_vertical), luamethod(ObjectRef, set_look_yaw), luamethod(ObjectRef, set_look_pitch), + luamethod(ObjectRef, get_fov), + luamethod(ObjectRef, set_fov), luamethod(ObjectRef, get_breath), luamethod(ObjectRef, set_breath), luamethod(ObjectRef, get_attribute), @@ -1951,5 +2033,6 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, get_local_animation), luamethod(ObjectRef, set_eye_offset), luamethod(ObjectRef, get_eye_offset), + luamethod(ObjectRef, send_mapblock), {0,0} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index c7d963d87..e817e1d33 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -212,6 +212,12 @@ private: // get_player_velocity(self) static int l_get_player_velocity(lua_State *L); + // add_player_velocity(self, {x=num, y=num, z=num}) + static int l_add_player_velocity(lua_State *L); + + // get_fov(self) + static int l_get_fov(lua_State *L); + // get_look_dir(self) static int l_get_look_dir(lua_State *L); @@ -229,6 +235,9 @@ private: // get_look_yaw2(self) static int l_get_look_horizontal(lua_State *L); + // set_fov(self, degrees, is_multiplier) + static int l_set_fov(lua_State *L); + // set_look_vertical(self, radians) static int l_set_look_vertical(lua_State *L); @@ -351,4 +360,6 @@ private: // get_nametag_attributes(self) static int l_get_nametag_attributes(lua_State *L); + // send_mapblock(pos) + static int l_send_mapblock(lua_State *L); }; diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 6017a5475..7c083e652 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -233,6 +233,10 @@ int ModApiServer::l_get_player_information(lua_State *L) lua_pushnumber(L, prot_vers); lua_settable(L, table); + lua_pushstring(L, "formspec_version"); + lua_pushnumber(L, player->formspec_version); + lua_settable(L, table); + #ifndef NDEBUG lua_pushstring(L,"serialization_version"); lua_pushnumber(L, ser_vers); diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp index c92983bd3..fd73d21d1 100644 --- a/src/script/lua_api/l_vmanip.cpp +++ b/src/script/lua_api/l_vmanip.cpp @@ -126,7 +126,7 @@ int LuaVoxelManip::l_write_to_map(lua_State *L) for (const auto &modified_block : o->modified_blocks) event.modified_blocks.insert(modified_block.first); - map->dispatchEvent(&event); + map->dispatchEvent(event); o->modified_blocks.clear(); return 0; diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp index 86e5f2874..c3e0ca373 100644 --- a/src/script/scripting_client.cpp +++ b/src/script/scripting_client.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_client.h" #include "lua_api/l_env.h" #include "lua_api/l_item.h" +#include "lua_api/l_itemstackmeta.h" #include "lua_api/l_minimap.h" #include "lua_api/l_modchannels.h" #include "lua_api/l_particles_local.h" @@ -67,6 +68,7 @@ ClientScripting::ClientScripting(Client *client): void ClientScripting::InitializeModApi(lua_State *L, int top) { LuaItemStack::Register(L); + ItemStackMetaRef::Register(L); StorageRef::Register(L); LuaMinimap::Register(L); NodeMetaRef::RegisterClient(L); @@ -84,8 +86,7 @@ void ClientScripting::InitializeModApi(lua_State *L, int top) void ClientScripting::on_client_ready(LocalPlayer *localplayer) { - lua_State *L = getStack(); - LuaLocalPlayer::create(L, localplayer); + LuaLocalPlayer::create(getStack(), localplayer); } void ClientScripting::on_camera_ready(Camera *camera) |