From 80d12dbedb67191a5eb3e4f3c36b04baed1f8afb Mon Sep 17 00:00:00 2001 From: hecks <42101236+hecktest@users.noreply.github.com> Date: Thu, 29 Jul 2021 05:10:10 +0200 Subject: Add a simple PNG image encoder with Lua API (#11485) * Add a simple PNG image encoder with Lua API Add ColorSpec to RGBA converter Make a safety wrapper for the encoder Create devtest examples Co-authored-by: hecktest <> Co-authored-by: sfan5 --- src/script/lua_api/l_util.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'src/script/lua_api/l_util.cpp') diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 8de2d67c8..87436fce0 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 #include @@ -497,6 +498,43 @@ 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(L, 1); + u32 height = readParam(L, 2); + const char *data = luaL_checklstring(L, 3, NULL); + s32 compression = readParam(L, 4); + + std::string out = encodePNG((const u8*)data, width, height, compression); + + lua_pushlstring(L, out.data(), out.size()); + return 1; +} + void ModApiUtil::Initialize(lua_State *L, int top) { API_FCT(log); @@ -532,6 +570,9 @@ 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); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); @@ -557,6 +598,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); } void ModApiUtil::InitializeAsync(lua_State *L, int top) @@ -585,6 +627,7 @@ 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); LuaSettings::create(L, g_settings, g_settings_path); lua_setfield(L, top, "settings"); -- cgit v1.2.3 From 6a1424f2b18520f40ba8cfd12f7988f6b33db9a6 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 28 Aug 2021 12:15:12 +0200 Subject: Async-related script cleanups --- builtin/async/init.lua | 10 +--- src/gui/guiEngine.cpp | 7 --- src/gui/guiEngine.h | 4 -- src/script/cpp_api/s_async.cpp | 108 ++++++++++++++++++++------------------ src/script/cpp_api/s_async.h | 39 +++++++------- src/script/cpp_api/s_base.cpp | 4 -- src/script/cpp_api/s_base.h | 5 +- src/script/cpp_api/s_security.cpp | 21 ++------ src/script/lua_api/l_mainmenu.cpp | 11 ++-- src/script/lua_api/l_server.cpp | 29 +--------- src/script/lua_api/l_server.h | 6 --- src/script/lua_api/l_util.cpp | 30 +++++++++++ src/script/lua_api/l_util.h | 6 +++ src/script/scripting_mainmenu.cpp | 6 +-- src/script/scripting_mainmenu.h | 5 +- 15 files changed, 135 insertions(+), 156 deletions(-) (limited to 'src/script/lua_api/l_util.cpp') diff --git a/builtin/async/init.lua b/builtin/async/init.lua index 1b2549685..3803994d6 100644 --- a/builtin/async/init.lua +++ b/builtin/async/init.lua @@ -1,16 +1,10 @@ core.log("info", "Initializing Asynchronous environment") -function core.job_processor(serialized_func, serialized_param) - local func = loadstring(serialized_func) +function core.job_processor(func, serialized_param) local param = core.deserialize(serialized_param) - local retval = nil - if type(func) == "function" then - retval = core.serialize(func(param)) - else - core.log("error", "ASYNC WORKER: Unable to deserialize function") - end + local retval = core.serialize(func(param)) return retval or core.serialize(nil) end diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index 694baf482..b3808535c 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -614,10 +614,3 @@ void GUIEngine::stopSound(s32 handle) { m_sound_manager->stopSound(handle); } - -/******************************************************************************/ -unsigned int GUIEngine::queueAsync(const std::string &serialized_func, - const std::string &serialized_params) -{ - return m_script->queueAsync(serialized_func, serialized_params); -} diff --git a/src/gui/guiEngine.h b/src/gui/guiEngine.h index 70abce181..d7e6485ef 100644 --- a/src/gui/guiEngine.h +++ b/src/gui/guiEngine.h @@ -175,10 +175,6 @@ public: return m_scriptdir; } - /** pass async callback to scriptengine **/ - unsigned int queueAsync(const std::string &serialized_fct, - const std::string &serialized_params); - private: /** find and run the main menu script */ 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::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, ""); } - 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, ""); + } 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 #include -#include #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 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 jobQueue; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index f965975a3..921f713c0 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -331,13 +331,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 86f7f7bac..7a8ebc85a 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! @@ -108,7 +107,9 @@ public: Client* getClient(); #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); diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index add7b1658..580042ec2 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" @@ -538,15 +538,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; @@ -669,13 +662,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/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index ad00de1c4..6e9a5c34f 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" @@ -816,20 +817,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(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; } diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index bf5292521..9866e0bc8 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" @@ -498,31 +499,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(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); @@ -555,7 +531,4 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(remove_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..fb7a851f4 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -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_util.cpp b/src/script/lua_api/l_util.cpp index 87436fce0..9152b5f7f 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -535,6 +535,30 @@ int ModApiUtil::l_encode_png(lua_State *L) 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(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); @@ -574,6 +598,9 @@ void ModApiUtil::Initialize(lua_State *L, int top) 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"); } @@ -629,6 +656,9 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top) 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 54d2be619..cc91e8d39 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -110,6 +110,12 @@ private: // 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/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); -- cgit v1.2.3 From 75bf9b75caba5fc876f20eabea3fabc142d1b51e Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 11 Sep 2021 21:06:57 +0200 Subject: Make sure relevant std::stringstreams are set to binary --- src/client/client.cpp | 8 ++++---- src/client/game.cpp | 2 +- src/database/database-leveldb.cpp | 16 ++++++++-------- src/database/database-postgresql.cpp | 14 ++++++++------ src/database/database-redis.cpp | 6 ++---- src/database/database-sqlite3.cpp | 13 +++++++++---- src/gui/guiChatConsole.cpp | 1 - src/gui/guiFormSpecMenu.cpp | 10 +++------- src/inventory.cpp | 1 - src/itemstackmetadata.cpp | 2 +- src/network/clientpackethandler.cpp | 12 +++++------- src/script/common/c_converter.cpp | 5 +---- src/script/lua_api/l_mapgen.cpp | 4 +--- src/script/lua_api/l_util.cpp | 12 ++++++------ src/settings.cpp | 5 +---- src/unittest/test_areastore.cpp | 4 ++-- src/util/serialize.cpp | 5 ++--- 17 files changed, 54 insertions(+), 66 deletions(-) (limited to 'src/script/lua_api/l_util.cpp') diff --git a/src/client/client.cpp b/src/client/client.cpp index 13ff22e8e..45cc62a33 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1693,13 +1693,13 @@ float Client::mediaReceiveProgress() return 1.0; // downloader only exists when not yet done } -typedef struct TextureUpdateArgs { +struct TextureUpdateArgs { gui::IGUIEnvironment *guienv; u64 last_time_ms; u16 last_percent; const wchar_t* text_base; ITextureSource *tsrc; -} TextureUpdateArgs; +}; void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress) { @@ -1718,8 +1718,8 @@ void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progres if (do_draw) { targs->last_time_ms = time_ms; - std::basic_stringstream strm; - strm << targs->text_base << " " << targs->last_percent << "%..."; + std::wostringstream strm; + strm << targs->text_base << L" " << targs->last_percent << L"%..."; m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0, 72 + (u16) ((18. / 100.) * (double) targs->last_percent), true); } diff --git a/src/client/game.cpp b/src/client/game.cpp index 18df5cc58..a24ded844 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1618,7 +1618,7 @@ bool Game::getServerContent(bool *aborted) dtime, progress); delete[] text; } else { - std::stringstream message; + std::ostringstream message; std::fixed(message); message.precision(0); float receive = client->mediaReceiveProgress() * 100; diff --git a/src/database/database-leveldb.cpp b/src/database/database-leveldb.cpp index 73cd63f6d..39f4c8442 100644 --- a/src/database/database-leveldb.cpp +++ b/src/database/database-leveldb.cpp @@ -70,11 +70,11 @@ bool Database_LevelDB::saveBlock(const v3s16 &pos, const std::string &data) void Database_LevelDB::loadBlock(const v3s16 &pos, std::string *block) { - std::string datastr; leveldb::Status status = m_database->Get(leveldb::ReadOptions(), - i64tos(getBlockAsInteger(pos)), &datastr); + i64tos(getBlockAsInteger(pos)), block); - *block = (status.ok()) ? datastr : ""; + if (!status.ok()) + block->clear(); } bool Database_LevelDB::deleteBlock(const v3s16 &pos) @@ -131,7 +131,7 @@ void PlayerDatabaseLevelDB::savePlayer(RemotePlayer *player) std::string (long) serialized_inventory */ - std::ostringstream os; + std::ostringstream os(std::ios_base::binary); writeU8(os, 1); PlayerSAO *sao = player->getPlayerSAO(); @@ -142,7 +142,7 @@ void PlayerDatabaseLevelDB::savePlayer(RemotePlayer *player) writeF32(os, sao->getRotation().Y); writeU16(os, sao->getBreath()); - StringMap stringvars = sao->getMeta().getStrings(); + const auto &stringvars = sao->getMeta().getStrings(); writeU32(os, stringvars.size()); for (const auto &it : stringvars) { os << serializeString16(it.first); @@ -170,7 +170,7 @@ bool PlayerDatabaseLevelDB::loadPlayer(RemotePlayer *player, PlayerSAO *sao) player->getName(), &raw); if (!s.ok()) return false; - std::istringstream is(raw); + std::istringstream is(raw, std::ios_base::binary); if (readU8(is) > 1) return false; @@ -230,7 +230,7 @@ bool AuthDatabaseLevelDB::getAuth(const std::string &name, AuthEntry &res) leveldb::Status s = m_database->Get(leveldb::ReadOptions(), name, &raw); if (!s.ok()) return false; - std::istringstream is(raw); + std::istringstream is(raw, std::ios_base::binary); /* u8 version = 1 @@ -262,7 +262,7 @@ bool AuthDatabaseLevelDB::getAuth(const std::string &name, AuthEntry &res) bool AuthDatabaseLevelDB::saveAuth(const AuthEntry &authEntry) { - std::ostringstream os; + std::ostringstream os(std::ios_base::binary); writeU8(os, 1); os << serializeString16(authEntry.password); diff --git a/src/database/database-postgresql.cpp b/src/database/database-postgresql.cpp index 29ecd4223..3469f4242 100644 --- a/src/database/database-postgresql.cpp +++ b/src/database/database-postgresql.cpp @@ -274,10 +274,10 @@ void MapDatabasePostgreSQL::loadBlock(const v3s16 &pos, std::string *block) PGresult *results = execPrepared("read_block", ARRLEN(args), args, argLen, argFmt, false); - *block = ""; - if (PQntuples(results)) - *block = std::string(PQgetvalue(results, 0, 0), PQgetlength(results, 0, 0)); + block->assign(PQgetvalue(results, 0, 0), PQgetlength(results, 0, 0)); + else + block->clear(); PQclear(results); } @@ -496,6 +496,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player) execPrepared("remove_player_inventory_items", 1, rmvalues); std::vector inventory_lists = sao->getInventory()->getLists(); + std::ostringstream oss; for (u16 i = 0; i < inventory_lists.size(); i++) { const InventoryList* list = inventory_lists[i]; const std::string &name = list->getName(); @@ -512,9 +513,10 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player) execPrepared("add_player_inventory", 5, inv_values); for (u32 j = 0; j < list->getSize(); j++) { - std::ostringstream os; - list->getItem(j).serialize(os); - std::string itemStr = os.str(), slotId = itos(j); + oss.str(""); + oss.clear(); + list->getItem(j).serialize(oss); + std::string itemStr = oss.str(), slotId = itos(j); const char* invitem_values[] = { player->getName(), diff --git a/src/database/database-redis.cpp b/src/database/database-redis.cpp index 096ea504d..5ffff67b7 100644 --- a/src/database/database-redis.cpp +++ b/src/database/database-redis.cpp @@ -127,8 +127,7 @@ void Database_Redis::loadBlock(const v3s16 &pos, std::string *block) switch (reply->type) { case REDIS_REPLY_STRING: { - *block = std::string(reply->str, reply->len); - // std::string copies the memory so this won't cause any problems + block->assign(reply->str, reply->len); freeReplyObject(reply); return; } @@ -141,8 +140,7 @@ void Database_Redis::loadBlock(const v3s16 &pos, std::string *block) "Redis command 'HGET %s %s' errored: ") + errstr); } case REDIS_REPLY_NIL: { - *block = ""; - // block not found in database + block->clear(); freeReplyObject(reply); return; } diff --git a/src/database/database-sqlite3.cpp b/src/database/database-sqlite3.cpp index 4560743b9..898acc265 100644 --- a/src/database/database-sqlite3.cpp +++ b/src/database/database-sqlite3.cpp @@ -302,7 +302,10 @@ void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block) const char *data = (const char *) sqlite3_column_blob(m_stmt_read, 0); size_t len = sqlite3_column_bytes(m_stmt_read, 0); - *block = (data) ? std::string(data, len) : ""; + if (data) + block->assign(data, len); + else + block->clear(); sqlite3_step(m_stmt_read); // We should never get more than 1 row, so ok to reset @@ -491,6 +494,7 @@ void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player) sqlite3_reset(m_stmt_player_remove_inventory_items); std::vector inventory_lists = sao->getInventory()->getLists(); + std::ostringstream oss; for (u16 i = 0; i < inventory_lists.size(); i++) { const InventoryList* list = inventory_lists[i]; @@ -503,9 +507,10 @@ void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player) sqlite3_reset(m_stmt_player_add_inventory); for (u32 j = 0; j < list->getSize(); j++) { - std::ostringstream os; - list->getItem(j).serialize(os); - std::string itemStr = os.str(); + oss.str(""); + oss.clear(); + list->getItem(j).serialize(oss); + std::string itemStr = oss.str(); str_to_sqlite(m_stmt_player_add_inventory_items, 1, player->getName()); int_to_sqlite(m_stmt_player_add_inventory_items, 2, i); diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp index 049e21a16..0610c85cc 100644 --- a/src/gui/guiChatConsole.cpp +++ b/src/gui/guiChatConsole.cpp @@ -729,7 +729,6 @@ void GUIChatConsole::middleClick(s32 col, s32 row) msg << gettext("Failed to open webpage"); } msg << " '" << weblink << "'"; - msg.flush(); m_chat_backend->addUnparsedMessage(utf8_to_wide(msg.str())); } } diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 09b004f8f..797fd3ff6 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3933,9 +3933,7 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode) } if (e != 0) { - std::stringstream ss; - ss << (e->getActiveTab() +1); - fields[name] = ss.str(); + fields[name] = itos(e->getActiveTab() + 1); } } else if (s.ftype == f_CheckBox) { // No dynamic cast possible due to some distributions shipped @@ -3961,12 +3959,10 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode) e = static_cast(element); if (e) { - std::stringstream os; - os << e->getPos(); if (s.fdefault == L"Changed") - fields[name] = "CHG:" + os.str(); + fields[name] = "CHG:" + itos(e->getPos()); else - fields[name] = "VAL:" + os.str(); + fields[name] = "VAL:" + itos(e->getPos()); } } else if (s.ftype == f_AnimatedImage) { // No dynamic cast possible due to some distributions shipped diff --git a/src/inventory.cpp b/src/inventory.cpp index b3bed623a..da6517e62 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -460,7 +460,6 @@ void InventoryList::deSerialize(std::istream &is) std::getline(is, line, '\n'); std::istringstream iss(line); - //iss.imbue(std::locale("C")); std::string name; std::getline(iss, name, ' '); diff --git a/src/itemstackmetadata.cpp b/src/itemstackmetadata.cpp index 7a26fbb0e..529e0149f 100644 --- a/src/itemstackmetadata.cpp +++ b/src/itemstackmetadata.cpp @@ -60,7 +60,7 @@ bool ItemStackMetadata::setString(const std::string &name, const std::string &va void ItemStackMetadata::serialize(std::ostream &os) const { - std::ostringstream os2; + std::ostringstream os2(std::ios_base::binary); os2 << DESERIALIZE_START; for (const auto &stringvar : m_stringvars) { if (!stringvar.first.empty() || !stringvar.second.empty()) diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 9c9c59d13..128240c02 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -261,7 +261,7 @@ void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt) return; std::istringstream is(pkt->readLongString(), std::ios::binary); - std::stringstream sstr; + std::stringstream sstr(std::ios::binary); decompressZlib(is, sstr); NodeMetadataList meta_updates_list(false); @@ -760,12 +760,11 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt) // Decompress node definitions std::istringstream tmp_is(pkt->readLongString(), std::ios::binary); - std::ostringstream tmp_os; + std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out); decompressZlib(tmp_is, tmp_os); // Deserialize node definitions - std::istringstream tmp_is2(tmp_os.str()); - m_nodedef->deSerialize(tmp_is2); + m_nodedef->deSerialize(tmp_os); m_nodedef_received = true; } @@ -780,12 +779,11 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt) // Decompress item definitions std::istringstream tmp_is(pkt->readLongString(), std::ios::binary); - std::ostringstream tmp_os; + std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out); decompressZlib(tmp_is, tmp_os); // Deserialize node definitions - std::istringstream tmp_is2(tmp_os.str()); - m_itemdef->deSerialize(tmp_is2); + m_itemdef->deSerialize(tmp_os); m_itemdef_received = true; } diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index d848b75b8..19734b913 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -76,10 +76,7 @@ static void set_vector_metatable(lua_State *L) 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()); } 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(value); lua_pushinteger(L, seed); lua_setfield(L, -2, "seed"); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 9152b5f7f..2405cd90d 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -272,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(L, 3); + if (!lua_isnoneornil(L, 3)) + level = readParam(L, 3); - std::ostringstream os; - compressZlib(std::string(data, size), os, level); + std::ostringstream os(std::ios_base::binary); + compressZlib(reinterpret_cast(data), size, os, level); std::string out = os.str(); @@ -292,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(); diff --git a/src/settings.cpp b/src/settings.cpp index 4def46112..f4de5bec9 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -537,11 +537,8 @@ float Settings::getFloat(const std::string &name) const u64 Settings::getU64(const std::string &name) const { - u64 value = 0; std::string s = get(name); - std::istringstream ss(s); - ss >> value; - return value; + return from_string(s); } diff --git a/src/unittest/test_areastore.cpp b/src/unittest/test_areastore.cpp index 691cd69d2..2af3ca90c 100644 --- a/src/unittest/test_areastore.cpp +++ b/src/unittest/test_areastore.cpp @@ -135,7 +135,7 @@ void TestAreaStore::testSerialization() b.data = "Area BB"; store.insertArea(&b); - std::ostringstream os; + std::ostringstream os(std::ios_base::binary); store.serialize(os); std::string str = os.str(); @@ -157,7 +157,7 @@ void TestAreaStore::testSerialization() UASSERTEQ(const std::string &, str, str_wanted); - std::istringstream is(str); + std::istringstream is(str, std::ios_base::binary); store.deserialize(is); // deserialize() doesn't clear the store diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index d770101f2..281061229 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -248,7 +248,7 @@ std::string serializeJsonStringIfNeeded(const std::string &s) std::string deSerializeJsonStringIfNeeded(std::istream &is) { - std::ostringstream tmp_os; + std::stringstream tmp_os(std::ios_base::binary | std::ios_base::in | std::ios_base::out); bool expect_initial_quote = true; bool is_json = false; bool was_backslash = false; @@ -280,8 +280,7 @@ std::string deSerializeJsonStringIfNeeded(std::istream &is) expect_initial_quote = false; } if (is_json) { - std::istringstream tmp_is(tmp_os.str(), std::ios::binary); - return deSerializeJsonString(tmp_is); + return deSerializeJsonString(tmp_os); } return tmp_os.str(); -- cgit v1.2.3