summaryrefslogtreecommitdiff
path: root/src/script/cpp_api
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/cpp_api')
-rw-r--r--src/script/cpp_api/CMakeLists.txt1
-rw-r--r--src/script/cpp_api/s_async.cpp33
-rw-r--r--src/script/cpp_api/s_async.h25
-rw-r--r--src/script/cpp_api/s_base.cpp45
-rw-r--r--src/script/cpp_api/s_base.h17
-rw-r--r--src/script/cpp_api/s_client.cpp230
-rw-r--r--src/script/cpp_api/s_client.h63
-rw-r--r--src/script/cpp_api/s_entity.cpp22
-rw-r--r--src/script/cpp_api/s_entity.h4
-rw-r--r--src/script/cpp_api/s_env.cpp12
-rw-r--r--src/script/cpp_api/s_item.cpp35
-rw-r--r--src/script/cpp_api/s_mainmenu.cpp8
-rw-r--r--src/script/cpp_api/s_node.cpp27
-rw-r--r--src/script/cpp_api/s_node.h1
-rw-r--r--src/script/cpp_api/s_player.h14
-rw-r--r--src/script/cpp_api/s_security.cpp187
-rw-r--r--src/script/cpp_api/s_security.h2
17 files changed, 589 insertions, 137 deletions
diff --git a/src/script/cpp_api/CMakeLists.txt b/src/script/cpp_api/CMakeLists.txt
index be4d0131e..4b13356a8 100644
--- a/src/script/cpp_api/CMakeLists.txt
+++ b/src/script/cpp_api/CMakeLists.txt
@@ -13,6 +13,7 @@ set(common_SCRIPT_CPP_API_SRCS
PARENT_SCOPE)
set(client_SCRIPT_CPP_API_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
PARENT_SCOPE)
diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp
index 1fb84fab6..722359066 100644
--- a/src/script/cpp_api/s_async.cpp
+++ b/src/script/cpp_api/s_async.cpp
@@ -46,26 +46,26 @@ AsyncEngine::~AsyncEngine()
// Request all threads to stop
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
(*it)->stop();
}
// Wake up all threads
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
jobQueueCounter.post();
}
// Wait for threads to finish
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
(*it)->wait();
}
// Force kill all threads
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
- it != workerThreads.end(); it++) {
+ it != workerThreads.end(); ++it) {
delete *it;
}
@@ -76,14 +76,9 @@ AsyncEngine::~AsyncEngine()
}
/******************************************************************************/
-bool AsyncEngine::registerFunction(const char* name, lua_CFunction func)
+void AsyncEngine::registerStateInitializer(StateInitializer func)
{
- if (initDone) {
- return false;
- }
-
- functionList[name] = func;
- return true;
+ stateInitializers.push_back(func);
}
/******************************************************************************/
@@ -100,7 +95,8 @@ void AsyncEngine::initialize(unsigned int numEngines)
}
/******************************************************************************/
-unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
+unsigned int AsyncEngine::queueAsyncJob(const std::string &func,
+ const std::string &params)
{
jobQueueMutex.lock();
LuaJobInfo toAdd;
@@ -124,7 +120,6 @@ LuaJobInfo AsyncEngine::getJob()
jobQueueMutex.lock();
LuaJobInfo retval;
- retval.valid = false;
if (!jobQueue.empty()) {
retval = jobQueue.front();
@@ -137,7 +132,7 @@ LuaJobInfo AsyncEngine::getJob()
}
/******************************************************************************/
-void AsyncEngine::putJobResult(LuaJobInfo result)
+void AsyncEngine::putJobResult(const LuaJobInfo &result)
{
resultQueueMutex.lock();
resultQueue.push_back(result);
@@ -204,11 +199,9 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) {
/******************************************************************************/
void AsyncEngine::prepareEnvironment(lua_State* L, int top)
{
- for (UNORDERED_MAP<std::string, lua_CFunction>::iterator it = functionList.begin();
- it != functionList.end(); it++) {
- lua_pushstring(L, it->first.c_str());
- lua_pushcfunction(L, it->second);
- lua_settable(L, top);
+ for (std::vector<StateInitializer>::iterator it = stateInitializers.begin();
+ it != stateInitializers.end(); it++) {
+ (*it)(L, top);
}
}
@@ -264,7 +257,7 @@ void* AsyncWorkerThread::run()
// Wait for job
LuaJobInfo toProcess = jobDispatcher->getJob();
- if (toProcess.valid == false || stopRequested()) {
+ if (!toProcess.valid || stopRequested()) {
continue;
}
diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h
index 016381e5f..dbe0654e2 100644
--- a/src/script/cpp_api/s_async.h
+++ b/src/script/cpp_api/s_async.h
@@ -38,7 +38,16 @@ class AsyncEngine;
// Declarations
// Data required to queue a job
-struct LuaJobInfo {
+struct LuaJobInfo
+{
+ LuaJobInfo() :
+ serializedFunction(""),
+ serializedParams(""),
+ serializedResult(""),
+ id(0),
+ valid(false)
+ {}
+
// Function to be called in async environment
std::string serializedFunction;
// Parameter to be passed to function
@@ -66,16 +75,16 @@ private:
// Asynchornous thread and job management
class AsyncEngine {
friend class AsyncWorkerThread;
+ typedef void (*StateInitializer)(lua_State *L, int top);
public:
AsyncEngine();
~AsyncEngine();
/**
- * Register function to be used within engine
- * @param name Function name to be used within Lua environment
+ * Register function to be called on new states
* @param func C function to be called
*/
- bool registerFunction(const char* name, lua_CFunction func);
+ void registerStateInitializer(StateInitializer func);
/**
* Create async engine tasks and lock function registration
@@ -89,7 +98,7 @@ public:
* @param params Serialized parameters
* @return jobid The job is queued
*/
- unsigned int queueAsyncJob(std::string func, std::string params);
+ unsigned int queueAsyncJob(const std::string &func, const std::string &params);
/**
* Engine step to process finished jobs
@@ -116,7 +125,7 @@ protected:
* Put a Job result back to result queue
* @param result result of completed job
*/
- void putJobResult(LuaJobInfo result);
+ void putJobResult(const LuaJobInfo &result);
/**
* Initialize environment with current registred functions
@@ -131,8 +140,8 @@ private:
// Variable locking the engine against further modification
bool initDone;
- // Internal store for registred functions
- UNORDERED_MAP<std::string, lua_CFunction> functionList;
+ // Internal store for registred state initializers
+ std::vector<StateInitializer> stateInitializers;
// Internal counter to create job IDs
unsigned int jobIdCounter;
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index 679a517ee..4d7461c5b 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -23,12 +23,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_object.h"
#include "common/c_converter.h"
#include "serverobject.h"
-#include "debug.h"
#include "filesys.h"
-#include "log.h"
#include "mods.h"
#include "porting.h"
#include "util/string.h"
+#include "server.h"
+#ifndef SERVER
+#include "client.h"
+#endif
extern "C" {
@@ -40,6 +42,8 @@ extern "C" {
#include <stdio.h>
#include <cstdarg>
+#include "script/common/c_content.h"
+#include <sstream>
class ModNameStorer
@@ -68,7 +72,8 @@ public:
*/
ScriptApiBase::ScriptApiBase() :
- m_luastackmutex()
+ m_luastackmutex(),
+ m_gamedef(NULL)
{
#ifdef SCRIPTAPI_LOCK_DEBUG
m_lock_recursion_count = 0;
@@ -77,6 +82,8 @@ ScriptApiBase::ScriptApiBase() :
m_luastack = luaL_newstate();
FATAL_ERROR_IF(!m_luastack, "luaL_newstate() failed");
+ lua_atpanic(m_luastack, &luaPanic);
+
luaL_openlibs(m_luastack);
// Make the ScriptApiBase* accessible to ModApiBase
@@ -110,7 +117,6 @@ ScriptApiBase::ScriptApiBase() :
// Default to false otherwise
m_secure = false;
- m_server = NULL;
m_environment = NULL;
m_guiengine = NULL;
}
@@ -120,6 +126,16 @@ ScriptApiBase::~ScriptApiBase()
lua_close(m_luastack);
}
+int ScriptApiBase::luaPanic(lua_State *L)
+{
+ std::ostringstream oss;
+ oss << "LUA PANIC: unprotected error in call to Lua API ("
+ << lua_tostring(L, -1) << ")";
+ FATAL_ERROR(oss.str().c_str());
+ // NOTREACHED
+ return 0;
+}
+
void ScriptApiBase::loadMod(const std::string &script_path,
const std::string &mod_name)
{
@@ -224,7 +240,7 @@ void ScriptApiBase::stackDump(std::ostream &o)
break;
case LUA_TNUMBER: /* numbers */ {
char buf[10];
- snprintf(buf, 10, "%g", lua_tonumber(m_luastack, i));
+ snprintf(buf, 10, "%lf", lua_tonumber(m_luastack, i));
o << buf;
break;
}
@@ -305,18 +321,17 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
if (cobj == NULL || cobj->getId() == 0) {
ObjectRef::create(L, cobj);
} else {
- objectrefGet(L, cobj->getId());
+ push_objectRef(L, cobj->getId());
}
}
-void ScriptApiBase::objectrefGet(lua_State *L, u16 id)
+Server* ScriptApiBase::getServer()
{
- // Get core.object_refs[i]
- lua_getglobal(L, "core");
- lua_getfield(L, -1, "object_refs");
- luaL_checktype(L, -1, LUA_TTABLE);
- lua_pushnumber(L, id);
- lua_gettable(L, -2);
- lua_remove(L, -2); // object_refs
- lua_remove(L, -2); // core
+ return dynamic_cast<Server *>(m_gamedef);
}
+#ifndef SERVER
+Client* ScriptApiBase::getClient()
+{
+ return dynamic_cast<Client *>(m_gamedef);
+}
+#endif
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index f52474f00..5b047a081 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -55,6 +55,10 @@ extern "C" {
setOriginFromTableRaw(index, __FUNCTION__)
class Server;
+#ifndef SERVER
+class Client;
+#endif
+class IGameDef;
class Environment;
class GUIEngine;
class ServerActiveObject;
@@ -75,7 +79,11 @@ public:
void addObjectReference(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj);
- Server* getServer() { return m_server; }
+ IGameDef *getGameDef() { return m_gamedef; }
+ Server* getServer();
+#ifndef SERVER
+ Client* getClient();
+#endif
std::string getOrigin() { return m_last_run_mod; }
void setOriginDirect(const char *origin);
@@ -98,7 +106,7 @@ protected:
void scriptError(int result, const char *fxn);
void stackDump(std::ostream &o);
- void setServer(Server* server) { m_server = server; }
+ void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; }
Environment* getEnv() { return m_environment; }
void setEnv(Environment* env) { m_environment = env; }
@@ -107,7 +115,6 @@ protected:
void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; }
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
- void objectrefGet(lua_State *L, u16 id);
RecursiveMutex m_luastackmutex;
std::string m_last_run_mod;
@@ -118,9 +125,11 @@ protected:
#endif
private:
+ static int luaPanic(lua_State *L);
+
lua_State* m_luastack;
- Server* m_server;
+ IGameDef* m_gamedef;
Environment* m_environment;
GUIEngine* m_guiengine;
};
diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp
new file mode 100644
index 000000000..55d309fda
--- /dev/null
+++ b/src/script/cpp_api/s_client.cpp
@@ -0,0 +1,230 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "s_client.h"
+#include "s_internal.h"
+#include "client.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
+#include "s_item.h"
+
+void ScriptApiClient::on_shutdown()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get registered shutdown hooks
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_shutdown");
+ // Call callbacks
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::on_connect()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // get registered connect hooks
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_connect");
+ // Call callback
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
+}
+
+bool ScriptApiClient::on_sending_message(const std::string &message)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_sending_chat_messages");
+ // Call callbacks
+ lua_pushstring(L, message.c_str());
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+ bool ate = lua_toboolean(L, -1);
+ return ate;
+}
+
+bool ScriptApiClient::on_receiving_message(const std::string &message)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_receiving_chat_messages");
+ // Call callbacks
+ lua_pushstring(L, message.c_str());
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+ bool ate = lua_toboolean(L, -1);
+ return ate;
+}
+
+void ScriptApiClient::on_damage_taken(int32_t damage_amount)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_damage_taken");
+ // Call callbacks
+ lua_pushinteger(L, damage_amount);
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+}
+
+void ScriptApiClient::on_hp_modification(int32_t newhp)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_hp_modification");
+ // Call callbacks
+ lua_pushinteger(L, newhp);
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC);
+}
+
+void ScriptApiClient::on_death()
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get registered shutdown hooks
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_death");
+ // Call callbacks
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
+}
+
+void ScriptApiClient::environment_step(float dtime)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_globalsteps
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_globalsteps");
+ // Call callbacks
+ lua_pushnumber(L, dtime);
+ try {
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+ } catch (LuaError &e) {
+ getClient()->setFatalError(std::string("Client environment_step: ") + e.what() + "\n"
+ + script_get_backtrace(L));
+ }
+}
+
+void ScriptApiClient::on_formspec_input(const std::string &formname,
+ const StringMap &fields)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_chat_messages
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_formspec_input");
+ // Call callbacks
+ // param 1
+ lua_pushstring(L, formname.c_str());
+ // param 2
+ lua_newtable(L);
+ StringMap::const_iterator it;
+ for (it = fields.begin(); it != fields.end(); ++it) {
+ const std::string &name = it->first;
+ const std::string &value = it->second;
+ lua_pushstring(L, name.c_str());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
+}
+
+bool ScriptApiClient::on_dignode(v3s16 p, MapNode node)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ INodeDefManager *ndef = getClient()->ndef();
+
+ // Get core.registered_on_dignode
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_dignode");
+
+ // Push data
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+bool ScriptApiClient::on_punchnode(v3s16 p, MapNode node)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ INodeDefManager *ndef = getClient()->ndef();
+
+ // Get core.registered_on_punchgnode
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_punchnode");
+
+ // Push data
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ bool blocked = lua_toboolean(L, -1);
+ return blocked;
+}
+
+bool ScriptApiClient::on_placenode(const PointedThing &pointed, const ItemDefinition &item)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_placenode
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_placenode");
+
+ // Push data
+ push_pointed_thing(L, pointed, true);
+ push_item_definition(L, item);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+bool ScriptApiClient::on_item_use(const ItemStack &item, const PointedThing &pointed)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_item_use
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_item_use");
+
+ // Push data
+ LuaItemStack::create(L, item);
+ push_pointed_thing(L, pointed, true);
+
+ // Call functions
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+void ScriptApiClient::setEnv(ClientEnvironment *env)
+{
+ ScriptApiBase::setEnv(env);
+}
diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h
new file mode 100644
index 000000000..9133637a6
--- /dev/null
+++ b/src/script/cpp_api/s_client.h
@@ -0,0 +1,63 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef S_CLIENT_H_
+#define S_CLIENT_H_
+
+#include "util/pointedthing.h"
+#include "cpp_api/s_base.h"
+#include "mapnode.h"
+#include "itemdef.h"
+#include "util/string.h"
+#include "util/pointedthing.h"
+#include "lua_api/l_item.h"
+
+#ifdef _CRT_MSVCP_CURRENT
+#include <cstdint>
+#endif
+
+class ClientEnvironment;
+
+class ScriptApiClient : virtual public ScriptApiBase
+{
+public:
+ // Calls on_shutdown handlers
+ void on_shutdown();
+
+ void on_connect();
+
+ // Chat message handlers
+ bool on_sending_message(const std::string &message);
+ bool on_receiving_message(const std::string &message);
+
+ void on_damage_taken(int32_t damage_amount);
+ void on_hp_modification(int32_t newhp);
+ void on_death();
+ void environment_step(float dtime);
+ void on_formspec_input(const std::string &formname, const StringMap &fields);
+
+ bool on_dignode(v3s16 p, MapNode node);
+ bool on_punchnode(v3s16 p, MapNode node);
+ bool on_placenode(const PointedThing &pointed, const ItemDefinition &item);
+ bool on_item_use(const ItemStack &item, const PointedThing &pointed);
+
+ void setEnv(ClientEnvironment *env);
+};
+#endif
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index 378a6bf09..4c1e296d4 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "object_properties.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "server.h"
bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
{
@@ -56,7 +57,7 @@ bool ScriptApiEntity::luaentity_Add(u16 id, const char *name)
// Add object reference
// This should be userdata with metatable ObjectRef
- objectrefGet(L, id);
+ push_objectRef(L, id);
luaL_checktype(L, -1, LUA_TUSERDATA);
if (!luaL_checkudata(L, -1, "ObjectRef"))
luaL_typerror(L, -1, "ObjectRef");
@@ -187,11 +188,11 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id,
getstringfield(L, -1, "mesh", prop->mesh);
// Deprecated: read object properties directly
- read_object_properties(L, -1, prop);
+ read_object_properties(L, -1, prop, getServer()->idef());
// Read initial_properties
lua_getfield(L, -1, "initial_properties");
- read_object_properties(L, -1, prop);
+ read_object_properties(L, -1, prop, getServer()->idef());
lua_pop(L, 1);
}
@@ -224,10 +225,10 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
}
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
-// tool_capabilities, direction)
-void ScriptApiEntity::luaentity_Punch(u16 id,
+// tool_capabilities, direction, damage)
+bool ScriptApiEntity::luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir)
+ const ToolCapabilities *toolcap, v3f dir, s16 damage)
{
SCRIPTAPI_PRECHECKHEADER
@@ -242,8 +243,8 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
// Get function
lua_getfield(L, -1, "on_punch");
if (lua_isnil(L, -1)) {
- lua_pop(L, 2); // Pop on_punch and entitu
- return;
+ lua_pop(L, 2); // Pop on_punch and entity
+ return false;
}
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
@@ -251,11 +252,14 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
lua_pushnumber(L, time_from_last_punch);
push_tool_capabilities(L, *toolcap);
push_v3f(L, dir);
+ lua_pushnumber(L, damage);
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 5, 0, error_handler));
+ PCALL_RES(lua_pcall(L, 6, 1, error_handler));
+ bool retval = lua_toboolean(L, -1);
lua_pop(L, 2); // Pop object and error handler
+ return retval;
}
// Calls entity:on_rightclick(ObjectRef clicker)
diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h
index 8df9d7f00..4e2a056bb 100644
--- a/src/script/cpp_api/s_entity.h
+++ b/src/script/cpp_api/s_entity.h
@@ -38,9 +38,9 @@ public:
void luaentity_GetProperties(u16 id,
ObjectProperties *prop);
void luaentity_Step(u16 id, float dtime);
- void luaentity_Punch(u16 id,
+ bool luaentity_Punch(u16 id,
ServerActiveObject *puncher, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir);
+ const ToolCapabilities *toolcap, v3f dir, s16 damage);
void luaentity_Rightclick(u16 id,
ServerActiveObject *clicker);
};
diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp
index 913d8539d..b1404bf22 100644
--- a/src/script/cpp_api/s_env.cpp
+++ b/src/script/cpp_api/s_env.cpp
@@ -54,7 +54,9 @@ void ScriptApiEnv::environment_Step(float dtime)
try {
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
- getServer()->setAsyncFatalError(e.what());
+ getServer()->setAsyncFatalError(
+ std::string("environment_Step: ") + e.what() + "\n"
+ + script_get_backtrace(L));
}
}
@@ -75,7 +77,9 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t
try {
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
- getServer()->setAsyncFatalError(e.what());
+ getServer()->setAsyncFatalError(
+ std::string("player_event: ") + e.what() + "\n"
+ + script_get_backtrace(L) );
}
}
@@ -237,7 +241,9 @@ void ScriptApiEnv::on_emerge_area_completion(
try {
PCALL_RES(lua_pcall(L, 4, 0, error_handler));
} catch (LuaError &e) {
- server->setAsyncFatalError(e.what());
+ server->setAsyncFatalError(
+ std::string("on_emerge_area_completion: ") + e.what() + "\n"
+ + script_get_backtrace(L));
}
lua_pop(L, 1); // Pop error handler
diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp
index 3c84fb8cf..032018f2f 100644
--- a/src/script/cpp_api/s_item.cpp
+++ b/src/script/cpp_api/s_item.cpp
@@ -47,7 +47,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -74,7 +74,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -101,7 +101,7 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if(!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -127,7 +127,7 @@ bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *use
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L, -1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -159,7 +159,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
PCALL_RES(lua_pcall(L, 4, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -191,7 +191,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
PCALL_RES(lua_pcall(L, 4, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
- item = read_item(L,-1, getServer());
+ item = read_item(L, -1, getServer()->idef());
} catch (LuaError &e) {
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
@@ -249,27 +249,6 @@ void ScriptApiItem::pushPointedThing(const PointedThing& pointed)
{
lua_State* L = getStack();
- lua_newtable(L);
- if(pointed.type == POINTEDTHING_NODE)
- {
- lua_pushstring(L, "node");
- lua_setfield(L, -2, "type");
- push_v3s16(L, pointed.node_undersurface);
- lua_setfield(L, -2, "under");
- push_v3s16(L, pointed.node_abovesurface);
- lua_setfield(L, -2, "above");
- }
- else if(pointed.type == POINTEDTHING_OBJECT)
- {
- lua_pushstring(L, "object");
- lua_setfield(L, -2, "type");
- objectrefGet(L, pointed.object_id);
- lua_setfield(L, -2, "ref");
- }
- else
- {
- lua_pushstring(L, "nothing");
- lua_setfield(L, -2, "type");
- }
+ push_pointed_thing(L, pointed);
}
diff --git a/src/script/cpp_api/s_mainmenu.cpp b/src/script/cpp_api/s_mainmenu.cpp
index e9a7a13b9..1e9ba3a41 100644
--- a/src/script/cpp_api/s_mainmenu.cpp
+++ b/src/script/cpp_api/s_mainmenu.cpp
@@ -34,8 +34,7 @@ void ScriptApiMainMenu::setMainMenuData(MainMenuDataForScript *data)
lua_pushnil(L);
}
lua_settable(L, gamedata_idx);
- setboolfield(L, gamedata_idx, "reconnect_requested",
- data->reconnect_requested);
+ setboolfield(L, gamedata_idx, "reconnect_requested", data->reconnect_requested);
lua_pop(L, 1);
}
@@ -58,7 +57,7 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text)
// Call it
lua_pushstring(L, text.c_str());
PCALL_RES(lua_pcall(L, 1, 0, error_handler));
- lua_pop(L, 1); // Pop error handler
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
@@ -90,6 +89,5 @@ void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
// Call it
PCALL_RES(lua_pcall(L, 1, 0, error_handler));
- lua_pop(L, 1); // Pop error handler
+ lua_pop(L, 1); // Pop error handler
}
-
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index 379ed773f..1ae8f58a5 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -59,6 +59,10 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
{CPT2_LEVELED, "leveled"},
{CPT2_DEGROTATE, "degrotate"},
{CPT2_MESHOPTIONS, "meshoptions"},
+ {CPT2_COLOR, "color"},
+ {CPT2_COLORED_FACEDIR, "colorfacedir"},
+ {CPT2_COLORED_WALLMOUNTED, "colorwallmounted"},
+ {CPT2_GLASSLIKE_LIQUID_LEVEL, "glasslikeliquidlevel"},
{0, NULL},
};
@@ -174,6 +178,27 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
lua_pop(L, 1); // Pop error handler
}
+bool ScriptApiNode::node_on_flood(v3s16 p, MapNode node, MapNode newnode)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ INodeDefManager *ndef = getServer()->ndef();
+
+ // Push callback function on stack
+ if (!getItemCallback(ndef->get(node).name.c_str(), "on_flood"))
+ return false;
+
+ // Call function
+ push_v3s16(L, p);
+ pushnode(L, node, ndef);
+ pushnode(L, newnode, ndef);
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
+ lua_remove(L, error_handler);
+ return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
+}
+
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
@@ -238,7 +263,7 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
lua_pushstring(L, formname.c_str()); // formname
lua_newtable(L); // fields
StringMap::const_iterator it;
- for (it = fields.begin(); it != fields.end(); it++) {
+ for (it = fields.begin(); it != fields.end(); ++it) {
const std::string &name = it->first;
const std::string &value = it->second;
lua_pushstring(L, name.c_str());
diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h
index fe1180cb3..eb127909d 100644
--- a/src/script/cpp_api/s_node.h
+++ b/src/script/cpp_api/s_node.h
@@ -42,6 +42,7 @@ public:
ServerActiveObject *digger);
void node_on_construct(v3s16 p, MapNode node);
void node_on_destruct(v3s16 p, MapNode node);
+ bool node_on_flood(v3s16 p, MapNode node, MapNode newnode);
void node_after_destruct(v3s16 p, MapNode node);
bool node_on_timer(v3s16 p, MapNode node, f32 dtime);
void node_on_receive_fields(v3s16 p,
diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h
index 86ee1b024..9b4611f9e 100644
--- a/src/script/cpp_api/s_player.h
+++ b/src/script/cpp_api/s_player.h
@@ -26,8 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct ToolCapabilities;
-class ScriptApiPlayer
- : virtual public ScriptApiBase
+class ScriptApiPlayer : virtual public ScriptApiBase
{
public:
virtual ~ScriptApiPlayer();
@@ -36,17 +35,16 @@ public:
void on_dieplayer(ServerActiveObject *player);
bool on_respawnplayer(ServerActiveObject *player);
bool on_prejoinplayer(const std::string &name, const std::string &ip,
- std::string *reason);
+ std::string *reason);
void on_joinplayer(ServerActiveObject *player);
void on_leaveplayer(ServerActiveObject *player, bool timeout);
void on_cheat(ServerActiveObject *player, const std::string &cheat_type);
- bool on_punchplayer(ServerActiveObject *player,
- ServerActiveObject *hitter, float time_from_last_punch,
- const ToolCapabilities *toolcap, v3f dir, s16 damage);
+ bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter,
+ float time_from_last_punch, const ToolCapabilities *toolcap,
+ v3f dir, s16 damage);
s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change);
void on_playerReceiveFields(ServerActiveObject *player,
- const std::string &formname, const StringMap &fields);
+ const std::string &formname, const StringMap &fields);
};
-
#endif /* S_PLAYER_H_ */
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index 1b1f148cd..5ad7947d5 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -99,7 +99,6 @@ void ScriptApiSecurity::initializeSecurity()
"clock",
"date",
"difftime",
- "exit",
"getenv",
"setlocale",
"time",
@@ -124,6 +123,7 @@ void ScriptApiSecurity::initializeSecurity()
"path",
"searchpath",
};
+#if USE_LUAJIT
static const char *jit_whitelist[] = {
"arch",
"flush",
@@ -135,37 +135,13 @@ void ScriptApiSecurity::initializeSecurity()
"version",
"version_num",
};
-
+#endif
m_secure = true;
lua_State *L = getStack();
- // Backup globals to the registry
- lua_getglobal(L, "_G");
- lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
-
- // Replace the global environment with an empty one
-#if LUA_VERSION_NUM <= 501
- int is_main = lua_pushthread(L); // Push the main thread
- FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
- "isn't the main Lua thread!");
-#endif
- lua_newtable(L); // Create new environment
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "_G"); // Set _G of new environment
-#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
- // Set the global environment
- lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
-#else // Lua <= 5.1
- // Set the environment of the main thread
- FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
- "environment of the main Lua thread!");
- lua_pop(L, 1); // Pop thread
-#endif
- // Get old globals
- lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
- int old_globals = lua_gettop(L);
+ int old_globals = backupGlobals(L);
// Copy safe base functions
@@ -224,7 +200,113 @@ void ScriptApiSecurity::initializeSecurity()
lua_setglobal(L, "package");
lua_pop(L, 1); // Pop old package
+#if USE_LUAJIT
+ // Copy safe jit functions, if they exist
+ lua_getfield(L, -1, "jit");
+ if (!lua_isnil(L, -1)) {
+ lua_newtable(L);
+ copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
+ lua_setglobal(L, "jit");
+ }
+ lua_pop(L, 1); // Pop old jit
+#endif
+
+ lua_pop(L, 1); // Pop globals_backup
+}
+
+void ScriptApiSecurity::initializeSecurityClient()
+{
+ static const char *whitelist[] = {
+ "assert",
+ "core",
+ "collectgarbage",
+ "DIR_DELIM",
+ "error",
+ "getfenv",
+ "ipairs",
+ "next",
+ "pairs",
+ "pcall",
+ "print",
+ "rawequal",
+ "rawget",
+ "rawset",
+ "select",
+ "setfenv",
+ "setmetatable",
+ "tonumber",
+ "tostring",
+ "type",
+ "unpack",
+ "_VERSION",
+ "xpcall",
+ // Completely safe libraries
+ "coroutine",
+ "string",
+ "table",
+ "math",
+ };
+ static const char *os_whitelist[] = {
+ "clock",
+ "date",
+ "difftime",
+ "time",
+ "setlocale",
+ };
+ static const char *debug_whitelist[] = {
+ "getinfo",
+ };
+
+#if USE_LUAJIT
+ static const char *jit_whitelist[] = {
+ "arch",
+ "flush",
+ "off",
+ "on",
+ "opt",
+ "os",
+ "status",
+ "version",
+ "version_num",
+ };
+#endif
+
+ m_secure = true;
+
+ lua_State *L = getStack();
+
+
+ int old_globals = backupGlobals(L);
+
+
+ // Copy safe base functions
+ lua_getglobal(L, "_G");
+ copy_safe(L, whitelist, sizeof(whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(g, dofile);
+ SECURE_API(g, loadstring);
+ SECURE_API(g, require);
+ lua_pop(L, 1);
+
+
+
+ // Copy safe OS functions
+ lua_getfield(L, old_globals, "os");
+ lua_newtable(L);
+ copy_safe(L, os_whitelist, sizeof(os_whitelist));
+ lua_setglobal(L, "os");
+ lua_pop(L, 1); // Pop old OS
+
+
+ // Copy safe debug functions
+ lua_getfield(L, old_globals, "debug");
+ lua_newtable(L);
+ copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
+ lua_setglobal(L, "debug");
+ lua_pop(L, 1); // Pop old debug
+#if USE_LUAJIT
// Copy safe jit functions, if they exist
lua_getfield(L, -1, "jit");
if (!lua_isnil(L, -1)) {
@@ -233,10 +315,40 @@ void ScriptApiSecurity::initializeSecurity()
lua_setglobal(L, "jit");
}
lua_pop(L, 1); // Pop old jit
+#endif
lua_pop(L, 1); // Pop globals_backup
}
+int ScriptApiSecurity::backupGlobals(lua_State *L)
+{
+ // Backup globals to the registry
+ lua_getglobal(L, "_G");
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+
+ // Replace the global environment with an empty one
+#if LUA_VERSION_NUM <= 501
+ int is_main = lua_pushthread(L); // Push the main thread
+ FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
+ "isn't the main Lua thread!");
+#endif
+ lua_newtable(L); // Create new environment
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_G"); // Set _G of new environment
+#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
+ // Set the global environment
+ lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
+#else // Lua <= 5.1
+ // Set the environment of the main thread
+ FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
+ "environment of the main Lua thread!");
+ lua_pop(L, 1); // Pop thread
+#endif
+
+ // Get old globals
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
+ return lua_gettop(L);
+}
bool ScriptApiSecurity::isSecure(lua_State *L)
{
@@ -294,7 +406,14 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path)
// Read the file
int ret = std::fseek(fp, 0, SEEK_END);
- CHECK_FILE_ERR(ret, fp);
+ if (ret) {
+ lua_pushfstring(L, "%s: %s", path, strerror(errno));
+ std::fclose(fp);
+ if (path) {
+ delete [] chunk_name;
+ }
+ return false;
+ }
size_t size = std::ftell(fp) - start;
char *code = new char[size];
@@ -383,9 +502,9 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
lua_pop(L, 1);
- const Server *server = script->getServer();
-
- if (!server) return false;
+ const IGameDef *gamedef = script->getGameDef();
+ if (!gamedef)
+ return false;
// Get mod name
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
@@ -401,7 +520,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Allow paths in mod path
// Don't bother if write access isn't important, since it will be handled later
if (write_required || write_allowed != NULL) {
- const ModSpec *mod = server->getModSpec(mod_name);
+ const ModSpec *mod = gamedef->getModSpec(mod_name);
if (mod) {
str = fs::AbsolutePath(mod->path);
if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
@@ -415,7 +534,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
// Allow read-only access to all mod directories
if (!write_required) {
- const std::vector<ModSpec> mods = server->getMods();
+ const std::vector<ModSpec> mods = gamedef->getMods();
for (size_t i = 0; i < mods.size(); ++i) {
str = fs::AbsolutePath(mods[i].path);
if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
@@ -424,7 +543,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path,
}
}
- str = fs::AbsolutePath(server->getWorldPath());
+ str = fs::AbsolutePath(gamedef->getWorldPath());
if (!str.empty()) {
// Don't allow access to other paths in the world mod/game path.
// These have to be blocked so you can't override a trusted mod
diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h
index 6876108e8..f0eef00bb 100644
--- a/src/script/cpp_api/s_security.h
+++ b/src/script/cpp_api/s_security.h
@@ -41,8 +41,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ScriptApiSecurity : virtual public ScriptApiBase
{
public:
+ int backupGlobals(lua_State *L);
// Sets up security on the ScriptApi's Lua state
void initializeSecurity();
+ void initializeSecurityClient();
// Checks if the Lua state has been secured
static bool isSecure(lua_State *L);
// Loads a file as Lua code safely (doesn't allow bytecode).