diff options
Diffstat (limited to 'src/script/cpp_api')
-rw-r--r-- | src/script/cpp_api/s_async.cpp | 95 | ||||
-rw-r--r-- | src/script/cpp_api/s_async.h | 30 | ||||
-rw-r--r-- | src/script/cpp_api/s_base.cpp | 64 | ||||
-rw-r--r-- | src/script/cpp_api/s_base.h | 20 | ||||
-rw-r--r-- | src/script/cpp_api/s_entity.cpp | 31 | ||||
-rw-r--r-- | src/script/cpp_api/s_env.cpp | 195 | ||||
-rw-r--r-- | src/script/cpp_api/s_env.h | 20 | ||||
-rw-r--r-- | src/script/cpp_api/s_internal.h | 42 | ||||
-rw-r--r-- | src/script/cpp_api/s_inventory.cpp | 33 | ||||
-rw-r--r-- | src/script/cpp_api/s_item.cpp | 56 | ||||
-rw-r--r-- | src/script/cpp_api/s_item.h | 2 | ||||
-rw-r--r-- | src/script/cpp_api/s_mainmenu.cpp | 10 | ||||
-rw-r--r-- | src/script/cpp_api/s_node.cpp | 47 | ||||
-rw-r--r-- | src/script/cpp_api/s_nodemeta.cpp | 33 | ||||
-rw-r--r-- | src/script/cpp_api/s_player.cpp | 6 | ||||
-rw-r--r-- | src/script/cpp_api/s_security.cpp | 13 | ||||
-rw-r--r-- | src/script/cpp_api/s_security.h | 5 | ||||
-rw-r--r-- | src/script/cpp_api/s_server.cpp | 12 |
18 files changed, 466 insertions, 248 deletions
diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp index c00b22f98..9bf3fcf49 100644 --- a/src/script/cpp_api/s_async.cpp +++ b/src/script/cpp_api/s_async.cpp @@ -47,32 +47,31 @@ AsyncEngine::~AsyncEngine() // Request all threads to stop for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin(); it != workerThreads.end(); it++) { - (*it)->Stop(); + (*it)->stop(); } // Wake up all threads for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin(); it != workerThreads.end(); it++) { - jobQueueCounter.Post(); + jobQueueCounter.post(); } // Wait for threads to finish for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin(); it != workerThreads.end(); it++) { - (*it)->Wait(); + (*it)->wait(); } // Force kill all threads for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin(); it != workerThreads.end(); it++) { - (*it)->Kill(); delete *it; } - jobQueueMutex.Lock(); + jobQueueMutex.lock(); jobQueue.clear(); - jobQueueMutex.Unlock(); + jobQueueMutex.unlock(); workerThreads.clear(); } @@ -92,16 +91,17 @@ void AsyncEngine::initialize(unsigned int numEngines) initDone = true; for (unsigned int i = 0; i < numEngines; i++) { - AsyncWorkerThread *toAdd = new AsyncWorkerThread(this, i); + AsyncWorkerThread *toAdd = new AsyncWorkerThread(this, + std::string("AsyncWorker-") + itos(i)); workerThreads.push_back(toAdd); - toAdd->Start(); + toAdd->start(); } } /******************************************************************************/ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params) { - jobQueueMutex.Lock(); + jobQueueMutex.lock(); LuaJobInfo toAdd; toAdd.id = jobIdCounter++; toAdd.serializedFunction = func; @@ -109,9 +109,9 @@ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params) jobQueue.push_back(toAdd); - jobQueueCounter.Post(); + jobQueueCounter.post(); - jobQueueMutex.Unlock(); + jobQueueMutex.unlock(); return toAdd.id; } @@ -119,8 +119,8 @@ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params) /******************************************************************************/ LuaJobInfo AsyncEngine::getJob() { - jobQueueCounter.Wait(); - jobQueueMutex.Lock(); + jobQueueCounter.wait(); + jobQueueMutex.lock(); LuaJobInfo retval; retval.valid = false; @@ -130,7 +130,7 @@ LuaJobInfo AsyncEngine::getJob() jobQueue.pop_front(); retval.valid = true; } - jobQueueMutex.Unlock(); + jobQueueMutex.unlock(); return retval; } @@ -138,16 +138,17 @@ LuaJobInfo AsyncEngine::getJob() /******************************************************************************/ void AsyncEngine::putJobResult(LuaJobInfo result) { - resultQueueMutex.Lock(); + resultQueueMutex.lock(); resultQueue.push_back(result); - resultQueueMutex.Unlock(); + resultQueueMutex.unlock(); } /******************************************************************************/ -void AsyncEngine::step(lua_State *L, int errorhandler) +void AsyncEngine::step(lua_State *L) { + int error_handler = PUSH_ERROR_HANDLER(L); lua_getglobal(L, "core"); - resultQueueMutex.Lock(); + resultQueueMutex.lock(); while (!resultQueue.empty()) { LuaJobInfo jobDone = resultQueue.front(); resultQueue.pop_front(); @@ -164,16 +165,16 @@ void AsyncEngine::step(lua_State *L, int errorhandler) lua_pushlstring(L, jobDone.serializedResult.data(), jobDone.serializedResult.size()); - PCALL_RESL(L, lua_pcall(L, 2, 0, errorhandler)); + PCALL_RESL(L, lua_pcall(L, 2, 0, error_handler)); } - resultQueueMutex.Unlock(); - lua_pop(L, 1); // Pop core + resultQueueMutex.unlock(); + lua_pop(L, 2); // Pop core and error handler } /******************************************************************************/ void AsyncEngine::pushFinishedJobs(lua_State* L) { // Result Table - resultQueueMutex.Lock(); + MutexAutoLock l(resultQueueMutex); unsigned int index = 1; lua_createtable(L, resultQueue.size(), 0); @@ -197,8 +198,6 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) { lua_rawseti(L, top, index++); } - - resultQueueMutex.Unlock(); } /******************************************************************************/ @@ -214,10 +213,10 @@ void AsyncEngine::prepareEnvironment(lua_State* L, int top) /******************************************************************************/ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher, - unsigned int threadNum) : + const std::string &name) : + Thread(name), ScriptApiBase(), - jobDispatcher(jobDispatcher), - threadnum(threadNum) + jobDispatcher(jobDispatcher) { lua_State *L = getStack(); @@ -235,50 +234,42 @@ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher, /******************************************************************************/ AsyncWorkerThread::~AsyncWorkerThread() { - sanity_check(IsRunning() == false); + sanity_check(!isRunning()); } /******************************************************************************/ -void* AsyncWorkerThread::Thread() +void* AsyncWorkerThread::run() { - ThreadStarted(); - - // Register thread for error logging - char number[21]; - snprintf(number, sizeof(number), "%u", threadnum); - log_register_thread(std::string("AsyncWorkerThread_") + number); - - porting::setThreadName((std::string("AsyncWorkTh_") + number).c_str()); - lua_State *L = getStack(); std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua"; - if (!loadScript(script)) { - errorstream - << "AsyncWorkerThread execution of async base environment failed!" - << std::endl; - abort(); + try { + loadScript(script); + } catch (const ModError &e) { + errorstream << "Execution of async base environment failed: " + << e.what() << std::endl; + FATAL_ERROR("Execution of async base environment failed"); } + int error_handler = PUSH_ERROR_HANDLER(L); + lua_getglobal(L, "core"); if (lua_isnil(L, -1)) { - errorstream << "Unable to find core within async environment!"; - abort(); + FATAL_ERROR("Unable to find core within async environment!"); } // Main loop - while (!StopRequested()) { + while (!stopRequested()) { // Wait for job LuaJobInfo toProcess = jobDispatcher->getJob(); - if (toProcess.valid == false || StopRequested()) { + if (toProcess.valid == false || stopRequested()) { continue; } lua_getfield(L, -1, "job_processor"); if (lua_isnil(L, -1)) { - errorstream << "Unable to get async job processor!" << std::endl; - abort(); + FATAL_ERROR("Unable to get async job processor!"); } luaL_checktype(L, -1, LUA_TFUNCTION); @@ -291,7 +282,7 @@ void* AsyncWorkerThread::Thread() toProcess.serializedParams.data(), toProcess.serializedParams.size()); - int result = lua_pcall(L, 2, 1, m_errorhandler); + int result = lua_pcall(L, 2, 1, error_handler); if (result) { PCALL_RES(result); toProcess.serializedResult = ""; @@ -308,9 +299,7 @@ void* AsyncWorkerThread::Thread() jobDispatcher->putJobResult(toProcess); } - lua_pop(L, 1); // Pop core - - log_deregister_thread(); + lua_pop(L, 2); // Pop core and error handler return 0; } diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index a6459c18d..8d612d58c 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -24,9 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <deque> #include <map> -#include "jthread/jthread.h" -#include "jthread/jmutex.h" -#include "jthread/jsemaphore.h" +#include "threading/thread.h" +#include "threading/mutex.h" +#include "threading/semaphore.h" #include "debug.h" #include "lua.h" #include "cpp_api/s_base.h" @@ -52,24 +52,15 @@ struct LuaJobInfo { }; // Asynchronous working environment -class AsyncWorkerThread : public JThread, public ScriptApiBase { +class AsyncWorkerThread : public Thread, public ScriptApiBase { public: - /** - * default constructor - * @param pointer to job dispatcher - */ - AsyncWorkerThread(AsyncEngine* jobDispatcher, unsigned int threadNum); - + AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name); virtual ~AsyncWorkerThread(); - void *Thread(); + void *run(); private: AsyncEngine *jobDispatcher; - - // Thread number. Used for debug output - unsigned int threadnum; - }; // Asynchornous thread and job management @@ -104,9 +95,8 @@ public: * Engine step to process finished jobs * the engine step is one way to pass events back, PushFinishedJobs another * @param L The Lua stack - * @param errorhandler Stack index of the Lua error handler */ - void step(lua_State *L, int errorhandler); + void step(lua_State *L); /** * Push a list of finished jobs onto the stack @@ -148,13 +138,13 @@ private: unsigned int jobIdCounter; // Mutex to protect job queue - JMutex jobQueueMutex; + Mutex jobQueueMutex; // Job queue std::deque<LuaJobInfo> jobQueue; // Mutex to protect result queue - JMutex resultQueueMutex; + Mutex resultQueueMutex; // Result queue std::deque<LuaJobInfo> resultQueue; @@ -162,7 +152,7 @@ private: std::vector<AsyncWorkerThread*> workerThreads; // Counter semaphore for job dispatching - JSemaphore jobQueueCounter; + Semaphore jobQueueCounter; }; #endif // CPP_API_ASYNC_EVENTS_HEADER diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index dcfbac4bf..679a517ee 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -52,13 +52,13 @@ public: { // Store current mod name in registry lua_pushstring(L, mod_name.c_str()); - lua_setfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); } ~ModNameStorer() { // Clear current mod name from registry lua_pushnil(L); - lua_setfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); } }; @@ -67,10 +67,11 @@ public: ScriptApiBase */ -ScriptApiBase::ScriptApiBase() +ScriptApiBase::ScriptApiBase() : + m_luastackmutex() { #ifdef SCRIPTAPI_LOCK_DEBUG - m_locked = false; + m_lock_recursion_count = 0; #endif m_luastack = luaL_newstate(); @@ -78,13 +79,13 @@ ScriptApiBase::ScriptApiBase() luaL_openlibs(m_luastack); - // Add and save an error handler - lua_pushcfunction(m_luastack, script_error_handler); - m_errorhandler = lua_gettop(m_luastack); - // Make the ScriptApiBase* accessible to ModApiBase lua_pushlightuserdata(m_luastack, this); - lua_setfield(m_luastack, LUA_REGISTRYINDEX, "scriptapi"); + lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); + + // Add and save an error handler + lua_pushcfunction(m_luastack, script_error_handler); + lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_ERROR_HANDLER); // If we are using LuaJIT add a C++ wrapper function to catch // exceptions thrown in Lua -> C++ calls @@ -119,40 +120,36 @@ ScriptApiBase::~ScriptApiBase() lua_close(m_luastack); } -bool ScriptApiBase::loadMod(const std::string &script_path, - const std::string &mod_name, std::string *error) +void ScriptApiBase::loadMod(const std::string &script_path, + const std::string &mod_name) { ModNameStorer mod_name_storer(getStack(), mod_name); - return loadScript(script_path, error); + loadScript(script_path); } -bool ScriptApiBase::loadScript(const std::string &script_path, std::string *error) +void ScriptApiBase::loadScript(const std::string &script_path) { verbosestream << "Loading and running script from " << script_path << std::endl; lua_State *L = getStack(); + int error_handler = PUSH_ERROR_HANDLER(L); + bool ok; if (m_secure) { ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str()); } else { ok = !luaL_loadfile(L, script_path.c_str()); } - ok = ok && !lua_pcall(L, 0, 0, m_errorhandler); + ok = ok && !lua_pcall(L, 0, 0, error_handler); if (!ok) { std::string error_msg = lua_tostring(L, -1); - if (error) - *error = error_msg; - errorstream << "========== ERROR FROM LUA ===========" << std::endl - << "Failed to load and run script from " << std::endl - << script_path << ":" << std::endl << std::endl - << error_msg << std::endl << std::endl - << "======= END OF ERROR FROM LUA ========" << std::endl; - lua_pop(L, 1); // Pop error message from stack - return false; + lua_pop(L, 2); // Pop error message and error handler + throw ModError("Failed to load and run script from " + + script_path + ":\n" + error_msg); } - return true; + lua_pop(L, 1); // Pop error handler } // Push the list of callbacks (a lua table). @@ -161,35 +158,40 @@ bool ScriptApiBase::loadScript(const std::string &script_path, std::string *erro // - runs the callbacks // - replaces the table and arguments with the return value, // computed depending on mode +// This function must only be called with scriptlock held (i.e. inside of a +// code block with SCRIPTAPI_PRECHECKHEADER declared) void ScriptApiBase::runCallbacksRaw(int nargs, RunCallbacksMode mode, const char *fxn) { +#ifdef SCRIPTAPI_LOCK_DEBUG + assert(m_lock_recursion_count > 0); +#endif lua_State *L = getStack(); FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments"); // Insert error handler - lua_pushcfunction(L, script_error_handler); - int errorhandler = lua_gettop(L) - nargs - 1; - lua_insert(L, errorhandler); + 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, errorhandler + 1); + lua_insert(L, error_handler + 1); // Insert mode after table lua_pushnumber(L, (int)mode); - lua_insert(L, errorhandler + 3); + 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, errorhandler); + int result = lua_pcall(L, nargs + 2, 1, error_handler); if (result != 0) scriptError(result, fxn); - lua_remove(L, -2); // Remove error handler + lua_remove(L, error_handler); } void ScriptApiBase::realityCheck() diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index d653b5bac..f52474f00 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -28,15 +28,15 @@ extern "C" { } #include "irrlichttypes.h" -#include "jthread/jmutex.h" -#include "jthread/jmutexautolock.h" +#include "threads.h" +#include "threading/mutex.h" +#include "threading/mutex_auto_lock.h" #include "common/c_types.h" #include "common/c_internal.h" #define SCRIPTAPI_LOCK_DEBUG #define SCRIPTAPI_DEBUG -#define SCRIPT_MOD_NAME_FIELD "current_mod_name" // MUST be an invalid mod name so that mods can't // use that name to bypass security! #define BUILTIN_MOD_NAME "*builtin*" @@ -64,9 +64,9 @@ public: ScriptApiBase(); virtual ~ScriptApiBase(); - bool loadMod(const std::string &script_path, const std::string &mod_name, - std::string *error=NULL); - bool loadScript(const std::string &script_path, std::string *error=NULL); + // These throw a ModError on failure + void loadMod(const std::string &script_path, const std::string &mod_name); + void loadScript(const std::string &script_path); void runCallbacksRaw(int nargs, RunCallbacksMode mode, const char *fxn); @@ -83,6 +83,7 @@ public: protected: friend class LuaABM; + friend class LuaLBM; friend class InvRef; friend class ObjectRef; friend class NodeMetaRef; @@ -108,13 +109,12 @@ protected: void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj); void objectrefGet(lua_State *L, u16 id); - JMutex m_luastackmutex; + RecursiveMutex m_luastackmutex; std::string m_last_run_mod; - // Stack index of Lua error handler - int m_errorhandler; bool m_secure; #ifdef SCRIPTAPI_LOCK_DEBUG - bool m_locked; + int m_lock_recursion_count; + threadid_t m_owning_thread; #endif private: diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp index 0d159846a..378a6bf09 100644 --- a/src/script/cpp_api/s_entity.cpp +++ b/src/script/cpp_api/s_entity.cpp @@ -80,6 +80,8 @@ void ScriptApiEntity::luaentity_Activate(u16 id, verbosestream << "scriptapi_luaentity_activate: id=" << id << std::endl; + int error_handler = PUSH_ERROR_HANDLER(L); + // Get core.luaentities[id] luaentity_get(L, id); int object = lua_gettop(L); @@ -93,11 +95,11 @@ void ScriptApiEntity::luaentity_Activate(u16 id, lua_pushinteger(L, dtime_s); setOriginFromTable(object); - PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 3, 0, error_handler)); } else { lua_pop(L, 1); } - lua_pop(L, 1); // Pop object + lua_pop(L, 2); // Pop object and error handler } void ScriptApiEntity::luaentity_Remove(u16 id) @@ -126,6 +128,8 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id) //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl; + int error_handler = PUSH_ERROR_HANDLER(L); + // Get core.luaentities[id] luaentity_get(L, id); int object = lua_gettop(L); @@ -140,9 +144,10 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id) lua_pushvalue(L, object); // self setOriginFromTable(object); - PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 1, error_handler)); - lua_remove(L, object); // Remove object + lua_remove(L, object); + lua_remove(L, error_handler); size_t len = 0; const char *s = lua_tolstring(L, -1, &len); @@ -196,6 +201,8 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime) //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; + int error_handler = PUSH_ERROR_HANDLER(L); + // Get core.luaentities[id] luaentity_get(L, id); int object = lua_gettop(L); @@ -211,9 +218,9 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime) lua_pushnumber(L, dtime); // dtime setOriginFromTable(object); - PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 0, error_handler)); - lua_pop(L, 1); // Pop object + lua_pop(L, 2); // Pop object and error handler } // Calls entity:on_punch(ObjectRef puncher, time_from_last_punch, @@ -226,6 +233,8 @@ void ScriptApiEntity::luaentity_Punch(u16 id, //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; + int error_handler = PUSH_ERROR_HANDLER(L); + // Get core.luaentities[id] luaentity_get(L,id); int object = lua_gettop(L); @@ -244,9 +253,9 @@ void ScriptApiEntity::luaentity_Punch(u16 id, push_v3f(L, dir); setOriginFromTable(object); - PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 0, error_handler)); - lua_pop(L, 1); // Pop object + lua_pop(L, 2); // Pop object and error handler } // Calls entity:on_rightclick(ObjectRef clicker) @@ -257,6 +266,8 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id, //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; + int error_handler = PUSH_ERROR_HANDLER(L); + // Get core.luaentities[id] luaentity_get(L, id); int object = lua_gettop(L); @@ -272,8 +283,8 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id, objectrefGetOrCreate(L, clicker); // Clicker reference setOriginFromTable(object); - PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 0, error_handler)); - lua_pop(L, 1); // Pop object + lua_pop(L, 2); // Pop object and error handler } diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 9c733773a..82d0d4f0e 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server.h" void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, - u32 blockseed) + u32 blockseed) { SCRIPTAPI_PRECHECKHEADER @@ -44,7 +44,7 @@ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, void ScriptApiEnv::environment_Step(float dtime) { SCRIPTAPI_PRECHECKHEADER - //infostream<<"scriptapi_environment_step"<<std::endl; + //infostream << "scriptapi_environment_step" << std::endl; // Get core.registered_globalsteps lua_getglobal(L, "core"); @@ -58,7 +58,7 @@ void ScriptApiEnv::environment_Step(float dtime) } } -void ScriptApiEnv::player_event(ServerActiveObject* player, std::string type) +void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &type) { SCRIPTAPI_PRECHECKHEADER @@ -82,75 +82,166 @@ void ScriptApiEnv::player_event(ServerActiveObject* player, std::string type) void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) { SCRIPTAPI_PRECHECKHEADER - verbosestream<<"scriptapi_add_environment"<<std::endl; + verbosestream << "scriptapi_add_environment" << std::endl; setEnv(env); /* - Add ActiveBlockModifiers to environment + Add {Loading,Active}BlockModifiers to environment */ // Get core.registered_abms lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_abms"); - luaL_checktype(L, -1, LUA_TTABLE); int registered_abms = lua_gettop(L); - if(lua_istable(L, registered_abms)){ - int table = lua_gettop(L); - lua_pushnil(L); - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - int id = lua_tonumber(L, -2); - int current_abm = lua_gettop(L); - - std::set<std::string> trigger_contents; - lua_getfield(L, current_abm, "nodenames"); - if(lua_istable(L, -1)){ - int table = lua_gettop(L); - lua_pushnil(L); - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - trigger_contents.insert(lua_tostring(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if(lua_isstring(L, -1)){ + if (!lua_istable(L, registered_abms)) { + lua_pop(L, 1); + throw LuaError("core.registered_abms was not a lua table, as expected."); + } + lua_pushnil(L); + while (lua_next(L, registered_abms)) { + // key at index -2 and value at index -1 + int id = lua_tonumber(L, -2); + int current_abm = lua_gettop(L); + + std::set<std::string> trigger_contents; + lua_getfield(L, current_abm, "nodenames"); + if (lua_istable(L, -1)) { + int table = lua_gettop(L); + lua_pushnil(L); + while (lua_next(L, table)) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); trigger_contents.insert(lua_tostring(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); } - lua_pop(L, 1); - - std::set<std::string> required_neighbors; - lua_getfield(L, current_abm, "neighbors"); - if(lua_istable(L, -1)){ - int table = lua_gettop(L); - lua_pushnil(L); - while(lua_next(L, table) != 0){ - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - required_neighbors.insert(lua_tostring(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if(lua_isstring(L, -1)){ + } else if (lua_isstring(L, -1)) { + trigger_contents.insert(lua_tostring(L, -1)); + } + lua_pop(L, 1); + + std::set<std::string> required_neighbors; + lua_getfield(L, current_abm, "neighbors"); + if (lua_istable(L, -1)) { + int table = lua_gettop(L); + lua_pushnil(L); + while (lua_next(L, table)) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); required_neighbors.insert(lua_tostring(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); } - lua_pop(L, 1); + } else if (lua_isstring(L, -1)) { + required_neighbors.insert(lua_tostring(L, -1)); + } + lua_pop(L, 1); + + float trigger_interval = 10.0; + getfloatfield(L, current_abm, "interval", trigger_interval); + + int trigger_chance = 50; + getintfield(L, current_abm, "chance", trigger_chance); - float trigger_interval = 10.0; - getfloatfield(L, current_abm, "interval", trigger_interval); + bool simple_catch_up = true; + getboolfield(L, current_abm, "catch_up", simple_catch_up); - int trigger_chance = 50; - getintfield(L, current_abm, "chance", trigger_chance); + LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors, + trigger_interval, trigger_chance, simple_catch_up); + + env->addActiveBlockModifier(abm); + + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + lua_pop(L, 1); - LuaABM *abm = new LuaABM(L, id, trigger_contents, - required_neighbors, trigger_interval, trigger_chance); + // Get core.registered_lbms + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_lbms"); + int registered_lbms = lua_gettop(L); - env->addActiveBlockModifier(abm); + if (!lua_istable(L, registered_lbms)) { + lua_pop(L, 1); + throw LuaError("core.registered_lbms was not a lua table, as expected."); + } - // removes value, keeps key for next iteration - lua_pop(L, 1); + lua_pushnil(L); + while (lua_next(L, registered_lbms)) { + // key at index -2 and value at index -1 + int id = lua_tonumber(L, -2); + int current_lbm = lua_gettop(L); + + std::set<std::string> trigger_contents; + lua_getfield(L, current_lbm, "nodenames"); + if (lua_istable(L, -1)) { + int table = lua_gettop(L); + lua_pushnil(L); + while (lua_next(L, table)) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + trigger_contents.insert(lua_tostring(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } else if (lua_isstring(L, -1)) { + trigger_contents.insert(lua_tostring(L, -1)); } + lua_pop(L, 1); + + std::string name; + getstringfield(L, current_lbm, "name", name); + + bool run_at_every_load = getboolfield_default(L, current_lbm, + "run_at_every_load", false); + + LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name, + run_at_every_load); + + env->addLoadingBlockModifierDef(lbm); + + // removes value, keeps key for next iteration + lua_pop(L, 1); } lua_pop(L, 1); } + +void ScriptApiEnv::on_emerge_area_completion( + v3s16 blockpos, int action, ScriptCallbackState *state) +{ + Server *server = getServer(); + + // Note that the order of these locks is important! Envlock must *ALWAYS* + // be acquired before attempting to acquire scriptlock, or else ServerThread + // will try to acquire scriptlock after it already owns envlock, thus + // deadlocking EmergeThread and ServerThread + MutexAutoLock envlock(server->m_env_mutex); + + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + lua_rawgeti(L, LUA_REGISTRYINDEX, state->callback_ref); + luaL_checktype(L, -1, LUA_TFUNCTION); + + push_v3s16(L, blockpos); + lua_pushinteger(L, action); + lua_pushinteger(L, state->refcount); + lua_rawgeti(L, LUA_REGISTRYINDEX, state->args_ref); + + setOriginDirect(state->origin.c_str()); + + try { + PCALL_RES(lua_pcall(L, 4, 0, error_handler)); + } catch (LuaError &e) { + server->setAsyncFatalError(e.what()); + } + + lua_pop(L, 1); // Pop error handler + + if (state->refcount == 0) { + luaL_unref(L, LUA_REGISTRYINDEX, state->callback_ref); + luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref); + } +} diff --git a/src/script/cpp_api/s_env.h b/src/script/cpp_api/s_env.h index 180cfabd0..e07024565 100644 --- a/src/script/cpp_api/s_env.h +++ b/src/script/cpp_api/s_env.h @@ -24,19 +24,23 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irr_v3d.h" class ServerEnvironment; -struct MapgenParams; +struct ScriptCallbackState; -class ScriptApiEnv - : virtual public ScriptApiBase +class ScriptApiEnv : virtual public ScriptApiBase { public: - // On environment step + // Called on environment step void environment_Step(float dtime); - // After generating a piece of map - void environment_OnGenerated(v3s16 minp, v3s16 maxp,u32 blockseed); - //called on player event - void player_event(ServerActiveObject* player, std::string type); + // Called after generating a piece of map + void environment_OnGenerated(v3s16 minp, v3s16 maxp, u32 blockseed); + + // Called on player event + void player_event(ServerActiveObject *player, const std::string &type); + + // Called after emerge of a block queued from core.emerge_area() + void on_emerge_area_completion(v3s16 blockpos, int action, + ScriptCallbackState *state); void initializeEnvironment(ServerEnvironment *env); }; diff --git a/src/script/cpp_api/s_internal.h b/src/script/cpp_api/s_internal.h index 9999a584a..37473c497 100644 --- a/src/script/cpp_api/s_internal.h +++ b/src/script/cpp_api/s_internal.h @@ -32,28 +32,50 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifdef SCRIPTAPI_LOCK_DEBUG #include "debug.h" // assert() + class LockChecker { public: - LockChecker(bool* variable) { - assert(*variable == false); + LockChecker(int *recursion_counter, threadid_t *owning_thread) + { + m_lock_recursion_counter = recursion_counter; + m_owning_thread = owning_thread; + m_original_level = *recursion_counter; + + if (*m_lock_recursion_counter > 0) + assert(thr_is_current_thread(*m_owning_thread)); + else + *m_owning_thread = thr_get_current_thread_id(); - m_variable = variable; - *m_variable = true; + (*m_lock_recursion_counter)++; } - ~LockChecker() { - *m_variable = false; + + ~LockChecker() + { + assert(thr_is_current_thread(*m_owning_thread)); + assert(*m_lock_recursion_counter > 0); + + (*m_lock_recursion_counter)--; + + assert(*m_lock_recursion_counter == m_original_level); } + private: -bool* m_variable; + int *m_lock_recursion_counter; + int m_original_level; + threadid_t *m_owning_thread; }; -#define SCRIPTAPI_LOCK_CHECK LockChecker(&(this->m_locked)) +#define SCRIPTAPI_LOCK_CHECK \ + LockChecker scriptlock_checker( \ + &this->m_lock_recursion_count, \ + &this->m_owning_thread) + #else -#define SCRIPTAPI_LOCK_CHECK while(0) + #define SCRIPTAPI_LOCK_CHECK while(0) #endif #define SCRIPTAPI_PRECHECKHEADER \ - JMutexAutoLock(this->m_luastackmutex); \ + RecursiveMutexAutoLock scriptlock(this->m_luastackmutex); \ SCRIPTAPI_LOCK_CHECK; \ realityCheck(); \ lua_State *L = getStack(); \ diff --git a/src/script/cpp_api/s_inventory.cpp b/src/script/cpp_api/s_inventory.cpp index 019d1ccc0..c90c7d4e2 100644 --- a/src/script/cpp_api/s_inventory.cpp +++ b/src/script/cpp_api/s_inventory.cpp @@ -33,6 +33,8 @@ int ScriptApiDetached::detached_inventory_AllowMove( { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getDetachedInventoryCallback(name, "allow_move")) return count; @@ -48,11 +50,11 @@ int ScriptApiDetached::detached_inventory_AllowMove( lua_pushinteger(L, to_index + 1); // to_index lua_pushinteger(L, count); // count objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 7, 1, error_handler)); if(!lua_isnumber(L, -1)) throw LuaError("allow_move should return a number. name=" + name); int ret = luaL_checkinteger(L, -1); - lua_pop(L, 1); // Pop integer + lua_pop(L, 2); // Pop integer and error handler return ret; } @@ -64,6 +66,8 @@ int ScriptApiDetached::detached_inventory_AllowPut( { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getDetachedInventoryCallback(name, "allow_put")) return stack.count; // All will be accepted @@ -76,11 +80,11 @@ int ScriptApiDetached::detached_inventory_AllowPut( lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 1, error_handler)); if (!lua_isnumber(L, -1)) throw LuaError("allow_put should return a number. name=" + name); int ret = luaL_checkinteger(L, -1); - lua_pop(L, 1); // Pop integer + lua_pop(L, 2); // Pop integer and error handler return ret; } @@ -92,6 +96,8 @@ int ScriptApiDetached::detached_inventory_AllowTake( { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getDetachedInventoryCallback(name, "allow_take")) return stack.count; // All will be accepted @@ -104,11 +110,11 @@ int ScriptApiDetached::detached_inventory_AllowTake( lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 1, error_handler)); if (!lua_isnumber(L, -1)) throw LuaError("allow_take should return a number. name=" + name); int ret = luaL_checkinteger(L, -1); - lua_pop(L, 1); // Pop integer + lua_pop(L, 2); // Pop integer and error handler return ret; } @@ -121,6 +127,8 @@ void ScriptApiDetached::detached_inventory_OnMove( { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getDetachedInventoryCallback(name, "on_move")) return; @@ -136,7 +144,8 @@ void ScriptApiDetached::detached_inventory_OnMove( lua_pushinteger(L, to_index + 1); // to_index lua_pushinteger(L, count); // count objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 7, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } // Report put items @@ -147,6 +156,8 @@ void ScriptApiDetached::detached_inventory_OnPut( { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getDetachedInventoryCallback(name, "on_put")) return; @@ -160,7 +171,8 @@ void ScriptApiDetached::detached_inventory_OnPut( lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } // Report taken items @@ -171,6 +183,8 @@ void ScriptApiDetached::detached_inventory_OnTake( { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getDetachedInventoryCallback(name, "on_take")) return; @@ -184,7 +198,8 @@ void ScriptApiDetached::detached_inventory_OnTake( lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } // Retrieves core.detached_inventories[name][callbackname] diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp index 4d4d416ec..3c84fb8cf 100644 --- a/src/script/cpp_api/s_item.cpp +++ b/src/script/cpp_api/s_item.cpp @@ -34,6 +34,8 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getItemCallback(item.name.c_str(), "on_drop")) return false; @@ -42,7 +44,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item, LuaItemStack::create(L, item); objectrefGetOrCreate(L, dropper); pushFloatPos(L, pos); - PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if (!lua_isnil(L, -1)) { try { item = read_item(L,-1, getServer()); @@ -50,7 +52,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item, throw LuaError(std::string(e.what()) + ". item=" + item.name); } } - lua_pop(L, 1); // Pop item + lua_pop(L, 2); // Pop item and error handler return true; } @@ -59,6 +61,8 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getItemCallback(item.name.c_str(), "on_place")) return false; @@ -67,7 +71,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item, LuaItemStack::create(L, item); objectrefGetOrCreate(L, placer); pushPointedThing(pointed); - PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if (!lua_isnil(L, -1)) { try { item = read_item(L,-1, getServer()); @@ -75,7 +79,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item, throw LuaError(std::string(e.what()) + ". item=" + item.name); } } - lua_pop(L, 1); // Pop item + lua_pop(L, 2); // Pop item and error handler return true; } @@ -84,6 +88,8 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Push callback function on stack if (!getItemCallback(item.name.c_str(), "on_use")) return false; @@ -92,7 +98,7 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, LuaItemStack::create(L, item); objectrefGetOrCreate(L, user); pushPointedThing(pointed); - PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 3, 1, error_handler)); if(!lua_isnil(L, -1)) { try { item = read_item(L,-1, getServer()); @@ -100,7 +106,33 @@ bool ScriptApiItem::item_OnUse(ItemStack &item, throw LuaError(std::string(e.what()) + ". item=" + item.name); } } - lua_pop(L, 1); // Pop item + lua_pop(L, 2); // Pop item and error handler + return true; +} + +bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *user) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + if (!getItemCallback(item.name.c_str(), "on_secondary_use")) + return false; + + LuaItemStack::create(L, item); + objectrefGetOrCreate(L, user); + PointedThing pointed; + pointed.type = POINTEDTHING_NOTHING; + pushPointedThing(pointed); + PCALL_RES(lua_pcall(L, 3, 1, error_handler)); + if (!lua_isnil(L, -1)) { + try { + item = read_item(L, -1, getServer()); + } catch (LuaError &e) { + throw LuaError(std::string(e.what()) + ". item=" + item.name); + } + } + lua_pop(L, 2); // Pop item and error handler return true; } @@ -109,6 +141,8 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + lua_getglobal(L, "core"); lua_getfield(L, -1, "on_craft"); LuaItemStack::create(L, item); @@ -122,7 +156,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user, push_items(L, items); InvRef::create(L, craft_inv); - PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 4, 1, error_handler)); if (!lua_isnil(L, -1)) { try { item = read_item(L,-1, getServer()); @@ -130,7 +164,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user, throw LuaError(std::string(e.what()) + ". item=" + item.name); } } - lua_pop(L, 1); // Pop item + lua_pop(L, 2); // Pop item and error handler return true; } @@ -139,6 +173,8 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + lua_getglobal(L, "core"); lua_getfield(L, -1, "craft_predict"); LuaItemStack::create(L, item); @@ -152,7 +188,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user, push_items(L, items); InvRef::create(L, craft_inv); - PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 4, 1, error_handler)); if (!lua_isnil(L, -1)) { try { item = read_item(L,-1, getServer()); @@ -160,7 +196,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user, throw LuaError(std::string(e.what()) + ". item=" + item.name); } } - lua_pop(L, 1); // Pop item + lua_pop(L, 2); // Pop item and error handler return true; } diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h index 88cc1909d..7350a71c5 100644 --- a/src/script/cpp_api/s_item.h +++ b/src/script/cpp_api/s_item.h @@ -42,6 +42,8 @@ public: ServerActiveObject *placer, const PointedThing &pointed); bool item_OnUse(ItemStack &item, ServerActiveObject *user, const PointedThing &pointed); + bool item_OnSecondaryUse(ItemStack &item, + ServerActiveObject *user); bool item_OnCraft(ItemStack &item, ServerActiveObject *user, const InventoryList *old_craft_grid, const InventoryLocation &craft_inv); bool item_CraftPredict(ItemStack &item, ServerActiveObject *user, diff --git a/src/script/cpp_api/s_mainmenu.cpp b/src/script/cpp_api/s_mainmenu.cpp index 17ceff082..e9a7a13b9 100644 --- a/src/script/cpp_api/s_mainmenu.cpp +++ b/src/script/cpp_api/s_mainmenu.cpp @@ -43,6 +43,8 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Get handler function lua_getglobal(L, "core"); lua_getfield(L, -1, "event_handler"); @@ -55,13 +57,16 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text) // Call it lua_pushstring(L, text.c_str()); - PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Get handler function lua_getglobal(L, "core"); lua_getfield(L, -1, "button_handler"); @@ -84,6 +89,7 @@ void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields) } // Call it - PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp index dac058b13..17f0f0dac 100644 --- a/src/script/cpp_api/s_node.cpp +++ b/src/script/cpp_api/s_node.cpp @@ -57,6 +57,7 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] = {CPT2_FACEDIR, "facedir"}, {CPT2_WALLMOUNTED, "wallmounted"}, {CPT2_LEVELED, "leveled"}, + {CPT2_DEGROTATE, "degrotate"}, {0, NULL}, }; @@ -81,6 +82,7 @@ struct EnumString ScriptApiNode::es_NodeBoxType[] = {NODEBOX_FIXED, "fixed"}, {NODEBOX_WALLMOUNTED, "wallmounted"}, {NODEBOX_LEVELED, "leveled"}, + {NODEBOX_CONNECTED, "connected"}, {0, NULL}, }; @@ -95,6 +97,8 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // Push callback function on stack @@ -106,7 +110,8 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node, pushnode(L, node, ndef); objectrefGetOrCreate(L, puncher); pushPointedThing(pointed); - PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 4, 0, error_handler)); + lua_pop(L, 1); // Pop error handler return true; } @@ -115,6 +120,8 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // Push callback function on stack @@ -125,7 +132,8 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node, push_v3s16(L, p); pushnode(L, node, ndef); objectrefGetOrCreate(L, digger); - PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 3, 0, error_handler)); + lua_pop(L, 1); // Pop error handler return true; } @@ -133,6 +141,8 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // Push callback function on stack @@ -141,13 +151,16 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node) // Call function push_v3s16(L, p); - PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // Push callback function on stack @@ -156,13 +169,16 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node) // Call function push_v3s16(L, p); - PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // Push callback function on stack @@ -172,13 +188,16 @@ void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node) // Call function push_v3s16(L, p); pushnode(L, node, ndef); - PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // Push callback function on stack @@ -188,7 +207,8 @@ bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime) // Call function push_v3s16(L, p); lua_pushnumber(L,dtime); - PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 1, error_handler)); + lua_remove(L, error_handler); return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true; } @@ -199,6 +219,8 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -223,23 +245,30 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p, lua_settable(L, -3); } objectrefGetOrCreate(L, sender); // player - PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 4, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } void ScriptApiNode::node_falling_update(v3s16 p) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + lua_getglobal(L, "nodeupdate"); push_v3s16(L, p); - PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } void ScriptApiNode::node_falling_update_single(v3s16 p) { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + lua_getglobal(L, "nodeupdate_single"); push_v3s16(L, p); - PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp index 638750b0e..d050c0bc9 100644 --- a/src/script/cpp_api/s_nodemeta.cpp +++ b/src/script/cpp_api/s_nodemeta.cpp @@ -34,6 +34,8 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -54,12 +56,12 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p, lua_pushinteger(L, to_index + 1); // to_index lua_pushinteger(L, count); // count objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler)); + 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); int num = luaL_checkinteger(L, -1); - lua_pop(L, 1); // Pop integer + lua_pop(L, 2); // Pop integer and error handler return num; } @@ -70,6 +72,8 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -88,12 +92,12 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p, lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler)); + 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); int num = luaL_checkinteger(L, -1); - lua_pop(L, 1); // Pop integer + lua_pop(L, 2); // Pop integer and error handler return num; } @@ -104,6 +108,8 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -122,12 +128,12 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p, lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler)); + 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); int num = luaL_checkinteger(L, -1); - lua_pop(L, 1); // Pop integer + lua_pop(L, 2); // Pop integer and error handler return num; } @@ -139,6 +145,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -159,7 +167,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p, lua_pushinteger(L, to_index + 1); // to_index lua_pushinteger(L, count); // count objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 7, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } // Report put items @@ -169,6 +178,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -187,7 +198,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p, lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } // Report taken items @@ -197,6 +209,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + INodeDefManager *ndef = getServer()->ndef(); // If node doesn't exist, we don't know what callback to call @@ -215,7 +229,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p, lua_pushinteger(L, index + 1); // index LuaItemStack::create(L, stack); // stack objectrefGetOrCreate(L, player); // player - PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 5, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } ScriptApiNodemeta::ScriptApiNodemeta() diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp index ef3c31cfd..807430678 100644 --- a/src/script/cpp_api/s_player.cpp +++ b/src/script/cpp_api/s_player.cpp @@ -74,6 +74,8 @@ s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); + // Get core.registered_on_player_hpchange lua_getglobal(L, "core"); lua_getfield(L, -1, "registered_on_player_hpchange"); @@ -81,9 +83,9 @@ s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player, objectrefGetOrCreate(L, player); lua_pushnumber(L, hp_change); - PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 1, error_handler)); hp_change = lua_tointeger(L, -1); - lua_pop(L, -1); + lua_pop(L, 2); // Pop result and error handler return hp_change; } diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 6a6d40307..730235c7b 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -47,7 +47,7 @@ static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int // Pushes the original version of a library function on the stack, from the old version static inline void push_original(lua_State *L, const char *lib, const char *func) { - lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup"); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); lua_getfield(L, -1, lib); lua_remove(L, -2); // Remove globals_backup lua_getfield(L, -1, func); @@ -116,7 +116,6 @@ void ScriptApiSecurity::initializeSecurity() "upvaluejoin", "sethook", "debug", - "getupvalue", "setlocal", }; static const char *package_whitelist[] = { @@ -143,7 +142,7 @@ void ScriptApiSecurity::initializeSecurity() // Backup globals to the registry lua_getglobal(L, "_G"); - lua_setfield(L, LUA_REGISTRYINDEX, "globals_backup"); + lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); // Replace the global environment with an empty one #if LUA_VERSION_NUM <= 501 @@ -165,7 +164,7 @@ void ScriptApiSecurity::initializeSecurity() #endif // Get old globals - lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup"); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); int old_globals = lua_gettop(L); @@ -241,7 +240,7 @@ void ScriptApiSecurity::initializeSecurity() bool ScriptApiSecurity::isSecure(lua_State *L) { - lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup"); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); bool secure = !lua_isnil(L, -1); lua_pop(L, 1); return secure; @@ -356,7 +355,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path) if (!removed.empty()) abs_path += DIR_DELIM + removed; // Get server from registry - lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi"); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1); lua_pop(L, 1); const Server *server = script->getServer(); @@ -364,7 +363,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path) if (!server) return false; // Get mod name - lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); if (lua_isstring(L, -1)) { std::string mod_name = lua_tostring(L, -1); diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h index 4a4389cf5..97bc5c067 100644 --- a/src/script/cpp_api/s_security.h +++ b/src/script/cpp_api/s_security.h @@ -25,9 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define CHECK_SECURE_PATH(L, path) \ if (!ScriptApiSecurity::checkPath(L, path)) { \ - lua_pushstring(L, (std::string("Attempt to access external file ") + \ - path + " with mod security on.").c_str()); \ - lua_error(L); \ + throw LuaError(std::string("Attempt to access external file ") + \ + path + " with mod security on."); \ } #define CHECK_SECURE_PATH_OPTIONAL(L, path) \ if (ScriptApiSecurity::isSecure(L)) { \ diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp index ec2f9c0af..38bd41f87 100644 --- a/src/script/cpp_api/s_server.cpp +++ b/src/script/cpp_api/s_server.cpp @@ -27,13 +27,15 @@ bool ScriptApiServer::getAuth(const std::string &playername, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); getAuthHandler(); lua_getfield(L, -1, "get_auth"); if (lua_type(L, -1) != LUA_TFUNCTION) throw LuaError("Authentication handler missing get_auth"); lua_pushstring(L, playername.c_str()); - PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 1, 1, error_handler)); lua_remove(L, -2); // Remove auth handler + lua_remove(L, error_handler); // nil = login not allowed if (lua_isnil(L, -1)) @@ -99,6 +101,7 @@ void ScriptApiServer::createAuth(const std::string &playername, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); getAuthHandler(); lua_getfield(L, -1, "create_auth"); lua_remove(L, -2); // Remove auth handler @@ -106,7 +109,8 @@ void ScriptApiServer::createAuth(const std::string &playername, throw LuaError("Authentication handler missing create_auth"); lua_pushstring(L, playername.c_str()); lua_pushstring(L, password.c_str()); - PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 0, error_handler)); + lua_pop(L, 1); // Pop error handler } bool ScriptApiServer::setPassword(const std::string &playername, @@ -114,6 +118,7 @@ bool ScriptApiServer::setPassword(const std::string &playername, { SCRIPTAPI_PRECHECKHEADER + int error_handler = PUSH_ERROR_HANDLER(L); getAuthHandler(); lua_getfield(L, -1, "set_password"); lua_remove(L, -2); // Remove auth handler @@ -121,7 +126,8 @@ bool ScriptApiServer::setPassword(const std::string &playername, throw LuaError("Authentication handler missing set_password"); lua_pushstring(L, playername.c_str()); lua_pushstring(L, password.c_str()); - PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler)); + PCALL_RES(lua_pcall(L, 2, 1, error_handler)); + lua_remove(L, error_handler); return lua_toboolean(L, -1); } |