#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
#endif
}
-#include <stdio.h>
+#include <cstdio>
#include <cstdarg>
#include "script/common/c_content.h"
+#include "content_sao.h"
#include <sstream>
ScriptApiBase
*/
-ScriptApiBase::ScriptApiBase()
+ScriptApiBase::ScriptApiBase(ScriptingType type):
+ m_type(type)
{
#ifdef SCRIPTAPI_LOCK_DEBUG
m_lock_recursion_count = 0;
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
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()
{
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)
{
}
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);
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
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;
}
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");
}
}