Pass a errfunc to lua_pcall to get a traceback

This commit is contained in:
ShadowNinja 2013-11-05 12:06:15 -05:00
parent 3f519eb729
commit 371b39a09a
19 changed files with 424 additions and 324 deletions

View File

@ -871,6 +871,8 @@ void read_groups(lua_State *L, int index,
/******************************************************************************/ /******************************************************************************/
void push_items(lua_State *L, const std::vector<ItemStack> &items) void push_items(lua_State *L, const std::vector<ItemStack> &items)
{ {
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Get the table insert function // Get the table insert function
lua_getglobal(L, "table"); lua_getglobal(L, "table");
lua_getfield(L, -1, "insert"); lua_getfield(L, -1, "insert");
@ -883,11 +885,12 @@ void push_items(lua_State *L, const std::vector<ItemStack> &items)
lua_pushvalue(L, table_insert); lua_pushvalue(L, table_insert);
lua_pushvalue(L, table); lua_pushvalue(L, table);
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, errorhandler))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove insert lua_remove(L, -2); // Remove insert
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove error handler
} }
/******************************************************************************/ /******************************************************************************/

View File

@ -23,32 +23,41 @@ with this program; if not, write to the Free Software Foundation, Inc.,
std::string script_get_backtrace(lua_State *L) std::string script_get_backtrace(lua_State *L)
{ {
std::string s; std::string s;
lua_getfield(L, LUA_GLOBALSINDEX, "debug"); lua_getglobal(L, "debug");
if(lua_istable(L, -1)){ if(lua_istable(L, -1)){
lua_getfield(L, -1, "traceback"); lua_getfield(L, -1, "traceback");
if(lua_isfunction(L, -1)) { if(lua_isfunction(L, -1)) {
lua_call(L, 0, 1); lua_call(L, 0, 1);
if(lua_isstring(L, -1)){ if(lua_isstring(L, -1)){
s += lua_tostring(L, -1); s = lua_tostring(L, -1);
}
} }
lua_pop(L, 1); lua_pop(L, 1);
} }
else{
lua_pop(L, 1);
}
}
lua_pop(L, 1); lua_pop(L, 1);
return s; return s;
} }
void script_error(lua_State *L, const char *fmt, ...) int script_error_handler(lua_State *L) {
lua_getglobal(L, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1);
lua_pushinteger(L, 2);
lua_call(L, 2, 1);
return 1;
}
void script_error(lua_State *L)
{ {
va_list argp; throw LuaError(NULL, lua_tostring(L, -1));
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
throw LuaError(L, buf);
} }
// Push the list of callbacks (a lua table). // Push the list of callbacks (a lua table).
@ -61,13 +70,20 @@ void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
{ {
// Insert the return value into the lua stack, below the table // Insert the return value into the lua stack, below the table
assert(lua_gettop(L) >= nargs + 1); assert(lua_gettop(L) >= nargs + 1);
lua_pushnil(L);
lua_insert(L, -(nargs + 1) - 1);
// Stack now looks like this:
// ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
lua_pushnil(L);
int rv = lua_gettop(L) - nargs - 1; int rv = lua_gettop(L) - nargs - 1;
int table = rv + 1; lua_insert(L, rv);
// Insert error handler after return value
lua_pushcfunction(L, script_error_handler);
int errorhandler = rv + 1;
lua_insert(L, errorhandler);
// Stack now looks like this:
// ... <return value = nil> <error handler> <table> <arg#1> <arg#2> ... <arg#n>
int table = errorhandler + 1;
int arg = table + 1; int arg = table + 1;
luaL_checktype(L, table, LUA_TTABLE); luaL_checktype(L, table, LUA_TTABLE);
@ -81,8 +97,8 @@ void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
// Call function // Call function
for(int i = 0; i < nargs; i++) for(int i = 0; i < nargs; i++)
lua_pushvalue(L, arg+i); lua_pushvalue(L, arg+i);
if(lua_pcall(L, nargs, 1, 0)) if(lua_pcall(L, nargs, 1, errorhandler))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
// Move return value to designated space in stack // Move return value to designated space in stack
// Or pop it // Or pop it

View File

@ -65,7 +65,8 @@ enum RunCallbacksMode
}; };
std::string script_get_backtrace(lua_State *L); std::string script_get_backtrace(lua_State *L);
void script_error (lua_State *L, const char *fmt, ...); int script_error_handler(lua_State *L);
void script_error(lua_State *L);
void script_run_callbacks(lua_State *L, int nargs, void script_run_callbacks(lua_State *L, int nargs,
RunCallbacksMode mode); RunCallbacksMode mode);

View File

@ -25,9 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
LuaError::LuaError(lua_State *L, const std::string &s) LuaError::LuaError(lua_State *L, const std::string &s)
{ {
m_s = "LuaError: "; m_s = "LuaError: " + s;
m_s += s + "\n"; if (L) m_s += '\n' + script_get_backtrace(L);
m_s += script_get_backtrace(L);
} }
struct EnumString es_ItemType[] = struct EnumString es_ItemType[] =

View File

@ -55,23 +55,6 @@ public:
} }
}; };
static int loadScript_ErrorHandler(lua_State *L) {
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1);
lua_pushinteger(L, 2);
lua_call(L, 2, 1);
return 1;
}
/* /*
ScriptApiBase ScriptApiBase
@ -133,7 +116,7 @@ bool ScriptApiBase::loadScript(const std::string &scriptpath)
lua_State *L = getStack(); lua_State *L = getStack();
lua_pushcfunction(L, loadScript_ErrorHandler); lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L); int errorhandler = lua_gettop(L);
int ret = luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, errorhandler); int ret = luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, errorhandler);
@ -159,19 +142,13 @@ void ScriptApiBase::realityCheck()
if(top >= 30){ if(top >= 30){
dstream<<"Stack is over 30:"<<std::endl; dstream<<"Stack is over 30:"<<std::endl;
stackDump(dstream); stackDump(dstream);
scriptError("Stack is over 30 (reality check)"); throw LuaError(m_luastack, "Stack is over 30 (reality check)");
} }
} }
void ScriptApiBase::scriptError(const char *fmt, ...) void ScriptApiBase::scriptError()
{ {
va_list argp; throw LuaError(NULL, lua_tostring(m_luastack, -1));
va_start(argp, fmt);
char buf[10000];
vsnprintf(buf, 10000, fmt, argp);
va_end(argp);
//errorstream<<"SCRIPT ERROR: "<<buf;
throw LuaError(m_luastack, buf);
} }
void ScriptApiBase::stackDump(std::ostream &o) void ScriptApiBase::stackDump(std::ostream &o)

View File

@ -31,6 +31,7 @@ extern "C" {
#include "jthread/jmutex.h" #include "jthread/jmutex.h"
#include "jthread/jmutexautolock.h" #include "jthread/jmutexautolock.h"
#include "common/c_types.h" #include "common/c_types.h"
#include "common/c_internal.h"
#define SCRIPTAPI_LOCK_DEBUG #define SCRIPTAPI_LOCK_DEBUG
@ -65,7 +66,7 @@ protected:
{ return m_luastack; } { return m_luastack; }
void realityCheck(); void realityCheck();
void scriptError(const char *fmt, ...); void scriptError();
void stackDump(std::ostream &o); void stackDump(std::ostream &o);
Server* getServer() { return m_server; } Server* getServer() { return m_server; }

View File

@ -78,6 +78,9 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl; verbosestream<<"scriptapi_luaentity_activate: id="<<id<<std::endl;
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
@ -85,7 +88,6 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
int object = lua_gettop(L); int object = lua_gettop(L);
// Get on_activate function // Get on_activate function
lua_pushvalue(L, object);
lua_getfield(L, -1, "on_activate"); lua_getfield(L, -1, "on_activate");
if(!lua_isnil(L, -1)) { if(!lua_isnil(L, -1)) {
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
@ -93,10 +95,12 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
lua_pushlstring(L, staticdata.c_str(), staticdata.size()); lua_pushlstring(L, staticdata.c_str(), staticdata.size());
lua_pushinteger(L, dtime_s); lua_pushinteger(L, dtime_s);
// Call with 3 arguments, 0 results // Call with 3 arguments, 0 results
if(lua_pcall(L, 3, 0, 0)) if(lua_pcall(L, 3, 0, errorhandler))
scriptError("error running function on_activate: %s\n", scriptError();
lua_tostring(L, -1)); } else {
lua_pop(L, 1);
} }
lua_pop(L, 2); // Pop object and error handler
} }
void ScriptApiEntity::luaentity_Remove(u16 id) void ScriptApiEntity::luaentity_Remove(u16 id)
@ -123,6 +127,9 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
//infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
@ -130,7 +137,6 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
int object = lua_gettop(L); int object = lua_gettop(L);
// Get get_staticdata function // Get get_staticdata function
lua_pushvalue(L, object);
lua_getfield(L, -1, "get_staticdata"); lua_getfield(L, -1, "get_staticdata");
if(lua_isnil(L, -1)) if(lua_isnil(L, -1))
return ""; return "";
@ -138,9 +144,10 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
// Call with 1 arguments, 1 results // Call with 1 arguments, 1 results
if(lua_pcall(L, 1, 1, 0)) if(lua_pcall(L, 1, 1, errorhandler))
scriptError("error running function get_staticdata: %s\n", scriptError();
lua_tostring(L, -1)); lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
size_t len = 0; size_t len = 0;
const char *s = lua_tolstring(L, -1, &len); const char *s = lua_tolstring(L, -1, &len);
@ -192,6 +199,9 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
@ -206,8 +216,10 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
lua_pushnumber(L, dtime); // dtime lua_pushnumber(L, dtime); // dtime
// Call with 2 arguments, 0 results // Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, errorhandler))
scriptError("error running function 'on_step': %s\n", lua_tostring(L, -1)); scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
} }
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch, // Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
@ -218,6 +230,9 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
@ -235,8 +250,10 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
push_tool_capabilities(L, *toolcap); push_tool_capabilities(L, *toolcap);
push_v3f(L, dir); push_v3f(L, dir);
// Call with 5 arguments, 0 results // Call with 5 arguments, 0 results
if(lua_pcall(L, 5, 0, 0)) if(lua_pcall(L, 5, 0, errorhandler))
scriptError("error running function 'on_punch': %s\n", lua_tostring(L, -1)); scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
} }
// Calls entity:on_rightclick(ObjectRef clicker) // Calls entity:on_rightclick(ObjectRef clicker)
@ -245,6 +262,9 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
// Get minetest.luaentities[id] // Get minetest.luaentities[id]
@ -259,7 +279,9 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
lua_pushvalue(L, object); // self lua_pushvalue(L, object); // self
objectrefGetOrCreate(clicker); // Clicker reference objectrefGetOrCreate(clicker); // Clicker reference
// Call with 2 arguments, 0 results // Call with 2 arguments, 0 results
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, errorhandler))
scriptError("error running function 'on_rightclick': %s\n", lua_tostring(L, -1)); scriptError();
lua_remove(L, object); // Remove object
lua_remove(L, errorhandler); // Remove error handler
} }

View File

@ -33,6 +33,9 @@ int ScriptApiDetached::detached_inventory_AllowMove(
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getDetachedInventoryCallback(name, "allow_move")) if(!getDetachedInventoryCallback(name, "allow_move"))
return count; return count;
@ -42,23 +45,19 @@ int ScriptApiDetached::detached_inventory_AllowMove(
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc);
// from_list lua_pushstring(L, from_list.c_str()); // from_list
lua_pushstring(L, from_list.c_str()); lua_pushinteger(L, from_index + 1); // from_index
// from_index lua_pushstring(L, to_list.c_str()); // to_list
lua_pushinteger(L, from_index + 1); lua_pushinteger(L, to_index + 1); // to_index
// to_list lua_pushinteger(L, count); // count
lua_pushstring(L, to_list.c_str()); objectrefGetOrCreate(player); // player
// to_index if(lua_pcall(L, 7, 1, errorhandler))
lua_pushinteger(L, to_index + 1); scriptError();
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_move should return a number"); throw LuaError(L, "allow_move should return a number");
return luaL_checkinteger(L, -1); int ret = luaL_checkinteger(L, -1);
lua_pop(L, 2); // Pop integer and error handler
return ret;
} }
// Return number of accepted items to be put // Return number of accepted items to be put
@ -69,28 +68,28 @@ int ScriptApiDetached::detached_inventory_AllowPut(
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getDetachedInventoryCallback(name, "allow_put")) if(!getDetachedInventoryCallback(name, "allow_put"))
return stack.count; // All will be accepted return stack.count; // All will be accepted
// Call function(inv, listname, index, stack, player) // Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc); // inv
// listname lua_pushstring(L, listname.c_str()); // listname
lua_pushstring(L, listname.c_str()); lua_pushinteger(L, index + 1); // index
// index LuaItemStack::create(L, stack); // stack
lua_pushinteger(L, index + 1); objectrefGetOrCreate(player); // player
// stack if(lua_pcall(L, 5, 1, errorhandler))
LuaItemStack::create(L, stack); scriptError();
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_put should return a number"); throw LuaError(L, "allow_put should return a number");
return luaL_checkinteger(L, -1); int ret = luaL_checkinteger(L, -1);
lua_pop(L, 2); // Pop integer and error handler
return ret;
} }
// Return number of accepted items to be taken // Return number of accepted items to be taken
@ -101,28 +100,28 @@ int ScriptApiDetached::detached_inventory_AllowTake(
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getDetachedInventoryCallback(name, "allow_take")) if(!getDetachedInventoryCallback(name, "allow_take"))
return stack.count; // All will be accepted return stack.count; // All will be accepted
// Call function(inv, listname, index, stack, player) // Call function(inv, listname, index, stack, player)
// inv
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc); // inv
// listname lua_pushstring(L, listname.c_str()); // listname
lua_pushstring(L, listname.c_str()); lua_pushinteger(L, index + 1); // index
// index LuaItemStack::create(L, stack); // stack
lua_pushinteger(L, index + 1); objectrefGetOrCreate(player); // player
// stack if(lua_pcall(L, 5, 1, errorhandler))
LuaItemStack::create(L, stack); scriptError();
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_take should return a number"); throw LuaError(L, "allow_take should return a number");
return luaL_checkinteger(L, -1); int ret = luaL_checkinteger(L, -1);
lua_pop(L, 2); // Pop integer and error handler
return ret;
} }
// Report moved items // Report moved items
@ -134,6 +133,9 @@ void ScriptApiDetached::detached_inventory_OnMove(
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getDetachedInventoryCallback(name, "on_move")) if(!getDetachedInventoryCallback(name, "on_move"))
return; return;
@ -143,20 +145,15 @@ void ScriptApiDetached::detached_inventory_OnMove(
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc);
// from_list lua_pushstring(L, from_list.c_str()); // from_list
lua_pushstring(L, from_list.c_str()); lua_pushinteger(L, from_index + 1); // from_index
// from_index lua_pushstring(L, to_list.c_str()); // to_list
lua_pushinteger(L, from_index + 1); lua_pushinteger(L, to_index + 1); // to_index
// to_list lua_pushinteger(L, count); // count
lua_pushstring(L, to_list.c_str()); objectrefGetOrCreate(player); // player
// to_index if(lua_pcall(L, 7, 0, errorhandler))
lua_pushinteger(L, to_index + 1); scriptError();
// count lua_pop(L, 1); // Pop error handler
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
} }
// Report put items // Report put items
@ -167,6 +164,9 @@ void ScriptApiDetached::detached_inventory_OnPut(
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getDetachedInventoryCallback(name, "on_put")) if(!getDetachedInventoryCallback(name, "on_put"))
return; return;
@ -176,16 +176,13 @@ void ScriptApiDetached::detached_inventory_OnPut(
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc);
// listname lua_pushstring(L, listname.c_str()); // listname
lua_pushstring(L, listname.c_str()); lua_pushinteger(L, index + 1); // index
// index LuaItemStack::create(L, stack); // stack
lua_pushinteger(L, index + 1); objectrefGetOrCreate(player); // player
// stack if(lua_pcall(L, 5, 0, errorhandler))
LuaItemStack::create(L, stack); scriptError();
// player lua_pop(L, 1); // Pop error handler
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
} }
// Report taken items // Report taken items
@ -196,6 +193,9 @@ void ScriptApiDetached::detached_inventory_OnTake(
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getDetachedInventoryCallback(name, "on_take")) if(!getDetachedInventoryCallback(name, "on_take"))
return; return;
@ -205,16 +205,13 @@ void ScriptApiDetached::detached_inventory_OnTake(
InventoryLocation loc; InventoryLocation loc;
loc.setDetached(name); loc.setDetached(name);
InvRef::create(L, loc); InvRef::create(L, loc);
// listname lua_pushstring(L, listname.c_str()); // listname
lua_pushstring(L, listname.c_str()); lua_pushinteger(L, index + 1); // index
// index LuaItemStack::create(L, stack); // stack
lua_pushinteger(L, index + 1); objectrefGetOrCreate(player); // player
// stack if(lua_pcall(L, 5, 0, errorhandler))
LuaItemStack::create(L, stack); scriptError();
// player lua_pop(L, 1); // Pop error handler
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
} }
// Retrieves minetest.detached_inventories[name][callbackname] // Retrieves minetest.detached_inventories[name][callbackname]

View File

@ -34,6 +34,9 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getItemCallback(item.name.c_str(), "on_drop")) if(!getItemCallback(item.name.c_str(), "on_drop"))
return false; return false;
@ -42,10 +45,11 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
objectrefGetOrCreate(dropper); objectrefGetOrCreate(dropper);
pushFloatPos(L, pos); pushFloatPos(L, pos);
if(lua_pcall(L, 3, 1, 0)) if(lua_pcall(L, 3, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer()); item = read_item(L,-1, getServer());
lua_pop(L, 2); // Pop item and error handler
return true; return true;
} }
@ -54,6 +58,9 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getItemCallback(item.name.c_str(), "on_place")) if(!getItemCallback(item.name.c_str(), "on_place"))
return false; return false;
@ -62,10 +69,11 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
objectrefGetOrCreate(placer); objectrefGetOrCreate(placer);
pushPointedThing(pointed); pushPointedThing(pointed);
if(lua_pcall(L, 3, 1, 0)) if(lua_pcall(L, 3, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer()); item = read_item(L,-1, getServer());
lua_pop(L, 2); // Pop item and error handler
return true; return true;
} }
@ -74,6 +82,9 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Push callback function on stack // Push callback function on stack
if(!getItemCallback(item.name.c_str(), "on_use")) if(!getItemCallback(item.name.c_str(), "on_use"))
return false; return false;
@ -82,10 +93,11 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
objectrefGetOrCreate(user); objectrefGetOrCreate(user);
pushPointedThing(pointed); pushPointedThing(pointed);
if(lua_pcall(L, 3, 1, 0)) if(lua_pcall(L, 3, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer()); item = read_item(L,-1, getServer());
lua_pop(L, 2); // Pop item and error handler
return true; return true;
} }
@ -94,6 +106,9 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
lua_getglobal(L, "minetest"); lua_getglobal(L, "minetest");
lua_getfield(L, -1, "on_craft"); lua_getfield(L, -1, "on_craft");
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
@ -106,10 +121,11 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
push_items(L, items); push_items(L, items);
InvRef::create(L, craft_inv); InvRef::create(L, craft_inv);
if(lua_pcall(L, 4, 1, 0)) if(lua_pcall(L, 4, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer()); item = read_item(L,-1, getServer());
lua_pop(L, 2); // Pop item and error handler
return true; return true;
} }
@ -118,6 +134,9 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
lua_getglobal(L, "minetest"); lua_getglobal(L, "minetest");
lua_getfield(L, -1, "craft_predict"); lua_getfield(L, -1, "craft_predict");
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
@ -130,10 +149,11 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
push_items(L, items); push_items(L, items);
InvRef::create(L, craft_inv); InvRef::create(L, craft_inv);
if(lua_pcall(L, 4, 1, 0)) if(lua_pcall(L, 4, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
if(!lua_isnil(L, -1)) if(!lua_isnil(L, -1))
item = read_item(L,-1, getServer()); item = read_item(L,-1, getServer());
lua_pop(L, 2); // Pop item and error handler
return true; return true;
} }
@ -149,10 +169,10 @@ bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
lua_getglobal(L, "minetest"); lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_items"); lua_getfield(L, -1, "registered_items");
lua_remove(L, -2); lua_remove(L, -2); // Remove minetest
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, name); lua_getfield(L, -1, name);
lua_remove(L, -2); lua_remove(L, -2); // Remove registered_items
// Should be a table // Should be a table
if(lua_type(L, -1) != LUA_TTABLE) if(lua_type(L, -1) != LUA_TTABLE)
{ {
@ -167,25 +187,17 @@ bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
} }
lua_getfield(L, -1, callbackname); lua_getfield(L, -1, callbackname);
lua_remove(L, -2); lua_remove(L, -2); // Remove item def
// Should be a function or nil // Should be a function or nil
if(lua_type(L, -1) == LUA_TFUNCTION) if (lua_type(L, -1) == LUA_TFUNCTION) {
{
return true; return true;
} } else if (!lua_isnil(L, -1)) {
else if(lua_isnil(L, -1))
{
lua_pop(L, 1);
return false;
}
else
{
errorstream << "Item \"" << name << "\" callback \"" errorstream << "Item \"" << name << "\" callback \""
<<callbackname<<" is not a function"<<std::endl; << callbackname << "\" is not a function" << std::endl;
}
lua_pop(L, 1); lua_pop(L, 1);
return false; return false;
} }
}
void ScriptApiItem::pushPointedThing(const PointedThing& pointed) void ScriptApiItem::pushPointedThing(const PointedThing& pointed)
{ {

View File

@ -37,29 +37,41 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Get handler function // Get handler function
lua_getglobal(L, "engine"); lua_getglobal(L, "engine");
lua_getfield(L, -1, "event_handler"); lua_getfield(L, -1, "event_handler");
if(lua_isnil(L, -1)) lua_remove(L, -2); // Remove engine
if(lua_isnil(L, -1)) {
lua_pop(L, 1); // Pop event_handler
return; return;
}
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
// Call it // Call it
lua_pushstring(L, text.c_str()); lua_pushstring(L, text.c_str());
if(lua_pcall(L, 1, 0, 0)) if(lua_pcall(L, 1, 0, errorhandler))
scriptError("error running function engine.event_handler: %s\n", scriptError();
lua_tostring(L, -1)); lua_pop(L, 1); // Pop error handler
} }
void ScriptApiMainMenu::handleMainMenuButtons(std::map<std::string, std::string> fields) void ScriptApiMainMenu::handleMainMenuButtons(std::map<std::string, std::string> fields)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Get handler function // Get handler function
lua_getglobal(L, "engine"); lua_getglobal(L, "engine");
lua_getfield(L, -1, "button_handler"); lua_getfield(L, -1, "button_handler");
if(lua_isnil(L, -1)) lua_remove(L, -2); // Remove engine
if(lua_isnil(L, -1)) {
lua_pop(L, 1); // Pop button handler
return; return;
}
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
// Convert fields to lua table // Convert fields to lua table
@ -74,7 +86,7 @@ void ScriptApiMainMenu::handleMainMenuButtons(std::map<std::string, std::string>
} }
// Call it // Call it
if(lua_pcall(L, 1, 0, 0)) if(lua_pcall(L, 1, 0, errorhandler))
scriptError("error running function engine.button_handler: %s\n", scriptError();
lua_tostring(L, -1)); lua_pop(L, 1); // Pop error handler
} }

View File

@ -91,6 +91,9 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack // Push callback function on stack
@ -101,8 +104,9 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
push_v3s16(L, p); push_v3s16(L, p);
pushnode(L, node, ndef); pushnode(L, node, ndef);
objectrefGetOrCreate(puncher); objectrefGetOrCreate(puncher);
if(lua_pcall(L, 3, 0, 0)) if(lua_pcall(L, 3, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
return true; return true;
} }
@ -111,6 +115,9 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack // Push callback function on stack
@ -121,8 +128,9 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
push_v3s16(L, p); push_v3s16(L, p);
pushnode(L, node, ndef); pushnode(L, node, ndef);
objectrefGetOrCreate(digger); objectrefGetOrCreate(digger);
if(lua_pcall(L, 3, 0, 0)) if(lua_pcall(L, 3, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
return true; return true;
} }
@ -130,6 +138,9 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack // Push callback function on stack
@ -138,14 +149,18 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node)
// Call function // Call function
push_v3s16(L, p); push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0)) if(lua_pcall(L, 1, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
} }
void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node) void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack // Push callback function on stack
@ -154,14 +169,18 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
// Call function // Call function
push_v3s16(L, p); push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0)) if(lua_pcall(L, 1, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
} }
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node) void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack // Push callback function on stack
@ -171,14 +190,18 @@ void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
// Call function // Call function
push_v3s16(L, p); push_v3s16(L, p);
pushnode(L, node, ndef); pushnode(L, node, ndef);
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
} }
bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime) bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack // Push callback function on stack
@ -188,12 +211,10 @@ bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
// Call function // Call function
push_v3s16(L, p); push_v3s16(L, p);
lua_pushnumber(L,dtime); lua_pushnumber(L,dtime);
if(lua_pcall(L, 2, 1, 0)) if(lua_pcall(L, 2, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
if((bool)lua_isboolean(L,-1) && (bool)lua_toboolean(L,-1) == true) lua_remove(L, errorhandler); // Remove error handler
return true; return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
return false;
} }
void ScriptApiNode::node_on_receive_fields(v3s16 p, void ScriptApiNode::node_on_receive_fields(v3s16 p,
@ -203,6 +224,9 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -215,12 +239,9 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
return; return;
// Call function // Call function
// param 1 push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, formname.c_str()); // formname
// param 2 lua_newtable(L); // fields
lua_pushstring(L, formname.c_str());
// param 3
lua_newtable(L);
for(std::map<std::string, std::string>::const_iterator for(std::map<std::string, std::string>::const_iterator
i = fields.begin(); i != fields.end(); i++){ i = fields.begin(); i != fields.end(); i++){
const std::string &name = i->first; const std::string &name = i->first;
@ -229,26 +250,37 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
lua_pushlstring(L, value.c_str(), value.size()); lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3); lua_settable(L, -3);
} }
// param 4 objectrefGetOrCreate(sender); // player
objectrefGetOrCreate(sender); if(lua_pcall(L, 4, 0, errorhandler))
if(lua_pcall(L, 4, 0, 0)) scriptError();
scriptError("error: %s", lua_tostring(L, -1)); lua_pop(L, 1); // Pop error handler
} }
void ScriptApiNode::node_falling_update(v3s16 p) void ScriptApiNode::node_falling_update(v3s16 p)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
lua_getglobal(L, "nodeupdate"); lua_getglobal(L, "nodeupdate");
push_v3s16(L, p); push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0)) if(lua_pcall(L, 1, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
} }
void ScriptApiNode::node_falling_update_single(v3s16 p) void ScriptApiNode::node_falling_update_single(v3s16 p)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
lua_getglobal(L, "nodeupdate_single"); lua_getglobal(L, "nodeupdate_single");
push_v3s16(L, p); push_v3s16(L, p);
if(lua_pcall(L, 1, 0, 0)) if(lua_pcall(L, 1, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
} }

View File

@ -34,6 +34,9 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -47,25 +50,21 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p,
return count; return count;
// function(pos, from_list, from_index, to_list, to_index, count, player) // function(pos, from_list, from_index, to_list, to_index, count, player)
// pos push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, from_list.c_str()); // from_list
// from_list lua_pushinteger(L, from_index + 1); // from_index
lua_pushstring(L, from_list.c_str()); lua_pushstring(L, to_list.c_str()); // to_list
// from_index lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, from_index + 1); lua_pushinteger(L, count); // count
// to_list objectrefGetOrCreate(player); // player
lua_pushstring(L, to_list.c_str()); if(lua_pcall(L, 7, 1, errorhandler))
// to_index scriptError();
lua_pushinteger(L, to_index + 1); lua_remove(L, errorhandler); // Remove error handler
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_move should return a number"); throw LuaError(L, "allow_metadata_inventory_move should return a number");
return luaL_checkinteger(L, -1); int num = luaL_checkinteger(L, -1);
lua_pop(L, 1); // Pop integer
return num;
} }
// Return number of accepted items to be put // Return number of accepted items to be put
@ -75,6 +74,9 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -88,21 +90,19 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p,
return stack.count; return stack.count;
// Call function(pos, listname, index, stack, player) // Call function(pos, listname, index, stack, player)
// pos push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, listname.c_str()); // listname
// listname lua_pushinteger(L, index + 1); // index
lua_pushstring(L, listname.c_str()); LuaItemStack::create(L, stack); // stack
// index objectrefGetOrCreate(player); // player
lua_pushinteger(L, index + 1); if(lua_pcall(L, 5, 1, errorhandler))
// stack scriptError();
LuaItemStack::create(L, stack); lua_remove(L, errorhandler); // Remove error handler
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_put should return a number"); throw LuaError(L, "allow_metadata_inventory_put should return a number");
return luaL_checkinteger(L, -1); int num = luaL_checkinteger(L, -1);
lua_pop(L, 1); // Pop integer
return num;
} }
// Return number of accepted items to be taken // Return number of accepted items to be taken
@ -112,6 +112,9 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -125,21 +128,19 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p,
return stack.count; return stack.count;
// Call function(pos, listname, index, count, player) // Call function(pos, listname, index, count, player)
// pos push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, listname.c_str()); // listname
// listname lua_pushinteger(L, index + 1); // index
lua_pushstring(L, listname.c_str()); LuaItemStack::create(L, stack); // stack
// index objectrefGetOrCreate(player); // player
lua_pushinteger(L, index + 1); if(lua_pcall(L, 5, 1, errorhandler))
// stack scriptError();
LuaItemStack::create(L, stack); lua_remove(L, errorhandler); // Remove error handler
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 1, 0))
scriptError("error: %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) if(!lua_isnumber(L, -1))
throw LuaError(L, "allow_metadata_inventory_take should return a number"); throw LuaError(L, "allow_metadata_inventory_take should return a number");
return luaL_checkinteger(L, -1); int num = luaL_checkinteger(L, -1);
lua_pop(L, 1); // Pop integer
return num;
} }
// Report moved items // Report moved items
@ -150,6 +151,9 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -163,22 +167,16 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p,
return; return;
// function(pos, from_list, from_index, to_list, to_index, count, player) // function(pos, from_list, from_index, to_list, to_index, count, player)
// pos push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, from_list.c_str()); // from_list
// from_list lua_pushinteger(L, from_index + 1); // from_index
lua_pushstring(L, from_list.c_str()); lua_pushstring(L, to_list.c_str()); // to_list
// from_index lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, from_index + 1); lua_pushinteger(L, count); // count
// to_list objectrefGetOrCreate(player); // player
lua_pushstring(L, to_list.c_str()); if(lua_pcall(L, 7, 0, errorhandler))
// to_index scriptError();
lua_pushinteger(L, to_index + 1); lua_pop(L, 1); // Pop error handler
// count
lua_pushinteger(L, count);
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 7, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
} }
// Report put items // Report put items
@ -188,6 +186,9 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -201,18 +202,14 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p,
return; return;
// Call function(pos, listname, index, stack, player) // Call function(pos, listname, index, stack, player)
// pos push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, listname.c_str()); // listname
// listname lua_pushinteger(L, index + 1); // index
lua_pushstring(L, listname.c_str()); LuaItemStack::create(L, stack); // stack
// index objectrefGetOrCreate(player); // player
lua_pushinteger(L, index + 1); if(lua_pcall(L, 5, 0, errorhandler))
// stack scriptError();
LuaItemStack::create(L, stack); lua_pop(L, 1); // Pop error handler
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
} }
// Report taken items // Report taken items
@ -222,6 +219,9 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
INodeDefManager *ndef = getServer()->ndef(); INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call // If node doesn't exist, we don't know what callback to call
@ -235,18 +235,14 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
return; return;
// Call function(pos, listname, index, stack, player) // Call function(pos, listname, index, stack, player)
// pos push_v3s16(L, p); // pos
push_v3s16(L, p); lua_pushstring(L, listname.c_str()); // listname
// listname lua_pushinteger(L, index + 1); // index
lua_pushstring(L, listname.c_str()); LuaItemStack::create(L, stack); // stack
// index objectrefGetOrCreate(player); // player
lua_pushinteger(L, index + 1); if(lua_pcall(L, 5, 0, errorhandler))
// stack scriptError();
LuaItemStack::create(L, stack); lua_pop(L, 1); // Pop error handler
// player
objectrefGetOrCreate(player);
if(lua_pcall(L, 5, 0, 0))
scriptError("error: %s", lua_tostring(L, -1));
} }
ScriptApiNodemeta::ScriptApiNodemeta() { ScriptApiNodemeta::ScriptApiNodemeta() {

View File

@ -27,13 +27,18 @@ bool ScriptApiServer::getAuth(const std::string &playername,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
getAuthHandler(); getAuthHandler();
lua_getfield(L, -1, "get_auth"); lua_getfield(L, -1, "get_auth");
if(lua_type(L, -1) != LUA_TFUNCTION) if(lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError(L, "Authentication handler missing get_auth"); throw LuaError(L, "Authentication handler missing get_auth");
lua_pushstring(L, playername.c_str()); lua_pushstring(L, playername.c_str());
if(lua_pcall(L, 1, 1, 0)) if(lua_pcall(L, 1, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_remove(L, -2); // Remove auth handler
lua_remove(L, errorhandler); // Remove error handler
// nil = login not allowed // nil = login not allowed
if(lua_isnil(L, -1)) if(lua_isnil(L, -1))
@ -49,8 +54,7 @@ bool ScriptApiServer::getAuth(const std::string &playername,
lua_getfield(L, -1, "privileges"); lua_getfield(L, -1, "privileges");
if(!lua_istable(L, -1)) if(!lua_istable(L, -1))
throw LuaError(L, throw LuaError(L, "Authentication handler didn't return privilege table");
"Authentication handler didn't return privilege table");
if(dst_privs) if(dst_privs)
readPrivileges(-1, *dst_privs); readPrivileges(-1, *dst_privs);
lua_pop(L, 1); lua_pop(L, 1);
@ -68,6 +72,7 @@ void ScriptApiServer::getAuthHandler()
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, -1, "builtin_auth_handler"); lua_getfield(L, -1, "builtin_auth_handler");
} }
lua_remove(L, -2); // Remove minetest
if(lua_type(L, -1) != LUA_TTABLE) if(lua_type(L, -1) != LUA_TTABLE)
throw LuaError(L, "Authentication handler table not valid"); throw LuaError(L, "Authentication handler table not valid");
} }
@ -96,14 +101,19 @@ void ScriptApiServer::createAuth(const std::string &playername,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
getAuthHandler(); getAuthHandler();
lua_getfield(L, -1, "create_auth"); lua_getfield(L, -1, "create_auth");
lua_remove(L, -2); // Remove auth handler
if(lua_type(L, -1) != LUA_TFUNCTION) if(lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError(L, "Authentication handler missing create_auth"); throw LuaError(L, "Authentication handler missing create_auth");
lua_pushstring(L, playername.c_str()); lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str()); lua_pushstring(L, password.c_str());
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_pop(L, 1); // Pop error handler
} }
bool ScriptApiServer::setPassword(const std::string &playername, bool ScriptApiServer::setPassword(const std::string &playername,
@ -111,14 +121,19 @@ bool ScriptApiServer::setPassword(const std::string &playername,
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
getAuthHandler(); getAuthHandler();
lua_getfield(L, -1, "set_password"); lua_getfield(L, -1, "set_password");
lua_remove(L, -2); // Remove auth handler
if(lua_type(L, -1) != LUA_TFUNCTION) if(lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError(L, "Authentication handler missing set_password"); throw LuaError(L, "Authentication handler missing set_password");
lua_pushstring(L, playername.c_str()); lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str()); lua_pushstring(L, password.c_str());
if(lua_pcall(L, 2, 1, 0)) if(lua_pcall(L, 2, 1, errorhandler))
scriptError("error: %s", lua_tostring(L, -1)); scriptError();
lua_remove(L, -2); // Remove error handler
return lua_toboolean(L, -1); return lua_toboolean(L, -1);
} }

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define L_BASE_H_ #define L_BASE_H_
#include "common/c_types.h" #include "common/c_types.h"
#include "common/c_internal.h"
extern "C" { extern "C" {
#include <lua.h> #include <lua.h>

View File

@ -449,7 +449,7 @@ int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
lua_pushstring(L, &tmpout.item[0]); lua_pushstring(L, &tmpout.item[0]);
lua_setfield(L, -2, "output"); lua_setfield(L, -2, "output");
if (lua_pcall(L, 2, 0, 0)) if (lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
} }
return 1; return 1;

View File

@ -53,28 +53,34 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
assert(lua_checkstack(L, 20)); assert(lua_checkstack(L, 20));
StackUnroller stack_unroller(L); StackUnroller stack_unroller(L);
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Get minetest.registered_abms // Get minetest.registered_abms
lua_getglobal(L, "minetest"); lua_getglobal(L, "minetest");
lua_getfield(L, -1, "registered_abms"); lua_getfield(L, -1, "registered_abms");
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
int registered_abms = lua_gettop(L); lua_remove(L, -2); // Remove "minetest"
// Get minetest.registered_abms[m_id] // Get minetest.registered_abms[m_id]
lua_pushnumber(L, m_id); lua_pushnumber(L, m_id);
lua_gettable(L, registered_abms); lua_gettable(L, -2);
if(lua_isnil(L, -1)) if(lua_isnil(L, -1))
assert(0); assert(0);
lua_remove(L, -2); // Remove "registered_abms"
// Call action // Call action
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, "action"); lua_getfield(L, -1, "action");
luaL_checktype(L, -1, LUA_TFUNCTION); luaL_checktype(L, -1, LUA_TFUNCTION);
lua_remove(L, -2); // Remove "registered_abms[m_id]"
push_v3s16(L, p); push_v3s16(L, p);
pushnode(L, n, env->getGameDef()->ndef()); pushnode(L, n, env->getGameDef()->ndef());
lua_pushnumber(L, active_object_count); lua_pushnumber(L, active_object_count);
lua_pushnumber(L, active_object_count_wider); lua_pushnumber(L, active_object_count_wider);
if(lua_pcall(L, 4, 0, 0)) if(lua_pcall(L, 4, 0, errorhandler))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
lua_pop(L, 1); // Pop error handler
} }
// Exported functions // Exported functions
@ -370,15 +376,21 @@ int ModApiEnvMod::l_add_item(lua_State *L)
ItemStack item = read_item(L, 2,getServer(L)); ItemStack item = read_item(L, 2,getServer(L));
if(item.empty() || !item.isKnown(getServer(L)->idef())) if(item.empty() || !item.isKnown(getServer(L)->idef()))
return 0; return 0;
lua_pushcfunction(L, script_error_handler);
int errorhandler = lua_gettop(L);
// Use minetest.spawn_item to spawn a __builtin:item // Use minetest.spawn_item to spawn a __builtin:item
lua_getglobal(L, "minetest"); lua_getglobal(L, "minetest");
lua_getfield(L, -1, "spawn_item"); lua_getfield(L, -1, "spawn_item");
lua_remove(L, -2); // Remove minetest
if(lua_isnil(L, -1)) if(lua_isnil(L, -1))
return 0; return 0;
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str()); lua_pushstring(L, item.getItemString().c_str());
if(lua_pcall(L, 2, 1, 0)) if(lua_pcall(L, 2, 1, errorhandler))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
lua_remove(L, errorhandler); // Remove error handler
return 1; return 1;
/*lua_pushvalue(L, 1); /*lua_pushvalue(L, 1);
lua_pushstring(L, "__builtin:item"); lua_pushstring(L, "__builtin:item");
@ -441,7 +453,7 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
lua_pushvalue(L, table); lua_pushvalue(L, table);
getScriptApiBase(L)->objectrefGetOrCreate(obj); getScriptApiBase(L)->objectrefGetOrCreate(obj);
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
return 1; return 1;
} }
@ -569,7 +581,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
lua_pushvalue(L, table); lua_pushvalue(L, table);
push_v3s16(L, p); push_v3s16(L, p);
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
} }
return 1; return 1;

View File

@ -333,7 +333,10 @@ int LuaPseudoRandom::l_next(lua_State *L)
throw LuaError(L, "PseudoRandom.next(): max < min"); throw LuaError(L, "PseudoRandom.next(): max < min");
} }
if(max - min != 32767 && max - min > 32767/5) if(max - min != 32767 && max - min > 32767/5)
throw LuaError(L, "PseudoRandom.next() max-min is not 32767 and is > 32768/5. This is disallowed due to the bad random distribution the implementation would otherwise make."); throw LuaError(L, "PseudoRandom.next() max-min is not 32767"
" and is > 32768/5. This is disallowed due to"
" the bad random distribution the"
" implementation would otherwise make.");
PseudoRandom &pseudo = o->m_pseudo; PseudoRandom &pseudo = o->m_pseudo;
int val = pseudo.next(); int val = pseudo.next();
val = (val % (max-min+1)) + min; val = (val % (max-min+1)) + min;

View File

@ -66,7 +66,7 @@ int ModApiRollback::l_rollback_revert_actions_by(lua_State *L)
lua_pushvalue(L, table); lua_pushvalue(L, table);
lua_pushstring(L, i->c_str()); lua_pushstring(L, i->c_str());
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
lua_remove(L, -2); // Remove table lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove insert lua_remove(L, -2); // Remove insert

View File

@ -220,6 +220,7 @@ int ModApiServer::l_get_modpath(lua_State *L)
int ModApiServer::l_get_modnames(lua_State *L) int ModApiServer::l_get_modnames(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
// Get a list of mods // Get a list of mods
std::list<std::string> mods_unsorted, mods_sorted; std::list<std::string> mods_unsorted, mods_sorted;
getServer(L)->getModNames(mods_unsorted); getServer(L)->getModNames(mods_unsorted);
@ -263,7 +264,7 @@ int ModApiServer::l_get_modnames(lua_State *L)
lua_pushstring(L, (*i).c_str()); lua_pushstring(L, (*i).c_str());
if(lua_pcall(L, 2, 0, 0) != 0) if(lua_pcall(L, 2, 0, 0) != 0)
{ {
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L);
} }
++i; ++i;
} }