aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/misc_register.lua39
-rw-r--r--src/script/common/c_internal.cpp102
2 files changed, 57 insertions, 84 deletions
diff --git a/builtin/misc_register.lua b/builtin/misc_register.lua
index 54022a361..249d272eb 100644
--- a/builtin/misc_register.lua
+++ b/builtin/misc_register.lua
@@ -314,6 +314,45 @@ minetest.register_item(":", {
groups = {not_in_creative_inventory=1},
})
+
+function minetest.run_callbacks(callbacks, mode, ...)
+ assert(type(callbacks) == "table")
+ local cb_len = #callbacks
+ if cb_len == 0 then
+ if mode == 2 or mode == 3 then
+ return true
+ elseif mode == 4 or mode == 5 then
+ return false
+ end
+ end
+ local ret = nil
+ for i = 1, cb_len do
+ local cb_ret = callbacks[i](...)
+
+ if mode == 0 and i == 1 then
+ ret = cb_ret
+ elseif mode == 1 and i == cb_len then
+ ret = cb_ret
+ elseif mode == 2 then
+ if not cb_ret or i == 1 then
+ ret = cb_ret
+ end
+ elseif mode == 3 then
+ if cb_ret then
+ return cb_ret
+ end
+ ret = cb_ret
+ elseif mode == 4 then
+ if (cb_ret and not ret) or i == 1 then
+ ret = cb_ret
+ end
+ elseif mode == 5 and cb_ret then
+ return cb_ret
+ end
+ end
+ return ret
+end
+
--
-- Callback registration
--
diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp
index f22e9b0ff..2866cfe86 100644
--- a/src/script/common/c_internal.cpp
+++ b/src/script/common/c_internal.cpp
@@ -66,101 +66,35 @@ void script_error(lua_State *L)
// Then push nargs arguments.
// Then call this function, which
// - runs the callbacks
-// - removes the table and arguments from the lua stack
-// - pushes the return value, computed depending on mode
+// - replaces the table and arguments with the return value,
+// computed depending on mode
void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
{
- // Insert the return value into the lua stack, below the table
assert(lua_gettop(L) >= nargs + 1);
- lua_pushnil(L);
- int rv = lua_gettop(L) - nargs - 1;
- lua_insert(L, rv);
-
- // Insert error handler after return value
+ // Insert error handler
lua_pushcfunction(L, script_error_handler);
- int errorhandler = rv + 1;
+ int errorhandler = lua_gettop(L) - nargs - 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;
-
- luaL_checktype(L, table, LUA_TTABLE);
-
- // Foreach
- lua_pushnil(L);
- bool first_loop = true;
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TFUNCTION);
- // Call function
- for(int i = 0; i < nargs; i++)
- lua_pushvalue(L, arg+i);
- if(lua_pcall(L, nargs, 1, errorhandler))
- script_error(L);
-
- // Move return value to designated space in stack
- // Or pop it
- if(first_loop){
- // Result of first callback is always moved
- lua_replace(L, rv);
- first_loop = false;
- } else {
- // Otherwise, what happens depends on the mode
- if(mode == RUN_CALLBACKS_MODE_FIRST)
- lua_pop(L, 1);
- else if(mode == RUN_CALLBACKS_MODE_LAST)
- lua_replace(L, rv);
- else if(mode == RUN_CALLBACKS_MODE_AND ||
- mode == RUN_CALLBACKS_MODE_AND_SC){
- if((bool)lua_toboolean(L, rv) == true &&
- (bool)lua_toboolean(L, -1) == false)
- lua_replace(L, rv);
- else
- lua_pop(L, 1);
- }
- else if(mode == RUN_CALLBACKS_MODE_OR ||
- mode == RUN_CALLBACKS_MODE_OR_SC){
- if((bool)lua_toboolean(L, rv) == false &&
- (bool)lua_toboolean(L, -1) == true)
- lua_replace(L, rv);
- else
- lua_pop(L, 1);
- }
- else
- assert(0);
- }
+ // Insert minetest.run_callbacks between error handler and table
+ lua_getglobal(L, "minetest");
+ lua_getfield(L, -1, "run_callbacks");
+ lua_remove(L, -2);
+ lua_insert(L, errorhandler + 1);
- // Handle short circuit modes
- if(mode == RUN_CALLBACKS_MODE_AND_SC &&
- (bool)lua_toboolean(L, rv) == false)
- break;
- else if(mode == RUN_CALLBACKS_MODE_OR_SC &&
- (bool)lua_toboolean(L, rv) == true)
- break;
+ // Insert mode after table
+ lua_pushnumber(L, (int) mode);
+ lua_insert(L, errorhandler + 3);
- // value removed, keep key for next iteration
- }
-
- // Remove stuff from stack, leaving only the return value
- lua_settop(L, rv);
+ // Stack now looks like this:
+ // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
- // Fix return value in case no callbacks were called
- if(first_loop){
- if(mode == RUN_CALLBACKS_MODE_AND ||
- mode == RUN_CALLBACKS_MODE_AND_SC){
- lua_pop(L, 1);
- lua_pushboolean(L, true);
- }
- else if(mode == RUN_CALLBACKS_MODE_OR ||
- mode == RUN_CALLBACKS_MODE_OR_SC){
- lua_pop(L, 1);
- lua_pushboolean(L, false);
- }
+ if (lua_pcall(L, nargs + 2, 1, errorhandler)) {
+ script_error(L);
}
+
+ lua_remove(L, -2); // Remove error handler
}