diff options
Diffstat (limited to 'src/script/lua_api')
27 files changed, 1079 insertions, 276 deletions
diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt index 2501ce6d6..d507dcf70 100644 --- a/src/script/lua_api/CMakeLists.txt +++ b/src/script/lua_api/CMakeLists.txt @@ -16,6 +16,7 @@ set(common_SCRIPT_LUA_API_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/l_util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/l_http.cpp PARENT_SCOPE) set(client_SCRIPT_LUA_API_SRCS diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp index 1e9075119..20e7875c7 100644 --- a/src/script/lua_api/l_areastore.cpp +++ b/src/script/lua_api/l_areastore.cpp @@ -22,11 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_internal.h" #include "common/c_converter.h" #include "cpp_api/s_security.h" -#include "areastore.h" +#include "irr_v3d.h" +#include "util/areastore.h" #include "filesys.h" -#ifndef ANDROID - #include "cmake_config.h" -#endif #include <fstream> static inline void get_data_and_border_flags(lua_State *L, u8 start_i, @@ -45,6 +43,7 @@ static void push_area(lua_State *L, const Area *a, { if (!include_borders && !include_data) { lua_pushboolean(L, true); + return; } lua_newtable(L); if (include_borders) { @@ -71,6 +70,22 @@ static inline void push_areas(lua_State *L, const std::vector<Area *> &areas, } } +// Deserializes value and handles errors +static int deserialization_helper(lua_State *L, AreaStore *as, + std::istream &is) +{ + try { + as->deserialize(is); + } catch (const SerializationError &e) { + lua_pushboolean(L, false); + lua_pushstring(L, e.what()); + return 2; + } + + lua_pushboolean(L, true); + return 1; +} + // garbage collector int LuaAreaStore::gc_object(lua_State *L) { @@ -149,7 +164,7 @@ int LuaAreaStore::l_get_areas_in_area(lua_State *L) return 1; } -// insert_area(edge1, edge2, data) +// insert_area(edge1, edge2, data, id) int LuaAreaStore::l_insert_area(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -157,26 +172,18 @@ int LuaAreaStore::l_insert_area(lua_State *L) LuaAreaStore *o = checkobject(L, 1); AreaStore *ast = o->as; - Area a; - - a.minedge = check_v3s16(L, 2); - a.maxedge = check_v3s16(L, 3); - - a.extremifyEdges(); - a.id = ast->getFreeId(a.minedge, a.maxedge); - - if (a.id == AREA_ID_INVALID) { - // couldn't get free id - lua_pushnil(L); - return 1; - } + Area a(check_v3s16(L, 2), check_v3s16(L, 3)); size_t d_len; const char *data = luaL_checklstring(L, 4, &d_len); a.data = std::string(data, d_len); - ast->insertArea(a); + if (lua_isnumber(L, 5)) + a.id = lua_tonumber(L, 5); + + if (!ast->insertArea(&a)) + return 0; lua_pushnumber(L, a.id); return 1; @@ -229,17 +236,15 @@ int LuaAreaStore::l_set_cache_params(lua_State *L) return 0; } -#if 0 // to_string() int LuaAreaStore::l_to_string(lua_State *L) { NO_MAP_LOCK_REQUIRED; LuaAreaStore *o = checkobject(L, 1); - AreaStore *ast = o->as; std::ostringstream os(std::ios_base::binary); - ast->serialize(os); + o->as->serialize(os); std::string str = os.str(); lua_pushlstring(L, str.c_str(), str.length()); @@ -270,16 +275,12 @@ int LuaAreaStore::l_from_string(lua_State *L) NO_MAP_LOCK_REQUIRED; LuaAreaStore *o = checkobject(L, 1); - AreaStore *ast = o->as; size_t len; const char *str = luaL_checklstring(L, 2, &len); std::istringstream is(std::string(str, len), std::ios::binary); - bool success = ast->deserialize(is); - - lua_pushboolean(L, success); - return 1; + return deserialization_helper(L, o->as, is); } // from_file(filename) @@ -288,26 +289,17 @@ int LuaAreaStore::l_from_file(lua_State *L) NO_MAP_LOCK_REQUIRED; LuaAreaStore *o = checkobject(L, 1); - AreaStore *ast = o->as; const char *filename = luaL_checkstring(L, 2); CHECK_SECURE_PATH_OPTIONAL(L, filename); std::ifstream is(filename, std::ios::binary); - bool success = ast->deserialize(is); - - lua_pushboolean(L, success); - return 1; + return deserialization_helper(L, o->as, is); } -#endif LuaAreaStore::LuaAreaStore() { -#if USE_SPATIAL - this->as = new SpatialAreaStore(); -#else - this->as = new VectorAreaStore(); -#endif + this->as = AreaStore::getOptimalImplementation(); } LuaAreaStore::LuaAreaStore(const std::string &type) @@ -393,9 +385,9 @@ const luaL_reg LuaAreaStore::methods[] = { luamethod(LuaAreaStore, reserve), luamethod(LuaAreaStore, remove_area), luamethod(LuaAreaStore, set_cache_params), - /* luamethod(LuaAreaStore, to_string), + luamethod(LuaAreaStore, to_string), luamethod(LuaAreaStore, to_file), luamethod(LuaAreaStore, from_string), - luamethod(LuaAreaStore, from_file),*/ + luamethod(LuaAreaStore, from_file), {0,0} }; diff --git a/src/script/lua_api/l_areastore.h b/src/script/lua_api/l_areastore.h index a25529627..4bd94cebe 100644 --- a/src/script/lua_api/l_areastore.h +++ b/src/script/lua_api/l_areastore.h @@ -17,16 +17,14 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef L_AREASTORE_H_ -#define L_AREASTORE_H_ +#ifndef L_AREA_STORE_H_ +#define L_AREA_STORE_H_ #include "lua_api/l_base.h" -#include "irr_v3d.h" -#include "areastore.h" -/* - AreaStore - */ + +class AreaStore; + class LuaAreaStore : public ModApiBase { private: @@ -45,11 +43,11 @@ private: static int l_set_cache_params(lua_State *L); - /* static int l_to_string(lua_State *L); + static int l_to_string(lua_State *L); static int l_to_file(lua_State *L); static int l_from_string(lua_State *L); - static int l_from_file(lua_State *L); */ + static int l_from_file(lua_State *L); public: AreaStore *as; @@ -67,4 +65,4 @@ public: static void Register(lua_State *L); }; -#endif /* L_AREASTORE_H_ */ +#endif // L_AREA_STORE_H_ diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp index 6ad3e4ba2..515a7d933 100644 --- a/src/script/lua_api/l_base.cpp +++ b/src/script/lua_api/l_base.cpp @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ScriptApiBase *ModApiBase::getScriptApiBase(lua_State *L) { // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi"); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); ScriptApiBase *sapi_ptr = (ScriptApiBase*) lua_touserdata(L, -1); lua_pop(L, 1); return sapi_ptr; @@ -49,7 +49,7 @@ GUIEngine *ModApiBase::getGuiEngine(lua_State *L) std::string ModApiBase::getCurrentModPath(lua_State *L) { - lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); const char *current_mod_name = lua_tostring(L, -1); if (!current_mod_name) return "."; diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 28afdd071..8284c3fcb 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -33,11 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/pointedthing.h" #include "content_sao.h" #include "treegen.h" +#include "emerge.h" #include "pathfinder.h" -#define GET_ENV_PTR ServerEnvironment* env = \ - dynamic_cast<ServerEnvironment*>(getEnv(L)); \ - if (env == NULL) return 0 +struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = +{ + {CLEAR_OBJECTS_MODE_FULL, "full"}, + {CLEAR_OBJECTS_MODE_QUICK, "quick"}, + {0, NULL}, +}; /////////////////////////////////////////////////////////////////////////////// @@ -52,8 +56,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, sanity_check(lua_checkstack(L, 20)); StackUnroller stack_unroller(L); - lua_pushcfunction(L, script_error_handler); - int errorhandler = lua_gettop(L); + int error_handler = PUSH_ERROR_HANDLER(L); // Get registered_abms lua_getglobal(L, "core"); @@ -80,13 +83,68 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, lua_pushnumber(L, active_object_count); lua_pushnumber(L, active_object_count_wider); - int result = lua_pcall(L, 4, 0, errorhandler); + int result = lua_pcall(L, 4, 0, error_handler); if (result) scriptIface->scriptError(result, "LuaABM::trigger"); lua_pop(L, 1); // Pop error handler } +void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) +{ + GameScripting *scriptIface = env->getScriptIface(); + scriptIface->realityCheck(); + + lua_State *L = scriptIface->getStack(); + sanity_check(lua_checkstack(L, 20)); + StackUnroller stack_unroller(L); + + int error_handler = PUSH_ERROR_HANDLER(L); + + // Get registered_lbms + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_lbms"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_remove(L, -2); // Remove core + + // Get registered_lbms[m_id] + lua_pushnumber(L, m_id); + lua_gettable(L, -2); + FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); + lua_remove(L, -2); // Remove registered_lbms + + scriptIface->setOriginFromTable(-1); + + // Call action + luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, "action"); + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_remove(L, -2); // Remove registered_lbms[m_id] + push_v3s16(L, p); + pushnode(L, n, env->getGameDef()->ndef()); + + int result = lua_pcall(L, 2, 0, error_handler); + if (result) + scriptIface->scriptError(result, "LuaLBM::trigger"); + + lua_pop(L, 1); // Pop error handler +} + +void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param) +{ + ScriptCallbackState *state = (ScriptCallbackState *)param; + assert(state != NULL); + assert(state->script != NULL); + assert(state->refcount > 0); + + state->refcount--; + + state->script->on_emerge_area_completion(blockpos, action, state); + + if (state->refcount == 0) + delete state; +} + // Exported functions // set_node(pos, node) @@ -412,8 +470,7 @@ int ModApiEnvMod::l_add_item(lua_State *L) if(item.empty() || !item.isKnown(getServer(L)->idef())) return 0; - lua_pushcfunction(L, script_error_handler); - int errorhandler = lua_gettop(L); + int error_handler = PUSH_ERROR_HANDLER(L); // Use spawn_item to spawn a __builtin:item lua_getglobal(L, "core"); @@ -424,9 +481,9 @@ int ModApiEnvMod::l_add_item(lua_State *L) lua_pushvalue(L, 1); lua_pushstring(L, item.getItemString().c_str()); - PCALL_RESL(L, lua_pcall(L, 2, 1, errorhandler)); + PCALL_RESL(L, lua_pcall(L, 2, 1, error_handler)); - lua_remove(L, errorhandler); // Remove error handler + lua_remove(L, error_handler); return 1; } @@ -504,6 +561,15 @@ int ModApiEnvMod::l_get_timeofday(lua_State *L) return 1; } +// get_day_count() -> int +int ModApiEnvMod::l_get_day_count(lua_State *L) +{ + GET_ENV_PTR; + + lua_pushnumber(L, env->getDayCount()); + return 1; +} + // get_gametime() int ModApiEnvMod::l_get_gametime(lua_State *L) { @@ -659,7 +725,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) // returns world-specific PerlinNoise int ModApiEnvMod::l_get_perlin(lua_State *L) { - GET_ENV_PTR; + GET_ENV_PTR_NO_MAP_LOCK; NoiseParams params; @@ -685,7 +751,7 @@ int ModApiEnvMod::l_get_perlin(lua_State *L) // returns world-specific PerlinNoiseMap int ModApiEnvMod::l_get_perlin_map(lua_State *L) { - GET_ENV_PTR; + GET_ENV_PTR_NO_MAP_LOCK; NoiseParams np; if (!read_noiseparams(L, 1, &np)) @@ -717,13 +783,20 @@ int ModApiEnvMod::l_get_voxel_manip(lua_State *L) return 1; } -// clear_objects() +// clear_objects([options]) // clear all objects in the environment +// where options = {mode = "full" or "quick"} int ModApiEnvMod::l_clear_objects(lua_State *L) { GET_ENV_PTR; - env->clearAllObjects(); + ClearObjectsMode mode = CLEAR_OBJECTS_MODE_FULL; + if (lua_istable(L, 1)) { + mode = (ClearObjectsMode)getenumfield(L, 1, "mode", + ModApiEnvMod::es_ClearObjectsMode, mode); + } + + env->clearObjects(mode); return 0; } @@ -753,6 +826,51 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L) return 1; } +// emerge_area(p1, p2, [callback, context]) +// emerge mapblocks in area p1..p2, calls callback with context upon completion +int ModApiEnvMod::l_emerge_area(lua_State *L) +{ + GET_ENV_PTR; + + EmergeCompletionCallback callback = NULL; + ScriptCallbackState *state = NULL; + + EmergeManager *emerge = getServer(L)->getEmergeManager(); + + v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1)); + v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2)); + sortBoxVerticies(bpmin, bpmax); + + size_t num_blocks = VoxelArea(bpmin, bpmax).getVolume(); + assert(num_blocks != 0); + + if (lua_isfunction(L, 3)) { + callback = LuaEmergeAreaCallback; + + lua_pushvalue(L, 3); + int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + lua_pushvalue(L, 4); + int args_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + state = new ScriptCallbackState; + state->script = getServer(L)->getScriptIface(); + state->callback_ref = callback_ref; + state->args_ref = args_ref; + state->refcount = num_blocks; + state->origin = getScriptApiBase(L)->getOrigin(); + } + + for (s16 z = bpmin.Z; z <= bpmax.Z; z++) + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) + for (s16 x = bpmin.X; x <= bpmax.X; x++) { + emerge->enqueueBlockEmergeEx(v3s16(x, y, z), PEER_ID_INEXISTENT, + BLOCK_EMERGE_ALLOW_GEN | BLOCK_EMERGE_FORCE_QUEUE, callback, state); + } + + return 0; +} + // delete_area(p1, p2) // delete mapblocks in area p1..p2 int ModApiEnvMod::l_delete_area(lua_State *L) @@ -797,19 +915,19 @@ int ModApiEnvMod::l_find_path(lua_State *L) unsigned int searchdistance = luaL_checkint(L, 3); unsigned int max_jump = luaL_checkint(L, 4); unsigned int max_drop = luaL_checkint(L, 5); - algorithm algo = A_PLAIN_NP; + PathAlgorithm algo = PA_PLAIN_NP; if (!lua_isnil(L, 6)) { std::string algorithm = luaL_checkstring(L,6); if (algorithm == "A*") - algo = A_PLAIN; + algo = PA_PLAIN; if (algorithm == "Dijkstra") - algo = DIJKSTRA; + algo = PA_DIJKSTRA; } - std::vector<v3s16> path = - get_Path(env,pos1,pos2,searchdistance,max_jump,max_drop,algo); + std::vector<v3s16> path = get_path(env, pos1, pos2, + searchdistance, max_jump, max_drop, algo); if (path.size() > 0) { @@ -920,13 +1038,6 @@ int ModApiEnvMod::l_forceload_free_block(lua_State *L) return 0; } -// get_us_time() -int ModApiEnvMod::l_get_us_time(lua_State *L) -{ - lua_pushnumber(L, porting::getTimeUs()); - return 1; -} - void ModApiEnvMod::Initialize(lua_State *L, int top) { API_FCT(set_node); @@ -953,9 +1064,11 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(set_timeofday); API_FCT(get_timeofday); API_FCT(get_gametime); + API_FCT(get_day_count); API_FCT(find_node_near); API_FCT(find_nodes_in_area); API_FCT(find_nodes_in_area_under_air); + API_FCT(emerge_area); API_FCT(delete_area); API_FCT(get_perlin); API_FCT(get_perlin_map); @@ -967,5 +1080,4 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(transforming_liquid_add); API_FCT(forceload_block); API_FCT(forceload_free_block); - API_FCT(get_us_time); } diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 0d4ca788e..89dd7978f 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -113,6 +113,9 @@ private: // get_gametime() static int l_get_gametime(lua_State *L); + // get_day_count() -> int + static int l_get_day_count(lua_State *L); + // find_node_near(pos, radius, nodenames) -> pos or nil // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" static int l_find_node_near(lua_State *L); @@ -125,6 +128,9 @@ private: // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" static int l_find_nodes_in_area_under_air(lua_State *L); + // emerge_area(p1, p2) + static int l_emerge_area(lua_State *L); + // delete_area(p1, p2) -> true/false static int l_delete_area(lua_State *L); @@ -165,15 +171,13 @@ private: // stops forceloading a position static int l_forceload_free_block(lua_State *L); - // get us precision time - static int l_get_us_time(lua_State *L); - public: static void Initialize(lua_State *L, int top); + + static struct EnumString es_ClearObjectsMode[]; }; -class LuaABM : public ActiveBlockModifier -{ +class LuaABM : public ActiveBlockModifier { private: int m_id; @@ -181,16 +185,18 @@ private: std::set<std::string> m_required_neighbors; float m_trigger_interval; u32 m_trigger_chance; + bool m_simple_catch_up; public: LuaABM(lua_State *L, int id, const std::set<std::string> &trigger_contents, const std::set<std::string> &required_neighbors, - float trigger_interval, u32 trigger_chance): + float trigger_interval, u32 trigger_chance, bool simple_catch_up): m_id(id), m_trigger_contents(trigger_contents), m_required_neighbors(required_neighbors), m_trigger_interval(trigger_interval), - m_trigger_chance(trigger_chance) + m_trigger_chance(trigger_chance), + m_simple_catch_up(simple_catch_up) { } virtual std::set<std::string> getTriggerContents() @@ -209,8 +215,38 @@ public: { return m_trigger_chance; } + virtual bool getSimpleCatchUp() + { + return m_simple_catch_up; + } virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider); }; +class LuaLBM : public LoadingBlockModifierDef +{ +private: + int m_id; +public: + LuaLBM(lua_State *L, int id, + const std::set<std::string> &trigger_contents, + const std::string &name, + bool run_at_every_load): + m_id(id) + { + this->run_at_every_load = run_at_every_load; + this->trigger_contents = trigger_contents; + this->name = name; + } + virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n); +}; + +struct ScriptCallbackState { + GameScripting *script; + int callback_ref; + int args_ref; + unsigned int refcount; + std::string origin; +}; + #endif /* L_ENV_H_ */ diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp new file mode 100644 index 000000000..8bd39b6ed --- /dev/null +++ b/src/script/lua_api/l_http.cpp @@ -0,0 +1,193 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "lua_api/l_internal.h" +#include "common/c_converter.h" +#include "common/c_content.h" +#include "lua_api/l_http.h" +#include "httpfetch.h" +#include "settings.h" +#include "debug.h" +#include "log.h" + +#include <algorithm> +#include <iomanip> +#include <cctype> + +#define HTTP_API(name) \ + lua_pushstring(L, #name); \ + lua_pushcfunction(L, l_http_##name); \ + lua_settable(L, -3); + +#if USE_CURL +void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + req.caller = httpfetch_caller_alloc_secure(); + getstringfield(L, 1, "url", req.url); + lua_getfield(L, 1, "user_agent"); + if (lua_isstring(L, -1)) + req.useragent = getstringfield_default(L, 1, "user_agent", ""); + lua_pop(L, 1); + req.multipart = getboolfield_default(L, 1, "multipart", false); + req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000; + + // post_data: if table, post form data, otherwise raw data + 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); + lua_pop(L, 1); + } + } else if (lua_isstring(L, 2)) { + req.post_data = lua_tostring(L, 2); + } + lua_pop(L, 1); + + 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.push_back(header); + lua_pop(L, 1); + } + } + lua_pop(L, 1); +} + +void ModApiHttp::push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed) +{ + lua_newtable(L); + setboolfield(L, -1, "succeeded", res.succeeded); + 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()); +} + +// http_api.fetch_async(HTTPRequest definition) +int ModApiHttp::l_http_fetch_async(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + HTTPFetchRequest req; + read_http_fetch_request(L, req); + + actionstream << "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 + std::stringstream handle_conversion_stream; + handle_conversion_stream << std::hex << req.caller; + std::string caller_handle(handle_conversion_stream.str()); + + lua_pushstring(L, caller_handle.c_str()); + return 1; +} + +// http_api.fetch_async_get(handle) +int ModApiHttp::l_http_fetch_async_get(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + std::string handle_str = luaL_checkstring(L, 1); + + // Convert hex string back to 64-bit handle + u64 handle; + std::stringstream handle_conversion_stream; + handle_conversion_stream << std::hex << handle_str; + handle_conversion_stream >> handle; + + HTTPFetchResult res; + bool completed = httpfetch_async_get(handle, res); + + push_http_fetch_result(L, res, completed); + + return 1; +} + +int ModApiHttp::l_request_http_api(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + // We have to make sure that this function is being called directly by + // a mod, otherwise a malicious mod could override this function and + // steal its return value. + lua_Debug info; + + // Make sure there's only one item below this function on the stack... + if (lua_getstack(L, 2, &info)) { + return 0; + } + FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); + FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); + + // ...and that that item is the main file scope. + if (strcmp(info.what, "main") != 0) { + return 0; + } + + // Mod must be listed in secure.http_mods or secure.trusted_mods + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); + if (!lua_isstring(L, -1)) { + return 0; + } + + const char *mod_name = lua_tostring(L, -1); + std::string http_mods = g_settings->get("secure.http_mods"); + http_mods.erase(std::remove(http_mods.begin(), http_mods.end(), ' '), http_mods.end()); + std::vector<std::string> mod_list_http = str_split(http_mods, ','); + + std::string trusted_mods = g_settings->get("secure.trusted_mods"); + trusted_mods.erase(std::remove(trusted_mods.begin(), trusted_mods.end(), ' '), trusted_mods.end()); + std::vector<std::string> mod_list_trusted = str_split(trusted_mods, ','); + + mod_list_http.insert(mod_list_http.end(), mod_list_trusted.begin(), mod_list_trusted.end()); + if (std::find(mod_list_http.begin(), mod_list_http.end(), mod_name) == mod_list_http.end()) { + lua_pushnil(L); + return 1; + } + + lua_getglobal(L, "core"); + lua_getfield(L, -1, "http_add_fetch"); + + lua_newtable(L); + HTTP_API(fetch_async); + HTTP_API(fetch_async_get); + + // Stack now looks like this: + // <core.http_add_fetch> <table with fetch_async, fetch_async_get> + // Now call core.http_add_fetch to append .fetch(request, callback) to table + lua_call(L, 1, 1); + + return 1; +} +#endif + +void ModApiHttp::Initialize(lua_State *L, int top) +{ +#if USE_CURL + API_FCT(request_http_api); +#endif +} diff --git a/src/script/lua_api/l_http.h b/src/script/lua_api/l_http.h new file mode 100644 index 000000000..077ade691 --- /dev/null +++ b/src/script/lua_api/l_http.h @@ -0,0 +1,50 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef L_HTTP_H_ +#define L_HTTP_H_ + +#include "lua_api/l_base.h" +#include "config.h" + +struct HTTPFetchRequest; +struct HTTPFetchResult; + +class ModApiHttp : public ModApiBase { +private: +#if USE_CURL + // Helpers for HTTP fetch functions + static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req); + static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true); + + // http_fetch_async({url=, timeout=, post_data=}) + static int l_http_fetch_async(lua_State *L); + + // http_fetch_async_get(handle) + static int l_http_fetch_async_get(lua_State *L); + + // request_http_api() + static int l_request_http_api(lua_State *L); +#endif + +public: + static void Initialize(lua_State *L, int top); +}; + +#endif /* L_HTTP_H_ */ diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h index 1e40c5c4a..456c8fcce 100644 --- a/src/script/lua_api/l_internal.h +++ b/src/script/lua_api/l_internal.h @@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define API_FCT(name) registerFunction(L, #name, l_##name,top) #define ASYNC_API_FCT(name) engine.registerFunction(#name, l_##name) +#define MAP_LOCK_REQUIRED #define NO_MAP_LOCK_REQUIRED /* @@ -45,4 +46,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif */ +#define GET_ENV_PTR_NO_MAP_LOCK \ + ServerEnvironment *env = (ServerEnvironment *)getEnv(L); \ + if (env == NULL) \ + return 0 + +#define GET_ENV_PTR \ + MAP_LOCK_REQUIRED; \ + GET_ENV_PTR_NO_MAP_LOCK + #endif /* L_INTERNAL_H_ */ diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index f48f6083b..de9f9374a 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -491,6 +491,7 @@ int ModApiInventory::l_get_inventory(lua_State *L) std::string type = checkstringfield(L, 1, "type"); if(type == "node"){ + MAP_LOCK_REQUIRED; lua_getfield(L, 1, "pos"); v3s16 pos = check_v3s16(L, -1); loc.setNodeMeta(pos); @@ -514,7 +515,7 @@ int ModApiInventory::l_get_inventory(lua_State *L) InvRef::create(L, loc); else lua_pushnil(L); - return 1; + return 1; // END NO_MAP_LOCK_REQUIRED; } } diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 842b15709..5381cba76 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -94,7 +94,7 @@ int LuaItemStack::l_set_count(lua_State *L) bool status; lua_Integer count = luaL_checkinteger(L, 2); - if (count <= 65535) { + if (count > 0 && count <= 65535) { item.count = count; status = true; } else { diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 92311d6fc..7b29db159 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -706,16 +706,13 @@ int ModApiMainMenu::l_set_topleft_text(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_mapgen_names(lua_State *L) { - lua_newtable(L); - - std::list<const char *> names; - EmergeManager::getMapgenNames(names); + std::vector<const char *> names; + EmergeManager::getMapgenNames(&names, lua_toboolean(L, 1)); - int i = 1; - for (std::list<const char *>::const_iterator - it = names.begin(); it != names.end(); ++it) { - lua_pushstring(L, *it); - lua_rawseti(L, -2, i++); + lua_newtable(L); + for (size_t i = 0; i != names.size(); i++) { + lua_pushstring(L, names[i]); + lua_rawseti(L, -2, i + 1); } return 1; @@ -725,8 +722,8 @@ int ModApiMainMenu::l_get_mapgen_names(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_modpath(lua_State *L) { - std::string modpath - = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods" + DIR_DELIM); + std::string modpath = fs::RemoveRelativePathComponents( + porting::path_user + DIR_DELIM + "mods" + DIR_DELIM); lua_pushstring(L, modpath.c_str()); return 1; } @@ -734,8 +731,8 @@ int ModApiMainMenu::l_get_modpath(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_gamepath(lua_State *L) { - std::string gamepath - = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "games" + DIR_DELIM); + std::string gamepath = fs::RemoveRelativePathComponents( + porting::path_user + DIR_DELIM + "games" + DIR_DELIM); lua_pushstring(L, gamepath.c_str()); return 1; } @@ -743,44 +740,46 @@ int ModApiMainMenu::l_get_gamepath(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_texturepath(lua_State *L) { - std::string gamepath - = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "textures"); + std::string gamepath = fs::RemoveRelativePathComponents( + porting::path_user + DIR_DELIM + "textures"); lua_pushstring(L, gamepath.c_str()); return 1; } int ModApiMainMenu::l_get_texturepath_share(lua_State *L) { - std::string gamepath - = fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "textures"); + std::string gamepath = fs::RemoveRelativePathComponents( + porting::path_share + DIR_DELIM + "textures"); lua_pushstring(L, gamepath.c_str()); return 1; } /******************************************************************************/ int ModApiMainMenu::l_create_dir(lua_State *L) { - const char *path = luaL_checkstring(L, 1); + const char *path = luaL_checkstring(L, 1); if (ModApiMainMenu::isMinetestPath(path)) { - lua_pushboolean(L,fs::CreateAllDirs(path)); + lua_pushboolean(L, fs::CreateAllDirs(path)); return 1; } - lua_pushboolean(L,false); + + lua_pushboolean(L, false); return 1; } /******************************************************************************/ int ModApiMainMenu::l_delete_dir(lua_State *L) { - const char *path = luaL_checkstring(L, 1); + const char *path = luaL_checkstring(L, 1); std::string absolute_path = fs::RemoveRelativePathComponents(path); if (ModApiMainMenu::isMinetestPath(absolute_path)) { - lua_pushboolean(L,fs::RecursiveDelete(absolute_path)); + lua_pushboolean(L, fs::RecursiveDelete(absolute_path)); return 1; } - lua_pushboolean(L,false); + + lua_pushboolean(L, false); return 1; } @@ -1060,8 +1059,8 @@ int ModApiMainMenu::l_get_video_modes(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_gettext(lua_State *L) { - std::wstring wtext = wstrgettext((std::string) luaL_checkstring(L, 1)); - lua_pushstring(L, wide_to_utf8(wtext).c_str()); + std::string text = strgettext(std::string(luaL_checkstring(L, 1))); + lua_pushstring(L, text.c_str()); return 1; } @@ -1096,7 +1095,9 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_get_min_supp_proto(lua_State *L) { - lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MIN); + u16 proto_version_min = g_settings->getFlag("send_pre_v25_init") ? + CLIENT_PROTOCOL_VERSION_MIN_LEGACY : CLIENT_PROTOCOL_VERSION_MIN; + lua_pushinteger(L, proto_version_min); return 1; } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 9c1fed272..405af25e8 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -119,8 +119,6 @@ private: static int l_get_texturepath_share(lua_State *L); - static int l_get_dirlist(lua_State *L); - static int l_create_dir(lua_State *L); static int l_delete_dir(lua_State *L); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index d30b68054..fb839176b 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -70,6 +70,7 @@ struct EnumString ModApiMapgen::es_OreType[] = { {ORE_SCATTER, "scatter"}, {ORE_SHEET, "sheet"}, + {ORE_PUFF, "puff"}, {ORE_BLOB, "blob"}, {ORE_VEIN, "vein"}, {0, NULL}, @@ -449,10 +450,38 @@ size_t get_biome_list(lua_State *L, int index, /////////////////////////////////////////////////////////////////////////////// +// get_biome_id(biomename) +// returns the biome id used in biomemap +int ModApiMapgen::l_get_biome_id(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + const char *biome_str = lua_tostring(L, 1); + if (!biome_str) + return 0; + + BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + + if (!bmgr) + return 0; + + Biome *biome = (Biome *)bmgr->getByName(biome_str); + + if (!biome || biome->index == OBJDEF_INVALID_INDEX) + return 0; + + lua_pushinteger(L, biome->index); + + return 1; +} + + // get_mapgen_object(objectname) // returns the requested object used during map generation int ModApiMapgen::l_get_mapgen_object(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + const char *mgobjstr = lua_tostring(L, 1); int mgobjint; @@ -464,7 +493,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) EmergeManager *emerge = getServer(L)->getEmergeManager(); Mapgen *mg = emerge->getCurrentMapgen(); if (!mg) - return 0; + throw LuaError("Must only be called in a mapgen thread!"); size_t maplen = mg->csize.X * mg->csize.Z; @@ -563,6 +592,8 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) int ModApiMapgen::l_get_mapgen_params(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + MapgenParams *params = &getServer(L)->getEmergeManager()->params; lua_newtable(L); @@ -579,7 +610,7 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L) lua_pushinteger(L, params->chunksize); lua_setfield(L, -2, "chunksize"); - std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, (u32)-1); + std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, U32_MAX); lua_pushstring(L, flagstr.c_str()); lua_setfield(L, -2, "flags"); @@ -591,10 +622,16 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L) // set mapgen parameters int ModApiMapgen::l_set_mapgen_params(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + if (!lua_istable(L, 1)) return 0; - MapgenParams *params = &getServer(L)->getEmergeManager()->params; + EmergeManager *emerge = getServer(L)->getEmergeManager(); + if (emerge->isRunning()) + throw LuaError("Cannot set parameters while mapgen is running"); + + MapgenParams *params = &emerge->params; u32 flags = 0, flagmask = 0; lua_getfield(L, 1, "mgname"); @@ -612,6 +649,10 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L) if (lua_isnumber(L, -1)) params->water_level = lua_tointeger(L, -1); + lua_getfield(L, 1, "chunksize"); + if (lua_isnumber(L, -1)) + params->chunksize = lua_tointeger(L, -1); + warn_if_field_exists(L, 1, "flagmask", "Deprecated: flags field now includes unset flags."); lua_getfield(L, 1, "flagmask"); @@ -631,6 +672,8 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L) // set global config values for noise parameters int ModApiMapgen::l_set_noiseparams(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + const char *name = luaL_checkstring(L, 1); NoiseParams np; @@ -648,6 +691,8 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L) // get_noiseparams(name) int ModApiMapgen::l_get_noiseparams(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + std::string name = luaL_checkstring(L, 1); NoiseParams np; @@ -662,6 +707,8 @@ int ModApiMapgen::l_get_noiseparams(lua_State *L) // set_gen_notify(flags, {deco_id_table}) int ModApiMapgen::l_set_gen_notify(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + u32 flags = 0, flagmask = 0; EmergeManager *emerge = getServer(L)->getEmergeManager(); @@ -686,6 +733,8 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L) // get_gen_notify() int ModApiMapgen::l_get_gen_notify(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + EmergeManager *emerge = getServer(L)->getEmergeManager(); push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on, emerge->gen_notify_on); @@ -705,6 +754,8 @@ int ModApiMapgen::l_get_gen_notify(lua_State *L) // register_biome({lots of stuff}) int ModApiMapgen::l_register_biome(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + int index = 1; luaL_checktype(L, index, LUA_TTABLE); @@ -729,6 +780,8 @@ int ModApiMapgen::l_register_biome(lua_State *L) // register_decoration({lots of stuff}) int ModApiMapgen::l_register_decoration(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + int index = 1; luaL_checktype(L, index, LUA_TTABLE); @@ -869,6 +922,8 @@ bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic // register_ore({lots of stuff}) int ModApiMapgen::l_register_ore(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + int index = 1; luaL_checktype(L, index, LUA_TTABLE); @@ -880,7 +935,7 @@ int ModApiMapgen::l_register_ore(lua_State *L) "ore_type", es_OreType, ORE_SCATTER); Ore *ore = oremgr->create(oretype); if (!ore) { - errorstream << "register_ore: ore_type " << oretype << " not implemented"; + errorstream << "register_ore: ore_type " << oretype << " not implemented\n"; return 0; } @@ -889,10 +944,19 @@ int ModApiMapgen::l_register_ore(lua_State *L) ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); - ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0); ore->noise = NULL; ore->flags = 0; + //// Get noise_threshold + warn_if_field_exists(L, index, "noise_threshhold", + "Deprecated: new name is \"noise_threshold\"."); + + float nthresh; + if (!getfloatfield(L, index, "noise_threshold", nthresh) && + !getfloatfield(L, index, "noise_threshhold", nthresh)) + nthresh = 0; + ore->nthresh = nthresh; + //// Get y_min/y_max warn_if_field_exists(L, index, "height_min", "Deprecated: new name is \"y_min\"."); @@ -937,10 +1001,43 @@ int ModApiMapgen::l_register_ore(lua_State *L) } lua_pop(L, 1); - if (oretype == ORE_VEIN) { - OreVein *orevein = (OreVein *)ore; - orevein->random_factor = getfloatfield_default(L, index, - "random_factor", 1.f); + //// Get type-specific parameters + switch (oretype) { + case ORE_SHEET: { + OreSheet *oresheet = (OreSheet *)ore; + + oresheet->column_height_min = getintfield_default(L, index, + "column_height_min", 1); + oresheet->column_height_max = getintfield_default(L, index, + "column_height_max", ore->clust_size); + oresheet->column_midpoint_factor = getfloatfield_default(L, index, + "column_midpoint_factor", 0.5f); + + break; + } + case ORE_PUFF: { + OrePuff *orepuff = (OrePuff *)ore; + + lua_getfield(L, index, "np_puff_top"); + read_noiseparams(L, -1, &orepuff->np_puff_top); + lua_pop(L, 1); + + lua_getfield(L, index, "np_puff_bottom"); + read_noiseparams(L, -1, &orepuff->np_puff_bottom); + lua_pop(L, 1); + + break; + } + case ORE_VEIN: { + OreVein *orevein = (OreVein *)ore; + + orevein->random_factor = getfloatfield_default(L, index, + "random_factor", 1.f); + + break; + } + default: + break; } ObjDefHandle handle = oremgr->add(ore); @@ -964,6 +1061,8 @@ int ModApiMapgen::l_register_ore(lua_State *L) // register_schematic({schematic}, replacements={}) int ModApiMapgen::l_register_schematic(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; StringMap replace_names; @@ -989,6 +1088,8 @@ int ModApiMapgen::l_register_schematic(lua_State *L) // clear_registered_biomes() int ModApiMapgen::l_clear_registered_biomes(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; bmgr->clear(); return 0; @@ -998,6 +1099,8 @@ int ModApiMapgen::l_clear_registered_biomes(lua_State *L) // clear_registered_decorations() int ModApiMapgen::l_clear_registered_decorations(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr; dmgr->clear(); return 0; @@ -1007,6 +1110,8 @@ int ModApiMapgen::l_clear_registered_decorations(lua_State *L) // clear_registered_ores() int ModApiMapgen::l_clear_registered_ores(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + OreManager *omgr = getServer(L)->getEmergeManager()->oremgr; omgr->clear(); return 0; @@ -1016,6 +1121,8 @@ int ModApiMapgen::l_clear_registered_ores(lua_State *L) // clear_registered_schematics() int ModApiMapgen::l_clear_registered_schematics(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr; smgr->clear(); return 0; @@ -1025,6 +1132,8 @@ int ModApiMapgen::l_clear_registered_schematics(lua_State *L) // generate_ores(vm, p1, p2, [ore_id]) int ModApiMapgen::l_generate_ores(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + EmergeManager *emerge = getServer(L)->getEmergeManager(); Mapgen mg; @@ -1049,6 +1158,8 @@ int ModApiMapgen::l_generate_ores(lua_State *L) // generate_decorations(vm, p1, p2, [deco_id]) int ModApiMapgen::l_generate_decorations(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + EmergeManager *emerge = getServer(L)->getEmergeManager(); Mapgen mg; @@ -1073,6 +1184,8 @@ int ModApiMapgen::l_generate_decorations(lua_State *L) // create_schematic(p1, p2, probability_list, filename, y_slice_prob_list) int ModApiMapgen::l_create_schematic(lua_State *L) { + MAP_LOCK_REQUIRED; + INodeDefManager *ndef = getServer(L)->getNodeDefManager(); const char *filename = luaL_checkstring(L, 4); @@ -1136,6 +1249,8 @@ int ModApiMapgen::l_create_schematic(lua_State *L) // place_schematic(p, schematic, rotation, replacement) int ModApiMapgen::l_place_schematic(lua_State *L) { + MAP_LOCK_REQUIRED; + Map *map = &(getEnv(L)->getMap()); SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; @@ -1165,15 +1280,59 @@ int ModApiMapgen::l_place_schematic(lua_State *L) return 0; } - schem->placeStructure(map, p, 0, (Rotation)rot, force_placement); + schem->placeOnMap(map, p, 0, (Rotation)rot, force_placement); lua_pushboolean(L, true); return 1; } +int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + + //// Read VoxelManip object + MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm; + + //// Read position + v3s16 p = check_v3s16(L, 2); + + //// Read rotation + int rot = ROTATE_0; + const char *enumstr = lua_tostring(L, 4); + if (enumstr) + string_to_enum(es_Rotation, rot, std::string(enumstr)); + + //// Read force placement + bool force_placement = true; + if (lua_isboolean(L, 6)) + force_placement = lua_toboolean(L, 6); + + //// Read node replacements + StringMap replace_names; + if (lua_istable(L, 5)) + read_schematic_replacements(L, 5, &replace_names); + + //// Read schematic + Schematic *schem = get_or_load_schematic(L, 3, schemmgr, &replace_names); + if (!schem) { + errorstream << "place_schematic: failed to get schematic" << std::endl; + return 0; + } + + bool schematic_did_fit = schem->placeOnVManip( + vm, p, 0, (Rotation)rot, force_placement); + + lua_pushboolean(L, schematic_did_fit); + return 1; +} + // serialize_schematic(schematic, format, options={...}) int ModApiMapgen::l_serialize_schematic(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; //// Read options @@ -1223,6 +1382,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) void ModApiMapgen::Initialize(lua_State *L, int top) { + API_FCT(get_biome_id); API_FCT(get_mapgen_object); API_FCT(get_mapgen_params); @@ -1246,5 +1406,6 @@ void ModApiMapgen::Initialize(lua_State *L, int top) API_FCT(generate_decorations); API_FCT(create_schematic); API_FCT(place_schematic); + API_FCT(place_schematic_on_vmanip); API_FCT(serialize_schematic); } diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index 7440d1285..9751c0db6 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -24,6 +24,10 @@ with this program; if not, write to the Free Software Foundation, Inc., class ModApiMapgen : public ModApiBase { private: + // get_biome_id(biomename) + // returns the biome id used in biomemap + static int l_get_biome_id(lua_State *L); + // get_mapgen_object(objectname) // returns the requested object used during map generation static int l_get_mapgen_object(lua_State *L); @@ -81,9 +85,13 @@ private: // create_schematic(p1, p2, probability_list, filename) static int l_create_schematic(lua_State *L); - // place_schematic(p, schematic, rotation, replacement) + // place_schematic(p, schematic, rotation, replacements, force_placement) static int l_place_schematic(lua_State *L); + // place_schematic_on_vmanip(vm, p, schematic, + // rotation, replacements, force_placement) + static int l_place_schematic_on_vmanip(lua_State *L); + // serialize_schematic(schematic, format, options={...}) static int l_serialize_schematic(lua_State *L); diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 6cdbe5c68..c8bc7d558 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "environment.h" #include "map.h" +#include "gamedef.h" #include "nodemetadata.h" @@ -43,7 +44,7 @@ NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create) { NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); if(meta == NULL && auto_create) { - meta = new NodeMetadata(ref->m_env->getGameDef()); + meta = new NodeMetadata(ref->m_env->getGameDef()->idef()); if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) { delete meta; return NULL; @@ -81,6 +82,8 @@ int NodeMetaRef::gc_object(lua_State *L) { // get_string(self, name) int NodeMetaRef::l_get_string(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); std::string name = luaL_checkstring(L, 2); @@ -97,6 +100,8 @@ int NodeMetaRef::l_get_string(lua_State *L) // set_string(self, name, var) int NodeMetaRef::l_set_string(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); std::string name = luaL_checkstring(L, 2); size_t len = 0; @@ -114,6 +119,8 @@ int NodeMetaRef::l_set_string(lua_State *L) // get_int(self, name) int NodeMetaRef::l_get_int(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); std::string name = lua_tostring(L, 2); @@ -130,6 +137,8 @@ int NodeMetaRef::l_get_int(lua_State *L) // set_int(self, name, var) int NodeMetaRef::l_set_int(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); std::string name = lua_tostring(L, 2); int a = lua_tointeger(L, 3); @@ -146,6 +155,8 @@ int NodeMetaRef::l_set_int(lua_State *L) // get_float(self, name) int NodeMetaRef::l_get_float(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); std::string name = lua_tostring(L, 2); @@ -162,6 +173,8 @@ int NodeMetaRef::l_get_float(lua_State *L) // set_float(self, name, var) int NodeMetaRef::l_set_float(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); std::string name = lua_tostring(L, 2); float a = lua_tonumber(L, 3); @@ -178,6 +191,8 @@ int NodeMetaRef::l_set_float(lua_State *L) // get_inventory(self) int NodeMetaRef::l_get_inventory(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); getmeta(ref, true); // try to ensure the metadata exists InvRef::createNodeMeta(L, ref->m_p); @@ -187,6 +202,8 @@ int NodeMetaRef::l_get_inventory(lua_State *L) // to_table(self) int NodeMetaRef::l_to_table(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); NodeMetadata *meta = getmeta(ref, true); @@ -229,6 +246,8 @@ int NodeMetaRef::l_to_table(lua_State *L) // from_table(self, table) int NodeMetaRef::l_from_table(lua_State *L) { + MAP_LOCK_REQUIRED; + NodeMetaRef *ref = checkobject(L, 1); int base = 2; diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp index c81a7ebc9..601113516 100644 --- a/src/script/lua_api/l_nodetimer.cpp +++ b/src/script/lua_api/l_nodetimer.cpp @@ -39,6 +39,7 @@ NodeTimerRef* NodeTimerRef::checkobject(lua_State *L, int narg) int NodeTimerRef::l_set(lua_State *L) { + MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); ServerEnvironment *env = o->m_env; if(env == NULL) return 0; @@ -50,6 +51,7 @@ int NodeTimerRef::l_set(lua_State *L) int NodeTimerRef::l_start(lua_State *L) { + MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); ServerEnvironment *env = o->m_env; if(env == NULL) return 0; @@ -60,6 +62,7 @@ int NodeTimerRef::l_start(lua_State *L) int NodeTimerRef::l_stop(lua_State *L) { + MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); ServerEnvironment *env = o->m_env; if(env == NULL) return 0; @@ -69,6 +72,7 @@ int NodeTimerRef::l_stop(lua_State *L) int NodeTimerRef::l_is_started(lua_State *L) { + MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); ServerEnvironment *env = o->m_env; if(env == NULL) return 0; @@ -80,6 +84,7 @@ int NodeTimerRef::l_is_started(lua_State *L) int NodeTimerRef::l_get_timeout(lua_State *L) { + MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); ServerEnvironment *env = o->m_env; if(env == NULL) return 0; @@ -91,6 +96,7 @@ int NodeTimerRef::l_get_timeout(lua_State *L) int NodeTimerRef::l_get_elapsed(lua_State *L) { + MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); ServerEnvironment *env = o->m_env; if(env == NULL) return 0; diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index c8dc2d2dc..04dc6048f 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_converter.h" #include "common/c_content.h" #include "log.h" +#include "porting.h" +#include "util/numeric.h" /////////////////////////////////////// /* @@ -410,6 +412,7 @@ const luaL_reg LuaPerlinNoiseMap::methods[] = { int LuaPseudoRandom::l_next(lua_State *L) { NO_MAP_LOCK_REQUIRED; + LuaPseudoRandom *o = checkobject(L, 1); int min = 0; int max = 32767; @@ -437,7 +440,9 @@ int LuaPseudoRandom::l_next(lua_State *L) int LuaPseudoRandom::create_object(lua_State *L) { - int seed = luaL_checknumber(L, 1); + NO_MAP_LOCK_REQUIRED; + + u64 seed = luaL_checknumber(L, 1); LuaPseudoRandom *o = new LuaPseudoRandom(seed); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); @@ -532,8 +537,10 @@ int LuaPcgRandom::l_rand_normal_dist(lua_State *L) int LuaPcgRandom::create_object(lua_State *L) { - lua_Integer seed = luaL_checknumber(L, 1); - LuaPcgRandom *o = lua_isnumber(L, 2) ? + NO_MAP_LOCK_REQUIRED; + + u64 seed = luaL_checknumber(L, 1); + LuaPcgRandom *o = lua_isnumber(L, 2) ? new LuaPcgRandom(seed, lua_tointeger(L, 2)) : new LuaPcgRandom(seed); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; @@ -595,3 +602,116 @@ const luaL_reg LuaPcgRandom::methods[] = { luamethod(LuaPcgRandom, rand_normal_dist), {0,0} }; + +/////////////////////////////////////// +/* + LuaSecureRandom +*/ + +bool LuaSecureRandom::fillRandBuf() +{ + return porting::secure_rand_fill_buf(m_rand_buf, RAND_BUF_SIZE); +} + +int LuaSecureRandom::l_next_bytes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + LuaSecureRandom *o = checkobject(L, 1); + u32 count = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : 1; + + // Limit count + count = MYMIN(RAND_BUF_SIZE, count); + + // Find out whether we can pass directly from our array, or have to do some gluing + size_t count_remaining = RAND_BUF_SIZE - o->m_rand_idx; + if (count_remaining >= count) { + lua_pushlstring(L, o->m_rand_buf + o->m_rand_idx, count); + o->m_rand_idx += count; + } else { + char output_buf[RAND_BUF_SIZE]; + + // Copy over with what we have left from our current buffer + memcpy(output_buf, o->m_rand_buf + o->m_rand_idx, count_remaining); + + // Refill buffer and copy over the remainder of what was requested + o->fillRandBuf(); + memcpy(output_buf + count_remaining, o->m_rand_buf, count - count_remaining); + + // Update index + o->m_rand_idx = count - count_remaining; + + lua_pushlstring(L, output_buf, count); + } + + return 1; +} + + +int LuaSecureRandom::create_object(lua_State *L) +{ + LuaSecureRandom *o = new LuaSecureRandom(); + + // Fail and return nil if we can't securely fill the buffer + if (!o->fillRandBuf()) { + delete o; + return 0; + } + + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + return 1; +} + + +int LuaSecureRandom::gc_object(lua_State *L) +{ + LuaSecureRandom *o = *(LuaSecureRandom **)(lua_touserdata(L, 1)); + delete o; + return 0; +} + + +LuaSecureRandom *LuaSecureRandom::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 *(LuaSecureRandom **)ud; +} + + +void LuaSecureRandom::Register(lua_State *L) +{ + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pop(L, 1); + + luaL_openlib(L, 0, methods, 0); + lua_pop(L, 1); + + lua_register(L, className, create_object); +} + +const char LuaSecureRandom::className[] = "SecureRandom"; +const luaL_reg LuaSecureRandom::methods[] = { + luamethod(LuaSecureRandom, next_bytes), + {0,0} +}; diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h index e958c5a23..492eb7550 100644 --- a/src/script/lua_api/l_noise.h +++ b/src/script/lua_api/l_noise.h @@ -160,4 +160,37 @@ public: static void Register(lua_State *L); }; + +/* + LuaSecureRandom +*/ +class LuaSecureRandom : public ModApiBase { +private: + static const size_t RAND_BUF_SIZE = 2048; + static const char className[]; + static const luaL_reg methods[]; + + u32 m_rand_idx; + char m_rand_buf[RAND_BUF_SIZE]; + + // Exported functions + + // garbage collector + static int gc_object(lua_State *L); + + // next_bytes(self, count) -> get count many bytes + static int l_next_bytes(lua_State *L); + +public: + bool fillRandBuf(); + + // LuaSecureRandom() + // Creates an LuaSecureRandom and leaves it on top of stack + static int create_object(lua_State *L); + + static LuaSecureRandom *checkobject(lua_State *L, int narg); + + static void Register(lua_State *L); +}; + #endif /* L_NOISE_H_ */ diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 3ac8eeefb..6d6614e7d 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -31,10 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "scripting_game.h" -#define GET_ENV_PTR ServerEnvironment* env = \ - dynamic_cast<ServerEnvironment*>(getEnv(L)); \ - if (env == NULL) return 0 - struct EnumString es_HudElementType[] = { {HUD_ELEM_IMAGE, "image"}, @@ -132,7 +128,6 @@ int ObjectRef::gc_object(lua_State *L) { // remove(self) int ObjectRef::l_remove(lua_State *L) { - NO_MAP_LOCK_REQUIRED; GET_ENV_PTR; ObjectRef *ref = checkobject(L, 1); @@ -409,6 +404,7 @@ int ObjectRef::l_get_armor_groups(lua_State *L) // physics_override_gravity, sneak, sneak_glitch) int ObjectRef::l_set_physics_override(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); PlayerSAO *co = (PlayerSAO *) getobject(ref); if (co == NULL) return 0; @@ -441,6 +437,7 @@ int ObjectRef::l_set_physics_override(lua_State *L) // get_physics_override(self) int ObjectRef::l_get_physics_override(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); PlayerSAO *co = (PlayerSAO *)getobject(ref); if (co == NULL) @@ -509,7 +506,7 @@ int ObjectRef::l_get_animation(lua_State *L) // set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed) int ObjectRef::l_set_local_animation(lua_State *L) { - //NO_MAP_LOCK_REQUIRED; + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -534,7 +531,7 @@ int ObjectRef::l_set_local_animation(lua_State *L) // get_local_animation(self) int ObjectRef::l_get_local_animation(lua_State *L) { - //NO_MAP_LOCK_REQUIRED + NO_MAP_LOCK_REQUIRED ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -555,7 +552,7 @@ int ObjectRef::l_get_local_animation(lua_State *L) // set_eye_offset(self, v3f first pv, v3f third pv) int ObjectRef::l_set_eye_offset(lua_State *L) { - //NO_MAP_LOCK_REQUIRED; + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -585,7 +582,7 @@ int ObjectRef::l_set_eye_offset(lua_State *L) // get_eye_offset(self) int ObjectRef::l_get_eye_offset(lua_State *L) { - //NO_MAP_LOCK_REQUIRED; + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -642,7 +639,6 @@ int ObjectRef::l_get_bone_position(lua_State *L) // set_attach(self, parent, bone, position, rotation) int ObjectRef::l_set_attach(lua_State *L) { - NO_MAP_LOCK_REQUIRED; GET_ENV_PTR; ObjectRef *ref = checkobject(L, 1); @@ -681,7 +677,6 @@ int ObjectRef::l_set_attach(lua_State *L) // get_attach(self) int ObjectRef::l_get_attach(lua_State *L) { - NO_MAP_LOCK_REQUIRED; GET_ENV_PTR; ObjectRef *ref = checkobject(L, 1); @@ -709,7 +704,6 @@ int ObjectRef::l_get_attach(lua_State *L) // set_detach(self) int ObjectRef::l_set_detach(lua_State *L) { - NO_MAP_LOCK_REQUIRED; GET_ENV_PTR; ObjectRef *ref = checkobject(L, 1); @@ -773,6 +767,59 @@ int ObjectRef::l_is_player(lua_State *L) return 1; } +// set_nametag_attributes(self, attributes) +int ObjectRef::l_set_nametag_attributes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + + if (co == NULL) + return 0; + ObjectProperties *prop = co->accessObjectProperties(); + if (!prop) + return 0; + + lua_getfield(L, 2, "color"); + if (!lua_isnil(L, -1)) { + video::SColor color = prop->nametag_color; + read_color(L, -1, &color); + prop->nametag_color = color; + } + lua_pop(L, 1); + + std::string nametag = getstringfield_default(L, 2, "text", ""); + if (nametag != "") + prop->nametag = nametag; + + co->notifyObjectPropertiesModified(); + lua_pushboolean(L, true); + return 1; +} + +// get_nametag_attributes(self) +int ObjectRef::l_get_nametag_attributes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + ServerActiveObject *co = getobject(ref); + + if (co == NULL) + return 0; + ObjectProperties *prop = co->accessObjectProperties(); + if (!prop) + return 0; + + video::SColor color = prop->nametag_color; + + lua_newtable(L); + push_ARGB8(L, color); + lua_setfield(L, -2, "color"); + lua_pushstring(L, prop->nametag.c_str()); + lua_setfield(L, -2, "text"); + return 1; +} + /* LuaEntitySAO-only */ // setvelocity(self, {x=num, y=num, z=num}) @@ -1137,6 +1184,7 @@ int ObjectRef::l_get_player_control_bits(lua_State *L) // hud_add(self, form) int ObjectRef::l_hud_add(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1187,7 +1235,7 @@ int ObjectRef::l_hud_add(lua_State *L) } u32 id = getServer(L)->hudAdd(player, elem); - if (id == (u32)-1) { + if (id == U32_MAX) { delete elem; return 0; } @@ -1199,6 +1247,7 @@ int ObjectRef::l_hud_add(lua_State *L) // hud_remove(self, id) int ObjectRef::l_hud_remove(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1218,6 +1267,7 @@ int ObjectRef::l_hud_remove(lua_State *L) // hud_change(self, id, stat, data) int ObjectRef::l_hud_change(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1294,6 +1344,7 @@ int ObjectRef::l_hud_change(lua_State *L) // hud_get(self, id) int ObjectRef::l_hud_get(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1344,6 +1395,7 @@ int ObjectRef::l_hud_get(lua_State *L) // hud_set_flags(self, flags) int ObjectRef::l_hud_set_flags(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1369,6 +1421,7 @@ int ObjectRef::l_hud_set_flags(lua_State *L) int ObjectRef::l_hud_get_flags(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1394,6 +1447,7 @@ int ObjectRef::l_hud_get_flags(lua_State *L) // hud_set_hotbar_itemcount(self, hotbar_itemcount) int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1411,6 +1465,7 @@ int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L) // hud_get_hotbar_itemcount(self) int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1425,6 +1480,7 @@ int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L) // hud_set_hotbar_image(self, name) int ObjectRef::l_hud_set_hotbar_image(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1439,6 +1495,7 @@ int ObjectRef::l_hud_set_hotbar_image(lua_State *L) // hud_get_hotbar_image(self) int ObjectRef::l_hud_get_hotbar_image(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1452,6 +1509,7 @@ int ObjectRef::l_hud_get_hotbar_image(lua_State *L) // hud_set_hotbar_selected_image(self, name) int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1466,6 +1524,7 @@ int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L) // hud_get_hotbar_selected_image(self) int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1479,6 +1538,7 @@ int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L) // set_sky(self, bgcolor, type, list) int ObjectRef::l_set_sky(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1517,6 +1577,7 @@ int ObjectRef::l_set_sky(lua_State *L) // get_sky(self) int ObjectRef::l_get_sky(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1544,6 +1605,7 @@ int ObjectRef::l_get_sky(lua_State *L) // override_day_night_ratio(self, brightness=0...1) int ObjectRef::l_override_day_night_ratio(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1566,6 +1628,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L) // get_day_night_ratio(self) int ObjectRef::l_get_day_night_ratio(lua_State *L) { + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); Player *player = getplayer(ref); if (player == NULL) @@ -1583,45 +1646,6 @@ int ObjectRef::l_get_day_night_ratio(lua_State *L) return 1; } -// set_nametag_attributes(self, attributes) -int ObjectRef::l_set_nametag_attributes(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - ObjectRef *ref = checkobject(L, 1); - PlayerSAO *playersao = getplayersao(ref); - if (playersao == NULL) - return 0; - - lua_getfield(L, 2, "color"); - if (!lua_isnil(L, -1)) { - video::SColor color = playersao->getNametagColor(); - if (!read_color(L, -1, &color)) - return 0; - playersao->setNametagColor(color); - } - - lua_pushboolean(L, true); - return 1; -} - -// get_nametag_attributes(self) -int ObjectRef::l_get_nametag_attributes(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - ObjectRef *ref = checkobject(L, 1); - PlayerSAO *playersao = getplayersao(ref); - if (playersao == NULL) - return 0; - - video::SColor color = playersao->getNametagColor(); - - lua_newtable(L); - push_ARGB8(L, color); - lua_setfield(L, -2, "color"); - - return 1; -} - ObjectRef::ObjectRef(ServerActiveObject *object): m_object(object) { @@ -1709,6 +1733,8 @@ const luaL_reg ObjectRef::methods[] = { luamethod(ObjectRef, set_detach), luamethod(ObjectRef, set_properties), luamethod(ObjectRef, get_properties), + luamethod(ObjectRef, set_nametag_attributes), + luamethod(ObjectRef, get_nametag_attributes), // LuaEntitySAO-only luamethod(ObjectRef, setvelocity), luamethod(ObjectRef, getvelocity), @@ -1758,7 +1784,5 @@ const luaL_reg ObjectRef::methods[] = { luamethod(ObjectRef, get_local_animation), luamethod(ObjectRef, set_eye_offset), luamethod(ObjectRef, get_eye_offset), - luamethod(ObjectRef, set_nametag_attributes), - luamethod(ObjectRef, get_nametag_attributes), {0,0} }; diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp index 2532b2b08..f6c1725de 100644 --- a/src/script/lua_api/l_particles.cpp +++ b/src/script/lua_api/l_particles.cpp @@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc., // texture = e.g."default_wood.png" int ModApiParticles::l_add_particle(lua_State *L) { + MAP_LOCK_REQUIRED; + // Get parameters v3f pos, vel, acc; pos = vel = acc = v3f(0, 0, 0); @@ -119,6 +121,8 @@ int ModApiParticles::l_add_particle(lua_State *L) // texture = e.g."default_wood.png" int ModApiParticles::l_add_particlespawner(lua_State *L) { + MAP_LOCK_REQUIRED; + // Get parameters u16 amount = 1; v3f minpos, maxpos, minvel, maxvel, minacc, maxacc; @@ -208,6 +212,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) // player (string) is optional int ModApiParticles::l_delete_particlespawner(lua_State *L) { + MAP_LOCK_REQUIRED; + // Get parameters u32 id = luaL_checknumber(L, 1); std::string playername = ""; diff --git a/src/script/lua_api/l_rollback.cpp b/src/script/lua_api/l_rollback.cpp index 5744e6813..482b0cbf5 100644 --- a/src/script/lua_api/l_rollback.cpp +++ b/src/script/lua_api/l_rollback.cpp @@ -38,6 +38,8 @@ void push_RollbackNode(lua_State *L, RollbackNode &node) // rollback_get_node_actions(pos, range, seconds, limit) -> {{actor, pos, time, oldnode, newnode}, ...} int ModApiRollback::l_rollback_get_node_actions(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + v3s16 pos = read_v3s16(L, 1); int range = luaL_checknumber(L, 2); time_t seconds = (time_t) luaL_checknumber(L, 3); @@ -79,6 +81,8 @@ int ModApiRollback::l_rollback_get_node_actions(lua_State *L) // rollback_revert_actions_by(actor, seconds) -> bool, log messages int ModApiRollback::l_rollback_revert_actions_by(lua_State *L) { + MAP_LOCK_REQUIRED; + std::string actor = luaL_checkstring(L, 1); int seconds = luaL_checknumber(L, 2); Server *server = getServer(L); diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 73eca9d60..59d3f5c70 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // request_shutdown() int ModApiServer::l_request_shutdown(lua_State *L) { + NO_MAP_LOCK_REQUIRED; const char *msg = lua_tolstring(L, 1, NULL); bool reconnect = lua_toboolean(L, 2); getServer(L)->requestShutdown(msg ? msg : "", reconnect); @@ -44,6 +45,16 @@ int ModApiServer::l_get_server_status(lua_State *L) return 1; } +// print(text) +int ModApiServer::l_print(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + std::string text; + text = luaL_checkstring(L, 1); + getServer(L)->printToConsoleOnly(text); + return 0; +} + // chat_send_all(text) int ModApiServer::l_chat_send_all(lua_State *L) { @@ -110,7 +121,7 @@ int ModApiServer::l_get_player_ip(lua_State *L) } catch(con::PeerNotFoundException) // unlikely { - dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; + dstream << FUNCTION_NAME << ": peer was not found" << std::endl; lua_pushnil(L); // error return 1; } @@ -136,7 +147,7 @@ int ModApiServer::l_get_player_information(lua_State *L) } catch(con::PeerNotFoundException) // unlikely { - dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; + dstream << FUNCTION_NAME << ": peer was not found" << std::endl; lua_pushnil(L); // error return 1; } @@ -150,7 +161,7 @@ int ModApiServer::l_get_player_information(lua_State *L) #define ERET(code) \ if (!(code)) { \ - dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; \ + dstream << FUNCTION_NAME << ": peer was not found" << std::endl; \ lua_pushnil(L); /* error */ \ return 1; \ } @@ -281,7 +292,7 @@ int ModApiServer::l_ban_player(lua_State *L) } catch(con::PeerNotFoundException) // unlikely { - dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; + dstream << FUNCTION_NAME << ": peer was not found" << std::endl; lua_pushboolean(L, false); // error return 1; } @@ -345,7 +356,7 @@ int ModApiServer::l_show_formspec(lua_State *L) int ModApiServer::l_get_current_modname(lua_State *L) { NO_MAP_LOCK_REQUIRED; - lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); return 1; } @@ -442,7 +453,7 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L) int ModApiServer::l_get_last_run_mod(lua_State *L) { NO_MAP_LOCK_REQUIRED; - lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); const char *current_mod = lua_tostring(L, -1); if (current_mod == NULL || current_mod[0] == '\0') { lua_pop(L, 1); @@ -504,6 +515,8 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(get_modpath); API_FCT(get_modnames); + API_FCT(print); + API_FCT(chat_send_all); API_FCT(chat_send_player); API_FCT(show_formspec); diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index df31f325f..06a5ddc24 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -46,6 +46,9 @@ private: // the returned list is sorted alphabetically for you static int l_get_modnames(lua_State *L); + // print(text) + static int l_print(lua_State *L); + // chat_send_all(text) static int l_chat_send_all(lua_State *L); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 12146e80a..c3e6c8964 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -25,9 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serialization.h" #include "json/json.h" #include "cpp_api/s_security.h" -#include "areastore.h" -#include "debug.h" #include "porting.h" +#include "debug.h" #include "log.h" #include "tool.h" #include "filesys.h" @@ -35,70 +34,49 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/auth.h" #include <algorithm> -// debug(...) -// Writes a line to dstream -int ModApiUtil::l_debug(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - // Handle multiple parameters to behave like standard lua print() - int n = lua_gettop(L); - lua_getglobal(L, "tostring"); - for (int i = 1; i <= n; i++) { - /* - Call tostring(i-th argument). - This is what print() does, and it behaves a bit - differently from directly calling lua_tostring. - */ - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); - size_t len; - const char *s = lua_tolstring(L, -1, &len); - if (i > 1) - dstream << "\t"; - if (s) - dstream << std::string(s, len); - lua_pop(L, 1); - } - dstream << std::endl; - return 0; -} - // log([level,] text) // Writes a line to the logger. // The one-argument version logs to infostream. -// The two-argument version accept a log level: error, action, info, or verbose. +// The two-argument version accepts a log level. +// Either the special case "deprecated" for deprecation notices, or any specified in +// Logger::stringToLevel(name). int ModApiUtil::l_log(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::string text; - LogMessageLevel level = LMT_INFO; + LogLevel level = LL_NONE; if (lua_isnone(L, 2)) { - text = lua_tostring(L, 1); - } - else { - std::string levelname = luaL_checkstring(L, 1); + text = luaL_checkstring(L, 1); + } else { + std::string name = luaL_checkstring(L, 1); text = luaL_checkstring(L, 2); - if(levelname == "error") - level = LMT_ERROR; - else if(levelname == "action") - level = LMT_ACTION; - else if(levelname == "verbose") - level = LMT_VERBOSE; - else if (levelname == "deprecated") { - log_deprecated(L,text); + if (name == "deprecated") { + log_deprecated(L, text); return 0; } - + level = Logger::stringToLevel(name); + if (level == LL_MAX) { + warningstream << "Tried to log at unknown level '" << name + << "'. Defaulting to \"none\"." << std::endl; + level = LL_NONE; + } } - log_printline(level, text); + g_logger.log(level, text); return 0; } +// get_us_time() +int ModApiUtil::l_get_us_time(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + lua_pushnumber(L, porting::getTimeUs()); + return 1; +} + #define CHECK_SECURE_SETTING(L, name) \ - if (name.compare(0, 7, "secure.") == 0) {\ - lua_pushliteral(L, "Attempt to set secure setting.");\ - lua_error(L);\ + if (ScriptApiSecurity::isSecure(L) && \ + name.compare(0, 7, "secure.") == 0) { \ + throw LuaError("Attempt to set secure setting."); \ } // setting_set(name, value) @@ -183,8 +161,14 @@ int ModApiUtil::l_parse_json(lua_State *L) if (!reader.parse(stream, root)) { errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages(); - errorstream << "data: \"" << jsonstr << "\"" - << std::endl; + size_t jlen = strlen(jsonstr); + if (jlen > 100) { + errorstream << "Data (" << jlen + << " bytes) printed to warningstream." << std::endl; + warningstream << "data: \"" << jsonstr << "\"" << std::endl; + } else { + errorstream << "data: \"" << jsonstr << "\"" << std::endl; + } lua_pushnil(L); return 1; } @@ -267,7 +251,7 @@ int ModApiUtil::l_get_password_hash(lua_State *L) NO_MAP_LOCK_REQUIRED; std::string name = luaL_checkstring(L, 1); std::string raw_password = luaL_checkstring(L, 2); - std::string hash = translatePassword(name, raw_password); + std::string hash = translate_password(name, raw_password); lua_pushstring(L, hash.c_str()); return 1; } @@ -290,6 +274,8 @@ int ModApiUtil::l_is_yes(lua_State *L) int ModApiUtil::l_get_builtin_path(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + std::string path = porting::path_share + DIR_DELIM + "builtin"; lua_pushstring(L, path.c_str()); return 1; @@ -298,6 +284,8 @@ int ModApiUtil::l_get_builtin_path(lua_State *L) // compress(data, method, level) int ModApiUtil::l_compress(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + size_t size; const char *data = luaL_checklstring(L, 1, &size); @@ -317,6 +305,8 @@ int ModApiUtil::l_compress(lua_State *L) // decompress(data, method) int ModApiUtil::l_decompress(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + size_t size; const char *data = luaL_checklstring(L, 1, &size); @@ -367,32 +357,57 @@ int ModApiUtil::l_get_dir_list(lua_State *L) int ModApiUtil::l_request_insecure_environment(lua_State *L) { NO_MAP_LOCK_REQUIRED; + + // Just return _G if security is disabled if (!ScriptApiSecurity::isSecure(L)) { lua_getglobal(L, "_G"); return 1; } - lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + + // We have to make sure that this function is being called directly by + // a mod, otherwise a malicious mod could override this function and + // steal its return value. + lua_Debug info; + // Make sure there's only one item below this function on the stack... + if (lua_getstack(L, 2, &info)) { + return 0; + } + FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); + FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); + // ...and that that item is the main file scope. + if (strcmp(info.what, "main") != 0) { + return 0; + } + + // Get mod name + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); if (!lua_isstring(L, -1)) { - lua_pushnil(L); - return 1; + return 0; } + + // Check secure.trusted_mods const char *mod_name = lua_tostring(L, -1); std::string trusted_mods = g_settings->get("secure.trusted_mods"); + trusted_mods.erase(std::remove(trusted_mods.begin(), + trusted_mods.end(), ' '), trusted_mods.end()); std::vector<std::string> mod_list = str_split(trusted_mods, ','); - if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) { - lua_pushnil(L); - return 1; + if (std::find(mod_list.begin(), mod_list.end(), mod_name) == + mod_list.end()) { + return 0; } - lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup"); + + // Push insecure environment + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); return 1; } void ModApiUtil::Initialize(lua_State *L, int top) { - API_FCT(debug); API_FCT(log); + API_FCT(get_us_time); + API_FCT(setting_set); API_FCT(setting_get); API_FCT(setting_setbool); @@ -422,9 +437,10 @@ void ModApiUtil::Initialize(lua_State *L, int top) void ModApiUtil::InitializeAsync(AsyncEngine& engine) { - ASYNC_API_FCT(debug); ASYNC_API_FCT(log); + ASYNC_API_FCT(get_us_time); + //ASYNC_API_FCT(setting_set); ASYNC_API_FCT(setting_get); //ASYNC_API_FCT(setting_setbool); diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index e75aa28cb..6fac7e7eb 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -35,16 +35,15 @@ private: GUIEngine instance should be in here. */ - // debug(text) - // Writes a line to dstream - static int l_debug(lua_State *L); - // log([level,] text) // Writes a line to the logger. // The one-argument version logs to infostream. - // The two-argument version accept a log level: error, action, info, or verbose. + // The two-argument version accepts a log level. static int l_log(lua_State *L); + // get us precision time + static int l_get_us_time(lua_State *L); + // setting_set(name, value) static int l_setting_set(lua_State *L); diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp index ac6c10303..f13866408 100644 --- a/src/script/lua_api/l_vmanip.cpp +++ b/src/script/lua_api/l_vmanip.cpp @@ -28,10 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server.h" #include "mapgen.h" -#define GET_ENV_PTR ServerEnvironment* env = \ - dynamic_cast<ServerEnvironment*>(getEnv(L)); \ - if (env == NULL) return 0 - // garbage collector int LuaVoxelManip::gc_object(lua_State *L) { @@ -43,6 +39,8 @@ int LuaVoxelManip::gc_object(lua_State *L) int LuaVoxelManip::l_read_from_map(lua_State *L) { + MAP_LOCK_REQUIRED; + LuaVoxelManip *o = checkobject(L, 1); MMVManip *vm = o->vm; @@ -108,6 +106,8 @@ int LuaVoxelManip::l_set_data(lua_State *L) int LuaVoxelManip::l_write_to_map(lua_State *L) { + MAP_LOCK_REQUIRED; + LuaVoxelManip *o = checkobject(L, 1); MMVManip *vm = o->vm; @@ -119,23 +119,25 @@ int LuaVoxelManip::l_write_to_map(lua_State *L) int LuaVoxelManip::l_get_node_at(lua_State *L) { NO_MAP_LOCK_REQUIRED; - GET_ENV_PTR; + + INodeDefManager *ndef = getServer(L)->getNodeDefManager(); LuaVoxelManip *o = checkobject(L, 1); v3s16 pos = check_v3s16(L, 2); - pushnode(L, o->vm->getNodeNoExNoEmerge(pos), env->getGameDef()->ndef()); + pushnode(L, o->vm->getNodeNoExNoEmerge(pos), ndef); return 1; } int LuaVoxelManip::l_set_node_at(lua_State *L) { NO_MAP_LOCK_REQUIRED; - GET_ENV_PTR; + + INodeDefManager *ndef = getServer(L)->getNodeDefManager(); LuaVoxelManip *o = checkobject(L, 1); v3s16 pos = check_v3s16(L, 2); - MapNode n = readnode(L, 3, env->getGameDef()->ndef()); + MapNode n = readnode(L, 3, ndef); o->vm->setNodeNoEmerge(pos, n); @@ -179,6 +181,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L) v3s16 fpmax = vm->m_area.MaxEdge; v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock; v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock; + bool propagate_shadow = lua_isboolean(L, 4) ? lua_toboolean(L, 4) : true; sortBoxVerticies(pmin, pmax); if (!vm->m_area.contains(VoxelArea(pmin, pmax))) @@ -189,7 +192,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L) mg.ndef = ndef; mg.water_level = emerge->params.water_level; - mg.calcLighting(pmin, pmax, fpmin, fpmax); + mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow); return 0; } @@ -313,14 +316,12 @@ int LuaVoxelManip::l_set_param2_data(lua_State *L) int LuaVoxelManip::l_update_map(lua_State *L) { + GET_ENV_PTR; + LuaVoxelManip *o = checkobject(L, 1); if (o->is_mapgen_vm) return 0; - Environment *env = getEnv(L); - if (!env) - return 0; - Map *map = &(env->getMap()); // TODO: Optimize this by using Mapgen::calcLighting() instead @@ -359,6 +360,8 @@ int LuaVoxelManip::l_was_modified(lua_State *L) int LuaVoxelManip::l_get_emerged_area(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + LuaVoxelManip *o = checkobject(L, 1); push_v3s16(L, o->vm->m_area.MinEdge); @@ -400,11 +403,7 @@ LuaVoxelManip::~LuaVoxelManip() // Creates an LuaVoxelManip and leaves it on top of stack int LuaVoxelManip::create_object(lua_State *L) { - NO_MAP_LOCK_REQUIRED; - - Environment *env = getEnv(L); - if (!env) - return 0; + GET_ENV_PTR; Map *map = &(env->getMap()); LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ? |