diff options
author | Elias Fleckenstein <eliasfleckenstein@web.de> | 2021-09-19 20:56:13 +0200 |
---|---|---|
committer | Elias Fleckenstein <eliasfleckenstein@web.de> | 2021-09-19 20:56:13 +0200 |
commit | c8900e169a1ddceec07a449f1ae7c4322ff02036 (patch) | |
tree | 5156605fb473d25786426eb6876ba2e7d3b7507b /src/script | |
parent | 950d2c9b3e10cbace9236e820c8119d1abb9e01f (diff) | |
parent | e0529da5c84f224c380e6d5e063392cb01f85683 (diff) | |
download | dragonfireclient-c8900e169a1ddceec07a449f1ae7c4322ff02036.tar.xz |
Merge branch 'master' of https://github.com/minetest/minetest
Diffstat (limited to 'src/script')
47 files changed, 646 insertions, 397 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 897ca2862..8ca3a722f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -203,8 +203,6 @@ void read_object_properties(lua_State *L, int index, if (sao && 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); } } @@ -1407,26 +1405,28 @@ void read_inventory_list(lua_State *L, int tableindex, { if(tableindex < 0) tableindex = lua_gettop(L) + 1 + tableindex; + // If nil, delete list if(lua_isnil(L, tableindex)){ inv->deleteList(name); return; } - // Otherwise set list + + // Get Lua-specified items to insert into the list std::vector<ItemStack> items = read_items(L, tableindex,srv); - int listsize = (forcesize != -1) ? forcesize : items.size(); + size_t listsize = (forcesize >= 0) ? forcesize : items.size(); + + // Create or resize/clear list InventoryList *invlist = inv->addList(name, listsize); - int index = 0; - for(std::vector<ItemStack>::const_iterator - i = items.begin(); i != items.end(); ++i){ - if(forcesize != -1 && index == forcesize) - break; - invlist->changeItem(index, *i); - index++; + if (!invlist) { + luaL_error(L, "inventory list: cannot create list named '%s'", name); + return; } - while(forcesize != -1 && index < forcesize){ - invlist->deleteItem(index); - index++; + + for (size_t i = 0; i < items.size(); ++i) { + if (i == listsize) + break; // Truncate provided list of items + invlist->changeItem(i, items[i]); } } @@ -2013,6 +2013,8 @@ void read_hud_element(lua_State *L, HudElement *elem) elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f(); lua_pop(L, 1); + elem->style = getintfield_default(L, 2, "style", 0); + /* check for known deprecated element usage */ if ((elem->type == HUD_ELEM_STATBAR) && (elem->size == v2s32())) log_deprecated(L,"Deprecated usage of statbar without size!"); @@ -2067,17 +2069,22 @@ void push_hud_element(lua_State *L, HudElement *elem) lua_pushstring(L, elem->text2.c_str()); lua_setfield(L, -2, "text2"); + + lua_pushinteger(L, elem->style); + lua_setfield(L, -2, "style"); } -HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) +bool read_hud_change(lua_State *L, HudElementStat &stat, HudElement *elem, void **value) { - HudElementStat stat = HUD_STAT_NUMBER; - std::string statstr; - if (lua_isstring(L, 3)) { + std::string statstr = lua_tostring(L, 3); + { int statint; - statstr = lua_tostring(L, 3); - stat = string_to_enum(es_HudElementStat, statint, statstr) ? - (HudElementStat)statint : stat; + if (!string_to_enum(es_HudElementStat, statint, statstr)) { + script_log_unique(L, "Unknown HUD stat type: " + statstr, warningstream); + return false; + } + + stat = (HudElementStat)statint; } switch (stat) { @@ -2135,8 +2142,13 @@ HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) elem->text2 = luaL_checkstring(L, 4); *value = &elem->text2; break; + case HUD_STAT_STYLE: + elem->style = luaL_checknumber(L, 4); + *value = &elem->style; + break; } - return stat; + + return true; } /******************************************************************************/ diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index dc8f19ef3..1aed7901e 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -122,7 +122,7 @@ void push_object_properties (lua_State *L, void push_inventory (lua_State *L, Inventory *inventory); - + void push_inventory_list (lua_State *L, Inventory *inv, const char *name); @@ -197,14 +197,14 @@ void read_json_value (lua_State *L, Json::Value &root, void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm = false, bool hitpoint = false); -void push_objectRef (lua_State *L, const u16 id); +void push_objectRef (lua_State *L, const u16 id); -void read_hud_element (lua_State *L, HudElement *elem); +void read_hud_element (lua_State *L, HudElement *elem); -void push_hud_element (lua_State *L, HudElement *elem); +void push_hud_element (lua_State *L, HudElement *elem); -HudElementStat read_hud_change (lua_State *L, HudElement *elem, void **value); +bool read_hud_change (lua_State *L, HudElementStat &stat, HudElement *elem, void **value); -void push_collision_move_result(lua_State *L, const collisionMoveResult &res); +void push_collision_move_result(lua_State *L, const collisionMoveResult &res); -void push_physics_override (lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move); +void push_physics_override (lua_State *L, float speed, float jump, float gravity, bool sneak, bool sneak_glitch, bool new_move); diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index c00401b58..19734b913 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -51,12 +51,32 @@ if (value < F1000_MIN || value > F1000_MAX) { \ #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE) +/** + * A helper which sets (if available) the vector metatable from builtin as metatable + * for the table on top of the stack + */ +static void set_vector_metatable(lua_State *L) +{ + // get vector.metatable + lua_getglobal(L, "vector"); + if (!lua_istable(L, -1)) { + // there is no global vector table + lua_pop(L, 1); + errorstream << "set_vector_metatable in c_converter.cpp: " << + "missing global vector table" << std::endl; + return; + } + lua_getfield(L, -1, "metatable"); + // set the metatable + lua_setmetatable(L, -3); + // pop vector global + lua_pop(L, 1); +} + + void push_float_string(lua_State *L, float value) { - std::stringstream ss; - std::string str; - ss << value; - str = ss.str(); + auto str = ftos(value); lua_pushstring(L, str.c_str()); } @@ -69,6 +89,7 @@ void push_v3f(lua_State *L, v3f p) lua_setfield(L, -2, "y"); lua_pushnumber(L, p.Z); lua_setfield(L, -2, "z"); + set_vector_metatable(L); } void push_v2f(lua_State *L, v2f p) @@ -281,6 +302,7 @@ void push_v3s16(lua_State *L, v3s16 p) lua_setfield(L, -2, "y"); lua_pushinteger(L, p.Z); lua_setfield(L, -2, "z"); + set_vector_metatable(L); } v3s16 read_v3s16(lua_State *L, int index) diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index ad5f836c5..df82dba14 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -18,10 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "common/c_internal.h" +#include "util/numeric.h" #include "debug.h" #include "log.h" #include "porting.h" #include "settings.h" +#include <algorithm> // std::find std::string script_get_backtrace(lua_State *L) { @@ -99,60 +101,35 @@ void script_error(lua_State *L, int pcall_result, const char *mod, const char *f throw LuaError(err_msg); } -// Push the list of callbacks (a lua table). -// Then push nargs arguments. -// Then call this function, which -// - runs the callbacks -// - replaces the table and arguments with the return value, -// computed depending on mode -void script_run_callbacks_f(lua_State *L, int nargs, - RunCallbacksMode mode, const char *fxn) -{ - FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments"); - - // Insert error handler - PUSH_ERROR_HANDLER(L); - int error_handler = lua_gettop(L) - nargs - 1; - lua_insert(L, error_handler); - - // Insert run_callbacks between error handler and table - lua_getglobal(L, "core"); - lua_getfield(L, -1, "run_callbacks"); - lua_remove(L, -2); - lua_insert(L, error_handler + 1); - - // Insert mode after table - lua_pushnumber(L, (int) mode); - lua_insert(L, error_handler + 3); - - // Stack now looks like this: - // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n> - - int result = lua_pcall(L, nargs + 2, 1, error_handler); - if (result != 0) - script_error(L, result, NULL, fxn); - - lua_remove(L, error_handler); -} - -static void script_log(lua_State *L, const std::string &message, - std::ostream &log_to, bool do_error, int stack_depth) +static void script_log_add_source(lua_State *L, std::string &message, int stack_depth) { lua_Debug ar; - log_to << message << " "; if (lua_getstack(L, stack_depth, &ar)) { FATAL_ERROR_IF(!lua_getinfo(L, "Sl", &ar), "lua_getinfo() failed"); - log_to << "(at " << ar.short_src << ":" << ar.currentline << ")"; + message.append(" (at " + std::string(ar.short_src) + ":" + + std::to_string(ar.currentline) + ")"); } else { - log_to << "(at ?:?)"; + message.append(" (at ?:?)"); } - log_to << std::endl; +} - if (do_error) - script_error(L, LUA_ERRRUN, NULL, NULL); - else - infostream << script_get_backtrace(L) << std::endl; +bool script_log_unique(lua_State *L, std::string message, std::ostream &log_to, + int stack_depth) +{ + thread_local std::vector<u64> logged_messages; + + script_log_add_source(L, message, stack_depth); + u64 hash = murmur_hash_64_ua(message.data(), message.length(), 0xBADBABE); + + if (std::find(logged_messages.begin(), logged_messages.end(), hash) + == logged_messages.end()) { + + logged_messages.emplace_back(hash); + log_to << message << std::endl; + return true; + } + return false; } DeprecatedHandlingMode get_deprecated_handling_mode() @@ -174,9 +151,18 @@ DeprecatedHandlingMode get_deprecated_handling_mode() return ret; } -void log_deprecated(lua_State *L, const std::string &message, int stack_depth) +void log_deprecated(lua_State *L, std::string message, int stack_depth) { DeprecatedHandlingMode mode = get_deprecated_handling_mode(); - if (mode != DeprecatedHandlingMode::Ignore) - script_log(L, message, warningstream, mode == DeprecatedHandlingMode::Error, stack_depth); + if (mode == DeprecatedHandlingMode::Ignore) + return; + + script_log_add_source(L, message, stack_depth); + warningstream << message << std::endl; + + if (mode == DeprecatedHandlingMode::Error) + script_error(L, LUA_ERRRUN, NULL, NULL); + else + infostream << script_get_backtrace(L) << std::endl; } + diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h index 452c2dd5e..ab2d7b975 100644 --- a/src/script/common/c_internal.h +++ b/src/script/common/c_internal.h @@ -75,9 +75,6 @@ extern "C" { } \ } -#define script_run_callbacks(L, nargs, mode) \ - script_run_callbacks_f((L), (nargs), (mode), __FUNCTION__) - // What script_run_callbacks does with the return values of callbacks. // Regardless of the mode, if only one callback is defined, // its return value is the total return value. @@ -108,13 +105,17 @@ enum RunCallbacksMode // are converted by readParam<bool> to true or false, respectively. }; +// Gets a backtrace of the current execution point std::string script_get_backtrace(lua_State *L); +// Wrapper for CFunction calls that converts C++ exceptions to Lua errors int script_exception_wrapper(lua_State *L, lua_CFunction f); +// Takes an error from lua_pcall and throws it as a LuaError void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn); -void script_run_callbacks_f(lua_State *L, int nargs, - RunCallbacksMode mode, const char *fxn); -enum class DeprecatedHandlingMode { +bool script_log_unique(lua_State *L, std::string message, std::ostream &log_to, + int stack_depth = 1); + +enum DeprecatedHandlingMode { Ignore, Log, Error @@ -134,5 +135,4 @@ DeprecatedHandlingMode get_deprecated_handling_mode(); * @param message The deprecation method * @param stack_depth How far on the stack to the first user function (ie: not builtin or core) */ -void log_deprecated(lua_State *L, const std::string &message, - int stack_depth=1); +void log_deprecated(lua_State *L, std::string message, int stack_depth = 1); diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp index 0619b32c0..dacdcd75a 100644 --- a/src/script/cpp_api/s_async.cpp +++ b/src/script/cpp_api/s_async.cpp @@ -32,20 +32,19 @@ extern "C" { #include "filesys.h" #include "porting.h" #include "common/c_internal.h" +#include "lua_api/l_base.h" /******************************************************************************/ AsyncEngine::~AsyncEngine() { - // Request all threads to stop for (AsyncWorkerThread *workerThread : workerThreads) { workerThread->stop(); } - // Wake up all threads - for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin(); - it != workerThreads.end(); ++it) { + for (auto it : workerThreads) { + (void)it; jobQueueCounter.post(); } @@ -68,6 +67,7 @@ AsyncEngine::~AsyncEngine() /******************************************************************************/ void AsyncEngine::registerStateInitializer(StateInitializer func) { + FATAL_ERROR_IF(initDone, "Initializer may not be registered after init"); stateInitializers.push_back(func); } @@ -85,36 +85,36 @@ void AsyncEngine::initialize(unsigned int numEngines) } /******************************************************************************/ -unsigned int AsyncEngine::queueAsyncJob(const std::string &func, - const std::string ¶ms) +u32 AsyncEngine::queueAsyncJob(std::string &&func, std::string &¶ms, + const std::string &mod_origin) { jobQueueMutex.lock(); - LuaJobInfo toAdd; - toAdd.id = jobIdCounter++; - toAdd.serializedFunction = func; - toAdd.serializedParams = params; + u32 jobId = jobIdCounter++; - jobQueue.push_back(toAdd); + jobQueue.emplace_back(); + auto &to_add = jobQueue.back(); + to_add.id = jobId; + to_add.function = std::move(func); + to_add.params = std::move(params); + to_add.mod_origin = mod_origin; jobQueueCounter.post(); - jobQueueMutex.unlock(); - - return toAdd.id; + return jobId; } /******************************************************************************/ -LuaJobInfo AsyncEngine::getJob() +bool AsyncEngine::getJob(LuaJobInfo *job) { jobQueueCounter.wait(); jobQueueMutex.lock(); - LuaJobInfo retval; + bool retval = false; if (!jobQueue.empty()) { - retval = jobQueue.front(); + *job = std::move(jobQueue.front()); jobQueue.pop_front(); - retval.valid = true; + retval = true; } jobQueueMutex.unlock(); @@ -122,10 +122,10 @@ LuaJobInfo AsyncEngine::getJob() } /******************************************************************************/ -void AsyncEngine::putJobResult(const LuaJobInfo &result) +void AsyncEngine::putJobResult(LuaJobInfo &&result) { resultQueueMutex.lock(); - resultQueue.push_back(result); + resultQueue.emplace_back(std::move(result)); resultQueueMutex.unlock(); } @@ -134,26 +134,30 @@ void AsyncEngine::step(lua_State *L) { int error_handler = PUSH_ERROR_HANDLER(L); lua_getglobal(L, "core"); - resultQueueMutex.lock(); + + ScriptApiBase *script = ModApiBase::getScriptApiBase(L); + + MutexAutoLock autolock(resultQueueMutex); while (!resultQueue.empty()) { - LuaJobInfo jobDone = resultQueue.front(); + LuaJobInfo j = std::move(resultQueue.front()); resultQueue.pop_front(); lua_getfield(L, -1, "async_event_handler"); - - if (lua_isnil(L, -1)) { + if (lua_isnil(L, -1)) FATAL_ERROR("Async event handler does not exist!"); - } - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_pushinteger(L, jobDone.id); - lua_pushlstring(L, jobDone.serializedResult.data(), - jobDone.serializedResult.size()); + lua_pushinteger(L, j.id); + lua_pushlstring(L, j.result.data(), j.result.size()); - PCALL_RESL(L, lua_pcall(L, 2, 0, error_handler)); + // Call handler + const char *origin = j.mod_origin.empty() ? nullptr : j.mod_origin.c_str(); + script->setOriginDirect(origin); + int result = lua_pcall(L, 2, 0, error_handler); + if (result) + script_error(L, result, origin, "<async>"); } - resultQueueMutex.unlock(); + lua_pop(L, 2); // Pop core and error handler } @@ -168,8 +172,8 @@ void AsyncEngine::prepareEnvironment(lua_State* L, int top) /******************************************************************************/ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name) : - Thread(name), ScriptApiBase(ScriptingType::Async), + Thread(name), jobDispatcher(jobDispatcher) { lua_State *L = getStack(); @@ -196,9 +200,9 @@ void* AsyncWorkerThread::run() { lua_State *L = getStack(); - std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua"; try { - loadScript(script); + loadMod(getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua", + BUILTIN_MOD_NAME); } catch (const ModError &e) { errorstream << "Execution of async base environment failed: " << e.what() << std::endl; @@ -213,44 +217,44 @@ void* AsyncWorkerThread::run() } // Main loop + LuaJobInfo j; while (!stopRequested()) { // Wait for job - LuaJobInfo toProcess = jobDispatcher->getJob(); - - if (!toProcess.valid || stopRequested()) { + if (!jobDispatcher->getJob(&j) || stopRequested()) continue; - } lua_getfield(L, -1, "job_processor"); - if (lua_isnil(L, -1)) { + if (lua_isnil(L, -1)) FATAL_ERROR("Unable to get async job processor!"); - } - luaL_checktype(L, -1, LUA_TFUNCTION); - // Call it - lua_pushlstring(L, - toProcess.serializedFunction.data(), - toProcess.serializedFunction.size()); - lua_pushlstring(L, - toProcess.serializedParams.data(), - toProcess.serializedParams.size()); + if (luaL_loadbuffer(L, j.function.data(), j.function.size(), "=(async)")) { + errorstream << "ASYNC WORKER: Unable to deserialize function" << std::endl; + lua_pushnil(L); + } + lua_pushlstring(L, j.params.data(), j.params.size()); + // Call it + setOriginDirect(j.mod_origin.empty() ? nullptr : j.mod_origin.c_str()); int result = lua_pcall(L, 2, 1, error_handler); if (result) { - PCALL_RES(result); - toProcess.serializedResult = ""; + try { + scriptError(result, "<async>"); + } catch (const ModError &e) { + errorstream << e.what() << std::endl; + } } else { // Fetch result size_t length; const char *retval = lua_tolstring(L, -1, &length); - toProcess.serializedResult = std::string(retval, length); + j.result.assign(retval, length); } lua_pop(L, 1); // Pop retval // Put job result - jobDispatcher->putJobResult(toProcess); + if (!j.result.empty()) + jobDispatcher->putJobResult(std::move(j)); } lua_pop(L, 2); // Pop core and error handler diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index 99a4f891c..697cb0221 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <vector> #include <deque> -#include <map> #include "threading/semaphore.h" #include "threading/thread.h" @@ -39,26 +38,29 @@ struct LuaJobInfo { LuaJobInfo() = default; - // Function to be called in async environment - std::string serializedFunction = ""; - // Parameter to be passed to function - std::string serializedParams = ""; - // Result of function call - std::string serializedResult = ""; + // Function to be called in async environment (from string.dump) + std::string function; + // Parameter to be passed to function (serialized) + std::string params; + // Result of function call (serialized) + std::string result; + // Name of the mod who invoked this call + std::string mod_origin; // JobID used to identify a job and match it to callback - unsigned int id = 0; - - bool valid = false; + u32 id; }; // Asynchronous working environment -class AsyncWorkerThread : public Thread, public ScriptApiBase { +class AsyncWorkerThread : public Thread, virtual public ScriptApiBase { + friend class AsyncEngine; public: - AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name); virtual ~AsyncWorkerThread(); void *run(); +protected: + AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name); + private: AsyncEngine *jobDispatcher = nullptr; }; @@ -89,7 +91,8 @@ public: * @param params Serialized parameters * @return jobid The job is queued */ - unsigned int queueAsyncJob(const std::string &func, const std::string ¶ms); + u32 queueAsyncJob(std::string &&func, std::string &¶ms, + const std::string &mod_origin = ""); /** * Engine step to process finished jobs @@ -102,15 +105,16 @@ protected: /** * Get a Job from queue to be processed * this function blocks until a job is ready - * @return a job to be processed + * @param job a job to be processed + * @return whether a job was available */ - LuaJobInfo getJob(); + bool getJob(LuaJobInfo *job); /** * Put a Job result back to result queue * @param result result of completed job */ - void putJobResult(const LuaJobInfo &result); + void putJobResult(LuaJobInfo &&result); /** * Initialize environment with current registred functions @@ -129,11 +133,10 @@ private: std::vector<StateInitializer> stateInitializers; // Internal counter to create job IDs - unsigned int jobIdCounter = 0; + u32 jobIdCounter = 0; // Mutex to protect job queue std::mutex jobQueueMutex; - // Job queue std::deque<LuaJobInfo> jobQueue; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index 5711ccbfd..27d730b1d 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -332,13 +332,9 @@ void ScriptApiBase::setOriginDirect(const char *origin) void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn) { -#ifdef SCRIPTAPI_DEBUG lua_State *L = getStack(); - m_last_run_mod = lua_istable(L, index) ? getstringfield_default(L, index, "mod_origin", "") : ""; - //printf(">>>> running %s for mod: %s\n", fxn, m_last_run_mod.c_str()); -#endif } /* diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index a7a2c7203..e49745f4e 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -39,7 +39,6 @@ extern "C" { #include "config.h" #define SCRIPTAPI_LOCK_DEBUG -#define SCRIPTAPI_DEBUG // MUST be an invalid mod name so that mods can't // use that name to bypass security! @@ -111,7 +110,9 @@ public: Game *getGame() { return m_game; } #endif - std::string getOrigin() { return m_last_run_mod; } + // IMPORTANT: these cannot be used for any security-related uses, they exist + // only to enrich error messages + const std::string &getOrigin() { return m_last_run_mod; } void setOriginDirect(const char *origin); void setOriginFromTableRaw(int index, const char *fxn); @@ -130,8 +131,11 @@ protected: lua_State* getStack() { return m_luastack; } + // Checks that stack size is sane void realityCheck(); + // Takes an error from lua_pcall and throws it as a LuaError void scriptError(int result, const char *fxn); + // Dumps stack contents for debugging void stackDump(std::ostream &o); void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; } diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp index 1ed273a30..5d20f547d 100644 --- a/src/script/cpp_api/s_client.cpp +++ b/src/script/cpp_api/s_client.cpp @@ -36,7 +36,11 @@ void ScriptApiClient::on_mods_loaded() lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_mods_loaded"); // Call callbacks - runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); + try { + runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); + } catch (LuaError &e) { + getClient()->setFatalError(e); + } } void ScriptApiClient::on_shutdown() @@ -47,7 +51,11 @@ void ScriptApiClient::on_shutdown() lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_shutdown"); // Call callbacks - runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); + try { + runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); + } catch (LuaError &e) { + getClient()->setFatalError(e); + } } bool ScriptApiClient::on_sending_message(const std::string &message) @@ -59,7 +67,12 @@ bool ScriptApiClient::on_sending_message(const std::string &message) lua_getfield(L, -1, "registered_on_sending_chat_message"); // Call callbacks lua_pushstring(L, message.c_str()); - runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + try { + runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return readParam<bool>(L, -1); } @@ -72,7 +85,12 @@ bool ScriptApiClient::on_receiving_message(const std::string &message) lua_getfield(L, -1, "registered_on_receiving_chat_message"); // Call callbacks lua_pushstring(L, message.c_str()); - runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + try { + runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return readParam<bool>(L, -1); } @@ -85,7 +103,11 @@ void ScriptApiClient::on_damage_taken(int32_t damage_amount) lua_getfield(L, -1, "registered_on_damage_taken"); // Call callbacks lua_pushinteger(L, damage_amount); - runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + try { + runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + } catch (LuaError &e) { + getClient()->setFatalError(e); + } } void ScriptApiClient::on_hp_modification(int32_t newhp) @@ -97,7 +119,11 @@ void ScriptApiClient::on_hp_modification(int32_t newhp) lua_getfield(L, -1, "registered_on_hp_modification"); // Call callbacks lua_pushinteger(L, newhp); - runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + try { + runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + } catch (LuaError &e) { + getClient()->setFatalError(e); + } } void ScriptApiClient::on_death() @@ -108,7 +134,11 @@ void ScriptApiClient::on_death() lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_death"); // Call callbacks - runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); + try { + runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); + } catch (LuaError &e) { + getClient()->setFatalError(e); + } } void ScriptApiClient::environment_step(float dtime) @@ -123,8 +153,7 @@ void ScriptApiClient::environment_step(float dtime) try { runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); } catch (LuaError &e) { - getClient()->setFatalError(std::string("Client environment_step: ") + e.what() + "\n" - + script_get_backtrace(L)); + getClient()->setFatalError(e); } } @@ -149,7 +178,11 @@ void ScriptApiClient::on_formspec_input(const std::string &formname, lua_pushlstring(L, value.c_str(), value.size()); lua_settable(L, -3); } - runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC); + try { + runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC); + } catch (LuaError &e) { + getClient()->setFatalError(e); + } } bool ScriptApiClient::on_dignode(v3s16 p, MapNode node) @@ -167,7 +200,12 @@ bool ScriptApiClient::on_dignode(v3s16 p, MapNode node) pushnode(L, node, ndef); // Call functions - runCallbacks(2, RUN_CALLBACKS_MODE_OR); + try { + runCallbacks(2, RUN_CALLBACKS_MODE_OR); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return lua_toboolean(L, -1); } @@ -186,7 +224,12 @@ bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node) pushnode(L, node, ndef); // Call functions - runCallbacks(2, RUN_CALLBACKS_MODE_OR); + try { + runCallbacks(2, RUN_CALLBACKS_MODE_OR); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return readParam<bool>(L, -1); } @@ -203,7 +246,12 @@ bool ScriptApiClient::on_placenode(const PointedThing &pointed, const ItemDefini push_item_definition(L, item); // Call functions - runCallbacks(2, RUN_CALLBACKS_MODE_OR); + try { + runCallbacks(2, RUN_CALLBACKS_MODE_OR); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return readParam<bool>(L, -1); } @@ -220,7 +268,12 @@ bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &poi push_pointed_thing(L, pointed, true); // Call functions - runCallbacks(2, RUN_CALLBACKS_MODE_OR); + try { + runCallbacks(2, RUN_CALLBACKS_MODE_OR); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return readParam<bool>(L, -1); } @@ -348,7 +401,12 @@ bool ScriptApiClient::on_inventory_open(Inventory *inventory) push_inventory(L, inventory); - runCallbacks(1, RUN_CALLBACKS_MODE_OR); + try { + runCallbacks(1, RUN_CALLBACKS_MODE_OR); + } catch (LuaError &e) { + getClient()->setFatalError(e); + return true; + } return readParam<bool>(L, -1); } diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 8da5debaa..874c37b6e 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen/mapgen.h" #include "lua_api/l_env.h" #include "server.h" +#include "script/common/c_content.h" + void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, u32 blockseed) @@ -51,13 +53,7 @@ void ScriptApiEnv::environment_Step(float dtime) lua_getfield(L, -1, "registered_globalsteps"); // Call callbacks lua_pushnumber(L, dtime); - try { - runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); - } catch (LuaError &e) { - getServer()->setAsyncFatalError( - std::string("environment_Step: ") + e.what() + "\n" - + script_get_backtrace(L)); - } + runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); } void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &type) @@ -74,13 +70,7 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t // Call callbacks objectrefGetOrCreate(L, player); // player lua_pushstring(L,type.c_str()); // event type - try { - runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); - } catch (LuaError &e) { - getServer()->setAsyncFatalError( - std::string("player_event: ") + e.what() + "\n" - + script_get_backtrace(L) ); - } + runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); } void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) @@ -150,13 +140,19 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) bool simple_catch_up = true; getboolfield(L, current_abm, "catch_up", simple_catch_up); + + s16 min_y = INT16_MIN; + getintfield(L, current_abm, "min_y", min_y); + + s16 max_y = INT16_MAX; + getintfield(L, current_abm, "max_y", max_y); 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); + trigger_interval, trigger_chance, simple_catch_up, min_y, max_y); env->addActiveBlockModifier(abm); @@ -249,9 +245,8 @@ void ScriptApiEnv::on_emerge_area_completion( try { PCALL_RES(lua_pcall(L, 4, 0, error_handler)); } catch (LuaError &e) { - server->setAsyncFatalError( - std::string("on_emerge_area_completion: ") + e.what() + "\n" - + script_get_backtrace(L)); + // Note: don't throw here, we still need to run the cleanup code below + server->setAsyncFatalError(e); } lua_pop(L, 1); // Pop error handler @@ -261,3 +256,35 @@ void ScriptApiEnv::on_emerge_area_completion( luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref); } } + +void ScriptApiEnv::on_liquid_transformed( + const std::vector<std::pair<v3s16, MapNode>> &list) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_liquid_transformed + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_liquid_transformed"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_remove(L, -2); + + // Skip converting list and calling hook if there are + // no registered callbacks. + if(lua_objlen(L, -1) < 1) return; + + // Convert the list to a pos array and a node array for lua + int index = 1; + const NodeDefManager *ndef = getEnv()->getGameDef()->ndef(); + lua_createtable(L, list.size(), 0); + lua_createtable(L, list.size(), 0); + for(std::pair<v3s16, MapNode> p : list) { + lua_pushnumber(L, index); + push_v3s16(L, p.first); + lua_rawset(L, -4); + lua_pushnumber(L, index++); + pushnode(L, p.second, ndef); + lua_rawset(L, -3); + } + + runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); +} diff --git a/src/script/cpp_api/s_env.h b/src/script/cpp_api/s_env.h index 232a08aaf..090858f17 100644 --- a/src/script/cpp_api/s_env.h +++ b/src/script/cpp_api/s_env.h @@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "irr_v3d.h" +#include "mapnode.h" +#include <vector> class ServerEnvironment; struct ScriptCallbackState; @@ -41,5 +43,8 @@ public: void on_emerge_area_completion(v3s16 blockpos, int action, ScriptCallbackState *state); + // Called after liquid transform changes + void on_liquid_transformed(const std::vector<std::pair<v3s16, MapNode>> &list); + void initializeEnvironment(ServerEnvironment *env); }; diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp index 24955cefc..48dce14f3 100644 --- a/src/script/cpp_api/s_item.cpp +++ b/src/script/cpp_api/s_item.cpp @@ -29,6 +29,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventory.h" #include "inventorymanager.h" +#define WRAP_LUAERROR(e, detail) \ + LuaError(std::string(__FUNCTION__) + ": " + (e).what() + ". " detail) + bool ScriptApiItem::item_OnDrop(ItemStack &item, ServerActiveObject *dropper, v3f pos) { @@ -49,7 +52,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item, try { item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { - throw LuaError(std::string(e.what()) + ". item=" + item.name); + throw WRAP_LUAERROR(e, "item=" + item.name); } } lua_pop(L, 2); // Pop item and error handler @@ -81,7 +84,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item, try { item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { - throw LuaError(std::string(e.what()) + ". item=" + item.name); + throw WRAP_LUAERROR(e, "item=" + item.name); } } lua_pop(L, 2); // Pop item and error handler @@ -108,7 +111,7 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, try { item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { - throw LuaError(std::string(e.what()) + ". item=" + item.name); + throw WRAP_LUAERROR(e, "item=" + item.name); } } lua_pop(L, 2); // Pop item and error handler @@ -133,7 +136,7 @@ bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, try { item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { - throw LuaError(std::string(e.what()) + ". item=" + item.name); + throw WRAP_LUAERROR(e, "item=" + item.name); } } lua_pop(L, 2); // Pop item and error handler @@ -165,7 +168,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user, try { item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { - throw LuaError(std::string(e.what()) + ". item=" + item.name); + throw WRAP_LUAERROR(e, "item=" + item.name); } } lua_pop(L, 2); // Pop item and error handler @@ -197,7 +200,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user, try { item = read_item(L, -1, getServer()->idef()); } catch (LuaError &e) { - throw LuaError(std::string(e.what()) + ". item=" + item.name); + throw WRAP_LUAERROR(e, "item=" + item.name); } } lua_pop(L, 2); // Pop item and error handler diff --git a/src/script/cpp_api/s_mainmenu.h b/src/script/cpp_api/s_mainmenu.h index aef36ce39..470577a29 100644 --- a/src/script/cpp_api/s_mainmenu.h +++ b/src/script/cpp_api/s_mainmenu.h @@ -38,7 +38,7 @@ public: void handleMainMenuEvent(std::string text); /** - * process field data recieved from formspec + * process field data received from formspec * @param fields data in field format */ void handleMainMenuButtons(const StringMap &fields); diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp index c081e9fc4..7ab3757f3 100644 --- a/src/script/cpp_api/s_nodemeta.cpp +++ b/src/script/cpp_api/s_nodemeta.cpp @@ -43,7 +43,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove( return 0; // Push callback function on stack - std::string nodename = ndef->get(node).name; + const auto &nodename = ndef->get(node).name; if (!getItemCallback(nodename.c_str(), "allow_metadata_inventory_move", &ma.to_inv.p)) return count; @@ -58,7 +58,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove( PCALL_RES(lua_pcall(L, 7, 1, error_handler)); if (!lua_isnumber(L, -1)) throw LuaError("allow_metadata_inventory_move should" - " return a number, guilty node: " + nodename); + " return a number. node=" + nodename); int num = luaL_checkinteger(L, -1); lua_pop(L, 2); // Pop integer and error handler return num; @@ -81,7 +81,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut( return 0; // Push callback function on stack - std::string nodename = ndef->get(node).name; + const auto &nodename = ndef->get(node).name; if (!getItemCallback(nodename.c_str(), "allow_metadata_inventory_put", &ma.to_inv.p)) return stack.count; @@ -94,7 +94,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut( PCALL_RES(lua_pcall(L, 5, 1, error_handler)); if(!lua_isnumber(L, -1)) throw LuaError("allow_metadata_inventory_put should" - " return a number, guilty node: " + nodename); + " return a number. node=" + nodename); int num = luaL_checkinteger(L, -1); lua_pop(L, 2); // Pop integer and error handler return num; @@ -117,7 +117,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake( return 0; // Push callback function on stack - std::string nodename = ndef->get(node).name; + const auto &nodename = ndef->get(node).name; if (!getItemCallback(nodename.c_str(), "allow_metadata_inventory_take", &ma.from_inv.p)) return stack.count; @@ -130,7 +130,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake( PCALL_RES(lua_pcall(L, 5, 1, error_handler)); if (!lua_isnumber(L, -1)) throw LuaError("allow_metadata_inventory_take should" - " return a number, guilty node: " + nodename); + " return a number. node=" + nodename); int num = luaL_checkinteger(L, -1); lua_pop(L, 2); // Pop integer and error handler return num; @@ -153,7 +153,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove( return; // Push callback function on stack - std::string nodename = ndef->get(node).name; + const auto &nodename = ndef->get(node).name; if (!getItemCallback(nodename.c_str(), "on_metadata_inventory_move", &ma.from_inv.p)) return; @@ -186,7 +186,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut( return; // Push callback function on stack - std::string nodename = ndef->get(node).name; + const auto &nodename = ndef->get(node).name; if (!getItemCallback(nodename.c_str(), "on_metadata_inventory_put", &ma.to_inv.p)) return; @@ -217,7 +217,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake( return; // Push callback function on stack - std::string nodename = ndef->get(node).name; + const auto &nodename = ndef->get(node).name; if (!getItemCallback(nodename.c_str(), "on_metadata_inventory_take", &ma.from_inv.p)) return; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 8fe5d2c5a..bd9c80e15 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "cpp_api/s_security.h" - +#include "lua_api/l_base.h" #include "filesys.h" #include "porting.h" #include "server.h" @@ -541,15 +541,8 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, if (!removed.empty()) abs_path += DIR_DELIM + removed; - // Get server from registry - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); - ScriptApiBase *script; -#if INDIRECT_SCRIPTAPI_RIDX - script = (ScriptApiBase *) *(void**)(lua_touserdata(L, -1)); -#else - script = (ScriptApiBase *) lua_touserdata(L, -1); -#endif - lua_pop(L, 1); + // Get gamedef from registry + ScriptApiBase *script = ModApiBase::getScriptApiBase(L); const IGameDef *gamedef = script->getGameDef(); if (!gamedef) return false; @@ -672,13 +665,7 @@ int ScriptApiSecurity::sl_g_load(lua_State *L) int ScriptApiSecurity::sl_g_loadfile(lua_State *L) { #ifndef SERVER - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); -#if INDIRECT_SCRIPTAPI_RIDX - ScriptApiBase *script = (ScriptApiBase *) *(void**)(lua_touserdata(L, -1)); -#else - ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1); -#endif - lua_pop(L, 1); + ScriptApiBase *script = ModApiBase::getScriptApiBase(L); // Client implementation if (script->getType() == ScriptingType::Client) { diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp index 96cb28b28..6ddb2630d 100644 --- a/src/script/cpp_api/s_server.cpp +++ b/src/script/cpp_api/s_server.cpp @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_server.h" #include "cpp_api/s_internal.h" #include "common/c_converter.h" +#include "util/numeric.h" // myrand bool ScriptApiServer::getAuth(const std::string &playername, std::string *dst_password, @@ -196,3 +197,68 @@ std::string ScriptApiServer::formatChatMessage(const std::string &name, return ret; } + +u32 ScriptApiServer::allocateDynamicMediaCallback(int f_idx) +{ + lua_State *L = getStack(); + + if (f_idx < 0) + f_idx = lua_gettop(L) + f_idx + 1; + + lua_getglobal(L, "core"); + lua_getfield(L, -1, "dynamic_media_callbacks"); + luaL_checktype(L, -1, LUA_TTABLE); + + // Find a randomly generated token that doesn't exist yet + int tries = 100; + u32 token; + while (1) { + token = myrand(); + lua_rawgeti(L, -2, token); + bool is_free = lua_isnil(L, -1); + lua_pop(L, 1); + if (is_free) + break; + if (--tries < 0) + FATAL_ERROR("Ran out of callbacks IDs?!"); + } + + // core.dynamic_media_callbacks[token] = callback_func + lua_pushvalue(L, f_idx); + lua_rawseti(L, -2, token); + + lua_pop(L, 2); + + verbosestream << "allocateDynamicMediaCallback() = " << token << std::endl; + return token; +} + +void ScriptApiServer::freeDynamicMediaCallback(u32 token) +{ + lua_State *L = getStack(); + + verbosestream << "freeDynamicMediaCallback(" << token << ")" << std::endl; + + // core.dynamic_media_callbacks[token] = nil + lua_getglobal(L, "core"); + lua_getfield(L, -1, "dynamic_media_callbacks"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_pushnil(L); + lua_rawseti(L, -2, token); + lua_pop(L, 2); +} + +void ScriptApiServer::on_dynamic_media_added(u32 token, const char *playername) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + lua_getglobal(L, "core"); + lua_getfield(L, -1, "dynamic_media_callbacks"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_rawgeti(L, -1, token); + luaL_checktype(L, -1, LUA_TFUNCTION); + + lua_pushstring(L, playername); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); +} diff --git a/src/script/cpp_api/s_server.h b/src/script/cpp_api/s_server.h index d8639cba7..c5c3d5596 100644 --- a/src/script/cpp_api/s_server.h +++ b/src/script/cpp_api/s_server.h @@ -49,6 +49,12 @@ public: const std::string &password); bool setPassword(const std::string &playername, const std::string &password); + + /* dynamic media handling */ + u32 allocateDynamicMediaCallback(int f_idx); + void freeDynamicMediaCallback(u32 token); + void on_dynamic_media_added(u32 token, const char *playername); + 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 908c766b0..45724e604 100644 --- a/src/script/lua_api/l_areastore.cpp +++ b/src/script/lua_api/l_areastore.cpp @@ -372,7 +372,7 @@ void LuaAreaStore::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (AreaStore()) diff --git a/src/script/lua_api/l_auth.cpp b/src/script/lua_api/l_auth.cpp index 0fc57ba3a..32d8a7411 100644 --- a/src/script/lua_api/l_auth.cpp +++ b/src/script/lua_api/l_auth.cpp @@ -32,8 +32,11 @@ AuthDatabase *ModApiAuth::getAuthDb(lua_State *L) { ServerEnvironment *server_environment = dynamic_cast<ServerEnvironment *>(getEnv(L)); - if (!server_environment) + if (!server_environment) { + luaL_error(L, "Attempt to access an auth function but the auth" + " system is yet not initialized. This causes bugs."); return nullptr; + } return server_environment->getAuthDatabase(); } diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp index 40251154c..d85d16283 100644 --- a/src/script/lua_api/l_camera.cpp +++ b/src/script/lua_api/l_camera.cpp @@ -219,7 +219,7 @@ void LuaCamera::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); } diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index d6dc79ca8..74db996a4 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -46,13 +46,22 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/client.h" #endif -struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = +const EnumString ModApiEnvMod::es_ClearObjectsMode[] = { {CLEAR_OBJECTS_MODE_FULL, "full"}, {CLEAR_OBJECTS_MODE_QUICK, "quick"}, {0, NULL}, }; +const EnumString ModApiEnvMod::es_BlockStatusType[] = +{ + {ServerEnvironment::BS_UNKNOWN, "unknown"}, + {ServerEnvironment::BS_EMERGING, "emerging"}, + {ServerEnvironment::BS_LOADED, "loaded"}, + {ServerEnvironment::BS_ACTIVE, "active"}, + {0, NULL}, +}; + /////////////////////////////////////////////////////////////////////////////// @@ -228,7 +237,7 @@ void LuaRaycast::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -1547,6 +1556,24 @@ int ModApiEnvMod::l_forceload_block(lua_State *L) return 0; } +// compare_block_status(nodepos) +int ModApiEnvMod::l_compare_block_status(lua_State *L) +{ + GET_ENV_PTR; + + v3s16 nodepos = check_v3s16(L, 1); + std::string condition_s = luaL_checkstring(L, 2); + auto status = env->getBlockStatus(getNodeBlockPos(nodepos)); + + int condition_i = -1; + if (!string_to_enum(es_BlockStatusType, condition_i, condition_s)) + return 0; // Unsupported + + lua_pushboolean(L, status >= condition_i); + return 1; +} + + // forceload_free_block(blockpos) // blockpos = {x=num, y=num, z=num} int ModApiEnvMod::l_forceload_free_block(lua_State *L) @@ -1620,6 +1647,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(transforming_liquid_add); API_FCT(forceload_block); API_FCT(forceload_free_block); + API_FCT(compare_block_status); API_FCT(get_translated_string); } diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 29044c0e8..a5ac21e21 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -207,6 +207,9 @@ private: // stops forceloading a position static int l_forceload_free_block(lua_State *L); + // compare_block_status(nodepos) + static int l_compare_block_status(lua_State *L); + // Get a string translated server side static int l_get_translated_string(lua_State * L); @@ -219,7 +222,8 @@ public: static void Initialize(lua_State *L, int top); static void InitializeClient(lua_State *L, int top); - static struct EnumString es_ClearObjectsMode[]; + static const EnumString es_ClearObjectsMode[]; + static const EnumString es_BlockStatusType[]; }; class LuaABM : public ActiveBlockModifier { @@ -231,17 +235,21 @@ private: float m_trigger_interval; u32 m_trigger_chance; bool m_simple_catch_up; + s16 m_min_y; + s16 m_max_y; public: LuaABM(lua_State *L, int id, const std::vector<std::string> &trigger_contents, const std::vector<std::string> &required_neighbors, - float trigger_interval, u32 trigger_chance, bool simple_catch_up): + float trigger_interval, u32 trigger_chance, bool simple_catch_up, s16 min_y, s16 max_y): m_id(id), m_trigger_contents(trigger_contents), m_required_neighbors(required_neighbors), m_trigger_interval(trigger_interval), m_trigger_chance(trigger_chance), - m_simple_catch_up(simple_catch_up) + m_simple_catch_up(simple_catch_up), + m_min_y(min_y), + m_max_y(max_y) { } virtual const std::vector<std::string> &getTriggerContents() const @@ -264,6 +272,14 @@ public: { return m_simple_catch_up; } + virtual s16 getMinY() + { + return m_min_y; + } + virtual s16 getMaxY() + { + return m_max_y; + } virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider); }; diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp index 5ea3b3f99..751ec9837 100644 --- a/src/script/lua_api/l_http.cpp +++ b/src/script/lua_api/l_http.cpp @@ -42,12 +42,10 @@ void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req) 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); + getstringfield(L, 1, "user_agent", req.useragent); req.multipart = getboolfield_default(L, 1, "multipart", false); - req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000; + if (getintfield(L, 1, "timeout", req.timeout)) + req.timeout *= 1000; lua_getfield(L, 1, "method"); if (lua_isstring(L, -1)) { diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index 434d0a76c..0dd418462 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -456,7 +456,7 @@ void InvRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Cannot be created from Lua diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index b098eccf0..2ea2bd4f6 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -488,7 +488,7 @@ void LuaItemStack::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (ItemStack(itemstack or itemstring or table or nil)) diff --git a/src/script/lua_api/l_itemstackmeta.cpp b/src/script/lua_api/l_itemstackmeta.cpp index d1ba1bda4..739fb9221 100644 --- a/src/script/lua_api/l_itemstackmeta.cpp +++ b/src/script/lua_api/l_itemstackmeta.cpp @@ -114,7 +114,7 @@ void ItemStackMetaRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Cannot be created from Lua diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index 4f57ee00f..769b3ef2b 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -295,16 +295,20 @@ int LuaLocalPlayer::l_get_control(lua_State *L) }; lua_createtable(L, 0, 12); - set("up", c.up); - set("down", c.down); - set("left", c.left); - set("right", c.right); - set("jump", c.jump); - set("aux1", c.aux1); + set("jump", c.jump); + set("aux1", c.aux1); set("sneak", c.sneak); - set("zoom", c.zoom); - set("dig", c.dig); + set("zoom", c.zoom); + set("dig", c.dig); set("place", c.place); + // Player movement in polar coordinates and non-binary speed + set("movement_speed", c.movement_speed); + set("movement_direction", c.movement_direction); + // Provide direction keys to ensure compatibility + set("up", player->keyPressed & (1 << 0)); // Up, down, left, and right were removed in favor of + set("down", player->keyPressed & (1 << 1)); // analog direction indicators and are therefore not + set("left", player->keyPressed & (1 << 2)); // available as booleans anymore. The corresponding values + set("right", player->keyPressed & (1 << 3)); // can still be read from the keyPressed bits though. return 1; } @@ -452,10 +456,11 @@ int LuaLocalPlayer::l_hud_change(lua_State *L) if (!element) return 0; + HudElementStat stat; void *unused; - read_hud_change(L, element, &unused); + bool ok = read_hud_change(L, stat, element, &unused); - lua_pushboolean(L, true); + lua_pushboolean(L, ok); return 1; } @@ -550,7 +555,7 @@ void LuaLocalPlayer::Register(lua_State *L) lua_pop(L, 1); // Drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // Drop methodtable } diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index d88bf31c1..8eb0e252a 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_internal.h" #include "common/c_content.h" #include "cpp_api/s_async.h" +#include "scripting_mainmenu.h" #include "gui/guiEngine.h" #include "gui/guiMainMenu.h" #include "gui/guiKeyChangeMenu.h" @@ -741,13 +742,12 @@ int ModApiMainMenu::l_get_video_drivers(lua_State *L) lua_newtable(L); for (u32 i = 0; i != drivers.size(); i++) { - const char *name = RenderingEngine::getVideoDriverName(drivers[i]); - const char *fname = RenderingEngine::getVideoDriverFriendlyName(drivers[i]); + auto &info = RenderingEngine::getVideoDriverInfo(drivers[i]); lua_newtable(L); - lua_pushstring(L, name); + lua_pushstring(L, info.name.c_str()); lua_setfield(L, -2, "name"); - lua_pushstring(L, fname); + lua_pushstring(L, info.friendly_name.c_str()); lua_setfield(L, -2, "friendly_name"); lua_rawseti(L, -2, i + 1); @@ -757,28 +757,6 @@ int ModApiMainMenu::l_get_video_drivers(lua_State *L) } /******************************************************************************/ -int ModApiMainMenu::l_get_video_modes(lua_State *L) -{ - std::vector<core::vector3d<u32> > videomodes - = RenderingEngine::getSupportedVideoModes(); - - lua_newtable(L); - for (u32 i = 0; i != videomodes.size(); i++) { - lua_newtable(L); - lua_pushnumber(L, videomodes[i].X); - lua_setfield(L, -2, "w"); - lua_pushnumber(L, videomodes[i].Y); - lua_setfield(L, -2, "h"); - lua_pushnumber(L, videomodes[i].Z); - lua_setfield(L, -2, "depth"); - - lua_rawseti(L, -2, i + 1); - } - - return 1; -} - -/******************************************************************************/ int ModApiMainMenu::l_gettext(lua_State *L) { std::string text = strgettext(std::string(luaL_checkstring(L, 1))); @@ -843,20 +821,20 @@ int ModApiMainMenu::l_open_dir(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_do_async_callback(lua_State *L) { - GUIEngine* engine = getGuiEngine(L); + MainMenuScripting *script = getScriptApi<MainMenuScripting>(L); size_t func_length, param_length; const char* serialized_func_raw = luaL_checklstring(L, 1, &func_length); - const char* serialized_param_raw = luaL_checklstring(L, 2, ¶m_length); sanity_check(serialized_func_raw != NULL); sanity_check(serialized_param_raw != NULL); - std::string serialized_func = std::string(serialized_func_raw, func_length); - std::string serialized_param = std::string(serialized_param_raw, param_length); + u32 jobId = script->queueAsync( + std::string(serialized_func_raw, func_length), + std::string(serialized_param_raw, param_length)); - lua_pushinteger(L, engine->queueAsync(serialized_func, serialized_param)); + lua_pushinteger(L, jobId); return 1; } @@ -899,7 +877,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(download_file); API_FCT(gettext); API_FCT(get_video_drivers); - API_FCT(get_video_modes); API_FCT(get_screen_info); API_FCT(get_min_supp_proto); API_FCT(get_max_supp_proto); diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 33ac9e721..ec2d20da2 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -140,8 +140,6 @@ private: static int l_get_video_drivers(lua_State *L); - static int l_get_video_modes(lua_State *L); - //version compatibility static int l_get_min_supp_proto(lua_State *L); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index eb3d49a5e..f173bd162 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -752,9 +752,7 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L) lua_setfield(L, -2, "mgname"); settingsmgr->getMapSetting("seed", &value); - std::istringstream ss(value); - u64 seed; - ss >> seed; + u64 seed = from_string<u64>(value); lua_pushinteger(L, seed); lua_setfield(L, -2, "seed"); diff --git a/src/script/lua_api/l_minimap.cpp b/src/script/lua_api/l_minimap.cpp index 3bbb6e5e3..a135e0bd5 100644 --- a/src/script/lua_api/l_minimap.cpp +++ b/src/script/lua_api/l_minimap.cpp @@ -211,7 +211,7 @@ void LuaMinimap::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_modchannels.cpp b/src/script/lua_api/l_modchannels.cpp index 0485b276a..931c2749c 100644 --- a/src/script/lua_api/l_modchannels.cpp +++ b/src/script/lua_api/l_modchannels.cpp @@ -107,7 +107,7 @@ void ModChannelRef::Register(lua_State *L) lua_pop(L, 1); // Drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // Drop methodtable } diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 57052cb42..60d14f8f2 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -234,7 +234,7 @@ void NodeMetaRef::RegisterCommon(lua_State *L) void NodeMetaRef::Register(lua_State *L) { RegisterCommon(L); - luaL_openlib(L, 0, methodsServer, 0); // fill methodtable + luaL_register(L, nullptr, methodsServer); // fill methodtable lua_pop(L, 1); // drop methodtable } @@ -260,7 +260,7 @@ const luaL_Reg NodeMetaRef::methodsServer[] = { void NodeMetaRef::RegisterClient(lua_State *L) { RegisterCommon(L); - luaL_openlib(L, 0, methodsClient, 0); // fill methodtable + luaL_register(L, nullptr, methodsClient); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp index c2df52c05..8a302149f 100644 --- a/src/script/lua_api/l_nodetimer.cpp +++ b/src/script/lua_api/l_nodetimer.cpp @@ -122,7 +122,7 @@ void NodeTimerRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Cannot be created from Lua diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index e0861126a..f43ba837a 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -122,7 +122,7 @@ void LuaPerlinNoise::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -380,7 +380,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -485,7 +485,7 @@ void LuaPseudoRandom::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -584,7 +584,7 @@ void LuaPcgRandom::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); @@ -699,7 +699,7 @@ void LuaSecureRandom::Register(lua_State *L) lua_pop(L, 1); - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); lua_register(L, className, create_object); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 8ae99b929..b7185f7ec 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -172,27 +172,11 @@ int ObjectRef::l_punch(lua_State *L) float time_from_last_punch = readParam<float>(L, 3, 1000000.0f); ToolCapabilities toolcap = read_tool_capabilities(L, 4); v3f dir = readParam<v3f>(L, 5, sao->getBasePosition() - puncher->getBasePosition()); - dir.normalize(); - u16 src_original_hp = sao->getHP(); - u16 dst_origin_hp = puncher->getHP(); u16 wear = sao->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 != sao->getHP() && - sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)sao, - PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher)); - } - - // If the puncher is a player, and its HP changed - if (dst_origin_hp != puncher->getHP() && - puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher, - PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, sao)); - } return 1; } @@ -238,8 +222,6 @@ int ObjectRef::l_set_hp(lua_State *L) } sao->setHP(hp, reason); - if (sao->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerHPOrDie((PlayerSAO *)sao, reason); if (reason.hasLuaReference()) luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference); return 0; @@ -685,6 +667,7 @@ int ObjectRef::l_set_properties(lua_State *L) return 0; read_object_properties(L, 2, sao, prop, getServer(L)->idef()); + prop->validate(); sao->notifyObjectPropertiesModified(); return 0; } @@ -752,6 +735,7 @@ int ObjectRef::l_set_nametag_attributes(lua_State *L) std::string nametag = getstringfield_default(L, 2, "text", ""); prop->nametag = nametag; + prop->validate(); sao->notifyObjectPropertiesModified(); lua_pushboolean(L, true); return 1; @@ -1390,13 +1374,13 @@ int ObjectRef::l_get_player_control(lua_State *L) const PlayerControl &control = player->getPlayerControl(); lua_newtable(L); - lua_pushboolean(L, control.up); + lua_pushboolean(L, player->keyPressed & (1 << 0)); lua_setfield(L, -2, "up"); - lua_pushboolean(L, control.down); + lua_pushboolean(L, player->keyPressed & (1 << 1)); lua_setfield(L, -2, "down"); - lua_pushboolean(L, control.left); + lua_pushboolean(L, player->keyPressed & (1 << 2)); lua_setfield(L, -2, "left"); - lua_pushboolean(L, control.right); + lua_pushboolean(L, player->keyPressed & (1 << 3)); lua_setfield(L, -2, "right"); lua_pushboolean(L, control.jump); lua_setfield(L, -2, "jump"); @@ -1553,12 +1537,14 @@ int ObjectRef::l_hud_change(lua_State *L) if (elem == nullptr) return 0; + HudElementStat stat; void *value = nullptr; - HudElementStat stat = read_hud_change(L, elem, &value); + bool ok = read_hud_change(L, stat, elem, &value); - getServer(L)->hudChange(player, id, stat, value); + if (ok) + getServer(L)->hudChange(player, id, stat, value); - lua_pushboolean(L, true); + lua_pushboolean(L, ok); return 1; } @@ -2311,7 +2297,7 @@ void ObjectRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_playermeta.cpp b/src/script/lua_api/l_playermeta.cpp index 558672e38..2706c99df 100644 --- a/src/script/lua_api/l_playermeta.cpp +++ b/src/script/lua_api/l_playermeta.cpp @@ -97,7 +97,7 @@ void PlayerMetaRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); + luaL_register(L, nullptr, methods); lua_pop(L, 1); // Cannot be created from Lua diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 026f5282c..b4672fe2a 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "cpp_api/s_base.h" #include "cpp_api/s_security.h" +#include "scripting_server.h" #include "server.h" #include "environment.h" #include "remoteplayer.h" @@ -453,29 +454,37 @@ int ModApiServer::l_sound_fade(lua_State *L) } // dynamic_add_media(filepath) -int ModApiServer::l_dynamic_add_media_raw(lua_State *L) +int ModApiServer::l_dynamic_add_media(lua_State *L) { NO_MAP_LOCK_REQUIRED; if (!getEnv(L)) throw LuaError("Dynamic media cannot be added before server has started up"); + Server *server = getServer(L); - std::string filepath = readParam<std::string>(L, 1); - CHECK_SECURE_PATH(L, filepath.c_str(), false); + std::string filepath; + std::string to_player; + bool ephemeral = false; - std::vector<RemotePlayer*> sent_to; - bool ok = getServer(L)->dynamicAddMedia(filepath, sent_to); - if (ok) { - // (see wrapper code in builtin) - lua_createtable(L, sent_to.size(), 0); - int i = 0; - for (RemotePlayer *player : sent_to) { - lua_pushstring(L, player->getName()); - lua_rawseti(L, -2, ++i); - } + if (lua_istable(L, 1)) { + getstringfield(L, 1, "filepath", filepath); + getstringfield(L, 1, "to_player", to_player); + getboolfield(L, 1, "ephemeral", ephemeral); } else { - lua_pushboolean(L, false); + filepath = readParam<std::string>(L, 1); } + if (filepath.empty()) + luaL_typerror(L, 1, "non-empty string"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + CHECK_SECURE_PATH(L, filepath.c_str(), false); + + u32 token = server->getScriptIface()->allocateDynamicMediaCallback(2); + + bool ok = server->dynamicAddMedia(filepath, token, to_player, ephemeral); + if (!ok) + server->getScriptIface()->freeDynamicMediaCallback(token); + lua_pushboolean(L, ok); return 1; } @@ -499,31 +508,6 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L) return 0; } -// get_last_run_mod() -int ModApiServer::l_get_last_run_mod(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); - std::string current_mod = readParam<std::string>(L, -1, ""); - if (current_mod.empty()) { - lua_pop(L, 1); - lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str()); - } - return 1; -} - -// set_last_run_mod(modname) -int ModApiServer::l_set_last_run_mod(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; -#ifdef SCRIPTAPI_DEBUG - const char *mod = lua_tostring(L, 1); - getScriptApiBase(L)->setOriginDirect(mod); - //printf(">>>> last mod set from Lua: %s\n", mod); -#endif - return 0; -} - void ModApiServer::Initialize(lua_State *L, int top) { API_FCT(request_shutdown); @@ -544,7 +528,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(sound_play); API_FCT(sound_stop); API_FCT(sound_fade); - API_FCT(dynamic_add_media_raw); + API_FCT(dynamic_add_media); API_FCT(get_player_information); API_FCT(get_player_privs); @@ -555,7 +539,4 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(kick_player); API_FCT(unban_player_or_ip); API_FCT(notify_authentication_modified); - - API_FCT(get_last_run_mod); - API_FCT(set_last_run_mod); } diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 2df180b17..c688e494b 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -71,7 +71,7 @@ private: static int l_sound_fade(lua_State *L); // dynamic_add_media(filepath) - static int l_dynamic_add_media_raw(lua_State *L); + static int l_dynamic_add_media(lua_State *L); // get_player_privs(name, text) static int l_get_player_privs(lua_State *L); @@ -103,12 +103,6 @@ private: // notify_authentication_modified(name) static int l_notify_authentication_modified(lua_State *L); - // get_last_run_mod() - static int l_get_last_run_mod(lua_State *L); - - // set_last_run_mod(modname) - static int l_set_last_run_mod(lua_State *L); - public: static void Initialize(lua_State *L, int top); }; diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index a82073ed4..14398dda2 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -334,7 +334,7 @@ void LuaSettings::Register(lua_State* L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (Settings(filename)) diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp index cba34fb63..978b315d5 100644 --- a/src/script/lua_api/l_storage.cpp +++ b/src/script/lua_api/l_storage.cpp @@ -110,7 +110,7 @@ void StorageRef::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable } diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 624828956..d575eb603 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "util/hex.h" #include "util/sha1.h" +#include "util/png.h" #include <algorithm> #include <cstdio> @@ -271,11 +272,11 @@ int ModApiUtil::l_compress(lua_State *L) const char *data = luaL_checklstring(L, 1, &size); int level = -1; - if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) - level = readParam<float>(L, 3); + if (!lua_isnoneornil(L, 3)) + level = readParam<int>(L, 3); - std::ostringstream os; - compressZlib(std::string(data, size), os, level); + std::ostringstream os(std::ios_base::binary); + compressZlib(reinterpret_cast<const u8 *>(data), size, os, level); std::string out = os.str(); @@ -291,8 +292,8 @@ int ModApiUtil::l_decompress(lua_State *L) size_t size; const char *data = luaL_checklstring(L, 1, &size); - std::istringstream is(std::string(data, size)); - std::ostringstream os; + std::istringstream is(std::string(data, size), std::ios_base::binary); + std::ostringstream os(std::ios_base::binary); decompressZlib(is, os); std::string out = os.str(); @@ -497,6 +498,67 @@ int ModApiUtil::l_colorspec_to_colorstring(lua_State *L) return 0; } +// colorspec_to_bytes(colorspec) +int ModApiUtil::l_colorspec_to_bytes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + video::SColor color(0); + if (read_color(L, 1, &color)) { + u8 colorbytes[4] = { + (u8) color.getRed(), + (u8) color.getGreen(), + (u8) color.getBlue(), + (u8) color.getAlpha(), + }; + lua_pushlstring(L, (const char*) colorbytes, 4); + return 1; + } + + return 0; +} + +// encode_png(w, h, data, level) +int ModApiUtil::l_encode_png(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + // The args are already pre-validated on the lua side. + u32 width = readParam<int>(L, 1); + u32 height = readParam<int>(L, 2); + const char *data = luaL_checklstring(L, 3, NULL); + s32 compression = readParam<int>(L, 4); + + std::string out = encodePNG((const u8*)data, width, height, compression); + + lua_pushlstring(L, out.data(), out.size()); + return 1; +} + +// get_last_run_mod() +int ModApiUtil::l_get_last_run_mod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); + std::string current_mod = readParam<std::string>(L, -1, ""); + if (current_mod.empty()) { + lua_pop(L, 1); + lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str()); + } + return 1; +} + +// set_last_run_mod(modname) +int ModApiUtil::l_set_last_run_mod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + const char *mod = luaL_checkstring(L, 1); + getScriptApiBase(L)->setOriginDirect(mod); + return 0; +} + void ModApiUtil::Initialize(lua_State *L, int top) { API_FCT(log); @@ -532,6 +594,12 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); + + API_FCT(encode_png); + + API_FCT(get_last_run_mod); + API_FCT(set_last_run_mod); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); @@ -559,6 +627,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); @@ -590,6 +659,10 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); + + API_FCT(get_last_run_mod); + API_FCT(set_last_run_mod); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index 6943a6afb..cc91e8d39 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -104,6 +104,18 @@ private: // colorspec_to_colorstring(colorspec) static int l_colorspec_to_colorstring(lua_State *L); + // colorspec_to_bytes(colorspec) + static int l_colorspec_to_bytes(lua_State *L); + + // encode_png(w, h, data, level) + static int l_encode_png(lua_State *L); + + // get_last_run_mod() + static int l_get_last_run_mod(lua_State *L); + + // set_last_run_mod(modname) + static int l_set_last_run_mod(lua_State *L); + public: static void Initialize(lua_State *L, int top); static void InitializeAsync(lua_State *L, int top); diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp index b99b1d98c..e040e545b 100644 --- a/src/script/lua_api/l_vmanip.cpp +++ b/src/script/lua_api/l_vmanip.cpp @@ -450,7 +450,7 @@ void LuaVoxelManip::Register(lua_State *L) lua_pop(L, 1); // drop metatable - luaL_openlib(L, 0, methods, 0); // fill methodtable + luaL_register(L, nullptr, methods); // fill methodtable lua_pop(L, 1); // drop methodtable // Can be created from Lua (VoxelManip()) diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp index b102a66a1..2a0cadb23 100644 --- a/src/script/scripting_mainmenu.cpp +++ b/src/script/scripting_mainmenu.cpp @@ -92,9 +92,9 @@ void MainMenuScripting::step() } /******************************************************************************/ -unsigned int MainMenuScripting::queueAsync(const std::string &serialized_func, - const std::string &serialized_param) +u32 MainMenuScripting::queueAsync(std::string &&serialized_func, + std::string &&serialized_param) { - return asyncEngine.queueAsyncJob(serialized_func, serialized_param); + return asyncEngine.queueAsyncJob(std::move(serialized_func), std::move(serialized_param)); } diff --git a/src/script/scripting_mainmenu.h b/src/script/scripting_mainmenu.h index 9e23bdc1b..3c329654a 100644 --- a/src/script/scripting_mainmenu.h +++ b/src/script/scripting_mainmenu.h @@ -38,8 +38,9 @@ public: void step(); // Pass async events from engine to async threads - unsigned int queueAsync(const std::string &serialized_func, - const std::string &serialized_params); + u32 queueAsync(std::string &&serialized_func, + std::string &&serialized_param); + private: void initializeModApi(lua_State *L, int top); static void registerLuaClasses(lua_State *L, int top); |