diff options
-rw-r--r-- | builtin/misc_register.lua | 39 | ||||
-rw-r--r-- | src/script/common/c_internal.cpp | 102 |
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 } |