diff --git a/builtin/game/auth.lua b/builtin/game/auth.lua
index 93b0099818afb9ebc6dd37b88ede5228ac3550ee..423eb3134a29964b1f23a7738df408b620ad432c 100644
--- a/builtin/game/auth.lua
+++ b/builtin/game/auth.lua
@@ -171,6 +171,7 @@ function core.register_authentication_handler(handler)
 	end
 	core.registered_auth_handler = handler
 	core.registered_auth_handler_modname = core.get_current_modname()
+	handler.mod_origin = core.registered_auth_handler_modname
 end
 
 function core.get_auth_handler()
diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua
index 6c8ca8699f63d3bf69c2c77b5f7aa07f9a3e9e28..5d317de4b870289c91db5b39e258f28138d25566 100644
--- a/builtin/game/chatcommands.lua
+++ b/builtin/game/chatcommands.lua
@@ -10,6 +10,7 @@ function core.register_chatcommand(cmd, def)
 	def.params = def.params or ""
 	def.description = def.description or ""
 	def.privs = def.privs or {}
+	def.mod_origin = core.get_current_modname() or "??"
 	core.chatcommands[cmd] = def
 end
 
@@ -37,6 +38,7 @@ core.register_on_chat_message(function(name, message)
 	end
 	local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs)
 	if has_privs then
+		core.set_last_run_mod(cmd_def.mod_origin)
 		local success, message = cmd_def.func(name, param)
 		if message then
 			core.chat_send_player(name, message)
diff --git a/builtin/game/detached_inventory.lua b/builtin/game/detached_inventory.lua
index e8f03b56ce3b43466b759f3425d72c4cf7faf19a..b5d106b042ccfb13e963f0ba13aef45024bb9eab 100644
--- a/builtin/game/detached_inventory.lua
+++ b/builtin/game/detached_inventory.lua
@@ -13,6 +13,7 @@ function core.create_detached_inventory(name, callbacks)
 		stuff.on_put = callbacks.on_put
 		stuff.on_take = callbacks.on_take
 	end
+	stuff.mod_origin = core.get_current_modname() or "??"
 	core.detached_inventories[name] = stuff
 	return core.create_detached_inventory_raw(name)
 end
diff --git a/builtin/game/item.lua b/builtin/game/item.lua
index d25f4eff0ecf79fe39443d62303c68d2c3b2448c..6628a40813ffef0be47561b11fb609800d1c97b2 100644
--- a/builtin/game/item.lua
+++ b/builtin/game/item.lua
@@ -479,6 +479,15 @@ function core.node_dig(pos, node, digger)
 	-- Run script hook
 	local _, callback
 	for _, callback in ipairs(core.registered_on_dignodes) do
+		local origin = core.callback_origins[callback]
+		if origin then
+			core.set_last_run_mod(origin.mod)
+			--print("Running " .. tostring(callback) ..
+			--	" (a " .. origin.name .. " callback in " .. origin.mod .. ")")
+		else
+			--print("No data associated with callback")
+		end
+
 		-- Copy pos and node because callback can modify them
 		local pos_copy = {x=pos.x, y=pos.y, z=pos.z}
 		local node_copy = {name=node.name, param1=node.param1, param2=node.param2}
diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua
index 7fa95742e969a1896f4b654040405a8373b26192..e3b7d82bcc91966c5c7139ccdf0dc88726f132fd 100644
--- a/builtin/game/misc.lua
+++ b/builtin/game/misc.lua
@@ -14,6 +14,7 @@ local function update_timers(delay)
 		local timer = timers[index]
 		timer.time = timer.time - delay
 		if timer.time <= 0 then
+			core.set_last_run_mod(timer.mod_origin)
 			timer.func(unpack(timer.args or {}))
 			table.remove(timers, index)
 			sub = sub + 1
@@ -55,12 +56,22 @@ function core.after(time, func, ...)
 			"Invalid core.after invocation")
 	if not mintime then
 		mintime = time
-		timers_to_add = {{time=time+delay, func=func, args={...}}}
+		timers_to_add = {{
+			time   = time+delay,
+			func   = func,
+			args   = {...},
+			mod_origin = core.get_last_run_mod(),
+		}}
 		return
 	end
 	mintime = math.min(mintime, time)
 	timers_to_add = timers_to_add or {}
-	timers_to_add[#timers_to_add+1] = {time=time+delay, func=func, args={...}}
+	timers_to_add[#timers_to_add+1] = {
+		time   = time+delay,
+		func   = func,
+		args   = {...},
+		mod_origin = core.get_last_run_mod(),
+	}
 end
 
 function core.check_player_privs(name, privs)
diff --git a/builtin/game/register.lua b/builtin/game/register.lua
index 3a13abfb35e364b9fc71ce981d589a8a03da46ff..d0e04bfc37e1a80c172a923424530f5b09f18c7c 100644
--- a/builtin/game/register.lua
+++ b/builtin/game/register.lua
@@ -72,6 +72,7 @@ end
 function core.register_abm(spec)
 	-- Add to core.registered_abms
 	core.registered_abms[#core.registered_abms+1] = spec
+	spec.mod_origin = core.get_current_modname() or "??"
 end
 
 function core.register_entity(name, prototype)
@@ -86,6 +87,7 @@ function core.register_entity(name, prototype)
 
 	-- Add to core.registered_entities
 	core.registered_entities[name] = prototype
+	prototype.mod_origin = core.get_current_modname() or "??"
 end
 
 function core.register_item(name, itemdef)
@@ -147,6 +149,8 @@ function core.register_item(name, itemdef)
 	end
 	-- END Legacy stuff
 
+	itemdef.mod_origin = core.get_current_modname() or "??"
+
 	-- Disable all further modifications
 	getmetatable(itemdef).__newindex = {}
 
@@ -326,6 +330,8 @@ function core.override_item(name, redefinition)
 end
 
 
+core.callback_origins = {}
+
 function core.run_callbacks(callbacks, mode, ...)
 	assert(type(callbacks) == "table")
 	local cb_len = #callbacks
@@ -338,6 +344,14 @@ function core.run_callbacks(callbacks, mode, ...)
 	end
 	local ret = nil
 	for i = 1, cb_len do
+		local origin = core.callback_origins[callbacks[i]]
+		if origin then
+			core.set_last_run_mod(origin.mod)
+			--print("Running " .. tostring(callbacks[i]) ..
+			--	" (a " .. origin.name .. " callback in " .. origin.mod .. ")")
+		else
+			--print("No data associated with callback")
+		end
 		local cb_ret = callbacks[i](...)
 
 		if mode == 0 and i == 1 then
@@ -370,13 +384,29 @@ end
 
 local function make_registration()
 	local t = {}
-	local registerfunc = function(func) table.insert(t, func) end
+	local registerfunc = function(func)
+		table.insert(t, func)
+		core.callback_origins[func] = {
+			mod = core.get_current_modname() or "??",
+			name = debug.getinfo(1, "n").name or "??"
+		}
+		--local origin = core.callback_origins[func]
+		--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
+	end
 	return t, registerfunc
 end
 
 local function make_registration_reverse()
 	local t = {}
-	local registerfunc = function(func) table.insert(t, 1, func) end
+	local registerfunc = function(func)
+		table.insert(t, 1, func)
+		core.callback_origins[func] = {
+			mod = core.get_current_modname() or "??",
+			name = debug.getinfo(1, "n").name or "??"
+		}
+		--local origin = core.callback_origins[func]
+		--print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func))
+	end
 	return t, registerfunc
 end
 
@@ -408,6 +438,7 @@ local function make_registration_wrap(reg_fn_name, clear_fn_name)
 end
 
 core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } }
+
 function core.registered_on_player_hpchange(player, hp_change)
 	local last = false
 	for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do
@@ -427,12 +458,17 @@ function core.registered_on_player_hpchange(player, hp_change)
 	end
 	return hp_change
 end
+
 function core.register_on_player_hpchange(func, modifier)
 	if modifier then
 		table.insert(core.registered_on_player_hpchanges.modifiers, func)
 	else
 		table.insert(core.registered_on_player_hpchanges.loggers, func)
 	end
+	core.callback_origins[func] = {
+		mod = core.get_current_modname() or "??",
+		name = debug.getinfo(1, "n").name or "??"
+	}
 end
 
 core.registered_biomes      = make_registration_wrap("register_biome",      "clear_registered_biomes")
diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp
index 0df0a72702055241842251a0ddf39e555b353436..2a10ce0f25050ab1d1026646f568815e6834e1a3 100644
--- a/src/script/common/c_internal.cpp
+++ b/src/script/common/c_internal.cpp
@@ -79,7 +79,7 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f)
  * to gather a coherent backtrace.  Realistically, the best we can do here is
  * print which C function performed the failing pcall.
  */
-void script_error(lua_State *L, int pcall_result, const char *fxn)
+void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn)
 {
 	if (pcall_result == 0)
 		return;
@@ -99,18 +99,21 @@ void script_error(lua_State *L, int pcall_result, const char *fxn)
 		err_type = "Unknown";
 	}
 
+	if (!mod)
+		mod = "??";
+
+	if (!fxn)
+		fxn = "??";
+
 	const char *err_descr = lua_tostring(L, -1);
 	if (!err_descr)
 		err_descr = "<no description>";
 
-	std::string err_msg(err_type);
-	if (fxn) {
-		err_msg += " error in ";
-		err_msg += fxn;
-		err_msg += "(): ";
-	} else {
-		err_msg += " error: ";
-	}
+	char buf[256];
+	snprintf(buf, sizeof(buf), "%s error from mod '%s' in callback %s(): ",
+		err_type, mod, fxn);
+
+	std::string err_msg(buf);
 	err_msg += err_descr;
 
 	if (pcall_result == LUA_ERRMEM) {
@@ -152,7 +155,7 @@ void script_run_callbacks_f(lua_State *L, int nargs,
 
 	int result = lua_pcall(L, nargs + 2, 1, errorhandler);
 	if (result != 0)
-		script_error(L, result, fxn);
+		script_error(L, result, NULL, fxn);
 
 	lua_remove(L, -2); // Remove error handler
 }
@@ -176,7 +179,7 @@ void log_deprecated(lua_State *L, const std::string &message)
 
 	if (doerror) {
 		if (L != NULL) {
-			script_error(L, LUA_ERRRUN, NULL);
+			script_error(L, LUA_ERRRUN, NULL, NULL);
 		} else {
 			FATAL_ERROR("Can't do a scripterror for this deprecated message, "
 				"so exit completely!");
diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h
index 54cdd7da7bcd542f8ca6471b50b80be8e2e1ba45..ecb514c8fb8f95cbb84293d387221af2bf1d4a29 100644
--- a/src/script/common/c_internal.h
+++ b/src/script/common/c_internal.h
@@ -34,11 +34,11 @@ extern "C" {
 
 #include "common/c_types.h"
 
-#define PCALL_RESL(L, RES) do {                   \
-	int result_ = (RES);                          \
-	if (result_ != 0) {                           \
-		script_error((L), result_, __FUNCTION__); \
-	}                                             \
+#define PCALL_RESL(L, RES) do {                         \
+	int result_ = (RES);                                \
+	if (result_ != 0) {                                 \
+		script_error((L), result_, NULL, __FUNCTION__); \
+	}                                                   \
 } while (0)
 
 #define script_run_callbacks(L, nargs, mode) \
@@ -77,7 +77,7 @@ enum RunCallbacksMode
 std::string script_get_backtrace(lua_State *L);
 int script_error_handler(lua_State *L);
 int script_exception_wrapper(lua_State *L, lua_CFunction f);
-void script_error(lua_State *L, int pcall_result, const char *fxn);
+void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn);
 void script_run_callbacks_f(lua_State *L, int nargs,
 	RunCallbacksMode mode, const char *fxn);
 void log_deprecated(lua_State *L, const std::string &message);
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index 680e661ea3f5df470582a3ff72ae7597c0d8a72d..dcfbac4bfe99468fb1db73e395fb2e248489eebd 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "cpp_api/s_internal.h"
 #include "cpp_api/s_security.h"
 #include "lua_api/l_object.h"
+#include "common/c_converter.h"
 #include "serverobject.h"
 #include "debug.h"
 #include "filesys.h"
@@ -68,9 +69,9 @@ class ModNameStorer
 
 ScriptApiBase::ScriptApiBase()
 {
-	#ifdef SCRIPTAPI_LOCK_DEBUG
+#ifdef SCRIPTAPI_LOCK_DEBUG
 	m_locked = false;
-	#endif
+#endif
 
 	m_luastack = luaL_newstate();
 	FATAL_ERROR_IF(!m_luastack, "luaL_newstate() failed");
@@ -154,6 +155,43 @@ bool ScriptApiBase::loadScript(const std::string &script_path, std::string *erro
 	return true;
 }
 
+// Push the list of callbacks (a lua table).
+// Then push nargs arguments.
+// Then call this function, which
+// - runs the callbacks
+// - replaces the table and arguments with the return value,
+//     computed depending on mode
+void ScriptApiBase::runCallbacksRaw(int nargs,
+		RunCallbacksMode mode, const char *fxn)
+{
+	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);
+
+	// 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);
+
+	// Insert mode after table
+	lua_pushnumber(L, (int)mode);
+	lua_insert(L, errorhandler + 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);
+	if (result != 0)
+		scriptError(result, fxn);
+
+	lua_remove(L, -2); // Remove error handler
+}
+
 void ScriptApiBase::realityCheck()
 {
 	int top = lua_gettop(m_luastack);
@@ -167,7 +205,7 @@ void ScriptApiBase::realityCheck()
 
 void ScriptApiBase::scriptError(int result, const char *fxn)
 {
-	script_error(getStack(), result, fxn);
+	script_error(getStack(), result, m_last_run_mod.c_str(), fxn);
 }
 
 void ScriptApiBase::stackDump(std::ostream &o)
@@ -197,6 +235,22 @@ void ScriptApiBase::stackDump(std::ostream &o)
 	o << std::endl;
 }
 
+void ScriptApiBase::setOriginDirect(const char *origin)
+{
+	m_last_run_mod = origin ? origin : "??";
+}
+
+void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
+{
+#ifdef SCRIPTAPI_DEBUG
+	lua_State *L = getStack();
+
+	m_last_run_mod = lua_istable(L, index) ?
+		getstringfield_default(L, index, "mod_origin", "") : "";
+	//printf(">>>> running %s for mod: %s\n", fxn, m_last_run_mod.c_str());
+#endif
+}
+
 void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
 {
 	SCRIPTAPI_PRECHECKHEADER
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index 0c2dfafd1f9f9fdec4cd97d82d3965e0f1591cb4..d653b5bacb8d70b7f6edf5859ef316cc92f94275 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -34,6 +34,7 @@ extern "C" {
 #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
@@ -47,6 +48,12 @@ extern "C" {
 	}                                       \
 } while (0)
 
+#define runCallbacks(nargs, mode) \
+	runCallbacksRaw((nargs), (mode), __FUNCTION__)
+
+#define setOriginFromTable(index) \
+	setOriginFromTableRaw(index, __FUNCTION__)
+
 class Server;
 class Environment;
 class GUIEngine;
@@ -61,12 +68,19 @@ class ScriptApiBase {
 		std::string *error=NULL);
 	bool loadScript(const std::string &script_path, std::string *error=NULL);
 
+	void runCallbacksRaw(int nargs,
+		RunCallbacksMode mode, const char *fxn);
+
 	/* object */
 	void addObjectReference(ServerActiveObject *cobj);
 	void removeObjectReference(ServerActiveObject *cobj);
 
 	Server* getServer() { return m_server; }
 
+	std::string getOrigin() { return m_last_run_mod; }
+	void setOriginDirect(const char *origin);
+	void setOriginFromTableRaw(int index, const char *fxn);
+
 protected:
 	friend class LuaABM;
 	friend class InvRef;
@@ -95,6 +109,7 @@ class ScriptApiBase {
 	void objectrefGet(lua_State *L, u16 id);
 
 	JMutex          m_luastackmutex;
+	std::string     m_last_run_mod;
 	// Stack index of Lua error handler
 	int             m_errorhandler;
 	bool            m_secure;
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index 08e06ccbcef499817f25ff0fe4041a7f097151bd..0d159846a0b6662ce1422d6dac425a1dce0a9ed2 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -91,7 +91,8 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
 		lua_pushvalue(L, object); // self
 		lua_pushlstring(L, staticdata.c_str(), staticdata.size());
 		lua_pushinteger(L, dtime_s);
-		// Call with 3 arguments, 0 results
+
+		setOriginFromTable(object);
 		PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
 	} else {
 		lua_pop(L, 1);
@@ -135,11 +136,12 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
 		lua_pop(L, 2); // Pop entity and  get_staticdata
 		return "";
 	}
-
 	luaL_checktype(L, -1, LUA_TFUNCTION);
 	lua_pushvalue(L, object); // self
-	// Call with 1 arguments, 1 results
+
+	setOriginFromTable(object);
 	PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
+
 	lua_remove(L, object); // Remove object
 
 	size_t len = 0;
@@ -207,8 +209,10 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
 	luaL_checktype(L, -1, LUA_TFUNCTION);
 	lua_pushvalue(L, object); // self
 	lua_pushnumber(L, dtime); // dtime
-	// Call with 2 arguments, 0 results
+
+	setOriginFromTable(object);
 	PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+
 	lua_pop(L, 1); // Pop object
 }
 
@@ -238,8 +242,10 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
 	lua_pushnumber(L, time_from_last_punch);
 	push_tool_capabilities(L, *toolcap);
 	push_v3f(L, dir);
-	// Call with 5 arguments, 0 results
+
+	setOriginFromTable(object);
 	PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+
 	lua_pop(L, 1); // Pop object
 }
 
@@ -264,8 +270,10 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
 	luaL_checktype(L, -1, LUA_TFUNCTION);
 	lua_pushvalue(L, object); // self
 	objectrefGetOrCreate(L, clicker); // Clicker reference
-	// Call with 2 arguments, 0 results
+
+	setOriginFromTable(object);
 	PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+
 	lua_pop(L, 1); // Pop object
 }
 
diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp
index c171bbf0249776d6789703ce8c78dbcfb1c33dc1..9c733773a6d14ed8ab11cf3e5663f5d08b0982d6 100644
--- a/src/script/cpp_api/s_env.cpp
+++ b/src/script/cpp_api/s_env.cpp
@@ -38,7 +38,7 @@ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
 	push_v3s16(L, minp);
 	push_v3s16(L, maxp);
 	lua_pushnumber(L, blockseed);
-	script_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
 }
 
 void ScriptApiEnv::environment_Step(float dtime)
@@ -52,7 +52,7 @@ void ScriptApiEnv::environment_Step(float dtime)
 	// Call callbacks
 	lua_pushnumber(L, dtime);
 	try {
-		script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+		runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
 	} catch (LuaError &e) {
 		getServer()->setAsyncFatalError(e.what());
 	}
@@ -73,7 +73,7 @@ void ScriptApiEnv::player_event(ServerActiveObject* player, std::string type)
 	objectrefGetOrCreate(L, player);   // player
 	lua_pushstring(L,type.c_str()); // event type
 	try {
-		script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_FIRST);
+		runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
 	} catch (LuaError &e) {
 		getServer()->setAsyncFatalError(e.what());
 	}
diff --git a/src/script/cpp_api/s_inventory.cpp b/src/script/cpp_api/s_inventory.cpp
index c8c90fd8f1f69bddd5a177eee9de25c8b2353f14..019d1ccc07deeae8b4f6a5776b8d482ced12caed 100644
--- a/src/script/cpp_api/s_inventory.cpp
+++ b/src/script/cpp_api/s_inventory.cpp
@@ -209,6 +209,9 @@ bool ScriptApiDetached::getDetachedInventoryCallback(
 		lua_pop(L, 1);
 		return false;
 	}
+
+	setOriginFromTable(-1);
+
 	lua_getfield(L, -1, callbackname);
 	lua_remove(L, -2);
 	// Should be a function or nil
diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp
index 1ca06de7646af2a4a16549df7b2bce391c5b83da..4d4d416ec7ad33639cd2f37d11931d0961abda21 100644
--- a/src/script/cpp_api/s_item.cpp
+++ b/src/script/cpp_api/s_item.cpp
@@ -193,6 +193,9 @@ bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
 		lua_remove(L, -2);
 		luaL_checktype(L, -1, LUA_TTABLE);
 	}
+
+	setOriginFromTable(-1);
+
 	lua_getfield(L, -1, callbackname);
 	lua_remove(L, -2); // Remove item def
 	// Should be a function or nil
diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp
index 676b07537345e6f0b3d357025fc04559dc6844a4..ef3c31cfd2cdcb0b4ee42bab36f76d5b7a30440c 100644
--- a/src/script/cpp_api/s_player.cpp
+++ b/src/script/cpp_api/s_player.cpp
@@ -32,7 +32,7 @@ void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
 	lua_getfield(L, -1, "registered_on_newplayers");
 	// Call callbacks
 	objectrefGetOrCreate(L, player);
-	script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
 }
 
 void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player)
@@ -44,7 +44,7 @@ void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player)
 	lua_getfield(L, -1, "registered_on_dieplayers");
 	// Call callbacks
 	objectrefGetOrCreate(L, player);
-	script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
 }
 
 bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
@@ -65,7 +65,7 @@ bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
 	push_tool_capabilities(L, *toolcap);
 	push_v3f(L, dir);
 	lua_pushnumber(L, damage);
-	script_run_callbacks(L, 6, RUN_CALLBACKS_MODE_OR);
+	runCallbacks(6, RUN_CALLBACKS_MODE_OR);
 	return lua_toboolean(L, -1);
 }
 
@@ -96,7 +96,7 @@ bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
 	lua_getfield(L, -1, "registered_on_respawnplayers");
 	// Call callbacks
 	objectrefGetOrCreate(L, player);
-	script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_OR);
+	runCallbacks(1, RUN_CALLBACKS_MODE_OR);
 	bool positioning_handled_by_some = lua_toboolean(L, -1);
 	return positioning_handled_by_some;
 }
@@ -113,7 +113,7 @@ bool ScriptApiPlayer::on_prejoinplayer(
 	lua_getfield(L, -1, "registered_on_prejoinplayers");
 	lua_pushstring(L, name.c_str());
 	lua_pushstring(L, ip.c_str());
-	script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR);
+	runCallbacks(2, RUN_CALLBACKS_MODE_OR);
 	if (lua_isstring(L, -1)) {
 		reason->assign(lua_tostring(L, -1));
 		return true;
@@ -130,7 +130,7 @@ void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
 	lua_getfield(L, -1, "registered_on_joinplayers");
 	// Call callbacks
 	objectrefGetOrCreate(L, player);
-	script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
 }
 
 void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
@@ -142,7 +142,7 @@ void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
 	lua_getfield(L, -1, "registered_on_leaveplayers");
 	// Call callbacks
 	objectrefGetOrCreate(L, player);
-	script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
 }
 
 void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
@@ -158,7 +158,7 @@ void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
 	lua_newtable(L);
 	lua_pushlstring(L, cheat_type.c_str(), cheat_type.size());
 	lua_setfield(L, -2, "type");
-	script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
 }
 
 void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
@@ -185,7 +185,7 @@ void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
 		lua_pushlstring(L, value.c_str(), value.size());
 		lua_settable(L, -3);
 	}
-	script_run_callbacks(L, 3, RUN_CALLBACKS_MODE_OR_SC);
+	runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
 }
 
 ScriptApiPlayer::~ScriptApiPlayer()
diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp
index 5b4626f40943c35638693234795f927a410aae6e..ec2f9c0af879ac5415cf938ec5dafac81d8ef198 100644
--- a/src/script/cpp_api/s_server.cpp
+++ b/src/script/cpp_api/s_server.cpp
@@ -67,6 +67,9 @@ void ScriptApiServer::getAuthHandler()
 		lua_pop(L, 1);
 		lua_getfield(L, -1, "builtin_auth_handler");
 	}
+
+	setOriginFromTable(-1);
+
 	lua_remove(L, -2); // Remove core
 	if (lua_type(L, -1) != LUA_TTABLE)
 		throw LuaError("Authentication handler table not valid");
@@ -133,7 +136,7 @@ bool ScriptApiServer::on_chat_message(const std::string &name,
 	// Call callbacks
 	lua_pushstring(L, name.c_str());
 	lua_pushstring(L, message.c_str());
-	script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR_SC);
+	runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
 	bool ate = lua_toboolean(L, -1);
 	return ate;
 }
@@ -146,6 +149,6 @@ void ScriptApiServer::on_shutdown()
 	lua_getglobal(L, "core");
 	lua_getfield(L, -1, "registered_on_shutdown");
 	// Call callbacks
-	script_run_callbacks(L, 0, RUN_CALLBACKS_MODE_FIRST);
+	runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
 }
 
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 48c46c07999e1d0e469980e7a917ec7d83b0806d..9d1936769192d03c8f03dbcc59297d7541ed94ad 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -68,6 +68,8 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
 		FATAL_ERROR("");
 	lua_remove(L, -2); // Remove registered_abms
 
+	scriptIface->setOriginFromTable(-1);
+
 	// Call action
 	luaL_checktype(L, -1, LUA_TTABLE);
 	lua_getfield(L, -1, "action");
@@ -78,7 +80,9 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
 	lua_pushnumber(L, active_object_count);
 	lua_pushnumber(L, active_object_count_wider);
 
-	PCALL_RESL(L, lua_pcall(L, 4, 0, errorhandler));
+	int result = lua_pcall(L, 4, 0, errorhandler);
+	if (result)
+		scriptIface->scriptError(result, "LuaABM::trigger");
 
 	lua_pop(L, 1); // Pop error handler
 }
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 96c0327df0e9dff6c3ed529b085c54a27a03c4c7..73eca9d6099d533c8bfc744d47b24468f63f9b11 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -438,6 +438,31 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L)
 	return 0;
 }
 
+// get_last_run_mod()
+int ModApiServer::l_get_last_run_mod(lua_State *L)
+{
+	NO_MAP_LOCK_REQUIRED;
+	lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+	const char *current_mod = lua_tostring(L, -1);
+	if (current_mod == NULL || current_mod[0] == '\0') {
+		lua_pop(L, 1);
+		lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
+	}
+	return 1;
+}
+
+// set_last_run_mod(modname)
+int ModApiServer::l_set_last_run_mod(lua_State *L)
+{
+	NO_MAP_LOCK_REQUIRED;
+#ifdef SCRIPTAPI_DEBUG
+	const char *mod = lua_tostring(L, 1);
+	getScriptApiBase(L)->setOriginDirect(mod);
+	//printf(">>>> last mod set from Lua: %s\n", mod);
+#endif
+	return 0;
+}
+
 #ifndef NDEBUG
 // cause_error(type_of_error)
 int ModApiServer::l_cause_error(lua_State *L)
@@ -495,6 +520,8 @@ void ModApiServer::Initialize(lua_State *L, int top)
 	API_FCT(unban_player_or_ip);
 	API_FCT(notify_authentication_modified);
 
+	API_FCT(get_last_run_mod);
+	API_FCT(set_last_run_mod);
 #ifndef NDEBUG
 	API_FCT(cause_error);
 #endif
diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h
index e14bef043a8a1005d065036808894b9f4a413bf8..df31f325f03281f323a03e29f1bb2f0532cb23b4 100644
--- a/src/script/lua_api/l_server.h
+++ b/src/script/lua_api/l_server.h
@@ -88,6 +88,12 @@ class ModApiServer : public ModApiBase {
 	// notify_authentication_modified(name)
 	static int l_notify_authentication_modified(lua_State *L);
 
+	// get_last_run_mod()
+	static int l_get_last_run_mod(lua_State *L);
+
+	// set_last_run_mod(modname)
+	static int l_set_last_run_mod(lua_State *L);
+
 #ifndef NDEBUG
 	//  cause_error(type_of_error)
 	static int l_cause_error(lua_State *L);