]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/script/common/c_internal.cpp
Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[dragonfireclient.git] / src / script / common / c_internal.cpp
index 42e9fb3e1e66a02943fd67f3cc4b670148478b45..5c16b88d9d281c8518122f8fd05ed736bef9db6d 100644 (file)
@@ -18,17 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "common/c_internal.h"
-#include "server.h"
-#include "cpp_api/scriptapi.h"
-
-ScriptApi* get_scriptapi(lua_State *L)
-{
-       // Get server from registry
-       lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
-       ScriptApi* sapi_ptr = (ScriptApi*) lua_touserdata(L, -1);
-       lua_pop(L, 1);
-       return sapi_ptr;
-}
+#include "debug.h"
 
 std::string script_get_backtrace(lua_State *L)
 {
@@ -51,15 +41,108 @@ std::string script_get_backtrace(lua_State *L)
        return s;
 }
 
-void script_error(lua_State* L,const char *fmt, ...)
+void script_error(lua_State *L, const char *fmt, ...)
 {
        va_list argp;
        va_start(argp, fmt);
        char buf[10000];
        vsnprintf(buf, 10000, fmt, argp);
        va_end(argp);
-       //errorstream<<"SCRIPT ERROR: "<<buf;
        throw LuaError(L, buf);
 }
 
+// Push the list of callbacks (a lua table).
+// 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
+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);
+       lua_insert(L, -(nargs + 1) - 1);
+       // Stack now looks like this:
+       // ... <return value = nil> <table> <arg#1> <arg#2> ... <arg#n>
+
+       int rv = lua_gettop(L) - nargs - 1;
+       int table = rv + 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, 0))
+                       script_error(L, "error: %s", lua_tostring(L, -1));
+
+               // 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);
+               }
+
+               // 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;
+
+               // value removed, keep key for next iteration
+       }
+
+       // Remove stuff from stack, leaving only the return value
+       lua_settop(L, rv);
+
+       // 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);
+               }
+       }
+}
+