]> git.lizzy.rs Git - minetest.git/blobdiff - src/script/cpp_api/s_base.cpp
Merge pull request #8776 from osjc/FixGetNode
[minetest.git] / src / script / cpp_api / s_base.cpp
index aaf26a9c3bec9d0dabff9992caf11bc0a48c35ea..e73f613ce6a1013071ac037eace60366db2c74cb 100644 (file)
@@ -24,12 +24,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common/c_converter.h"
 #include "serverobject.h"
 #include "filesys.h"
-#include "mods.h"
+#include "content/mods.h"
 #include "porting.h"
 #include "util/string.h"
 #include "server.h"
 #ifndef SERVER
-#include "client.h"
+#include "client/client.h"
 #endif
 
 
@@ -40,9 +40,10 @@ extern "C" {
 #endif
 }
 
-#include <stdio.h>
+#include <cstdio>
 #include <cstdarg>
 #include "script/common/c_content.h"
+#include "content_sao.h"
 #include <sstream>
 
 
@@ -71,7 +72,8 @@ class ModNameStorer
        ScriptApiBase
 */
 
-ScriptApiBase::ScriptApiBase()
+ScriptApiBase::ScriptApiBase(ScriptingType type):
+               m_type(type)
 {
 #ifdef SCRIPTAPI_LOCK_DEBUG
        m_lock_recursion_count = 0;
@@ -82,15 +84,20 @@ ScriptApiBase::ScriptApiBase()
 
        lua_atpanic(m_luastack, &luaPanic);
 
-       luaL_openlibs(m_luastack);
+       if (m_type == ScriptingType::Client)
+               clientOpenLibs(m_luastack);
+       else
+               luaL_openlibs(m_luastack);
 
        // Make the ScriptApiBase* accessible to ModApiBase
        lua_pushlightuserdata(m_luastack, this);
        lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
 
        // Add and save an error handler
-       lua_pushcfunction(m_luastack, script_error_handler);
-       lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_ERROR_HANDLER);
+       lua_getglobal(m_luastack, "debug");
+       lua_getfield(m_luastack, -1, "traceback");
+       lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE);
+       lua_pop(m_luastack, 1); // pop debug
 
        // If we are using LuaJIT add a C++ wrapper function to catch
        // exceptions thrown in Lua -> C++ calls
@@ -104,11 +111,17 @@ ScriptApiBase::ScriptApiBase()
        lua_newtable(m_luastack);
        lua_setglobal(m_luastack, "core");
 
-       lua_pushstring(m_luastack, DIR_DELIM);
+       if (m_type == ScriptingType::Client)
+               lua_pushstring(m_luastack, "/");
+       else
+               lua_pushstring(m_luastack, DIR_DELIM);
        lua_setglobal(m_luastack, "DIR_DELIM");
 
        lua_pushstring(m_luastack, porting::getPlatformName());
        lua_setglobal(m_luastack, "PLATFORM");
+
+       // Make sure Lua uses the right locale
+       setlocale(LC_NUMERIC, "C");
 }
 
 ScriptApiBase::~ScriptApiBase()
@@ -120,12 +133,33 @@ int ScriptApiBase::luaPanic(lua_State *L)
 {
        std::ostringstream oss;
        oss << "LUA PANIC: unprotected error in call to Lua API ("
-               << lua_tostring(L, -1) << ")";
+               << readParam<std::string>(L, -1) << ")";
        FATAL_ERROR(oss.str().c_str());
        // NOTREACHED
        return 0;
 }
 
+void ScriptApiBase::clientOpenLibs(lua_State *L)
+{
+       static const std::vector<std::pair<std::string, lua_CFunction>> m_libs = {
+               { "", luaopen_base },
+               { LUA_TABLIBNAME,  luaopen_table   },
+               { LUA_OSLIBNAME,   luaopen_os      },
+               { LUA_STRLIBNAME,  luaopen_string  },
+               { LUA_MATHLIBNAME, luaopen_math    },
+               { LUA_DBLIBNAME,   luaopen_debug   },
+#if USE_LUAJIT
+               { LUA_JITLIBNAME,  luaopen_jit     },
+#endif
+       };
+
+       for (const std::pair<std::string, lua_CFunction> &lib : m_libs) {
+           lua_pushcfunction(L, lib.second);
+           lua_pushstring(L, lib.first.c_str());
+           lua_call(L, 1, 0);
+       }
+}
+
 void ScriptApiBase::loadMod(const std::string &script_path,
                const std::string &mod_name)
 {
@@ -150,7 +184,7 @@ void ScriptApiBase::loadScript(const std::string &script_path)
        }
        ok = ok && !lua_pcall(L, 0, 0, error_handler);
        if (!ok) {
-               std::string error_msg = lua_tostring(L, -1);
+               std::string error_msg = readParam<std::string>(L, -1);
                lua_pop(L, 2); // Pop error message and error handler
                throw ModError("Failed to load and run script from " +
                                script_path + ":\n" + error_msg);
@@ -158,6 +192,35 @@ void ScriptApiBase::loadScript(const std::string &script_path)
        lua_pop(L, 1); // Pop error handler
 }
 
+#ifndef SERVER
+void ScriptApiBase::loadModFromMemory(const std::string &mod_name)
+{
+       ModNameStorer mod_name_storer(getStack(), mod_name);
+
+       const std::string *init_filename = getClient()->getModFile(mod_name + ":init.lua");
+       const std::string display_filename = mod_name + ":init.lua";
+       if(init_filename == NULL)
+               throw ModError("Mod:\"" + mod_name + "\" lacks init.lua");
+
+       verbosestream << "Loading and running script " << display_filename << std::endl;
+
+       lua_State *L = getStack();
+
+       int error_handler = PUSH_ERROR_HANDLER(L);
+
+       bool ok = ScriptApiSecurity::safeLoadFile(L, init_filename->c_str(), display_filename.c_str());
+       if (ok)
+               ok = !lua_pcall(L, 0, 0, error_handler);
+       if (!ok) {
+               std::string error_msg = luaL_checkstring(L, -1);
+               lua_pop(L, 2); // Pop error message and error handler
+               throw ModError("Failed to load and run mod \"" +
+                               mod_name + "\":\n" + error_msg);
+       }
+       lua_pop(L, 1); // Pop error handler
+}
+#endif
+
 // Push the list of callbacks (a lua table).
 // Then push nargs arguments.
 // Then call this function, which
@@ -223,14 +286,14 @@ void ScriptApiBase::stackDump(std::ostream &o)
                int t = lua_type(m_luastack, i);
                switch (t) {
                        case LUA_TSTRING:  /* strings */
-                               o << "\"" << lua_tostring(m_luastack, i) << "\"";
+                               o << "\"" << readParam<std::string>(m_luastack, i) << "\"";
                                break;
                        case LUA_TBOOLEAN:  /* booleans */
-                               o << (lua_toboolean(m_luastack, i) ? "true" : "false");
+                               o << (readParam<bool>(m_luastack, i) ? "true" : "false");
                                break;
                        case LUA_TNUMBER:  /* numbers */ {
                                char buf[10];
-                               snprintf(buf, 10, "%lf", lua_tonumber(m_luastack, i));
+                               porting::mt_snprintf(buf, sizeof(buf), "%lf", lua_tonumber(m_luastack, i));
                                o << buf;
                                break;
                        }
@@ -312,6 +375,38 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
                ObjectRef::create(L, cobj);
        } else {
                push_objectRef(L, cobj->getId());
+               if (cobj->isGone())
+                       warningstream << "ScriptApiBase::objectrefGetOrCreate(): "
+                                       << "Pushing ObjectRef to removed/deactivated object"
+                                       << ", this is probably a bug." << std::endl;
+       }
+}
+
+void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
+{
+       if (reason.hasLuaReference())
+               lua_rawgeti(L, LUA_REGISTRYINDEX, reason.lua_reference);
+       else
+               lua_newtable(L);
+
+       lua_getfield(L, -1, "type");
+       bool has_type = (bool)lua_isstring(L, -1);
+       lua_pop(L, 1);
+       if (!has_type) {
+               lua_pushstring(L, reason.getTypeAsString().c_str());
+               lua_setfield(L, -2, "type");
+       }
+
+       lua_pushstring(L, reason.from_mod ? "mod" : "engine");
+       lua_setfield(L, -2, "from");
+
+       if (reason.object) {
+               objectrefGetOrCreate(L, reason.object);
+               lua_setfield(L, -2, "object");
+       }
+       if (!reason.node.empty()) {
+               lua_pushstring(L, reason.node.c_str());
+               lua_setfield(L, -2, "node");
        }
 }