aboutsummaryrefslogtreecommitdiff
path: root/src/script/cpp_api
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/cpp_api')
-rw-r--r--src/script/cpp_api/s_async.cpp95
-rw-r--r--src/script/cpp_api/s_async.h30
-rw-r--r--src/script/cpp_api/s_base.cpp64
-rw-r--r--src/script/cpp_api/s_base.h20
-rw-r--r--src/script/cpp_api/s_entity.cpp31
-rw-r--r--src/script/cpp_api/s_env.cpp195
-rw-r--r--src/script/cpp_api/s_env.h20
-rw-r--r--src/script/cpp_api/s_internal.h42
-rw-r--r--src/script/cpp_api/s_inventory.cpp33
-rw-r--r--src/script/cpp_api/s_item.cpp56
-rw-r--r--src/script/cpp_api/s_item.h2
-rw-r--r--src/script/cpp_api/s_mainmenu.cpp10
-rw-r--r--src/script/cpp_api/s_node.cpp47
-rw-r--r--src/script/cpp_api/s_nodemeta.cpp33
-rw-r--r--src/script/cpp_api/s_player.cpp6
-rw-r--r--src/script/cpp_api/s_security.cpp13
-rw-r--r--src/script/cpp_api/s_security.h5
-rw-r--r--src/script/cpp_api/s_server.cpp12
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);
}