aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/common/c_content.cpp179
-rw-r--r--src/script/common/c_converter.cpp9
-rw-r--r--src/script/common/c_converter.h2
-rw-r--r--src/script/common/c_internal.cpp49
-rw-r--r--src/script/common/c_internal.h25
-rw-r--r--src/script/common/c_types.h4
-rw-r--r--src/script/cpp_api/s_async.cpp95
-rw-r--r--src/script/cpp_api/s_async.h30
-rw-r--r--src/script/cpp_api/s_base.cpp64
-rw-r--r--src/script/cpp_api/s_base.h20
-rw-r--r--src/script/cpp_api/s_entity.cpp31
-rw-r--r--src/script/cpp_api/s_env.cpp195
-rw-r--r--src/script/cpp_api/s_env.h20
-rw-r--r--src/script/cpp_api/s_internal.h42
-rw-r--r--src/script/cpp_api/s_inventory.cpp33
-rw-r--r--src/script/cpp_api/s_item.cpp56
-rw-r--r--src/script/cpp_api/s_item.h2
-rw-r--r--src/script/cpp_api/s_mainmenu.cpp10
-rw-r--r--src/script/cpp_api/s_node.cpp47
-rw-r--r--src/script/cpp_api/s_nodemeta.cpp33
-rw-r--r--src/script/cpp_api/s_player.cpp6
-rw-r--r--src/script/cpp_api/s_security.cpp13
-rw-r--r--src/script/cpp_api/s_security.h5
-rw-r--r--src/script/cpp_api/s_server.cpp12
-rw-r--r--src/script/lua_api/CMakeLists.txt1
-rw-r--r--src/script/lua_api/l_areastore.cpp72
-rw-r--r--src/script/lua_api/l_areastore.h18
-rw-r--r--src/script/lua_api/l_base.cpp4
-rw-r--r--src/script/lua_api/l_env.cpp166
-rw-r--r--src/script/lua_api/l_env.h50
-rw-r--r--src/script/lua_api/l_http.cpp193
-rw-r--r--src/script/lua_api/l_http.h50
-rw-r--r--src/script/lua_api/l_internal.h10
-rw-r--r--src/script/lua_api/l_inventory.cpp3
-rw-r--r--src/script/lua_api/l_item.cpp2
-rw-r--r--src/script/lua_api/l_mainmenu.cpp53
-rw-r--r--src/script/lua_api/l_mainmenu.h2
-rw-r--r--src/script/lua_api/l_mapgen.cpp181
-rw-r--r--src/script/lua_api/l_mapgen.h10
-rw-r--r--src/script/lua_api/l_nodemeta.cpp21
-rw-r--r--src/script/lua_api/l_nodetimer.cpp6
-rw-r--r--src/script/lua_api/l_noise.cpp126
-rw-r--r--src/script/lua_api/l_noise.h33
-rw-r--r--src/script/lua_api/l_object.cpp132
-rw-r--r--src/script/lua_api/l_particles.cpp6
-rw-r--r--src/script/lua_api/l_rollback.cpp4
-rw-r--r--src/script/lua_api/l_server.cpp25
-rw-r--r--src/script/lua_api/l_server.h3
-rw-r--r--src/script/lua_api/l_util.cpp140
-rw-r--r--src/script/lua_api/l_util.h9
-rw-r--r--src/script/lua_api/l_vmanip.cpp35
-rw-r--r--src/script/scripting_game.cpp3
-rw-r--r--src/script/scripting_mainmenu.cpp2
53 files changed, 1745 insertions, 597 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 3754fc2ff..06e20c2a0 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -76,7 +76,7 @@ ItemDefinition read_item_definition(lua_State* L,int index,
getboolfield(L, index, "liquids_pointable", def.liquids_pointable);
warn_if_field_exists(L, index, "tool_digging_properties",
- "deprecated: use tool_capabilities");
+ "Deprecated; use tool_capabilities");
lua_getfield(L, index, "tool_capabilities");
if(lua_istable(L, -1)){
@@ -100,6 +100,9 @@ ItemDefinition read_item_definition(lua_State* L,int index,
lua_getfield(L, -1, "place");
read_soundspec(L, -1, def.sound_place);
lua_pop(L, 1);
+ lua_getfield(L, -1, "place_failed");
+ read_soundspec(L, -1, def.sound_place_failed);
+ lua_pop(L, 1);
}
lua_pop(L, 1);
@@ -197,6 +200,23 @@ void read_object_properties(lua_State *L, int index,
prop->automatic_face_movement_dir_offset = 0.0;
}
lua_pop(L, 1);
+ getboolfield(L, -1, "backface_culling", prop->backface_culling);
+
+ getstringfield(L, -1, "nametag", prop->nametag);
+ lua_getfield(L, -1, "nametag_color");
+ if (!lua_isnil(L, -1)) {
+ video::SColor color = prop->nametag_color;
+ if (read_color(L, -1, &color))
+ prop->nametag_color = color;
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec");
+ if (lua_isnumber(L, -1)) {
+ prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
+ }
+ lua_pop(L, 1);
+ getstringfield(L, -1, "infotext", prop->infotext);
}
/******************************************************************************/
@@ -255,6 +275,16 @@ void push_object_properties(lua_State *L, ObjectProperties *prop)
else
lua_pushboolean(L, false);
lua_setfield(L, -2, "automatic_face_movement_dir");
+ lua_pushboolean(L, prop->backface_culling);
+ lua_setfield(L, -2, "backface_culling");
+ lua_pushlstring(L, prop->nametag.c_str(), prop->nametag.size());
+ lua_setfield(L, -2, "nametag");
+ push_ARGB8(L, prop->nametag_color);
+ lua_setfield(L, -2, "nametag_color");
+ lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec);
+ lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
+ lua_pushlstring(L, prop->infotext.c_str(), prop->infotext.size());
+ lua_setfield(L, -2, "infotext");
}
/******************************************************************************/
@@ -264,14 +294,31 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
index = lua_gettop(L) + 1 + index;
TileDef tiledef;
- bool default_tiling = (drawtype == NDT_PLANTLIKE || drawtype == NDT_FIRELIKE)
- ? false : true;
+
+ bool default_tiling = true;
+ bool default_culling = true;
+ switch (drawtype) {
+ case NDT_PLANTLIKE:
+ case NDT_FIRELIKE:
+ default_tiling = false;
+ // "break" is omitted here intentionaly, as PLANTLIKE
+ // FIRELIKE drawtype both should default to having
+ // backface_culling to false.
+ case NDT_MESH:
+ case NDT_LIQUID:
+ default_culling = false;
+ break;
+ default:
+ break;
+ }
+
// key at index -2 and value at index
if(lua_isstring(L, index)){
// "default_lava.png"
tiledef.name = lua_tostring(L, index);
tiledef.tileable_vertical = default_tiling;
tiledef.tileable_horizontal = default_tiling;
+ tiledef.backface_culling = default_culling;
}
else if(lua_istable(L, index))
{
@@ -280,7 +327,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
getstringfield(L, index, "name", tiledef.name);
getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
tiledef.backface_culling = getboolfield_default(
- L, index, "backface_culling", true);
+ L, index, "backface_culling", default_culling);
tiledef.tileable_horizontal = getboolfield_default(
L, index, "tileable_horizontal", default_tiling);
tiledef.tileable_vertical = getboolfield_default(
@@ -427,17 +474,17 @@ ContentFeatures read_content_features(lua_State *L, int index)
// Warn about some deprecated fields
warn_if_field_exists(L, index, "wall_mounted",
- "deprecated: use paramtype2 = 'wallmounted'");
+ "Deprecated; use paramtype2 = 'wallmounted'");
warn_if_field_exists(L, index, "light_propagates",
- "deprecated: determined from paramtype");
+ "Deprecated; determined from paramtype");
warn_if_field_exists(L, index, "dug_item",
- "deprecated: use 'drop' field");
+ "Deprecated; use 'drop' field");
warn_if_field_exists(L, index, "extra_dug_item",
- "deprecated: use 'drop' field");
+ "Deprecated; use 'drop' field");
warn_if_field_exists(L, index, "extra_dug_item_rarity",
- "deprecated: use 'drop' field");
+ "Deprecated; use 'drop' field");
warn_if_field_exists(L, index, "metadata_name",
- "deprecated: use on_add and metadata callbacks");
+ "Deprecated; use on_add and metadata callbacks");
// True for all ground-like things like stone and mud, false for eg. trees
getboolfield(L, index, "is_ground_content", f.is_ground_content);
@@ -454,6 +501,8 @@ ContentFeatures read_content_features(lua_State *L, int index)
getboolfield(L, index, "climbable", f.climbable);
// Player can build on these
getboolfield(L, index, "buildable_to", f.buildable_to);
+ // Liquids flow into and replace node
+ getboolfield(L, index, "floodable", f.floodable);
// Whether the node is non-liquid, source liquid or flowing liquid
f.liquid_type = (LiquidType)getenumfield(L, index, "liquidtype",
ScriptApiNode::es_LiquidType, LIQUID_NONE);
@@ -486,6 +535,46 @@ ContentFeatures read_content_features(lua_State *L, int index)
f.node_box = read_nodebox(L, -1);
lua_pop(L, 1);
+ lua_getfield(L, index, "connects_to");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table) != 0) {
+ // Value at -1
+ f.connects_to.push_back(lua_tostring(L, -1));
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "connect_sides");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table) != 0) {
+ // Value at -1
+ std::string side(lua_tostring(L, -1));
+ // Note faces are flipped to make checking easier
+ if (side == "top")
+ f.connect_sides |= 2;
+ else if (side == "bottom")
+ f.connect_sides |= 1;
+ else if (side == "front")
+ f.connect_sides |= 16;
+ else if (side == "left")
+ f.connect_sides |= 32;
+ else if (side == "back")
+ f.connect_sides |= 4;
+ else if (side == "right")
+ f.connect_sides |= 8;
+ else
+ warningstream << "Unknown value for \"connect_sides\": "
+ << side << std::endl;
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+
lua_getfield(L, index, "selection_box");
if(lua_istable(L, -1))
f.selection_box = read_nodebox(L, -1);
@@ -578,25 +667,31 @@ NodeBox read_nodebox(lua_State *L, int index)
nodebox.type = (NodeBoxType)getenumfield(L, index, "type",
ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR);
- lua_getfield(L, index, "fixed");
- if(lua_istable(L, -1))
- nodebox.fixed = read_aabb3f_vector(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_top");
- if(lua_istable(L, -1))
- nodebox.wall_top = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_bottom");
- if(lua_istable(L, -1))
- nodebox.wall_bottom = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
-
- lua_getfield(L, index, "wall_side");
- if(lua_istable(L, -1))
- nodebox.wall_side = read_aabb3f(L, -1, BS);
- lua_pop(L, 1);
+#define NODEBOXREAD(n, s) \
+ do { \
+ lua_getfield(L, index, (s)); \
+ if (lua_istable(L, -1)) \
+ (n) = read_aabb3f(L, -1, BS); \
+ lua_pop(L, 1); \
+ } while (0)
+
+#define NODEBOXREADVEC(n, s) \
+ do { \
+ lua_getfield(L, index, (s)); \
+ if (lua_istable(L, -1)) \
+ (n) = read_aabb3f_vector(L, -1, BS); \
+ lua_pop(L, 1); \
+ } while (0)
+ NODEBOXREADVEC(nodebox.fixed, "fixed");
+ NODEBOXREAD(nodebox.wall_top, "wall_top");
+ NODEBOXREAD(nodebox.wall_bottom, "wall_bottom");
+ NODEBOXREAD(nodebox.wall_side, "wall_side");
+ NODEBOXREADVEC(nodebox.connect_top, "connect_top");
+ NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom");
+ NODEBOXREADVEC(nodebox.connect_front, "connect_front");
+ NODEBOXREADVEC(nodebox.connect_left, "connect_left");
+ NODEBOXREADVEC(nodebox.connect_back, "connect_back");
+ NODEBOXREADVEC(nodebox.connect_right, "connect_right");
}
return nodebox;
}
@@ -639,14 +734,13 @@ void pushnode(lua_State *L, const MapNode &n, INodeDefManager *ndef)
/******************************************************************************/
void warn_if_field_exists(lua_State *L, int table,
- const char *fieldname, const std::string &message)
+ const char *name, const std::string &message)
{
- lua_getfield(L, table, fieldname);
- if(!lua_isnil(L, -1)){
-//TODO find way to access backtrace fct from here
- // infostream<<script_get_backtrace(L)<<std::endl;
- infostream<<"WARNING: field \""<<fieldname<<"\": "
- <<message<<std::endl;
+ lua_getfield(L, table, name);
+ if (!lua_isnil(L, -1)) {
+ warningstream << "Field \"" << name << "\": "
+ << message << std::endl;
+ infostream << script_get_backtrace(L) << std::endl;
}
lua_pop(L, 1);
}
@@ -705,7 +799,7 @@ ItemStack read_item(lua_State* L, int index,Server* srv)
}
catch(SerializationError &e)
{
- infostream<<"WARNING: unable to create item from itemstring"
+ warningstream<<"unable to create item from itemstring"
<<": "<<itemstring<<std::endl;
return ItemStack();
}
@@ -840,14 +934,14 @@ ToolCapabilities read_tool_capabilities(
getintfield(L, table_groupcap, "uses", groupcap.uses);
// DEPRECATED: maxwear
float maxwear = 0;
- if(getfloatfield(L, table_groupcap, "maxwear", maxwear)){
- if(maxwear != 0)
+ if (getfloatfield(L, table_groupcap, "maxwear", maxwear)){
+ if (maxwear != 0)
groupcap.uses = 1.0/maxwear;
else
groupcap.uses = 0;
- infostream<<script_get_backtrace(L)<<std::endl;
- infostream<<"WARNING: field \"maxwear\" is deprecated; "
- <<"should replace with uses=1/maxwear"<<std::endl;
+ warningstream << "Field \"maxwear\" is deprecated; "
+ << "replace with uses=1/maxwear" << std::endl;
+ infostream << script_get_backtrace(L) << std::endl;
}
// Read "times" table
lua_getfield(L, table_groupcap, "times");
@@ -1232,4 +1326,3 @@ void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion)
}
lua_pop(L, 1); // Pop value
}
-
diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp
index f1d3cc421..55c4a5f5a 100644
--- a/src/script/common/c_converter.cpp
+++ b/src/script/common/c_converter.cpp
@@ -517,6 +517,15 @@ bool getboolfield_default(lua_State *L, int table,
return result;
}
+void setstringfield(lua_State *L, int table,
+ const char *fieldname, const char *value)
+{
+ lua_pushstring(L, value);
+ if(table < 0)
+ table -= 1;
+ lua_setfield(L, table, fieldname);
+}
+
void setintfield(lua_State *L, int table,
const char *fieldname, int value)
{
diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h
index 18a045d2a..eefac0ed7 100644
--- a/src/script/common/c_converter.h
+++ b/src/script/common/c_converter.h
@@ -69,6 +69,8 @@ bool getfloatfield(lua_State *L, int table,
std::string checkstringfield(lua_State *L, int table,
const char *fieldname);
+void setstringfield(lua_State *L, int table,
+ const char *fieldname, const char *value);
void setintfield(lua_State *L, int table,
const char *fieldname, int value);
void setfloatfield(lua_State *L, int table,
diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp
index 2a10ce0f2..b349f9dd1 100644
--- a/src/script/common/c_internal.cpp
+++ b/src/script/common/c_internal.cpp
@@ -136,61 +136,56 @@ void script_run_callbacks_f(lua_State *L, int nargs,
FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments");
// Insert error handler
- lua_pushcfunction(L, script_error_handler);
- int errorhandler = lua_gettop(L) - nargs - 1;
- lua_insert(L, errorhandler);
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - nargs - 1;
+ lua_insert(L, error_handler);
// Insert run_callbacks between error handler and table
lua_getglobal(L, "core");
lua_getfield(L, -1, "run_callbacks");
lua_remove(L, -2);
- lua_insert(L, errorhandler + 1);
+ lua_insert(L, error_handler + 1);
// Insert mode after table
lua_pushnumber(L, (int) mode);
- lua_insert(L, errorhandler + 3);
+ lua_insert(L, error_handler + 3);
// Stack now looks like this:
// ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
- int result = lua_pcall(L, nargs + 2, 1, errorhandler);
+ int result = lua_pcall(L, nargs + 2, 1, error_handler);
if (result != 0)
script_error(L, result, NULL, fxn);
- lua_remove(L, -2); // Remove error handler
+ lua_remove(L, error_handler);
}
void log_deprecated(lua_State *L, const std::string &message)
{
static bool configured = false;
- static bool dolog = false;
- static bool doerror = false;
+ static bool do_log = false;
+ static bool do_error = false;
- // performance optimization to not have to read and compare setting for every logline
+ // Only read settings on first call
if (!configured) {
std::string value = g_settings->get("deprecated_lua_api_handling");
if (value == "log") {
- dolog = true;
+ do_log = true;
} else if (value == "error") {
- dolog = true;
- doerror = true;
+ do_log = true;
+ do_error = true;
}
}
- if (doerror) {
- if (L != NULL) {
- script_error(L, LUA_ERRRUN, NULL, NULL);
- } else {
- FATAL_ERROR("Can't do a scripterror for this deprecated message, "
- "so exit completely!");
- }
- }
-
- if (dolog) {
- /* abusing actionstream because of lack of file-only-logged loglevel */
- actionstream << message << std::endl;
- if (L != NULL) {
- actionstream << script_get_backtrace(L) << std::endl;
+ if (do_log) {
+ warningstream << message << std::endl;
+ // L can be NULL if we get called by log_deprecated(const std::string &msg)
+ // from scripting_game.cpp.
+ if (L) {
+ if (do_error)
+ script_error(L, LUA_ERRRUN, NULL, NULL);
+ else
+ infostream << script_get_backtrace(L) << std::endl;
}
}
}
diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h
index ecb514c8f..fc59b0e2e 100644
--- a/src/script/common/c_internal.h
+++ b/src/script/common/c_internal.h
@@ -34,6 +34,31 @@ extern "C" {
#include "common/c_types.h"
+
+/*
+ Define our custom indices into the Lua registry table.
+
+ Lua 5.2 and above define the LUA_RIDX_LAST macro. Only numbers above that
+ may be used for custom indices, anything else is reserved.
+
+ Lua 5.1 / LuaJIT do not use any numeric indices (only string indices),
+ so we can use numeric indices freely.
+*/
+#ifdef LUA_RIDX_LAST
+#define CUSTOM_RIDX_BASE ((LUA_RIDX_LAST)+1)
+#else
+#define CUSTOM_RIDX_BASE 1
+#endif
+
+#define CUSTOM_RIDX_SCRIPTAPI (CUSTOM_RIDX_BASE)
+#define CUSTOM_RIDX_GLOBALS_BACKUP (CUSTOM_RIDX_BASE + 1)
+#define CUSTOM_RIDX_CURRENT_MOD_NAME (CUSTOM_RIDX_BASE + 2)
+#define CUSTOM_RIDX_ERROR_HANDLER (CUSTOM_RIDX_BASE + 3)
+
+// Pushes the error handler onto the stack and returns its index
+#define PUSH_ERROR_HANDLER(L) \
+ (lua_rawgeti((L), LUA_REGISTRYINDEX, CUSTOM_RIDX_ERROR_HANDLER), lua_gettop((L)))
+
#define PCALL_RESL(L, RES) do { \
int result_ = (RES); \
if (result_ != 0) { \
diff --git a/src/script/common/c_types.h b/src/script/common/c_types.h
index 706470737..056f30251 100644
--- a/src/script/common/c_types.h
+++ b/src/script/common/c_types.h
@@ -52,10 +52,10 @@ public:
}
};
-class LuaError : public ServerError
+class LuaError : public ModError
{
public:
- LuaError(const std::string &s) : ServerError(s) {}
+ LuaError(const std::string &s) : ModError(s) {}
};
diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp
index c00b22f98..9bf3fcf49 100644
--- a/src/script/cpp_api/s_async.cpp
+++ b/src/script/cpp_api/s_async.cpp
@@ -47,32 +47,31 @@ AsyncEngine::~AsyncEngine()
// Request all threads to stop
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
it != workerThreads.end(); it++) {
- (*it)->Stop();
+ (*it)->stop();
}
// Wake up all threads
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
it != workerThreads.end(); it++) {
- jobQueueCounter.Post();
+ jobQueueCounter.post();
}
// Wait for threads to finish
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
it != workerThreads.end(); it++) {
- (*it)->Wait();
+ (*it)->wait();
}
// Force kill all threads
for (std::vector<AsyncWorkerThread *>::iterator it = workerThreads.begin();
it != workerThreads.end(); it++) {
- (*it)->Kill();
delete *it;
}
- jobQueueMutex.Lock();
+ jobQueueMutex.lock();
jobQueue.clear();
- jobQueueMutex.Unlock();
+ jobQueueMutex.unlock();
workerThreads.clear();
}
@@ -92,16 +91,17 @@ void AsyncEngine::initialize(unsigned int numEngines)
initDone = true;
for (unsigned int i = 0; i < numEngines; i++) {
- AsyncWorkerThread *toAdd = new AsyncWorkerThread(this, i);
+ AsyncWorkerThread *toAdd = new AsyncWorkerThread(this,
+ std::string("AsyncWorker-") + itos(i));
workerThreads.push_back(toAdd);
- toAdd->Start();
+ toAdd->start();
}
}
/******************************************************************************/
unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
{
- jobQueueMutex.Lock();
+ jobQueueMutex.lock();
LuaJobInfo toAdd;
toAdd.id = jobIdCounter++;
toAdd.serializedFunction = func;
@@ -109,9 +109,9 @@ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
jobQueue.push_back(toAdd);
- jobQueueCounter.Post();
+ jobQueueCounter.post();
- jobQueueMutex.Unlock();
+ jobQueueMutex.unlock();
return toAdd.id;
}
@@ -119,8 +119,8 @@ unsigned int AsyncEngine::queueAsyncJob(std::string func, std::string params)
/******************************************************************************/
LuaJobInfo AsyncEngine::getJob()
{
- jobQueueCounter.Wait();
- jobQueueMutex.Lock();
+ jobQueueCounter.wait();
+ jobQueueMutex.lock();
LuaJobInfo retval;
retval.valid = false;
@@ -130,7 +130,7 @@ LuaJobInfo AsyncEngine::getJob()
jobQueue.pop_front();
retval.valid = true;
}
- jobQueueMutex.Unlock();
+ jobQueueMutex.unlock();
return retval;
}
@@ -138,16 +138,17 @@ LuaJobInfo AsyncEngine::getJob()
/******************************************************************************/
void AsyncEngine::putJobResult(LuaJobInfo result)
{
- resultQueueMutex.Lock();
+ resultQueueMutex.lock();
resultQueue.push_back(result);
- resultQueueMutex.Unlock();
+ resultQueueMutex.unlock();
}
/******************************************************************************/
-void AsyncEngine::step(lua_State *L, int errorhandler)
+void AsyncEngine::step(lua_State *L)
{
+ int error_handler = PUSH_ERROR_HANDLER(L);
lua_getglobal(L, "core");
- resultQueueMutex.Lock();
+ resultQueueMutex.lock();
while (!resultQueue.empty()) {
LuaJobInfo jobDone = resultQueue.front();
resultQueue.pop_front();
@@ -164,16 +165,16 @@ void AsyncEngine::step(lua_State *L, int errorhandler)
lua_pushlstring(L, jobDone.serializedResult.data(),
jobDone.serializedResult.size());
- PCALL_RESL(L, lua_pcall(L, 2, 0, errorhandler));
+ PCALL_RESL(L, lua_pcall(L, 2, 0, error_handler));
}
- resultQueueMutex.Unlock();
- lua_pop(L, 1); // Pop core
+ resultQueueMutex.unlock();
+ lua_pop(L, 2); // Pop core and error handler
}
/******************************************************************************/
void AsyncEngine::pushFinishedJobs(lua_State* L) {
// Result Table
- resultQueueMutex.Lock();
+ MutexAutoLock l(resultQueueMutex);
unsigned int index = 1;
lua_createtable(L, resultQueue.size(), 0);
@@ -197,8 +198,6 @@ void AsyncEngine::pushFinishedJobs(lua_State* L) {
lua_rawseti(L, top, index++);
}
-
- resultQueueMutex.Unlock();
}
/******************************************************************************/
@@ -214,10 +213,10 @@ void AsyncEngine::prepareEnvironment(lua_State* L, int top)
/******************************************************************************/
AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher,
- unsigned int threadNum) :
+ const std::string &name) :
+ Thread(name),
ScriptApiBase(),
- jobDispatcher(jobDispatcher),
- threadnum(threadNum)
+ jobDispatcher(jobDispatcher)
{
lua_State *L = getStack();
@@ -235,50 +234,42 @@ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher,
/******************************************************************************/
AsyncWorkerThread::~AsyncWorkerThread()
{
- sanity_check(IsRunning() == false);
+ sanity_check(!isRunning());
}
/******************************************************************************/
-void* AsyncWorkerThread::Thread()
+void* AsyncWorkerThread::run()
{
- ThreadStarted();
-
- // Register thread for error logging
- char number[21];
- snprintf(number, sizeof(number), "%u", threadnum);
- log_register_thread(std::string("AsyncWorkerThread_") + number);
-
- porting::setThreadName((std::string("AsyncWorkTh_") + number).c_str());
-
lua_State *L = getStack();
std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua";
- if (!loadScript(script)) {
- errorstream
- << "AsyncWorkerThread execution of async base environment failed!"
- << std::endl;
- abort();
+ try {
+ loadScript(script);
+ } catch (const ModError &e) {
+ errorstream << "Execution of async base environment failed: "
+ << e.what() << std::endl;
+ FATAL_ERROR("Execution of async base environment failed");
}
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
lua_getglobal(L, "core");
if (lua_isnil(L, -1)) {
- errorstream << "Unable to find core within async environment!";
- abort();
+ FATAL_ERROR("Unable to find core within async environment!");
}
// Main loop
- while (!StopRequested()) {
+ while (!stopRequested()) {
// Wait for job
LuaJobInfo toProcess = jobDispatcher->getJob();
- if (toProcess.valid == false || StopRequested()) {
+ if (toProcess.valid == false || stopRequested()) {
continue;
}
lua_getfield(L, -1, "job_processor");
if (lua_isnil(L, -1)) {
- errorstream << "Unable to get async job processor!" << std::endl;
- abort();
+ FATAL_ERROR("Unable to get async job processor!");
}
luaL_checktype(L, -1, LUA_TFUNCTION);
@@ -291,7 +282,7 @@ void* AsyncWorkerThread::Thread()
toProcess.serializedParams.data(),
toProcess.serializedParams.size());
- int result = lua_pcall(L, 2, 1, m_errorhandler);
+ int result = lua_pcall(L, 2, 1, error_handler);
if (result) {
PCALL_RES(result);
toProcess.serializedResult = "";
@@ -308,9 +299,7 @@ void* AsyncWorkerThread::Thread()
jobDispatcher->putJobResult(toProcess);
}
- lua_pop(L, 1); // Pop core
-
- log_deregister_thread();
+ lua_pop(L, 2); // Pop core and error handler
return 0;
}
diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h
index a6459c18d..8d612d58c 100644
--- a/src/script/cpp_api/s_async.h
+++ b/src/script/cpp_api/s_async.h
@@ -24,9 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <deque>
#include <map>
-#include "jthread/jthread.h"
-#include "jthread/jmutex.h"
-#include "jthread/jsemaphore.h"
+#include "threading/thread.h"
+#include "threading/mutex.h"
+#include "threading/semaphore.h"
#include "debug.h"
#include "lua.h"
#include "cpp_api/s_base.h"
@@ -52,24 +52,15 @@ struct LuaJobInfo {
};
// Asynchronous working environment
-class AsyncWorkerThread : public JThread, public ScriptApiBase {
+class AsyncWorkerThread : public Thread, public ScriptApiBase {
public:
- /**
- * default constructor
- * @param pointer to job dispatcher
- */
- AsyncWorkerThread(AsyncEngine* jobDispatcher, unsigned int threadNum);
-
+ AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name);
virtual ~AsyncWorkerThread();
- void *Thread();
+ void *run();
private:
AsyncEngine *jobDispatcher;
-
- // Thread number. Used for debug output
- unsigned int threadnum;
-
};
// Asynchornous thread and job management
@@ -104,9 +95,8 @@ public:
* Engine step to process finished jobs
* the engine step is one way to pass events back, PushFinishedJobs another
* @param L The Lua stack
- * @param errorhandler Stack index of the Lua error handler
*/
- void step(lua_State *L, int errorhandler);
+ void step(lua_State *L);
/**
* Push a list of finished jobs onto the stack
@@ -148,13 +138,13 @@ private:
unsigned int jobIdCounter;
// Mutex to protect job queue
- JMutex jobQueueMutex;
+ Mutex jobQueueMutex;
// Job queue
std::deque<LuaJobInfo> jobQueue;
// Mutex to protect result queue
- JMutex resultQueueMutex;
+ Mutex resultQueueMutex;
// Result queue
std::deque<LuaJobInfo> resultQueue;
@@ -162,7 +152,7 @@ private:
std::vector<AsyncWorkerThread*> workerThreads;
// Counter semaphore for job dispatching
- JSemaphore jobQueueCounter;
+ Semaphore jobQueueCounter;
};
#endif // CPP_API_ASYNC_EVENTS_HEADER
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index dcfbac4bf..679a517ee 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -52,13 +52,13 @@ public:
{
// Store current mod name in registry
lua_pushstring(L, mod_name.c_str());
- lua_setfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
}
~ModNameStorer()
{
// Clear current mod name from registry
lua_pushnil(L);
- lua_setfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
}
};
@@ -67,10 +67,11 @@ public:
ScriptApiBase
*/
-ScriptApiBase::ScriptApiBase()
+ScriptApiBase::ScriptApiBase() :
+ m_luastackmutex()
{
#ifdef SCRIPTAPI_LOCK_DEBUG
- m_locked = false;
+ m_lock_recursion_count = 0;
#endif
m_luastack = luaL_newstate();
@@ -78,13 +79,13 @@ ScriptApiBase::ScriptApiBase()
luaL_openlibs(m_luastack);
- // Add and save an error handler
- lua_pushcfunction(m_luastack, script_error_handler);
- m_errorhandler = lua_gettop(m_luastack);
-
// Make the ScriptApiBase* accessible to ModApiBase
lua_pushlightuserdata(m_luastack, this);
- lua_setfield(m_luastack, LUA_REGISTRYINDEX, "scriptapi");
+ 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);
// If we are using LuaJIT add a C++ wrapper function to catch
// exceptions thrown in Lua -> C++ calls
@@ -119,40 +120,36 @@ ScriptApiBase::~ScriptApiBase()
lua_close(m_luastack);
}
-bool ScriptApiBase::loadMod(const std::string &script_path,
- const std::string &mod_name, std::string *error)
+void ScriptApiBase::loadMod(const std::string &script_path,
+ const std::string &mod_name)
{
ModNameStorer mod_name_storer(getStack(), mod_name);
- return loadScript(script_path, error);
+ loadScript(script_path);
}
-bool ScriptApiBase::loadScript(const std::string &script_path, std::string *error)
+void ScriptApiBase::loadScript(const std::string &script_path)
{
verbosestream << "Loading and running script from " << script_path << std::endl;
lua_State *L = getStack();
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
bool ok;
if (m_secure) {
ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str());
} else {
ok = !luaL_loadfile(L, script_path.c_str());
}
- ok = ok && !lua_pcall(L, 0, 0, m_errorhandler);
+ ok = ok && !lua_pcall(L, 0, 0, error_handler);
if (!ok) {
std::string error_msg = lua_tostring(L, -1);
- if (error)
- *error = error_msg;
- errorstream << "========== ERROR FROM LUA ===========" << std::endl
- << "Failed to load and run script from " << std::endl
- << script_path << ":" << std::endl << std::endl
- << error_msg << std::endl << std::endl
- << "======= END OF ERROR FROM LUA ========" << std::endl;
- lua_pop(L, 1); // Pop error message from stack
- return false;
+ lua_pop(L, 2); // Pop error message and error handler
+ throw ModError("Failed to load and run script from " +
+ script_path + ":\n" + error_msg);
}
- return true;
+ lua_pop(L, 1); // Pop error handler
}
// Push the list of callbacks (a lua table).
@@ -161,35 +158,40 @@ bool ScriptApiBase::loadScript(const std::string &script_path, std::string *erro
// - runs the callbacks
// - replaces the table and arguments with the return value,
// computed depending on mode
+// This function must only be called with scriptlock held (i.e. inside of a
+// code block with SCRIPTAPI_PRECHECKHEADER declared)
void ScriptApiBase::runCallbacksRaw(int nargs,
RunCallbacksMode mode, const char *fxn)
{
+#ifdef SCRIPTAPI_LOCK_DEBUG
+ assert(m_lock_recursion_count > 0);
+#endif
lua_State *L = getStack();
FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments");
// Insert error handler
- lua_pushcfunction(L, script_error_handler);
- int errorhandler = lua_gettop(L) - nargs - 1;
- lua_insert(L, errorhandler);
+ PUSH_ERROR_HANDLER(L);
+ int error_handler = lua_gettop(L) - nargs - 1;
+ lua_insert(L, error_handler);
// Insert run_callbacks between error handler and table
lua_getglobal(L, "core");
lua_getfield(L, -1, "run_callbacks");
lua_remove(L, -2);
- lua_insert(L, errorhandler + 1);
+ lua_insert(L, error_handler + 1);
// Insert mode after table
lua_pushnumber(L, (int)mode);
- lua_insert(L, errorhandler + 3);
+ lua_insert(L, error_handler + 3);
// Stack now looks like this:
// ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
- int result = lua_pcall(L, nargs + 2, 1, errorhandler);
+ int result = lua_pcall(L, nargs + 2, 1, error_handler);
if (result != 0)
scriptError(result, fxn);
- lua_remove(L, -2); // Remove error handler
+ lua_remove(L, error_handler);
}
void ScriptApiBase::realityCheck()
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index d653b5bac..f52474f00 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -28,15 +28,15 @@ extern "C" {
}
#include "irrlichttypes.h"
-#include "jthread/jmutex.h"
-#include "jthread/jmutexautolock.h"
+#include "threads.h"
+#include "threading/mutex.h"
+#include "threading/mutex_auto_lock.h"
#include "common/c_types.h"
#include "common/c_internal.h"
#define SCRIPTAPI_LOCK_DEBUG
#define SCRIPTAPI_DEBUG
-#define SCRIPT_MOD_NAME_FIELD "current_mod_name"
// MUST be an invalid mod name so that mods can't
// use that name to bypass security!
#define BUILTIN_MOD_NAME "*builtin*"
@@ -64,9 +64,9 @@ public:
ScriptApiBase();
virtual ~ScriptApiBase();
- bool loadMod(const std::string &script_path, const std::string &mod_name,
- std::string *error=NULL);
- bool loadScript(const std::string &script_path, std::string *error=NULL);
+ // These throw a ModError on failure
+ void loadMod(const std::string &script_path, const std::string &mod_name);
+ void loadScript(const std::string &script_path);
void runCallbacksRaw(int nargs,
RunCallbacksMode mode, const char *fxn);
@@ -83,6 +83,7 @@ public:
protected:
friend class LuaABM;
+ friend class LuaLBM;
friend class InvRef;
friend class ObjectRef;
friend class NodeMetaRef;
@@ -108,13 +109,12 @@ protected:
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
void objectrefGet(lua_State *L, u16 id);
- JMutex m_luastackmutex;
+ RecursiveMutex m_luastackmutex;
std::string m_last_run_mod;
- // Stack index of Lua error handler
- int m_errorhandler;
bool m_secure;
#ifdef SCRIPTAPI_LOCK_DEBUG
- bool m_locked;
+ int m_lock_recursion_count;
+ threadid_t m_owning_thread;
#endif
private:
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index 0d159846a..378a6bf09 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -80,6 +80,8 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
verbosestream << "scriptapi_luaentity_activate: id=" << id << std::endl;
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get core.luaentities[id]
luaentity_get(L, id);
int object = lua_gettop(L);
@@ -93,11 +95,11 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
lua_pushinteger(L, dtime_s);
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 3, 0, error_handler));
} else {
lua_pop(L, 1);
}
- lua_pop(L, 1); // Pop object
+ lua_pop(L, 2); // Pop object and error handler
}
void ScriptApiEntity::luaentity_Remove(u16 id)
@@ -126,6 +128,8 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
//infostream<<"scriptapi_luaentity_get_staticdata: id="<<id<<std::endl;
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get core.luaentities[id]
luaentity_get(L, id);
int object = lua_gettop(L);
@@ -140,9 +144,10 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
lua_pushvalue(L, object); // self
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 1, error_handler));
- lua_remove(L, object); // Remove object
+ lua_remove(L, object);
+ lua_remove(L, error_handler);
size_t len = 0;
const char *s = lua_tolstring(L, -1, &len);
@@ -196,6 +201,8 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get core.luaentities[id]
luaentity_get(L, id);
int object = lua_gettop(L);
@@ -211,9 +218,9 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
lua_pushnumber(L, dtime); // dtime
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 0, error_handler));
- lua_pop(L, 1); // Pop object
+ lua_pop(L, 2); // Pop object and error handler
}
// Calls entity:on_punch(ObjectRef puncher, time_from_last_punch,
@@ -226,6 +233,8 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get core.luaentities[id]
luaentity_get(L,id);
int object = lua_gettop(L);
@@ -244,9 +253,9 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
push_v3f(L, dir);
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 0, error_handler));
- lua_pop(L, 1); // Pop object
+ lua_pop(L, 2); // Pop object and error handler
}
// Calls entity:on_rightclick(ObjectRef clicker)
@@ -257,6 +266,8 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
//infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl;
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get core.luaentities[id]
luaentity_get(L, id);
int object = lua_gettop(L);
@@ -272,8 +283,8 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
objectrefGetOrCreate(L, clicker); // Clicker reference
setOriginFromTable(object);
- PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 0, error_handler));
- lua_pop(L, 1); // Pop object
+ lua_pop(L, 2); // Pop object and error handler
}
diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp
index 9c733773a..82d0d4f0e 100644
--- a/src/script/cpp_api/s_env.cpp
+++ b/src/script/cpp_api/s_env.cpp
@@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
- u32 blockseed)
+ u32 blockseed)
{
SCRIPTAPI_PRECHECKHEADER
@@ -44,7 +44,7 @@ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
void ScriptApiEnv::environment_Step(float dtime)
{
SCRIPTAPI_PRECHECKHEADER
- //infostream<<"scriptapi_environment_step"<<std::endl;
+ //infostream << "scriptapi_environment_step" << std::endl;
// Get core.registered_globalsteps
lua_getglobal(L, "core");
@@ -58,7 +58,7 @@ void ScriptApiEnv::environment_Step(float dtime)
}
}
-void ScriptApiEnv::player_event(ServerActiveObject* player, std::string type)
+void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &type)
{
SCRIPTAPI_PRECHECKHEADER
@@ -82,75 +82,166 @@ void ScriptApiEnv::player_event(ServerActiveObject* player, std::string type)
void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env)
{
SCRIPTAPI_PRECHECKHEADER
- verbosestream<<"scriptapi_add_environment"<<std::endl;
+ verbosestream << "scriptapi_add_environment" << std::endl;
setEnv(env);
/*
- Add ActiveBlockModifiers to environment
+ Add {Loading,Active}BlockModifiers to environment
*/
// Get core.registered_abms
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_abms");
- luaL_checktype(L, -1, LUA_TTABLE);
int registered_abms = lua_gettop(L);
- if(lua_istable(L, registered_abms)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- int id = lua_tonumber(L, -2);
- int current_abm = lua_gettop(L);
-
- std::set<std::string> trigger_contents;
- lua_getfield(L, current_abm, "nodenames");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- trigger_contents.insert(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if(lua_isstring(L, -1)){
+ if (!lua_istable(L, registered_abms)) {
+ lua_pop(L, 1);
+ throw LuaError("core.registered_abms was not a lua table, as expected.");
+ }
+ lua_pushnil(L);
+ while (lua_next(L, registered_abms)) {
+ // key at index -2 and value at index -1
+ int id = lua_tonumber(L, -2);
+ int current_abm = lua_gettop(L);
+
+ std::set<std::string> trigger_contents;
+ lua_getfield(L, current_abm, "nodenames");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table)) {
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
trigger_contents.insert(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
}
- lua_pop(L, 1);
-
- std::set<std::string> required_neighbors;
- lua_getfield(L, current_abm, "neighbors");
- if(lua_istable(L, -1)){
- int table = lua_gettop(L);
- lua_pushnil(L);
- while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- luaL_checktype(L, -1, LUA_TSTRING);
- required_neighbors.insert(lua_tostring(L, -1));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
- }
- } else if(lua_isstring(L, -1)){
+ } else if (lua_isstring(L, -1)) {
+ trigger_contents.insert(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+
+ std::set<std::string> required_neighbors;
+ lua_getfield(L, current_abm, "neighbors");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table)) {
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
required_neighbors.insert(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
}
- lua_pop(L, 1);
+ } else if (lua_isstring(L, -1)) {
+ required_neighbors.insert(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+
+ float trigger_interval = 10.0;
+ getfloatfield(L, current_abm, "interval", trigger_interval);
+
+ int trigger_chance = 50;
+ getintfield(L, current_abm, "chance", trigger_chance);
- float trigger_interval = 10.0;
- getfloatfield(L, current_abm, "interval", trigger_interval);
+ bool simple_catch_up = true;
+ getboolfield(L, current_abm, "catch_up", simple_catch_up);
- int trigger_chance = 50;
- getintfield(L, current_abm, "chance", trigger_chance);
+ LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors,
+ trigger_interval, trigger_chance, simple_catch_up);
+
+ env->addActiveBlockModifier(abm);
+
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
- LuaABM *abm = new LuaABM(L, id, trigger_contents,
- required_neighbors, trigger_interval, trigger_chance);
+ // Get core.registered_lbms
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_lbms");
+ int registered_lbms = lua_gettop(L);
- env->addActiveBlockModifier(abm);
+ if (!lua_istable(L, registered_lbms)) {
+ lua_pop(L, 1);
+ throw LuaError("core.registered_lbms was not a lua table, as expected.");
+ }
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
+ lua_pushnil(L);
+ while (lua_next(L, registered_lbms)) {
+ // key at index -2 and value at index -1
+ int id = lua_tonumber(L, -2);
+ int current_lbm = lua_gettop(L);
+
+ std::set<std::string> trigger_contents;
+ lua_getfield(L, current_lbm, "nodenames");
+ if (lua_istable(L, -1)) {
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, table)) {
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ trigger_contents.insert(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if (lua_isstring(L, -1)) {
+ trigger_contents.insert(lua_tostring(L, -1));
}
+ lua_pop(L, 1);
+
+ std::string name;
+ getstringfield(L, current_lbm, "name", name);
+
+ bool run_at_every_load = getboolfield_default(L, current_lbm,
+ "run_at_every_load", false);
+
+ LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name,
+ run_at_every_load);
+
+ env->addLoadingBlockModifierDef(lbm);
+
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
}
lua_pop(L, 1);
}
+
+void ScriptApiEnv::on_emerge_area_completion(
+ v3s16 blockpos, int action, ScriptCallbackState *state)
+{
+ Server *server = getServer();
+
+ // Note that the order of these locks is important! Envlock must *ALWAYS*
+ // be acquired before attempting to acquire scriptlock, or else ServerThread
+ // will try to acquire scriptlock after it already owns envlock, thus
+ // deadlocking EmergeThread and ServerThread
+ MutexAutoLock envlock(server->m_env_mutex);
+
+ SCRIPTAPI_PRECHECKHEADER
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, state->callback_ref);
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+
+ push_v3s16(L, blockpos);
+ lua_pushinteger(L, action);
+ lua_pushinteger(L, state->refcount);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, state->args_ref);
+
+ setOriginDirect(state->origin.c_str());
+
+ try {
+ PCALL_RES(lua_pcall(L, 4, 0, error_handler));
+ } catch (LuaError &e) {
+ server->setAsyncFatalError(e.what());
+ }
+
+ lua_pop(L, 1); // Pop error handler
+
+ if (state->refcount == 0) {
+ luaL_unref(L, LUA_REGISTRYINDEX, state->callback_ref);
+ luaL_unref(L, LUA_REGISTRYINDEX, state->args_ref);
+ }
+}
diff --git a/src/script/cpp_api/s_env.h b/src/script/cpp_api/s_env.h
index 180cfabd0..e07024565 100644
--- a/src/script/cpp_api/s_env.h
+++ b/src/script/cpp_api/s_env.h
@@ -24,19 +24,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irr_v3d.h"
class ServerEnvironment;
-struct MapgenParams;
+struct ScriptCallbackState;
-class ScriptApiEnv
- : virtual public ScriptApiBase
+class ScriptApiEnv : virtual public ScriptApiBase
{
public:
- // On environment step
+ // Called on environment step
void environment_Step(float dtime);
- // After generating a piece of map
- void environment_OnGenerated(v3s16 minp, v3s16 maxp,u32 blockseed);
- //called on player event
- void player_event(ServerActiveObject* player, std::string type);
+ // Called after generating a piece of map
+ void environment_OnGenerated(v3s16 minp, v3s16 maxp, u32 blockseed);
+
+ // Called on player event
+ void player_event(ServerActiveObject *player, const std::string &type);
+
+ // Called after emerge of a block queued from core.emerge_area()
+ void on_emerge_area_completion(v3s16 blockpos, int action,
+ ScriptCallbackState *state);
void initializeEnvironment(ServerEnvironment *env);
};
diff --git a/src/script/cpp_api/s_internal.h b/src/script/cpp_api/s_internal.h
index 9999a584a..37473c497 100644
--- a/src/script/cpp_api/s_internal.h
+++ b/src/script/cpp_api/s_internal.h
@@ -32,28 +32,50 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifdef SCRIPTAPI_LOCK_DEBUG
#include "debug.h" // assert()
+
class LockChecker {
public:
- LockChecker(bool* variable) {
- assert(*variable == false);
+ LockChecker(int *recursion_counter, threadid_t *owning_thread)
+ {
+ m_lock_recursion_counter = recursion_counter;
+ m_owning_thread = owning_thread;
+ m_original_level = *recursion_counter;
+
+ if (*m_lock_recursion_counter > 0)
+ assert(thr_is_current_thread(*m_owning_thread));
+ else
+ *m_owning_thread = thr_get_current_thread_id();
- m_variable = variable;
- *m_variable = true;
+ (*m_lock_recursion_counter)++;
}
- ~LockChecker() {
- *m_variable = false;
+
+ ~LockChecker()
+ {
+ assert(thr_is_current_thread(*m_owning_thread));
+ assert(*m_lock_recursion_counter > 0);
+
+ (*m_lock_recursion_counter)--;
+
+ assert(*m_lock_recursion_counter == m_original_level);
}
+
private:
-bool* m_variable;
+ int *m_lock_recursion_counter;
+ int m_original_level;
+ threadid_t *m_owning_thread;
};
-#define SCRIPTAPI_LOCK_CHECK LockChecker(&(this->m_locked))
+#define SCRIPTAPI_LOCK_CHECK \
+ LockChecker scriptlock_checker( \
+ &this->m_lock_recursion_count, \
+ &this->m_owning_thread)
+
#else
-#define SCRIPTAPI_LOCK_CHECK while(0)
+ #define SCRIPTAPI_LOCK_CHECK while(0)
#endif
#define SCRIPTAPI_PRECHECKHEADER \
- JMutexAutoLock(this->m_luastackmutex); \
+ RecursiveMutexAutoLock scriptlock(this->m_luastackmutex); \
SCRIPTAPI_LOCK_CHECK; \
realityCheck(); \
lua_State *L = getStack(); \
diff --git a/src/script/cpp_api/s_inventory.cpp b/src/script/cpp_api/s_inventory.cpp
index 019d1ccc0..c90c7d4e2 100644
--- a/src/script/cpp_api/s_inventory.cpp
+++ b/src/script/cpp_api/s_inventory.cpp
@@ -33,6 +33,8 @@ int ScriptApiDetached::detached_inventory_AllowMove(
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getDetachedInventoryCallback(name, "allow_move"))
return count;
@@ -48,11 +50,11 @@ int ScriptApiDetached::detached_inventory_AllowMove(
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 7, 1, error_handler));
if(!lua_isnumber(L, -1))
throw LuaError("allow_move should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
- lua_pop(L, 1); // Pop integer
+ lua_pop(L, 2); // Pop integer and error handler
return ret;
}
@@ -64,6 +66,8 @@ int ScriptApiDetached::detached_inventory_AllowPut(
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getDetachedInventoryCallback(name, "allow_put"))
return stack.count; // All will be accepted
@@ -76,11 +80,11 @@ int ScriptApiDetached::detached_inventory_AllowPut(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 1, error_handler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_put should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
- lua_pop(L, 1); // Pop integer
+ lua_pop(L, 2); // Pop integer and error handler
return ret;
}
@@ -92,6 +96,8 @@ int ScriptApiDetached::detached_inventory_AllowTake(
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getDetachedInventoryCallback(name, "allow_take"))
return stack.count; // All will be accepted
@@ -104,11 +110,11 @@ int ScriptApiDetached::detached_inventory_AllowTake(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 1, error_handler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_take should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
- lua_pop(L, 1); // Pop integer
+ lua_pop(L, 2); // Pop integer and error handler
return ret;
}
@@ -121,6 +127,8 @@ void ScriptApiDetached::detached_inventory_OnMove(
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getDetachedInventoryCallback(name, "on_move"))
return;
@@ -136,7 +144,8 @@ void ScriptApiDetached::detached_inventory_OnMove(
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 7, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
// Report put items
@@ -147,6 +156,8 @@ void ScriptApiDetached::detached_inventory_OnPut(
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getDetachedInventoryCallback(name, "on_put"))
return;
@@ -160,7 +171,8 @@ void ScriptApiDetached::detached_inventory_OnPut(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
// Report taken items
@@ -171,6 +183,8 @@ void ScriptApiDetached::detached_inventory_OnTake(
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getDetachedInventoryCallback(name, "on_take"))
return;
@@ -184,7 +198,8 @@ void ScriptApiDetached::detached_inventory_OnTake(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
// Retrieves core.detached_inventories[name][callbackname]
diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp
index 4d4d416ec..3c84fb8cf 100644
--- a/src/script/cpp_api/s_item.cpp
+++ b/src/script/cpp_api/s_item.cpp
@@ -34,6 +34,8 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getItemCallback(item.name.c_str(), "on_drop"))
return false;
@@ -42,7 +44,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, dropper);
pushFloatPos(L, pos);
- PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -50,7 +52,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
}
- lua_pop(L, 1); // Pop item
+ lua_pop(L, 2); // Pop item and error handler
return true;
}
@@ -59,6 +61,8 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getItemCallback(item.name.c_str(), "on_place"))
return false;
@@ -67,7 +71,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, placer);
pushPointedThing(pointed);
- PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -75,7 +79,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
}
- lua_pop(L, 1); // Pop item
+ lua_pop(L, 2); // Pop item and error handler
return true;
}
@@ -84,6 +88,8 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Push callback function on stack
if (!getItemCallback(item.name.c_str(), "on_use"))
return false;
@@ -92,7 +98,7 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, user);
pushPointedThing(pointed);
- PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
if(!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -100,7 +106,33 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
}
- lua_pop(L, 1); // Pop item
+ lua_pop(L, 2); // Pop item and error handler
+ return true;
+}
+
+bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *user)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ if (!getItemCallback(item.name.c_str(), "on_secondary_use"))
+ return false;
+
+ LuaItemStack::create(L, item);
+ objectrefGetOrCreate(L, user);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NOTHING;
+ pushPointedThing(pointed);
+ PCALL_RES(lua_pcall(L, 3, 1, error_handler));
+ if (!lua_isnil(L, -1)) {
+ try {
+ item = read_item(L, -1, getServer());
+ } catch (LuaError &e) {
+ throw LuaError(std::string(e.what()) + ". item=" + item.name);
+ }
+ }
+ lua_pop(L, 2); // Pop item and error handler
return true;
}
@@ -109,6 +141,8 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
lua_getglobal(L, "core");
lua_getfield(L, -1, "on_craft");
LuaItemStack::create(L, item);
@@ -122,7 +156,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
push_items(L, items);
InvRef::create(L, craft_inv);
- PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 4, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -130,7 +164,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
}
- lua_pop(L, 1); // Pop item
+ lua_pop(L, 2); // Pop item and error handler
return true;
}
@@ -139,6 +173,8 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
lua_getglobal(L, "core");
lua_getfield(L, -1, "craft_predict");
LuaItemStack::create(L, item);
@@ -152,7 +188,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
push_items(L, items);
InvRef::create(L, craft_inv);
- PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 4, 1, error_handler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -160,7 +196,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
throw LuaError(std::string(e.what()) + ". item=" + item.name);
}
}
- lua_pop(L, 1); // Pop item
+ lua_pop(L, 2); // Pop item and error handler
return true;
}
diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h
index 88cc1909d..7350a71c5 100644
--- a/src/script/cpp_api/s_item.h
+++ b/src/script/cpp_api/s_item.h
@@ -42,6 +42,8 @@ public:
ServerActiveObject *placer, const PointedThing &pointed);
bool item_OnUse(ItemStack &item,
ServerActiveObject *user, const PointedThing &pointed);
+ bool item_OnSecondaryUse(ItemStack &item,
+ ServerActiveObject *user);
bool item_OnCraft(ItemStack &item, ServerActiveObject *user,
const InventoryList *old_craft_grid, const InventoryLocation &craft_inv);
bool item_CraftPredict(ItemStack &item, ServerActiveObject *user,
diff --git a/src/script/cpp_api/s_mainmenu.cpp b/src/script/cpp_api/s_mainmenu.cpp
index 17ceff082..e9a7a13b9 100644
--- a/src/script/cpp_api/s_mainmenu.cpp
+++ b/src/script/cpp_api/s_mainmenu.cpp
@@ -43,6 +43,8 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get handler function
lua_getglobal(L, "core");
lua_getfield(L, -1, "event_handler");
@@ -55,13 +57,16 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text)
// Call it
lua_pushstring(L, text.c_str());
- PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get handler function
lua_getglobal(L, "core");
lua_getfield(L, -1, "button_handler");
@@ -84,6 +89,7 @@ void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
}
// Call it
- PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 0, 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 dac058b13..17f0f0dac 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -57,6 +57,7 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
{CPT2_FACEDIR, "facedir"},
{CPT2_WALLMOUNTED, "wallmounted"},
{CPT2_LEVELED, "leveled"},
+ {CPT2_DEGROTATE, "degrotate"},
{0, NULL},
};
@@ -81,6 +82,7 @@ struct EnumString ScriptApiNode::es_NodeBoxType[] =
{NODEBOX_FIXED, "fixed"},
{NODEBOX_WALLMOUNTED, "wallmounted"},
{NODEBOX_LEVELED, "leveled"},
+ {NODEBOX_CONNECTED, "connected"},
{0, NULL},
};
@@ -95,6 +97,8 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
@@ -106,7 +110,8 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
pushnode(L, node, ndef);
objectrefGetOrCreate(L, puncher);
pushPointedThing(pointed);
- PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 4, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
return true;
}
@@ -115,6 +120,8 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
@@ -125,7 +132,8 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
push_v3s16(L, p);
pushnode(L, node, ndef);
objectrefGetOrCreate(L, digger);
- PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 3, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
return true;
}
@@ -133,6 +141,8 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
@@ -141,13 +151,16 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
- PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
@@ -156,13 +169,16 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
- PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
@@ -172,13 +188,16 @@ void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
- PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// Push callback function on stack
@@ -188,7 +207,8 @@ bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
// Call function
push_v3s16(L, p);
lua_pushnumber(L,dtime);
- PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 1, error_handler));
+ lua_remove(L, error_handler);
return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
}
@@ -199,6 +219,8 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -223,23 +245,30 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
lua_settable(L, -3);
}
objectrefGetOrCreate(L, sender); // player
- PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 4, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiNode::node_falling_update(v3s16 p)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
lua_getglobal(L, "nodeupdate");
push_v3s16(L, p);
- PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
void ScriptApiNode::node_falling_update_single(v3s16 p)
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
lua_getglobal(L, "nodeupdate_single");
push_v3s16(L, p);
- PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp
index 638750b0e..d050c0bc9 100644
--- a/src/script/cpp_api/s_nodemeta.cpp
+++ b/src/script/cpp_api/s_nodemeta.cpp
@@ -34,6 +34,8 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -54,12 +56,12 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p,
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 7, 1, error_handler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_move should"
" return a number, guilty node: " + nodename);
int num = luaL_checkinteger(L, -1);
- lua_pop(L, 1); // Pop integer
+ lua_pop(L, 2); // Pop integer and error handler
return num;
}
@@ -70,6 +72,8 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -88,12 +92,12 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 1, error_handler));
if(!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_put should"
" return a number, guilty node: " + nodename);
int num = luaL_checkinteger(L, -1);
- lua_pop(L, 1); // Pop integer
+ lua_pop(L, 2); // Pop integer and error handler
return num;
}
@@ -104,6 +108,8 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -122,12 +128,12 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 1, error_handler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_take should"
" return a number, guilty node: " + nodename);
int num = luaL_checkinteger(L, -1);
- lua_pop(L, 1); // Pop integer
+ lua_pop(L, 2); // Pop integer and error handler
return num;
}
@@ -139,6 +145,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -159,7 +167,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p,
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 7, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
// Report put items
@@ -169,6 +178,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -187,7 +198,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
// Report taken items
@@ -197,6 +209,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
INodeDefManager *ndef = getServer()->ndef();
// If node doesn't exist, we don't know what callback to call
@@ -215,7 +229,8 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 5, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
ScriptApiNodemeta::ScriptApiNodemeta()
diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp
index ef3c31cfd..807430678 100644
--- a/src/script/cpp_api/s_player.cpp
+++ b/src/script/cpp_api/s_player.cpp
@@ -74,6 +74,8 @@ s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
// Get core.registered_on_player_hpchange
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_player_hpchange");
@@ -81,9 +83,9 @@ s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
objectrefGetOrCreate(L, player);
lua_pushnumber(L, hp_change);
- PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 1, error_handler));
hp_change = lua_tointeger(L, -1);
- lua_pop(L, -1);
+ lua_pop(L, 2); // Pop result and error handler
return hp_change;
}
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index 6a6d40307..730235c7b 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -47,7 +47,7 @@ static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int
// Pushes the original version of a library function on the stack, from the old version
static inline void push_original(lua_State *L, const char *lib, const char *func)
{
- lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
lua_getfield(L, -1, lib);
lua_remove(L, -2); // Remove globals_backup
lua_getfield(L, -1, func);
@@ -116,7 +116,6 @@ void ScriptApiSecurity::initializeSecurity()
"upvaluejoin",
"sethook",
"debug",
- "getupvalue",
"setlocal",
};
static const char *package_whitelist[] = {
@@ -143,7 +142,7 @@ void ScriptApiSecurity::initializeSecurity()
// Backup globals to the registry
lua_getglobal(L, "_G");
- lua_setfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
// Replace the global environment with an empty one
#if LUA_VERSION_NUM <= 501
@@ -165,7 +164,7 @@ void ScriptApiSecurity::initializeSecurity()
#endif
// Get old globals
- lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
int old_globals = lua_gettop(L);
@@ -241,7 +240,7 @@ void ScriptApiSecurity::initializeSecurity()
bool ScriptApiSecurity::isSecure(lua_State *L)
{
- lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
bool secure = !lua_isnil(L, -1);
lua_pop(L, 1);
return secure;
@@ -356,7 +355,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path)
if (!removed.empty()) abs_path += DIR_DELIM + removed;
// Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
lua_pop(L, 1);
const Server *server = script->getServer();
@@ -364,7 +363,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path)
if (!server) return false;
// Get mod name
- lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (lua_isstring(L, -1)) {
std::string mod_name = lua_tostring(L, -1);
diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h
index 4a4389cf5..97bc5c067 100644
--- a/src/script/cpp_api/s_security.h
+++ b/src/script/cpp_api/s_security.h
@@ -25,9 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define CHECK_SECURE_PATH(L, path) \
if (!ScriptApiSecurity::checkPath(L, path)) { \
- lua_pushstring(L, (std::string("Attempt to access external file ") + \
- path + " with mod security on.").c_str()); \
- lua_error(L); \
+ throw LuaError(std::string("Attempt to access external file ") + \
+ path + " with mod security on."); \
}
#define CHECK_SECURE_PATH_OPTIONAL(L, path) \
if (ScriptApiSecurity::isSecure(L)) { \
diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp
index ec2f9c0af..38bd41f87 100644
--- a/src/script/cpp_api/s_server.cpp
+++ b/src/script/cpp_api/s_server.cpp
@@ -27,13 +27,15 @@ bool ScriptApiServer::getAuth(const std::string &playername,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
getAuthHandler();
lua_getfield(L, -1, "get_auth");
if (lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError("Authentication handler missing get_auth");
lua_pushstring(L, playername.c_str());
- PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 1, 1, error_handler));
lua_remove(L, -2); // Remove auth handler
+ lua_remove(L, error_handler);
// nil = login not allowed
if (lua_isnil(L, -1))
@@ -99,6 +101,7 @@ void ScriptApiServer::createAuth(const std::string &playername,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
getAuthHandler();
lua_getfield(L, -1, "create_auth");
lua_remove(L, -2); // Remove auth handler
@@ -106,7 +109,8 @@ void ScriptApiServer::createAuth(const std::string &playername,
throw LuaError("Authentication handler missing create_auth");
lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str());
- PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 0, error_handler));
+ lua_pop(L, 1); // Pop error handler
}
bool ScriptApiServer::setPassword(const std::string &playername,
@@ -114,6 +118,7 @@ bool ScriptApiServer::setPassword(const std::string &playername,
{
SCRIPTAPI_PRECHECKHEADER
+ int error_handler = PUSH_ERROR_HANDLER(L);
getAuthHandler();
lua_getfield(L, -1, "set_password");
lua_remove(L, -2); // Remove auth handler
@@ -121,7 +126,8 @@ bool ScriptApiServer::setPassword(const std::string &playername,
throw LuaError("Authentication handler missing set_password");
lua_pushstring(L, playername.c_str());
lua_pushstring(L, password.c_str());
- PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
+ PCALL_RES(lua_pcall(L, 2, 1, error_handler));
+ lua_remove(L, error_handler);
return lua_toboolean(L, -1);
}
diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt
index 2501ce6d6..d507dcf70 100644
--- a/src/script/lua_api/CMakeLists.txt
+++ b/src/script/lua_api/CMakeLists.txt
@@ -16,6 +16,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_util.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_http.cpp
PARENT_SCOPE)
set(client_SCRIPT_LUA_API_SRCS
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp
index 1e9075119..20e7875c7 100644
--- a/src/script/lua_api/l_areastore.cpp
+++ b/src/script/lua_api/l_areastore.cpp
@@ -22,11 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "cpp_api/s_security.h"
-#include "areastore.h"
+#include "irr_v3d.h"
+#include "util/areastore.h"
#include "filesys.h"
-#ifndef ANDROID
- #include "cmake_config.h"
-#endif
#include <fstream>
static inline void get_data_and_border_flags(lua_State *L, u8 start_i,
@@ -45,6 +43,7 @@ static void push_area(lua_State *L, const Area *a,
{
if (!include_borders && !include_data) {
lua_pushboolean(L, true);
+ return;
}
lua_newtable(L);
if (include_borders) {
@@ -71,6 +70,22 @@ static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
}
}
+// Deserializes value and handles errors
+static int deserialization_helper(lua_State *L, AreaStore *as,
+ std::istream &is)
+{
+ try {
+ as->deserialize(is);
+ } catch (const SerializationError &e) {
+ lua_pushboolean(L, false);
+ lua_pushstring(L, e.what());
+ return 2;
+ }
+
+ lua_pushboolean(L, true);
+ return 1;
+}
+
// garbage collector
int LuaAreaStore::gc_object(lua_State *L)
{
@@ -149,7 +164,7 @@ int LuaAreaStore::l_get_areas_in_area(lua_State *L)
return 1;
}
-// insert_area(edge1, edge2, data)
+// insert_area(edge1, edge2, data, id)
int LuaAreaStore::l_insert_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -157,26 +172,18 @@ int LuaAreaStore::l_insert_area(lua_State *L)
LuaAreaStore *o = checkobject(L, 1);
AreaStore *ast = o->as;
- Area a;
-
- a.minedge = check_v3s16(L, 2);
- a.maxedge = check_v3s16(L, 3);
-
- a.extremifyEdges();
- a.id = ast->getFreeId(a.minedge, a.maxedge);
-
- if (a.id == AREA_ID_INVALID) {
- // couldn't get free id
- lua_pushnil(L);
- return 1;
- }
+ Area a(check_v3s16(L, 2), check_v3s16(L, 3));
size_t d_len;
const char *data = luaL_checklstring(L, 4, &d_len);
a.data = std::string(data, d_len);
- ast->insertArea(a);
+ if (lua_isnumber(L, 5))
+ a.id = lua_tonumber(L, 5);
+
+ if (!ast->insertArea(&a))
+ return 0;
lua_pushnumber(L, a.id);
return 1;
@@ -229,17 +236,15 @@ int LuaAreaStore::l_set_cache_params(lua_State *L)
return 0;
}
-#if 0
// to_string()
int LuaAreaStore::l_to_string(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaAreaStore *o = checkobject(L, 1);
- AreaStore *ast = o->as;
std::ostringstream os(std::ios_base::binary);
- ast->serialize(os);
+ o->as->serialize(os);
std::string str = os.str();
lua_pushlstring(L, str.c_str(), str.length());
@@ -270,16 +275,12 @@ int LuaAreaStore::l_from_string(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaAreaStore *o = checkobject(L, 1);
- AreaStore *ast = o->as;
size_t len;
const char *str = luaL_checklstring(L, 2, &len);
std::istringstream is(std::string(str, len), std::ios::binary);
- bool success = ast->deserialize(is);
-
- lua_pushboolean(L, success);
- return 1;
+ return deserialization_helper(L, o->as, is);
}
// from_file(filename)
@@ -288,26 +289,17 @@ int LuaAreaStore::l_from_file(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaAreaStore *o = checkobject(L, 1);
- AreaStore *ast = o->as;
const char *filename = luaL_checkstring(L, 2);
CHECK_SECURE_PATH_OPTIONAL(L, filename);
std::ifstream is(filename, std::ios::binary);
- bool success = ast->deserialize(is);
-
- lua_pushboolean(L, success);
- return 1;
+ return deserialization_helper(L, o->as, is);
}
-#endif
LuaAreaStore::LuaAreaStore()
{
-#if USE_SPATIAL
- this->as = new SpatialAreaStore();
-#else
- this->as = new VectorAreaStore();
-#endif
+ this->as = AreaStore::getOptimalImplementation();
}
LuaAreaStore::LuaAreaStore(const std::string &type)
@@ -393,9 +385,9 @@ const luaL_reg LuaAreaStore::methods[] = {
luamethod(LuaAreaStore, reserve),
luamethod(LuaAreaStore, remove_area),
luamethod(LuaAreaStore, set_cache_params),
- /* luamethod(LuaAreaStore, to_string),
+ luamethod(LuaAreaStore, to_string),
luamethod(LuaAreaStore, to_file),
luamethod(LuaAreaStore, from_string),
- luamethod(LuaAreaStore, from_file),*/
+ luamethod(LuaAreaStore, from_file),
{0,0}
};
diff --git a/src/script/lua_api/l_areastore.h b/src/script/lua_api/l_areastore.h
index a25529627..4bd94cebe 100644
--- a/src/script/lua_api/l_areastore.h
+++ b/src/script/lua_api/l_areastore.h
@@ -17,16 +17,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef L_AREASTORE_H_
-#define L_AREASTORE_H_
+#ifndef L_AREA_STORE_H_
+#define L_AREA_STORE_H_
#include "lua_api/l_base.h"
-#include "irr_v3d.h"
-#include "areastore.h"
-/*
- AreaStore
- */
+
+class AreaStore;
+
class LuaAreaStore : public ModApiBase {
private:
@@ -45,11 +43,11 @@ private:
static int l_set_cache_params(lua_State *L);
- /* static int l_to_string(lua_State *L);
+ static int l_to_string(lua_State *L);
static int l_to_file(lua_State *L);
static int l_from_string(lua_State *L);
- static int l_from_file(lua_State *L); */
+ static int l_from_file(lua_State *L);
public:
AreaStore *as;
@@ -67,4 +65,4 @@ public:
static void Register(lua_State *L);
};
-#endif /* L_AREASTORE_H_ */
+#endif // L_AREA_STORE_H_
diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp
index 6ad3e4ba2..515a7d933 100644
--- a/src/script/lua_api/l_base.cpp
+++ b/src/script/lua_api/l_base.cpp
@@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
ScriptApiBase *ModApiBase::getScriptApiBase(lua_State *L)
{
// Get server from registry
- lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI);
ScriptApiBase *sapi_ptr = (ScriptApiBase*) lua_touserdata(L, -1);
lua_pop(L, 1);
return sapi_ptr;
@@ -49,7 +49,7 @@ GUIEngine *ModApiBase::getGuiEngine(lua_State *L)
std::string ModApiBase::getCurrentModPath(lua_State *L)
{
- lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
const char *current_mod_name = lua_tostring(L, -1);
if (!current_mod_name)
return ".";
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 28afdd071..8284c3fcb 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -33,11 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/pointedthing.h"
#include "content_sao.h"
#include "treegen.h"
+#include "emerge.h"
#include "pathfinder.h"
-#define GET_ENV_PTR ServerEnvironment* env = \
- dynamic_cast<ServerEnvironment*>(getEnv(L)); \
- if (env == NULL) return 0
+struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
+{
+ {CLEAR_OBJECTS_MODE_FULL, "full"},
+ {CLEAR_OBJECTS_MODE_QUICK, "quick"},
+ {0, NULL},
+};
///////////////////////////////////////////////////////////////////////////////
@@ -52,8 +56,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
sanity_check(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
- lua_pushcfunction(L, script_error_handler);
- int errorhandler = lua_gettop(L);
+ int error_handler = PUSH_ERROR_HANDLER(L);
// Get registered_abms
lua_getglobal(L, "core");
@@ -80,13 +83,68 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
lua_pushnumber(L, active_object_count);
lua_pushnumber(L, active_object_count_wider);
- int result = lua_pcall(L, 4, 0, errorhandler);
+ int result = lua_pcall(L, 4, 0, error_handler);
if (result)
scriptIface->scriptError(result, "LuaABM::trigger");
lua_pop(L, 1); // Pop error handler
}
+void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
+{
+ GameScripting *scriptIface = env->getScriptIface();
+ scriptIface->realityCheck();
+
+ lua_State *L = scriptIface->getStack();
+ sanity_check(lua_checkstack(L, 20));
+ StackUnroller stack_unroller(L);
+
+ int error_handler = PUSH_ERROR_HANDLER(L);
+
+ // Get registered_lbms
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_lbms");
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_remove(L, -2); // Remove core
+
+ // Get registered_lbms[m_id]
+ lua_pushnumber(L, m_id);
+ lua_gettable(L, -2);
+ FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table");
+ lua_remove(L, -2); // Remove registered_lbms
+
+ scriptIface->setOriginFromTable(-1);
+
+ // Call action
+ luaL_checktype(L, -1, LUA_TTABLE);
+ lua_getfield(L, -1, "action");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ lua_remove(L, -2); // Remove registered_lbms[m_id]
+ push_v3s16(L, p);
+ pushnode(L, n, env->getGameDef()->ndef());
+
+ int result = lua_pcall(L, 2, 0, error_handler);
+ if (result)
+ scriptIface->scriptError(result, "LuaLBM::trigger");
+
+ lua_pop(L, 1); // Pop error handler
+}
+
+void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
+{
+ ScriptCallbackState *state = (ScriptCallbackState *)param;
+ assert(state != NULL);
+ assert(state->script != NULL);
+ assert(state->refcount > 0);
+
+ state->refcount--;
+
+ state->script->on_emerge_area_completion(blockpos, action, state);
+
+ if (state->refcount == 0)
+ delete state;
+}
+
// Exported functions
// set_node(pos, node)
@@ -412,8 +470,7 @@ int ModApiEnvMod::l_add_item(lua_State *L)
if(item.empty() || !item.isKnown(getServer(L)->idef()))
return 0;
- lua_pushcfunction(L, script_error_handler);
- int errorhandler = lua_gettop(L);
+ int error_handler = PUSH_ERROR_HANDLER(L);
// Use spawn_item to spawn a __builtin:item
lua_getglobal(L, "core");
@@ -424,9 +481,9 @@ int ModApiEnvMod::l_add_item(lua_State *L)
lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str());
- PCALL_RESL(L, lua_pcall(L, 2, 1, errorhandler));
+ PCALL_RESL(L, lua_pcall(L, 2, 1, error_handler));
- lua_remove(L, errorhandler); // Remove error handler
+ lua_remove(L, error_handler);
return 1;
}
@@ -504,6 +561,15 @@ int ModApiEnvMod::l_get_timeofday(lua_State *L)
return 1;
}
+// get_day_count() -> int
+int ModApiEnvMod::l_get_day_count(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ lua_pushnumber(L, env->getDayCount());
+ return 1;
+}
+
// get_gametime()
int ModApiEnvMod::l_get_gametime(lua_State *L)
{
@@ -659,7 +725,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
// returns world-specific PerlinNoise
int ModApiEnvMod::l_get_perlin(lua_State *L)
{
- GET_ENV_PTR;
+ GET_ENV_PTR_NO_MAP_LOCK;
NoiseParams params;
@@ -685,7 +751,7 @@ int ModApiEnvMod::l_get_perlin(lua_State *L)
// returns world-specific PerlinNoiseMap
int ModApiEnvMod::l_get_perlin_map(lua_State *L)
{
- GET_ENV_PTR;
+ GET_ENV_PTR_NO_MAP_LOCK;
NoiseParams np;
if (!read_noiseparams(L, 1, &np))
@@ -717,13 +783,20 @@ int ModApiEnvMod::l_get_voxel_manip(lua_State *L)
return 1;
}
-// clear_objects()
+// clear_objects([options])
// clear all objects in the environment
+// where options = {mode = "full" or "quick"}
int ModApiEnvMod::l_clear_objects(lua_State *L)
{
GET_ENV_PTR;
- env->clearAllObjects();
+ ClearObjectsMode mode = CLEAR_OBJECTS_MODE_FULL;
+ if (lua_istable(L, 1)) {
+ mode = (ClearObjectsMode)getenumfield(L, 1, "mode",
+ ModApiEnvMod::es_ClearObjectsMode, mode);
+ }
+
+ env->clearObjects(mode);
return 0;
}
@@ -753,6 +826,51 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L)
return 1;
}
+// emerge_area(p1, p2, [callback, context])
+// emerge mapblocks in area p1..p2, calls callback with context upon completion
+int ModApiEnvMod::l_emerge_area(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ EmergeCompletionCallback callback = NULL;
+ ScriptCallbackState *state = NULL;
+
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+
+ v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
+ v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
+ sortBoxVerticies(bpmin, bpmax);
+
+ size_t num_blocks = VoxelArea(bpmin, bpmax).getVolume();
+ assert(num_blocks != 0);
+
+ if (lua_isfunction(L, 3)) {
+ callback = LuaEmergeAreaCallback;
+
+ lua_pushvalue(L, 3);
+ int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ lua_pushvalue(L, 4);
+ int args_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ state = new ScriptCallbackState;
+ state->script = getServer(L)->getScriptIface();
+ state->callback_ref = callback_ref;
+ state->args_ref = args_ref;
+ state->refcount = num_blocks;
+ state->origin = getScriptApiBase(L)->getOrigin();
+ }
+
+ for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
+ for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
+ for (s16 x = bpmin.X; x <= bpmax.X; x++) {
+ emerge->enqueueBlockEmergeEx(v3s16(x, y, z), PEER_ID_INEXISTENT,
+ BLOCK_EMERGE_ALLOW_GEN | BLOCK_EMERGE_FORCE_QUEUE, callback, state);
+ }
+
+ return 0;
+}
+
// delete_area(p1, p2)
// delete mapblocks in area p1..p2
int ModApiEnvMod::l_delete_area(lua_State *L)
@@ -797,19 +915,19 @@ int ModApiEnvMod::l_find_path(lua_State *L)
unsigned int searchdistance = luaL_checkint(L, 3);
unsigned int max_jump = luaL_checkint(L, 4);
unsigned int max_drop = luaL_checkint(L, 5);
- algorithm algo = A_PLAIN_NP;
+ PathAlgorithm algo = PA_PLAIN_NP;
if (!lua_isnil(L, 6)) {
std::string algorithm = luaL_checkstring(L,6);
if (algorithm == "A*")
- algo = A_PLAIN;
+ algo = PA_PLAIN;
if (algorithm == "Dijkstra")
- algo = DIJKSTRA;
+ algo = PA_DIJKSTRA;
}
- std::vector<v3s16> path =
- get_Path(env,pos1,pos2,searchdistance,max_jump,max_drop,algo);
+ std::vector<v3s16> path = get_path(env, pos1, pos2,
+ searchdistance, max_jump, max_drop, algo);
if (path.size() > 0)
{
@@ -920,13 +1038,6 @@ int ModApiEnvMod::l_forceload_free_block(lua_State *L)
return 0;
}
-// get_us_time()
-int ModApiEnvMod::l_get_us_time(lua_State *L)
-{
- lua_pushnumber(L, porting::getTimeUs());
- return 1;
-}
-
void ModApiEnvMod::Initialize(lua_State *L, int top)
{
API_FCT(set_node);
@@ -953,9 +1064,11 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(set_timeofday);
API_FCT(get_timeofday);
API_FCT(get_gametime);
+ API_FCT(get_day_count);
API_FCT(find_node_near);
API_FCT(find_nodes_in_area);
API_FCT(find_nodes_in_area_under_air);
+ API_FCT(emerge_area);
API_FCT(delete_area);
API_FCT(get_perlin);
API_FCT(get_perlin_map);
@@ -967,5 +1080,4 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(transforming_liquid_add);
API_FCT(forceload_block);
API_FCT(forceload_free_block);
- API_FCT(get_us_time);
}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index 0d4ca788e..89dd7978f 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -113,6 +113,9 @@ private:
// get_gametime()
static int l_get_gametime(lua_State *L);
+ // get_day_count() -> int
+ static int l_get_day_count(lua_State *L);
+
// find_node_near(pos, radius, nodenames) -> pos or nil
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_node_near(lua_State *L);
@@ -125,6 +128,9 @@ private:
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_nodes_in_area_under_air(lua_State *L);
+ // emerge_area(p1, p2)
+ static int l_emerge_area(lua_State *L);
+
// delete_area(p1, p2) -> true/false
static int l_delete_area(lua_State *L);
@@ -165,15 +171,13 @@ private:
// stops forceloading a position
static int l_forceload_free_block(lua_State *L);
- // get us precision time
- static int l_get_us_time(lua_State *L);
-
public:
static void Initialize(lua_State *L, int top);
+
+ static struct EnumString es_ClearObjectsMode[];
};
-class LuaABM : public ActiveBlockModifier
-{
+class LuaABM : public ActiveBlockModifier {
private:
int m_id;
@@ -181,16 +185,18 @@ private:
std::set<std::string> m_required_neighbors;
float m_trigger_interval;
u32 m_trigger_chance;
+ bool m_simple_catch_up;
public:
LuaABM(lua_State *L, int id,
const std::set<std::string> &trigger_contents,
const std::set<std::string> &required_neighbors,
- float trigger_interval, u32 trigger_chance):
+ float trigger_interval, u32 trigger_chance, bool simple_catch_up):
m_id(id),
m_trigger_contents(trigger_contents),
m_required_neighbors(required_neighbors),
m_trigger_interval(trigger_interval),
- m_trigger_chance(trigger_chance)
+ m_trigger_chance(trigger_chance),
+ m_simple_catch_up(simple_catch_up)
{
}
virtual std::set<std::string> getTriggerContents()
@@ -209,8 +215,38 @@ public:
{
return m_trigger_chance;
}
+ virtual bool getSimpleCatchUp()
+ {
+ return m_simple_catch_up;
+ }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
u32 active_object_count, u32 active_object_count_wider);
};
+class LuaLBM : public LoadingBlockModifierDef
+{
+private:
+ int m_id;
+public:
+ LuaLBM(lua_State *L, int id,
+ const std::set<std::string> &trigger_contents,
+ const std::string &name,
+ bool run_at_every_load):
+ m_id(id)
+ {
+ this->run_at_every_load = run_at_every_load;
+ this->trigger_contents = trigger_contents;
+ this->name = name;
+ }
+ virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n);
+};
+
+struct ScriptCallbackState {
+ GameScripting *script;
+ int callback_ref;
+ int args_ref;
+ unsigned int refcount;
+ std::string origin;
+};
+
#endif /* L_ENV_H_ */
diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp
new file mode 100644
index 000000000..8bd39b6ed
--- /dev/null
+++ b/src/script/lua_api/l_http.cpp
@@ -0,0 +1,193 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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 "lua_api/l_internal.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
+#include "lua_api/l_http.h"
+#include "httpfetch.h"
+#include "settings.h"
+#include "debug.h"
+#include "log.h"
+
+#include <algorithm>
+#include <iomanip>
+#include <cctype>
+
+#define HTTP_API(name) \
+ lua_pushstring(L, #name); \
+ lua_pushcfunction(L, l_http_##name); \
+ lua_settable(L, -3);
+
+#if USE_CURL
+void ModApiHttp::read_http_fetch_request(lua_State *L, HTTPFetchRequest &req)
+{
+ luaL_checktype(L, 1, LUA_TTABLE);
+
+ req.caller = httpfetch_caller_alloc_secure();
+ getstringfield(L, 1, "url", req.url);
+ lua_getfield(L, 1, "user_agent");
+ if (lua_isstring(L, -1))
+ req.useragent = getstringfield_default(L, 1, "user_agent", "");
+ lua_pop(L, 1);
+ req.multipart = getboolfield_default(L, 1, "multipart", false);
+ req.timeout = getintfield_default(L, 1, "timeout", 3) * 1000;
+
+ // post_data: if table, post form data, otherwise raw data
+ lua_getfield(L, 1, "post_data");
+ if (lua_istable(L, 2)) {
+ lua_pushnil(L);
+ while (lua_next(L, 2) != 0)
+ {
+ req.post_fields[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ }
+ } else if (lua_isstring(L, 2)) {
+ req.post_data = lua_tostring(L, 2);
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "extra_headers");
+ if (lua_istable(L, 2)) {
+ lua_pushnil(L);
+ while (lua_next(L, 2) != 0)
+ {
+ const char *header = luaL_checkstring(L, -1);
+ req.extra_headers.push_back(header);
+ lua_pop(L, 1);
+ }
+ }
+ lua_pop(L, 1);
+}
+
+void ModApiHttp::push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed)
+{
+ lua_newtable(L);
+ setboolfield(L, -1, "succeeded", res.succeeded);
+ setboolfield(L, -1, "timeout", res.timeout);
+ setboolfield(L, -1, "completed", completed);
+ setintfield(L, -1, "code", res.response_code);
+ setstringfield(L, -1, "data", res.data.c_str());
+}
+
+// http_api.fetch_async(HTTPRequest definition)
+int ModApiHttp::l_http_fetch_async(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ HTTPFetchRequest req;
+ read_http_fetch_request(L, req);
+
+ actionstream << "Mod performs HTTP request with URL " << req.url << std::endl;
+ httpfetch_async(req);
+
+ // Convert handle to hex string since lua can't handle 64-bit integers
+ std::stringstream handle_conversion_stream;
+ handle_conversion_stream << std::hex << req.caller;
+ std::string caller_handle(handle_conversion_stream.str());
+
+ lua_pushstring(L, caller_handle.c_str());
+ return 1;
+}
+
+// http_api.fetch_async_get(handle)
+int ModApiHttp::l_http_fetch_async_get(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ std::string handle_str = luaL_checkstring(L, 1);
+
+ // Convert hex string back to 64-bit handle
+ u64 handle;
+ std::stringstream handle_conversion_stream;
+ handle_conversion_stream << std::hex << handle_str;
+ handle_conversion_stream >> handle;
+
+ HTTPFetchResult res;
+ bool completed = httpfetch_async_get(handle, res);
+
+ push_http_fetch_result(L, res, completed);
+
+ return 1;
+}
+
+int ModApiHttp::l_request_http_api(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ // We have to make sure that this function is being called directly by
+ // a mod, otherwise a malicious mod could override this function and
+ // steal its return value.
+ lua_Debug info;
+
+ // Make sure there's only one item below this function on the stack...
+ if (lua_getstack(L, 2, &info)) {
+ return 0;
+ }
+ FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
+ FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
+
+ // ...and that that item is the main file scope.
+ if (strcmp(info.what, "main") != 0) {
+ return 0;
+ }
+
+ // Mod must be listed in secure.http_mods or secure.trusted_mods
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
+ if (!lua_isstring(L, -1)) {
+ return 0;
+ }
+
+ const char *mod_name = lua_tostring(L, -1);
+ std::string http_mods = g_settings->get("secure.http_mods");
+ http_mods.erase(std::remove(http_mods.begin(), http_mods.end(), ' '), http_mods.end());
+ std::vector<std::string> mod_list_http = str_split(http_mods, ',');
+
+ std::string trusted_mods = g_settings->get("secure.trusted_mods");
+ trusted_mods.erase(std::remove(trusted_mods.begin(), trusted_mods.end(), ' '), trusted_mods.end());
+ std::vector<std::string> mod_list_trusted = str_split(trusted_mods, ',');
+
+ mod_list_http.insert(mod_list_http.end(), mod_list_trusted.begin(), mod_list_trusted.end());
+ if (std::find(mod_list_http.begin(), mod_list_http.end(), mod_name) == mod_list_http.end()) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "http_add_fetch");
+
+ lua_newtable(L);
+ HTTP_API(fetch_async);
+ HTTP_API(fetch_async_get);
+
+ // Stack now looks like this:
+ // <core.http_add_fetch> <table with fetch_async, fetch_async_get>
+ // Now call core.http_add_fetch to append .fetch(request, callback) to table
+ lua_call(L, 1, 1);
+
+ return 1;
+}
+#endif
+
+void ModApiHttp::Initialize(lua_State *L, int top)
+{
+#if USE_CURL
+ API_FCT(request_http_api);
+#endif
+}
diff --git a/src/script/lua_api/l_http.h b/src/script/lua_api/l_http.h
new file mode 100644
index 000000000..077ade691
--- /dev/null
+++ b/src/script/lua_api/l_http.h
@@ -0,0 +1,50 @@
+/*
+Minetest
+Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+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 L_HTTP_H_
+#define L_HTTP_H_
+
+#include "lua_api/l_base.h"
+#include "config.h"
+
+struct HTTPFetchRequest;
+struct HTTPFetchResult;
+
+class ModApiHttp : public ModApiBase {
+private:
+#if USE_CURL
+ // Helpers for HTTP fetch functions
+ static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req);
+ static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true);
+
+ // http_fetch_async({url=, timeout=, post_data=})
+ static int l_http_fetch_async(lua_State *L);
+
+ // http_fetch_async_get(handle)
+ static int l_http_fetch_async_get(lua_State *L);
+
+ // request_http_api()
+ static int l_request_http_api(lua_State *L);
+#endif
+
+public:
+ static void Initialize(lua_State *L, int top);
+};
+
+#endif /* L_HTTP_H_ */
diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h
index 1e40c5c4a..456c8fcce 100644
--- a/src/script/lua_api/l_internal.h
+++ b/src/script/lua_api/l_internal.h
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define API_FCT(name) registerFunction(L, #name, l_##name,top)
#define ASYNC_API_FCT(name) engine.registerFunction(#name, l_##name)
+#define MAP_LOCK_REQUIRED
#define NO_MAP_LOCK_REQUIRED
/*
@@ -45,4 +46,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif
*/
+#define GET_ENV_PTR_NO_MAP_LOCK \
+ ServerEnvironment *env = (ServerEnvironment *)getEnv(L); \
+ if (env == NULL) \
+ return 0
+
+#define GET_ENV_PTR \
+ MAP_LOCK_REQUIRED; \
+ GET_ENV_PTR_NO_MAP_LOCK
+
#endif /* L_INTERNAL_H_ */
diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp
index f48f6083b..de9f9374a 100644
--- a/src/script/lua_api/l_inventory.cpp
+++ b/src/script/lua_api/l_inventory.cpp
@@ -491,6 +491,7 @@ int ModApiInventory::l_get_inventory(lua_State *L)
std::string type = checkstringfield(L, 1, "type");
if(type == "node"){
+ MAP_LOCK_REQUIRED;
lua_getfield(L, 1, "pos");
v3s16 pos = check_v3s16(L, -1);
loc.setNodeMeta(pos);
@@ -514,7 +515,7 @@ int ModApiInventory::l_get_inventory(lua_State *L)
InvRef::create(L, loc);
else
lua_pushnil(L);
- return 1;
+ return 1;
// END NO_MAP_LOCK_REQUIRED;
}
}
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index 842b15709..5381cba76 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -94,7 +94,7 @@ int LuaItemStack::l_set_count(lua_State *L)
bool status;
lua_Integer count = luaL_checkinteger(L, 2);
- if (count <= 65535) {
+ if (count > 0 && count <= 65535) {
item.count = count;
status = true;
} else {
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 92311d6fc..7b29db159 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -706,16 +706,13 @@ int ModApiMainMenu::l_set_topleft_text(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
{
- lua_newtable(L);
-
- std::list<const char *> names;
- EmergeManager::getMapgenNames(names);
+ std::vector<const char *> names;
+ EmergeManager::getMapgenNames(&names, lua_toboolean(L, 1));
- int i = 1;
- for (std::list<const char *>::const_iterator
- it = names.begin(); it != names.end(); ++it) {
- lua_pushstring(L, *it);
- lua_rawseti(L, -2, i++);
+ lua_newtable(L);
+ for (size_t i = 0; i != names.size(); i++) {
+ lua_pushstring(L, names[i]);
+ lua_rawseti(L, -2, i + 1);
}
return 1;
@@ -725,8 +722,8 @@ int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_modpath(lua_State *L)
{
- std::string modpath
- = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
+ std::string modpath = fs::RemoveRelativePathComponents(
+ porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
lua_pushstring(L, modpath.c_str());
return 1;
}
@@ -734,8 +731,8 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_gamepath(lua_State *L)
{
- std::string gamepath
- = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "games" + DIR_DELIM);
+ std::string gamepath = fs::RemoveRelativePathComponents(
+ porting::path_user + DIR_DELIM + "games" + DIR_DELIM);
lua_pushstring(L, gamepath.c_str());
return 1;
}
@@ -743,44 +740,46 @@ int ModApiMainMenu::l_get_gamepath(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_texturepath(lua_State *L)
{
- std::string gamepath
- = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "textures");
+ std::string gamepath = fs::RemoveRelativePathComponents(
+ porting::path_user + DIR_DELIM + "textures");
lua_pushstring(L, gamepath.c_str());
return 1;
}
int ModApiMainMenu::l_get_texturepath_share(lua_State *L)
{
- std::string gamepath
- = fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "textures");
+ std::string gamepath = fs::RemoveRelativePathComponents(
+ porting::path_share + DIR_DELIM + "textures");
lua_pushstring(L, gamepath.c_str());
return 1;
}
/******************************************************************************/
int ModApiMainMenu::l_create_dir(lua_State *L) {
- const char *path = luaL_checkstring(L, 1);
+ const char *path = luaL_checkstring(L, 1);
if (ModApiMainMenu::isMinetestPath(path)) {
- lua_pushboolean(L,fs::CreateAllDirs(path));
+ lua_pushboolean(L, fs::CreateAllDirs(path));
return 1;
}
- lua_pushboolean(L,false);
+
+ lua_pushboolean(L, false);
return 1;
}
/******************************************************************************/
int ModApiMainMenu::l_delete_dir(lua_State *L)
{
- const char *path = luaL_checkstring(L, 1);
+ const char *path = luaL_checkstring(L, 1);
std::string absolute_path = fs::RemoveRelativePathComponents(path);
if (ModApiMainMenu::isMinetestPath(absolute_path)) {
- lua_pushboolean(L,fs::RecursiveDelete(absolute_path));
+ lua_pushboolean(L, fs::RecursiveDelete(absolute_path));
return 1;
}
- lua_pushboolean(L,false);
+
+ lua_pushboolean(L, false);
return 1;
}
@@ -1060,8 +1059,8 @@ int ModApiMainMenu::l_get_video_modes(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_gettext(lua_State *L)
{
- std::wstring wtext = wstrgettext((std::string) luaL_checkstring(L, 1));
- lua_pushstring(L, wide_to_utf8(wtext).c_str());
+ std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
+ lua_pushstring(L, text.c_str());
return 1;
}
@@ -1096,7 +1095,9 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_min_supp_proto(lua_State *L)
{
- lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MIN);
+ u16 proto_version_min = g_settings->getFlag("send_pre_v25_init") ?
+ CLIENT_PROTOCOL_VERSION_MIN_LEGACY : CLIENT_PROTOCOL_VERSION_MIN;
+ lua_pushinteger(L, proto_version_min);
return 1;
}
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index 9c1fed272..405af25e8 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -119,8 +119,6 @@ private:
static int l_get_texturepath_share(lua_State *L);
- static int l_get_dirlist(lua_State *L);
-
static int l_create_dir(lua_State *L);
static int l_delete_dir(lua_State *L);
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index d30b68054..fb839176b 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -70,6 +70,7 @@ struct EnumString ModApiMapgen::es_OreType[] =
{
{ORE_SCATTER, "scatter"},
{ORE_SHEET, "sheet"},
+ {ORE_PUFF, "puff"},
{ORE_BLOB, "blob"},
{ORE_VEIN, "vein"},
{0, NULL},
@@ -449,10 +450,38 @@ size_t get_biome_list(lua_State *L, int index,
///////////////////////////////////////////////////////////////////////////////
+// get_biome_id(biomename)
+// returns the biome id used in biomemap
+int ModApiMapgen::l_get_biome_id(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ const char *biome_str = lua_tostring(L, 1);
+ if (!biome_str)
+ return 0;
+
+ BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
+
+ if (!bmgr)
+ return 0;
+
+ Biome *biome = (Biome *)bmgr->getByName(biome_str);
+
+ if (!biome || biome->index == OBJDEF_INVALID_INDEX)
+ return 0;
+
+ lua_pushinteger(L, biome->index);
+
+ return 1;
+}
+
+
// get_mapgen_object(objectname)
// returns the requested object used during map generation
int ModApiMapgen::l_get_mapgen_object(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
const char *mgobjstr = lua_tostring(L, 1);
int mgobjint;
@@ -464,7 +493,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
EmergeManager *emerge = getServer(L)->getEmergeManager();
Mapgen *mg = emerge->getCurrentMapgen();
if (!mg)
- return 0;
+ throw LuaError("Must only be called in a mapgen thread!");
size_t maplen = mg->csize.X * mg->csize.Z;
@@ -563,6 +592,8 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
int ModApiMapgen::l_get_mapgen_params(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
MapgenParams *params = &getServer(L)->getEmergeManager()->params;
lua_newtable(L);
@@ -579,7 +610,7 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
lua_pushinteger(L, params->chunksize);
lua_setfield(L, -2, "chunksize");
- std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, (u32)-1);
+ std::string flagstr = writeFlagString(params->flags, flagdesc_mapgen, U32_MAX);
lua_pushstring(L, flagstr.c_str());
lua_setfield(L, -2, "flags");
@@ -591,10 +622,16 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
// set mapgen parameters
int ModApiMapgen::l_set_mapgen_params(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
if (!lua_istable(L, 1))
return 0;
- MapgenParams *params = &getServer(L)->getEmergeManager()->params;
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+ if (emerge->isRunning())
+ throw LuaError("Cannot set parameters while mapgen is running");
+
+ MapgenParams *params = &emerge->params;
u32 flags = 0, flagmask = 0;
lua_getfield(L, 1, "mgname");
@@ -612,6 +649,10 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)
if (lua_isnumber(L, -1))
params->water_level = lua_tointeger(L, -1);
+ lua_getfield(L, 1, "chunksize");
+ if (lua_isnumber(L, -1))
+ params->chunksize = lua_tointeger(L, -1);
+
warn_if_field_exists(L, 1, "flagmask",
"Deprecated: flags field now includes unset flags.");
lua_getfield(L, 1, "flagmask");
@@ -631,6 +672,8 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)
// set global config values for noise parameters
int ModApiMapgen::l_set_noiseparams(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
const char *name = luaL_checkstring(L, 1);
NoiseParams np;
@@ -648,6 +691,8 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L)
// get_noiseparams(name)
int ModApiMapgen::l_get_noiseparams(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
std::string name = luaL_checkstring(L, 1);
NoiseParams np;
@@ -662,6 +707,8 @@ int ModApiMapgen::l_get_noiseparams(lua_State *L)
// set_gen_notify(flags, {deco_id_table})
int ModApiMapgen::l_set_gen_notify(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
u32 flags = 0, flagmask = 0;
EmergeManager *emerge = getServer(L)->getEmergeManager();
@@ -686,6 +733,8 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L)
// get_gen_notify()
int ModApiMapgen::l_get_gen_notify(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
EmergeManager *emerge = getServer(L)->getEmergeManager();
push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on,
emerge->gen_notify_on);
@@ -705,6 +754,8 @@ int ModApiMapgen::l_get_gen_notify(lua_State *L)
// register_biome({lots of stuff})
int ModApiMapgen::l_register_biome(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
int index = 1;
luaL_checktype(L, index, LUA_TTABLE);
@@ -729,6 +780,8 @@ int ModApiMapgen::l_register_biome(lua_State *L)
// register_decoration({lots of stuff})
int ModApiMapgen::l_register_decoration(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
int index = 1;
luaL_checktype(L, index, LUA_TTABLE);
@@ -869,6 +922,8 @@ bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic
// register_ore({lots of stuff})
int ModApiMapgen::l_register_ore(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
int index = 1;
luaL_checktype(L, index, LUA_TTABLE);
@@ -880,7 +935,7 @@ int ModApiMapgen::l_register_ore(lua_State *L)
"ore_type", es_OreType, ORE_SCATTER);
Ore *ore = oremgr->create(oretype);
if (!ore) {
- errorstream << "register_ore: ore_type " << oretype << " not implemented";
+ errorstream << "register_ore: ore_type " << oretype << " not implemented\n";
return 0;
}
@@ -889,10 +944,19 @@ int ModApiMapgen::l_register_ore(lua_State *L)
ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
ore->clust_size = getintfield_default(L, index, "clust_size", 0);
- ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0);
ore->noise = NULL;
ore->flags = 0;
+ //// Get noise_threshold
+ warn_if_field_exists(L, index, "noise_threshhold",
+ "Deprecated: new name is \"noise_threshold\".");
+
+ float nthresh;
+ if (!getfloatfield(L, index, "noise_threshold", nthresh) &&
+ !getfloatfield(L, index, "noise_threshhold", nthresh))
+ nthresh = 0;
+ ore->nthresh = nthresh;
+
//// Get y_min/y_max
warn_if_field_exists(L, index, "height_min",
"Deprecated: new name is \"y_min\".");
@@ -937,10 +1001,43 @@ int ModApiMapgen::l_register_ore(lua_State *L)
}
lua_pop(L, 1);
- if (oretype == ORE_VEIN) {
- OreVein *orevein = (OreVein *)ore;
- orevein->random_factor = getfloatfield_default(L, index,
- "random_factor", 1.f);
+ //// Get type-specific parameters
+ switch (oretype) {
+ case ORE_SHEET: {
+ OreSheet *oresheet = (OreSheet *)ore;
+
+ oresheet->column_height_min = getintfield_default(L, index,
+ "column_height_min", 1);
+ oresheet->column_height_max = getintfield_default(L, index,
+ "column_height_max", ore->clust_size);
+ oresheet->column_midpoint_factor = getfloatfield_default(L, index,
+ "column_midpoint_factor", 0.5f);
+
+ break;
+ }
+ case ORE_PUFF: {
+ OrePuff *orepuff = (OrePuff *)ore;
+
+ lua_getfield(L, index, "np_puff_top");
+ read_noiseparams(L, -1, &orepuff->np_puff_top);
+ lua_pop(L, 1);
+
+ lua_getfield(L, index, "np_puff_bottom");
+ read_noiseparams(L, -1, &orepuff->np_puff_bottom);
+ lua_pop(L, 1);
+
+ break;
+ }
+ case ORE_VEIN: {
+ OreVein *orevein = (OreVein *)ore;
+
+ orevein->random_factor = getfloatfield_default(L, index,
+ "random_factor", 1.f);
+
+ break;
+ }
+ default:
+ break;
}
ObjDefHandle handle = oremgr->add(ore);
@@ -964,6 +1061,8 @@ int ModApiMapgen::l_register_ore(lua_State *L)
// register_schematic({schematic}, replacements={})
int ModApiMapgen::l_register_schematic(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
StringMap replace_names;
@@ -989,6 +1088,8 @@ int ModApiMapgen::l_register_schematic(lua_State *L)
// clear_registered_biomes()
int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
bmgr->clear();
return 0;
@@ -998,6 +1099,8 @@ int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
// clear_registered_decorations()
int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
dmgr->clear();
return 0;
@@ -1007,6 +1110,8 @@ int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
// clear_registered_ores()
int ModApiMapgen::l_clear_registered_ores(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
omgr->clear();
return 0;
@@ -1016,6 +1121,8 @@ int ModApiMapgen::l_clear_registered_ores(lua_State *L)
// clear_registered_schematics()
int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr;
smgr->clear();
return 0;
@@ -1025,6 +1132,8 @@ int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
// generate_ores(vm, p1, p2, [ore_id])
int ModApiMapgen::l_generate_ores(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
EmergeManager *emerge = getServer(L)->getEmergeManager();
Mapgen mg;
@@ -1049,6 +1158,8 @@ int ModApiMapgen::l_generate_ores(lua_State *L)
// generate_decorations(vm, p1, p2, [deco_id])
int ModApiMapgen::l_generate_decorations(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
EmergeManager *emerge = getServer(L)->getEmergeManager();
Mapgen mg;
@@ -1073,6 +1184,8 @@ int ModApiMapgen::l_generate_decorations(lua_State *L)
// create_schematic(p1, p2, probability_list, filename, y_slice_prob_list)
int ModApiMapgen::l_create_schematic(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
const char *filename = luaL_checkstring(L, 4);
@@ -1136,6 +1249,8 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
// place_schematic(p, schematic, rotation, replacement)
int ModApiMapgen::l_place_schematic(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
Map *map = &(getEnv(L)->getMap());
SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
@@ -1165,15 +1280,59 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
return 0;
}
- schem->placeStructure(map, p, 0, (Rotation)rot, force_placement);
+ schem->placeOnMap(map, p, 0, (Rotation)rot, force_placement);
lua_pushboolean(L, true);
return 1;
}
+int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
+
+ //// Read VoxelManip object
+ MMVManip *vm = LuaVoxelManip::checkobject(L, 1)->vm;
+
+ //// Read position
+ v3s16 p = check_v3s16(L, 2);
+
+ //// Read rotation
+ int rot = ROTATE_0;
+ const char *enumstr = lua_tostring(L, 4);
+ if (enumstr)
+ string_to_enum(es_Rotation, rot, std::string(enumstr));
+
+ //// Read force placement
+ bool force_placement = true;
+ if (lua_isboolean(L, 6))
+ force_placement = lua_toboolean(L, 6);
+
+ //// Read node replacements
+ StringMap replace_names;
+ if (lua_istable(L, 5))
+ read_schematic_replacements(L, 5, &replace_names);
+
+ //// Read schematic
+ Schematic *schem = get_or_load_schematic(L, 3, schemmgr, &replace_names);
+ if (!schem) {
+ errorstream << "place_schematic: failed to get schematic" << std::endl;
+ return 0;
+ }
+
+ bool schematic_did_fit = schem->placeOnVManip(
+ vm, p, 0, (Rotation)rot, force_placement);
+
+ lua_pushboolean(L, schematic_did_fit);
+ return 1;
+}
+
// serialize_schematic(schematic, format, options={...})
int ModApiMapgen::l_serialize_schematic(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
//// Read options
@@ -1223,6 +1382,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L)
void ModApiMapgen::Initialize(lua_State *L, int top)
{
+ API_FCT(get_biome_id);
API_FCT(get_mapgen_object);
API_FCT(get_mapgen_params);
@@ -1246,5 +1406,6 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
API_FCT(generate_decorations);
API_FCT(create_schematic);
API_FCT(place_schematic);
+ API_FCT(place_schematic_on_vmanip);
API_FCT(serialize_schematic);
}
diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h
index 7440d1285..9751c0db6 100644
--- a/src/script/lua_api/l_mapgen.h
+++ b/src/script/lua_api/l_mapgen.h
@@ -24,6 +24,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ModApiMapgen : public ModApiBase {
private:
+ // get_biome_id(biomename)
+ // returns the biome id used in biomemap
+ static int l_get_biome_id(lua_State *L);
+
// get_mapgen_object(objectname)
// returns the requested object used during map generation
static int l_get_mapgen_object(lua_State *L);
@@ -81,9 +85,13 @@ private:
// create_schematic(p1, p2, probability_list, filename)
static int l_create_schematic(lua_State *L);
- // place_schematic(p, schematic, rotation, replacement)
+ // place_schematic(p, schematic, rotation, replacements, force_placement)
static int l_place_schematic(lua_State *L);
+ // place_schematic_on_vmanip(vm, p, schematic,
+ // rotation, replacements, force_placement)
+ static int l_place_schematic_on_vmanip(lua_State *L);
+
// serialize_schematic(schematic, format, options={...})
static int l_serialize_schematic(lua_State *L);
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 6cdbe5c68..c8bc7d558 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_content.h"
#include "environment.h"
#include "map.h"
+#include "gamedef.h"
#include "nodemetadata.h"
@@ -43,7 +44,7 @@ NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create)
{
NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p);
if(meta == NULL && auto_create) {
- meta = new NodeMetadata(ref->m_env->getGameDef());
+ meta = new NodeMetadata(ref->m_env->getGameDef()->idef());
if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) {
delete meta;
return NULL;
@@ -81,6 +82,8 @@ int NodeMetaRef::gc_object(lua_State *L) {
// get_string(self, name)
int NodeMetaRef::l_get_string(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
std::string name = luaL_checkstring(L, 2);
@@ -97,6 +100,8 @@ int NodeMetaRef::l_get_string(lua_State *L)
// set_string(self, name, var)
int NodeMetaRef::l_set_string(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
std::string name = luaL_checkstring(L, 2);
size_t len = 0;
@@ -114,6 +119,8 @@ int NodeMetaRef::l_set_string(lua_State *L)
// get_int(self, name)
int NodeMetaRef::l_get_int(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
@@ -130,6 +137,8 @@ int NodeMetaRef::l_get_int(lua_State *L)
// set_int(self, name, var)
int NodeMetaRef::l_set_int(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
int a = lua_tointeger(L, 3);
@@ -146,6 +155,8 @@ int NodeMetaRef::l_set_int(lua_State *L)
// get_float(self, name)
int NodeMetaRef::l_get_float(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
@@ -162,6 +173,8 @@ int NodeMetaRef::l_get_float(lua_State *L)
// set_float(self, name, var)
int NodeMetaRef::l_set_float(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
float a = lua_tonumber(L, 3);
@@ -178,6 +191,8 @@ int NodeMetaRef::l_set_float(lua_State *L)
// get_inventory(self)
int NodeMetaRef::l_get_inventory(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
getmeta(ref, true); // try to ensure the metadata exists
InvRef::createNodeMeta(L, ref->m_p);
@@ -187,6 +202,8 @@ int NodeMetaRef::l_get_inventory(lua_State *L)
// to_table(self)
int NodeMetaRef::l_to_table(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref, true);
@@ -229,6 +246,8 @@ int NodeMetaRef::l_to_table(lua_State *L)
// from_table(self, table)
int NodeMetaRef::l_from_table(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
NodeMetaRef *ref = checkobject(L, 1);
int base = 2;
diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp
index c81a7ebc9..601113516 100644
--- a/src/script/lua_api/l_nodetimer.cpp
+++ b/src/script/lua_api/l_nodetimer.cpp
@@ -39,6 +39,7 @@ NodeTimerRef* NodeTimerRef::checkobject(lua_State *L, int narg)
int NodeTimerRef::l_set(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
@@ -50,6 +51,7 @@ int NodeTimerRef::l_set(lua_State *L)
int NodeTimerRef::l_start(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
@@ -60,6 +62,7 @@ int NodeTimerRef::l_start(lua_State *L)
int NodeTimerRef::l_stop(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
@@ -69,6 +72,7 @@ int NodeTimerRef::l_stop(lua_State *L)
int NodeTimerRef::l_is_started(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
@@ -80,6 +84,7 @@ int NodeTimerRef::l_is_started(lua_State *L)
int NodeTimerRef::l_get_timeout(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
@@ -91,6 +96,7 @@ int NodeTimerRef::l_get_timeout(lua_State *L)
int NodeTimerRef::l_get_elapsed(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
NodeTimerRef *o = checkobject(L, 1);
ServerEnvironment *env = o->m_env;
if(env == NULL) return 0;
diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp
index c8dc2d2dc..04dc6048f 100644
--- a/src/script/lua_api/l_noise.cpp
+++ b/src/script/lua_api/l_noise.cpp
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h"
#include "common/c_content.h"
#include "log.h"
+#include "porting.h"
+#include "util/numeric.h"
///////////////////////////////////////
/*
@@ -410,6 +412,7 @@ const luaL_reg LuaPerlinNoiseMap::methods[] = {
int LuaPseudoRandom::l_next(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+
LuaPseudoRandom *o = checkobject(L, 1);
int min = 0;
int max = 32767;
@@ -437,7 +440,9 @@ int LuaPseudoRandom::l_next(lua_State *L)
int LuaPseudoRandom::create_object(lua_State *L)
{
- int seed = luaL_checknumber(L, 1);
+ NO_MAP_LOCK_REQUIRED;
+
+ u64 seed = luaL_checknumber(L, 1);
LuaPseudoRandom *o = new LuaPseudoRandom(seed);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
@@ -532,8 +537,10 @@ int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
int LuaPcgRandom::create_object(lua_State *L)
{
- lua_Integer seed = luaL_checknumber(L, 1);
- LuaPcgRandom *o = lua_isnumber(L, 2) ?
+ NO_MAP_LOCK_REQUIRED;
+
+ u64 seed = luaL_checknumber(L, 1);
+ LuaPcgRandom *o = lua_isnumber(L, 2) ?
new LuaPcgRandom(seed, lua_tointeger(L, 2)) :
new LuaPcgRandom(seed);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
@@ -595,3 +602,116 @@ const luaL_reg LuaPcgRandom::methods[] = {
luamethod(LuaPcgRandom, rand_normal_dist),
{0,0}
};
+
+///////////////////////////////////////
+/*
+ LuaSecureRandom
+*/
+
+bool LuaSecureRandom::fillRandBuf()
+{
+ return porting::secure_rand_fill_buf(m_rand_buf, RAND_BUF_SIZE);
+}
+
+int LuaSecureRandom::l_next_bytes(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaSecureRandom *o = checkobject(L, 1);
+ u32 count = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : 1;
+
+ // Limit count
+ count = MYMIN(RAND_BUF_SIZE, count);
+
+ // Find out whether we can pass directly from our array, or have to do some gluing
+ size_t count_remaining = RAND_BUF_SIZE - o->m_rand_idx;
+ if (count_remaining >= count) {
+ lua_pushlstring(L, o->m_rand_buf + o->m_rand_idx, count);
+ o->m_rand_idx += count;
+ } else {
+ char output_buf[RAND_BUF_SIZE];
+
+ // Copy over with what we have left from our current buffer
+ memcpy(output_buf, o->m_rand_buf + o->m_rand_idx, count_remaining);
+
+ // Refill buffer and copy over the remainder of what was requested
+ o->fillRandBuf();
+ memcpy(output_buf + count_remaining, o->m_rand_buf, count - count_remaining);
+
+ // Update index
+ o->m_rand_idx = count - count_remaining;
+
+ lua_pushlstring(L, output_buf, count);
+ }
+
+ return 1;
+}
+
+
+int LuaSecureRandom::create_object(lua_State *L)
+{
+ LuaSecureRandom *o = new LuaSecureRandom();
+
+ // Fail and return nil if we can't securely fill the buffer
+ if (!o->fillRandBuf()) {
+ delete o;
+ return 0;
+ }
+
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+
+int LuaSecureRandom::gc_object(lua_State *L)
+{
+ LuaSecureRandom *o = *(LuaSecureRandom **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+
+LuaSecureRandom *LuaSecureRandom::checkobject(lua_State *L, int narg)
+{
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+ return *(LuaSecureRandom **)ud;
+}
+
+
+void LuaSecureRandom::Register(lua_State *L)
+{
+ lua_newtable(L);
+ int methodtable = lua_gettop(L);
+ luaL_newmetatable(L, className);
+ int metatable = lua_gettop(L);
+
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, methodtable);
+ lua_settable(L, metatable);
+
+ lua_pushliteral(L, "__gc");
+ lua_pushcfunction(L, gc_object);
+ lua_settable(L, metatable);
+
+ lua_pop(L, 1);
+
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
+
+ lua_register(L, className, create_object);
+}
+
+const char LuaSecureRandom::className[] = "SecureRandom";
+const luaL_reg LuaSecureRandom::methods[] = {
+ luamethod(LuaSecureRandom, next_bytes),
+ {0,0}
+};
diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h
index e958c5a23..492eb7550 100644
--- a/src/script/lua_api/l_noise.h
+++ b/src/script/lua_api/l_noise.h
@@ -160,4 +160,37 @@ public:
static void Register(lua_State *L);
};
+
+/*
+ LuaSecureRandom
+*/
+class LuaSecureRandom : public ModApiBase {
+private:
+ static const size_t RAND_BUF_SIZE = 2048;
+ static const char className[];
+ static const luaL_reg methods[];
+
+ u32 m_rand_idx;
+ char m_rand_buf[RAND_BUF_SIZE];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // next_bytes(self, count) -> get count many bytes
+ static int l_next_bytes(lua_State *L);
+
+public:
+ bool fillRandBuf();
+
+ // LuaSecureRandom()
+ // Creates an LuaSecureRandom and leaves it on top of stack
+ static int create_object(lua_State *L);
+
+ static LuaSecureRandom *checkobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
#endif /* L_NOISE_H_ */
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index 3ac8eeefb..6d6614e7d 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -31,10 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "scripting_game.h"
-#define GET_ENV_PTR ServerEnvironment* env = \
- dynamic_cast<ServerEnvironment*>(getEnv(L)); \
- if (env == NULL) return 0
-
struct EnumString es_HudElementType[] =
{
{HUD_ELEM_IMAGE, "image"},
@@ -132,7 +128,6 @@ int ObjectRef::gc_object(lua_State *L) {
// remove(self)
int ObjectRef::l_remove(lua_State *L)
{
- NO_MAP_LOCK_REQUIRED;
GET_ENV_PTR;
ObjectRef *ref = checkobject(L, 1);
@@ -409,6 +404,7 @@ int ObjectRef::l_get_armor_groups(lua_State *L)
// physics_override_gravity, sneak, sneak_glitch)
int ObjectRef::l_set_physics_override(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO *co = (PlayerSAO *) getobject(ref);
if (co == NULL) return 0;
@@ -441,6 +437,7 @@ int ObjectRef::l_set_physics_override(lua_State *L)
// get_physics_override(self)
int ObjectRef::l_get_physics_override(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO *co = (PlayerSAO *)getobject(ref);
if (co == NULL)
@@ -509,7 +506,7 @@ int ObjectRef::l_get_animation(lua_State *L)
// set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed)
int ObjectRef::l_set_local_animation(lua_State *L)
{
- //NO_MAP_LOCK_REQUIRED;
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -534,7 +531,7 @@ int ObjectRef::l_set_local_animation(lua_State *L)
// get_local_animation(self)
int ObjectRef::l_get_local_animation(lua_State *L)
{
- //NO_MAP_LOCK_REQUIRED
+ NO_MAP_LOCK_REQUIRED
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -555,7 +552,7 @@ int ObjectRef::l_get_local_animation(lua_State *L)
// set_eye_offset(self, v3f first pv, v3f third pv)
int ObjectRef::l_set_eye_offset(lua_State *L)
{
- //NO_MAP_LOCK_REQUIRED;
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -585,7 +582,7 @@ int ObjectRef::l_set_eye_offset(lua_State *L)
// get_eye_offset(self)
int ObjectRef::l_get_eye_offset(lua_State *L)
{
- //NO_MAP_LOCK_REQUIRED;
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -642,7 +639,6 @@ int ObjectRef::l_get_bone_position(lua_State *L)
// set_attach(self, parent, bone, position, rotation)
int ObjectRef::l_set_attach(lua_State *L)
{
- NO_MAP_LOCK_REQUIRED;
GET_ENV_PTR;
ObjectRef *ref = checkobject(L, 1);
@@ -681,7 +677,6 @@ int ObjectRef::l_set_attach(lua_State *L)
// get_attach(self)
int ObjectRef::l_get_attach(lua_State *L)
{
- NO_MAP_LOCK_REQUIRED;
GET_ENV_PTR;
ObjectRef *ref = checkobject(L, 1);
@@ -709,7 +704,6 @@ int ObjectRef::l_get_attach(lua_State *L)
// set_detach(self)
int ObjectRef::l_set_detach(lua_State *L)
{
- NO_MAP_LOCK_REQUIRED;
GET_ENV_PTR;
ObjectRef *ref = checkobject(L, 1);
@@ -773,6 +767,59 @@ int ObjectRef::l_is_player(lua_State *L)
return 1;
}
+// set_nametag_attributes(self, attributes)
+int ObjectRef::l_set_nametag_attributes(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+
+ if (co == NULL)
+ return 0;
+ ObjectProperties *prop = co->accessObjectProperties();
+ if (!prop)
+ return 0;
+
+ lua_getfield(L, 2, "color");
+ if (!lua_isnil(L, -1)) {
+ video::SColor color = prop->nametag_color;
+ read_color(L, -1, &color);
+ prop->nametag_color = color;
+ }
+ lua_pop(L, 1);
+
+ std::string nametag = getstringfield_default(L, 2, "text", "");
+ if (nametag != "")
+ prop->nametag = nametag;
+
+ co->notifyObjectPropertiesModified();
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// get_nametag_attributes(self)
+int ObjectRef::l_get_nametag_attributes(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+
+ if (co == NULL)
+ return 0;
+ ObjectProperties *prop = co->accessObjectProperties();
+ if (!prop)
+ return 0;
+
+ video::SColor color = prop->nametag_color;
+
+ lua_newtable(L);
+ push_ARGB8(L, color);
+ lua_setfield(L, -2, "color");
+ lua_pushstring(L, prop->nametag.c_str());
+ lua_setfield(L, -2, "text");
+ return 1;
+}
+
/* LuaEntitySAO-only */
// setvelocity(self, {x=num, y=num, z=num})
@@ -1137,6 +1184,7 @@ int ObjectRef::l_get_player_control_bits(lua_State *L)
// hud_add(self, form)
int ObjectRef::l_hud_add(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1187,7 +1235,7 @@ int ObjectRef::l_hud_add(lua_State *L)
}
u32 id = getServer(L)->hudAdd(player, elem);
- if (id == (u32)-1) {
+ if (id == U32_MAX) {
delete elem;
return 0;
}
@@ -1199,6 +1247,7 @@ int ObjectRef::l_hud_add(lua_State *L)
// hud_remove(self, id)
int ObjectRef::l_hud_remove(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1218,6 +1267,7 @@ int ObjectRef::l_hud_remove(lua_State *L)
// hud_change(self, id, stat, data)
int ObjectRef::l_hud_change(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1294,6 +1344,7 @@ int ObjectRef::l_hud_change(lua_State *L)
// hud_get(self, id)
int ObjectRef::l_hud_get(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1344,6 +1395,7 @@ int ObjectRef::l_hud_get(lua_State *L)
// hud_set_flags(self, flags)
int ObjectRef::l_hud_set_flags(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1369,6 +1421,7 @@ int ObjectRef::l_hud_set_flags(lua_State *L)
int ObjectRef::l_hud_get_flags(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1394,6 +1447,7 @@ int ObjectRef::l_hud_get_flags(lua_State *L)
// hud_set_hotbar_itemcount(self, hotbar_itemcount)
int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1411,6 +1465,7 @@ int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
// hud_get_hotbar_itemcount(self)
int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1425,6 +1480,7 @@ int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
// hud_set_hotbar_image(self, name)
int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1439,6 +1495,7 @@ int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
// hud_get_hotbar_image(self)
int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1452,6 +1509,7 @@ int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
// hud_set_hotbar_selected_image(self, name)
int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1466,6 +1524,7 @@ int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
// hud_get_hotbar_selected_image(self)
int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1479,6 +1538,7 @@ int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
// set_sky(self, bgcolor, type, list)
int ObjectRef::l_set_sky(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1517,6 +1577,7 @@ int ObjectRef::l_set_sky(lua_State *L)
// get_sky(self)
int ObjectRef::l_get_sky(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1544,6 +1605,7 @@ int ObjectRef::l_get_sky(lua_State *L)
// override_day_night_ratio(self, brightness=0...1)
int ObjectRef::l_override_day_night_ratio(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1566,6 +1628,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
// get_day_night_ratio(self)
int ObjectRef::l_get_day_night_ratio(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
if (player == NULL)
@@ -1583,45 +1646,6 @@ int ObjectRef::l_get_day_night_ratio(lua_State *L)
return 1;
}
-// set_nametag_attributes(self, attributes)
-int ObjectRef::l_set_nametag_attributes(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- ObjectRef *ref = checkobject(L, 1);
- PlayerSAO *playersao = getplayersao(ref);
- if (playersao == NULL)
- return 0;
-
- lua_getfield(L, 2, "color");
- if (!lua_isnil(L, -1)) {
- video::SColor color = playersao->getNametagColor();
- if (!read_color(L, -1, &color))
- return 0;
- playersao->setNametagColor(color);
- }
-
- lua_pushboolean(L, true);
- return 1;
-}
-
-// get_nametag_attributes(self)
-int ObjectRef::l_get_nametag_attributes(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- ObjectRef *ref = checkobject(L, 1);
- PlayerSAO *playersao = getplayersao(ref);
- if (playersao == NULL)
- return 0;
-
- video::SColor color = playersao->getNametagColor();
-
- lua_newtable(L);
- push_ARGB8(L, color);
- lua_setfield(L, -2, "color");
-
- return 1;
-}
-
ObjectRef::ObjectRef(ServerActiveObject *object):
m_object(object)
{
@@ -1709,6 +1733,8 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_detach),
luamethod(ObjectRef, set_properties),
luamethod(ObjectRef, get_properties),
+ luamethod(ObjectRef, set_nametag_attributes),
+ luamethod(ObjectRef, get_nametag_attributes),
// LuaEntitySAO-only
luamethod(ObjectRef, setvelocity),
luamethod(ObjectRef, getvelocity),
@@ -1758,7 +1784,5 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_local_animation),
luamethod(ObjectRef, set_eye_offset),
luamethod(ObjectRef, get_eye_offset),
- luamethod(ObjectRef, set_nametag_attributes),
- luamethod(ObjectRef, get_nametag_attributes),
{0,0}
};
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index 2532b2b08..f6c1725de 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// texture = e.g."default_wood.png"
int ModApiParticles::l_add_particle(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
// Get parameters
v3f pos, vel, acc;
pos = vel = acc = v3f(0, 0, 0);
@@ -119,6 +121,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
// texture = e.g."default_wood.png"
int ModApiParticles::l_add_particlespawner(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
// Get parameters
u16 amount = 1;
v3f minpos, maxpos, minvel, maxvel, minacc, maxacc;
@@ -208,6 +212,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
// player (string) is optional
int ModApiParticles::l_delete_particlespawner(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
// Get parameters
u32 id = luaL_checknumber(L, 1);
std::string playername = "";
diff --git a/src/script/lua_api/l_rollback.cpp b/src/script/lua_api/l_rollback.cpp
index 5744e6813..482b0cbf5 100644
--- a/src/script/lua_api/l_rollback.cpp
+++ b/src/script/lua_api/l_rollback.cpp
@@ -38,6 +38,8 @@ void push_RollbackNode(lua_State *L, RollbackNode &node)
// rollback_get_node_actions(pos, range, seconds, limit) -> {{actor, pos, time, oldnode, newnode}, ...}
int ModApiRollback::l_rollback_get_node_actions(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
v3s16 pos = read_v3s16(L, 1);
int range = luaL_checknumber(L, 2);
time_t seconds = (time_t) luaL_checknumber(L, 3);
@@ -79,6 +81,8 @@ int ModApiRollback::l_rollback_get_node_actions(lua_State *L)
// rollback_revert_actions_by(actor, seconds) -> bool, log messages
int ModApiRollback::l_rollback_revert_actions_by(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
std::string actor = luaL_checkstring(L, 1);
int seconds = luaL_checknumber(L, 2);
Server *server = getServer(L);
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 73eca9d60..59d3f5c70 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// request_shutdown()
int ModApiServer::l_request_shutdown(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
const char *msg = lua_tolstring(L, 1, NULL);
bool reconnect = lua_toboolean(L, 2);
getServer(L)->requestShutdown(msg ? msg : "", reconnect);
@@ -44,6 +45,16 @@ int ModApiServer::l_get_server_status(lua_State *L)
return 1;
}
+// print(text)
+int ModApiServer::l_print(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ std::string text;
+ text = luaL_checkstring(L, 1);
+ getServer(L)->printToConsoleOnly(text);
+ return 0;
+}
+
// chat_send_all(text)
int ModApiServer::l_chat_send_all(lua_State *L)
{
@@ -110,7 +121,7 @@ int ModApiServer::l_get_player_ip(lua_State *L)
}
catch(con::PeerNotFoundException) // unlikely
{
- dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
+ dstream << FUNCTION_NAME << ": peer was not found" << std::endl;
lua_pushnil(L); // error
return 1;
}
@@ -136,7 +147,7 @@ int ModApiServer::l_get_player_information(lua_State *L)
}
catch(con::PeerNotFoundException) // unlikely
{
- dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
+ dstream << FUNCTION_NAME << ": peer was not found" << std::endl;
lua_pushnil(L); // error
return 1;
}
@@ -150,7 +161,7 @@ int ModApiServer::l_get_player_information(lua_State *L)
#define ERET(code) \
if (!(code)) { \
- dstream << __FUNCTION_NAME << ": peer was not found" << std::endl; \
+ dstream << FUNCTION_NAME << ": peer was not found" << std::endl; \
lua_pushnil(L); /* error */ \
return 1; \
}
@@ -281,7 +292,7 @@ int ModApiServer::l_ban_player(lua_State *L)
}
catch(con::PeerNotFoundException) // unlikely
{
- dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
+ dstream << FUNCTION_NAME << ": peer was not found" << std::endl;
lua_pushboolean(L, false); // error
return 1;
}
@@ -345,7 +356,7 @@ int ModApiServer::l_show_formspec(lua_State *L)
int ModApiServer::l_get_current_modname(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
return 1;
}
@@ -442,7 +453,7 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L)
int ModApiServer::l_get_last_run_mod(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
const char *current_mod = lua_tostring(L, -1);
if (current_mod == NULL || current_mod[0] == '\0') {
lua_pop(L, 1);
@@ -504,6 +515,8 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(get_modpath);
API_FCT(get_modnames);
+ API_FCT(print);
+
API_FCT(chat_send_all);
API_FCT(chat_send_player);
API_FCT(show_formspec);
diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h
index df31f325f..06a5ddc24 100644
--- a/src/script/lua_api/l_server.h
+++ b/src/script/lua_api/l_server.h
@@ -46,6 +46,9 @@ private:
// the returned list is sorted alphabetically for you
static int l_get_modnames(lua_State *L);
+ // print(text)
+ static int l_print(lua_State *L);
+
// chat_send_all(text)
static int l_chat_send_all(lua_State *L);
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 12146e80a..c3e6c8964 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -25,9 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serialization.h"
#include "json/json.h"
#include "cpp_api/s_security.h"
-#include "areastore.h"
-#include "debug.h"
#include "porting.h"
+#include "debug.h"
#include "log.h"
#include "tool.h"
#include "filesys.h"
@@ -35,70 +34,49 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/auth.h"
#include <algorithm>
-// debug(...)
-// Writes a line to dstream
-int ModApiUtil::l_debug(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- // Handle multiple parameters to behave like standard lua print()
- int n = lua_gettop(L);
- lua_getglobal(L, "tostring");
- for (int i = 1; i <= n; i++) {
- /*
- Call tostring(i-th argument).
- This is what print() does, and it behaves a bit
- differently from directly calling lua_tostring.
- */
- lua_pushvalue(L, -1); /* function to be called */
- lua_pushvalue(L, i); /* value to print */
- lua_call(L, 1, 1);
- size_t len;
- const char *s = lua_tolstring(L, -1, &len);
- if (i > 1)
- dstream << "\t";
- if (s)
- dstream << std::string(s, len);
- lua_pop(L, 1);
- }
- dstream << std::endl;
- return 0;
-}
-
// log([level,] text)
// Writes a line to the logger.
// The one-argument version logs to infostream.
-// The two-argument version accept a log level: error, action, info, or verbose.
+// The two-argument version accepts a log level.
+// Either the special case "deprecated" for deprecation notices, or any specified in
+// Logger::stringToLevel(name).
int ModApiUtil::l_log(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::string text;
- LogMessageLevel level = LMT_INFO;
+ LogLevel level = LL_NONE;
if (lua_isnone(L, 2)) {
- text = lua_tostring(L, 1);
- }
- else {
- std::string levelname = luaL_checkstring(L, 1);
+ text = luaL_checkstring(L, 1);
+ } else {
+ std::string name = luaL_checkstring(L, 1);
text = luaL_checkstring(L, 2);
- if(levelname == "error")
- level = LMT_ERROR;
- else if(levelname == "action")
- level = LMT_ACTION;
- else if(levelname == "verbose")
- level = LMT_VERBOSE;
- else if (levelname == "deprecated") {
- log_deprecated(L,text);
+ if (name == "deprecated") {
+ log_deprecated(L, text);
return 0;
}
-
+ level = Logger::stringToLevel(name);
+ if (level == LL_MAX) {
+ warningstream << "Tried to log at unknown level '" << name
+ << "'. Defaulting to \"none\"." << std::endl;
+ level = LL_NONE;
+ }
}
- log_printline(level, text);
+ g_logger.log(level, text);
return 0;
}
+// get_us_time()
+int ModApiUtil::l_get_us_time(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ lua_pushnumber(L, porting::getTimeUs());
+ return 1;
+}
+
#define CHECK_SECURE_SETTING(L, name) \
- if (name.compare(0, 7, "secure.") == 0) {\
- lua_pushliteral(L, "Attempt to set secure setting.");\
- lua_error(L);\
+ if (ScriptApiSecurity::isSecure(L) && \
+ name.compare(0, 7, "secure.") == 0) { \
+ throw LuaError("Attempt to set secure setting."); \
}
// setting_set(name, value)
@@ -183,8 +161,14 @@ int ModApiUtil::l_parse_json(lua_State *L)
if (!reader.parse(stream, root)) {
errorstream << "Failed to parse json data "
<< reader.getFormattedErrorMessages();
- errorstream << "data: \"" << jsonstr << "\""
- << std::endl;
+ size_t jlen = strlen(jsonstr);
+ if (jlen > 100) {
+ errorstream << "Data (" << jlen
+ << " bytes) printed to warningstream." << std::endl;
+ warningstream << "data: \"" << jsonstr << "\"" << std::endl;
+ } else {
+ errorstream << "data: \"" << jsonstr << "\"" << std::endl;
+ }
lua_pushnil(L);
return 1;
}
@@ -267,7 +251,7 @@ int ModApiUtil::l_get_password_hash(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string name = luaL_checkstring(L, 1);
std::string raw_password = luaL_checkstring(L, 2);
- std::string hash = translatePassword(name, raw_password);
+ std::string hash = translate_password(name, raw_password);
lua_pushstring(L, hash.c_str());
return 1;
}
@@ -290,6 +274,8 @@ int ModApiUtil::l_is_yes(lua_State *L)
int ModApiUtil::l_get_builtin_path(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
std::string path = porting::path_share + DIR_DELIM + "builtin";
lua_pushstring(L, path.c_str());
return 1;
@@ -298,6 +284,8 @@ int ModApiUtil::l_get_builtin_path(lua_State *L)
// compress(data, method, level)
int ModApiUtil::l_compress(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
size_t size;
const char *data = luaL_checklstring(L, 1, &size);
@@ -317,6 +305,8 @@ int ModApiUtil::l_compress(lua_State *L)
// decompress(data, method)
int ModApiUtil::l_decompress(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
size_t size;
const char *data = luaL_checklstring(L, 1, &size);
@@ -367,32 +357,57 @@ int ModApiUtil::l_get_dir_list(lua_State *L)
int ModApiUtil::l_request_insecure_environment(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+
+ // Just return _G if security is disabled
if (!ScriptApiSecurity::isSecure(L)) {
lua_getglobal(L, "_G");
return 1;
}
- lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+
+ // We have to make sure that this function is being called directly by
+ // a mod, otherwise a malicious mod could override this function and
+ // steal its return value.
+ lua_Debug info;
+ // Make sure there's only one item below this function on the stack...
+ if (lua_getstack(L, 2, &info)) {
+ return 0;
+ }
+ FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
+ FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
+ // ...and that that item is the main file scope.
+ if (strcmp(info.what, "main") != 0) {
+ return 0;
+ }
+
+ // Get mod name
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
if (!lua_isstring(L, -1)) {
- lua_pushnil(L);
- return 1;
+ return 0;
}
+
+ // Check secure.trusted_mods
const char *mod_name = lua_tostring(L, -1);
std::string trusted_mods = g_settings->get("secure.trusted_mods");
+ trusted_mods.erase(std::remove(trusted_mods.begin(),
+ trusted_mods.end(), ' '), trusted_mods.end());
std::vector<std::string> mod_list = str_split(trusted_mods, ',');
- if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
- lua_pushnil(L);
- return 1;
+ if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
+ mod_list.end()) {
+ return 0;
}
- lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+
+ // Push insecure environment
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
return 1;
}
void ModApiUtil::Initialize(lua_State *L, int top)
{
- API_FCT(debug);
API_FCT(log);
+ API_FCT(get_us_time);
+
API_FCT(setting_set);
API_FCT(setting_get);
API_FCT(setting_setbool);
@@ -422,9 +437,10 @@ void ModApiUtil::Initialize(lua_State *L, int top)
void ModApiUtil::InitializeAsync(AsyncEngine& engine)
{
- ASYNC_API_FCT(debug);
ASYNC_API_FCT(log);
+ ASYNC_API_FCT(get_us_time);
+
//ASYNC_API_FCT(setting_set);
ASYNC_API_FCT(setting_get);
//ASYNC_API_FCT(setting_setbool);
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index e75aa28cb..6fac7e7eb 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -35,16 +35,15 @@ private:
GUIEngine instance should be in here.
*/
- // debug(text)
- // Writes a line to dstream
- static int l_debug(lua_State *L);
-
// log([level,] text)
// Writes a line to the logger.
// The one-argument version logs to infostream.
- // The two-argument version accept a log level: error, action, info, or verbose.
+ // The two-argument version accepts a log level.
static int l_log(lua_State *L);
+ // get us precision time
+ static int l_get_us_time(lua_State *L);
+
// setting_set(name, value)
static int l_setting_set(lua_State *L);
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index ac6c10303..f13866408 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -28,10 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "mapgen.h"
-#define GET_ENV_PTR ServerEnvironment* env = \
- dynamic_cast<ServerEnvironment*>(getEnv(L)); \
- if (env == NULL) return 0
-
// garbage collector
int LuaVoxelManip::gc_object(lua_State *L)
{
@@ -43,6 +39,8 @@ int LuaVoxelManip::gc_object(lua_State *L)
int LuaVoxelManip::l_read_from_map(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
@@ -108,6 +106,8 @@ int LuaVoxelManip::l_set_data(lua_State *L)
int LuaVoxelManip::l_write_to_map(lua_State *L)
{
+ MAP_LOCK_REQUIRED;
+
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
@@ -119,23 +119,25 @@ int LuaVoxelManip::l_write_to_map(lua_State *L)
int LuaVoxelManip::l_get_node_at(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- GET_ENV_PTR;
+
+ INodeDefManager *ndef = getServer(L)->getNodeDefManager();
LuaVoxelManip *o = checkobject(L, 1);
v3s16 pos = check_v3s16(L, 2);
- pushnode(L, o->vm->getNodeNoExNoEmerge(pos), env->getGameDef()->ndef());
+ pushnode(L, o->vm->getNodeNoExNoEmerge(pos), ndef);
return 1;
}
int LuaVoxelManip::l_set_node_at(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- GET_ENV_PTR;
+
+ INodeDefManager *ndef = getServer(L)->getNodeDefManager();
LuaVoxelManip *o = checkobject(L, 1);
v3s16 pos = check_v3s16(L, 2);
- MapNode n = readnode(L, 3, env->getGameDef()->ndef());
+ MapNode n = readnode(L, 3, ndef);
o->vm->setNodeNoEmerge(pos, n);
@@ -179,6 +181,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
v3s16 fpmax = vm->m_area.MaxEdge;
v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
+ bool propagate_shadow = lua_isboolean(L, 4) ? lua_toboolean(L, 4) : true;
sortBoxVerticies(pmin, pmax);
if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
@@ -189,7 +192,7 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
mg.ndef = ndef;
mg.water_level = emerge->params.water_level;
- mg.calcLighting(pmin, pmax, fpmin, fpmax);
+ mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);
return 0;
}
@@ -313,14 +316,12 @@ int LuaVoxelManip::l_set_param2_data(lua_State *L)
int LuaVoxelManip::l_update_map(lua_State *L)
{
+ GET_ENV_PTR;
+
LuaVoxelManip *o = checkobject(L, 1);
if (o->is_mapgen_vm)
return 0;
- Environment *env = getEnv(L);
- if (!env)
- return 0;
-
Map *map = &(env->getMap());
// TODO: Optimize this by using Mapgen::calcLighting() instead
@@ -359,6 +360,8 @@ int LuaVoxelManip::l_was_modified(lua_State *L)
int LuaVoxelManip::l_get_emerged_area(lua_State *L)
{
+ NO_MAP_LOCK_REQUIRED;
+
LuaVoxelManip *o = checkobject(L, 1);
push_v3s16(L, o->vm->m_area.MinEdge);
@@ -400,11 +403,7 @@ LuaVoxelManip::~LuaVoxelManip()
// Creates an LuaVoxelManip and leaves it on top of stack
int LuaVoxelManip::create_object(lua_State *L)
{
- NO_MAP_LOCK_REQUIRED;
-
- Environment *env = getEnv(L);
- if (!env)
- return 0;
+ GET_ENV_PTR;
Map *map = &(env->getMap());
LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
diff --git a/src/script/scripting_game.cpp b/src/script/scripting_game.cpp
index 4f0350d41..e313d55f8 100644
--- a/src/script/scripting_game.cpp
+++ b/src/script/scripting_game.cpp
@@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_util.h"
#include "lua_api/l_vmanip.h"
#include "lua_api/l_settings.h"
+#include "lua_api/l_http.h"
extern "C" {
#include "lualib.h"
@@ -89,6 +90,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
ModApiRollback::Initialize(L, top);
ModApiServer::Initialize(L, top);
ModApiUtil::Initialize(L, top);
+ ModApiHttp::Initialize(L, top);
// Register reference classes (userdata)
InvRef::Register(L);
@@ -98,6 +100,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
LuaPerlinNoiseMap::Register(L);
LuaPseudoRandom::Register(L);
LuaPcgRandom::Register(L);
+ LuaSecureRandom::Register(L);
LuaVoxelManip::Register(L);
NodeMetaRef::Register(L);
NodeTimerRef::Register(L);
diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp
index c74c18edc..b1e50c94b 100644
--- a/src/script/scripting_mainmenu.cpp
+++ b/src/script/scripting_mainmenu.cpp
@@ -78,7 +78,7 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top)
/******************************************************************************/
void MainMenuScripting::step() {
- asyncEngine.step(getStack(), m_errorhandler);
+ asyncEngine.step(getStack());
}
/******************************************************************************/