aboutsummaryrefslogtreecommitdiff
path: root/src/script/lua_api
diff options
context:
space:
mode:
Diffstat (limited to 'src/script/lua_api')
-rw-r--r--src/script/lua_api/l_areastore.cpp49
-rw-r--r--src/script/lua_api/l_client.cpp2
-rw-r--r--src/script/lua_api/l_craft.cpp32
-rw-r--r--src/script/lua_api/l_craft.h1
-rw-r--r--src/script/lua_api/l_env.cpp35
-rw-r--r--src/script/lua_api/l_env.h2
-rw-r--r--src/script/lua_api/l_http.cpp69
-rw-r--r--src/script/lua_api/l_http.h4
-rw-r--r--src/script/lua_api/l_internal.h2
-rw-r--r--src/script/lua_api/l_inventory.cpp36
-rw-r--r--src/script/lua_api/l_inventory.h2
-rw-r--r--src/script/lua_api/l_item.cpp31
-rw-r--r--src/script/lua_api/l_item.h7
-rw-r--r--src/script/lua_api/l_localplayer.cpp21
-rw-r--r--src/script/lua_api/l_localplayer.h3
-rw-r--r--src/script/lua_api/l_mainmenu.cpp121
-rw-r--r--src/script/lua_api/l_mainmenu.h2
-rw-r--r--src/script/lua_api/l_metadata.cpp5
-rw-r--r--src/script/lua_api/l_nodemeta.cpp17
-rw-r--r--src/script/lua_api/l_noise.cpp67
-rw-r--r--src/script/lua_api/l_noise.h17
-rw-r--r--src/script/lua_api/l_object.cpp369
-rw-r--r--src/script/lua_api/l_object.h9
-rw-r--r--src/script/lua_api/l_server.cpp150
-rw-r--r--src/script/lua_api/l_server.h17
-rw-r--r--src/script/lua_api/l_storage.cpp18
-rw-r--r--src/script/lua_api/l_util.cpp105
-rw-r--r--src/script/lua_api/l_util.h15
-rw-r--r--src/script/lua_api/l_vmanip.cpp51
-rw-r--r--src/script/lua_api/l_vmanip.h5
30 files changed, 830 insertions, 434 deletions
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp
index 45724e604..ec2656c4a 100644
--- a/src/script/lua_api/l_areastore.cpp
+++ b/src/script/lua_api/l_areastore.cpp
@@ -27,26 +27,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include <fstream>
-static inline void get_data_and_border_flags(lua_State *L, u8 start_i,
- bool *borders, bool *data)
+static inline void get_data_and_corner_flags(lua_State *L, u8 start_i,
+ bool *corners, bool *data)
{
if (!lua_isboolean(L, start_i))
return;
- *borders = lua_toboolean(L, start_i);
+ *corners = lua_toboolean(L, start_i);
if (!lua_isboolean(L, start_i + 1))
return;
*data = lua_toboolean(L, start_i + 1);
}
static void push_area(lua_State *L, const Area *a,
- bool include_borders, bool include_data)
+ bool include_corners, bool include_data)
{
- if (!include_borders && !include_data) {
+ if (!include_corners && !include_data) {
lua_pushboolean(L, true);
return;
}
lua_newtable(L);
- if (include_borders) {
+ if (include_corners) {
push_v3s16(L, a->minedge);
lua_setfield(L, -2, "min");
push_v3s16(L, a->maxedge);
@@ -59,13 +59,13 @@ static void push_area(lua_State *L, const Area *a,
}
static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
- bool borders, bool data)
+ bool corners, bool data)
{
lua_newtable(L);
size_t cnt = areas.size();
for (size_t i = 0; i < cnt; i++) {
lua_pushnumber(L, areas[i]->id);
- push_area(L, areas[i], borders, data);
+ push_area(L, areas[i], corners, data);
lua_settable(L, -3);
}
}
@@ -94,7 +94,7 @@ int LuaAreaStore::gc_object(lua_State *L)
return 0;
}
-// get_area(id, include_borders, include_data)
+// get_area(id, include_corners, include_data)
int LuaAreaStore::l_get_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -104,9 +104,9 @@ int LuaAreaStore::l_get_area(lua_State *L)
u32 id = luaL_checknumber(L, 2);
- bool include_borders = true;
+ bool include_corners = true;
bool include_data = false;
- get_data_and_border_flags(L, 3, &include_borders, &include_data);
+ get_data_and_corner_flags(L, 3, &include_corners, &include_data);
const Area *res;
@@ -114,12 +114,12 @@ int LuaAreaStore::l_get_area(lua_State *L)
if (!res)
return 0;
- push_area(L, res, include_borders, include_data);
+ push_area(L, res, include_corners, include_data);
return 1;
}
-// get_areas_for_pos(pos, include_borders, include_data)
+// get_areas_for_pos(pos, include_corners, include_data)
int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -129,19 +129,19 @@ int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
v3s16 pos = check_v3s16(L, 2);
- bool include_borders = true;
+ bool include_corners = true;
bool include_data = false;
- get_data_and_border_flags(L, 3, &include_borders, &include_data);
+ get_data_and_corner_flags(L, 3, &include_corners, &include_data);
std::vector<Area *> res;
ast->getAreasForPos(&res, pos);
- push_areas(L, res, include_borders, include_data);
+ push_areas(L, res, include_corners, include_data);
return 1;
}
-// get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)
+// get_areas_in_area(corner1, corner2, accept_overlap, include_corners, include_data)
int LuaAreaStore::l_get_areas_in_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -149,25 +149,26 @@ int LuaAreaStore::l_get_areas_in_area(lua_State *L)
LuaAreaStore *o = checkobject(L, 1);
AreaStore *ast = o->as;
- v3s16 minedge = check_v3s16(L, 2);
- v3s16 maxedge = check_v3s16(L, 3);
+ v3s16 minp = check_v3s16(L, 2);
+ v3s16 maxp = check_v3s16(L, 3);
+ sortBoxVerticies(minp, maxp);
- bool include_borders = true;
+ bool include_corners = true;
bool include_data = false;
bool accept_overlap = false;
if (lua_isboolean(L, 4)) {
accept_overlap = readParam<bool>(L, 4);
- get_data_and_border_flags(L, 5, &include_borders, &include_data);
+ get_data_and_corner_flags(L, 5, &include_corners, &include_data);
}
std::vector<Area *> res;
- ast->getAreasInArea(&res, minedge, maxedge, accept_overlap);
- push_areas(L, res, include_borders, include_data);
+ ast->getAreasInArea(&res, minp, maxp, accept_overlap);
+ push_areas(L, res, include_corners, include_data);
return 1;
}
-// insert_area(edge1, edge2, data, id)
+// insert_area(corner1, corner2, data, id)
int LuaAreaStore::l_insert_area(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp
index 1d769c73e..265c7d3fc 100644
--- a/src/script/lua_api/l_client.cpp
+++ b/src/script/lua_api/l_client.cpp
@@ -474,7 +474,7 @@ int ModApiClient::l_get_inventory(lua_State *L)
inventory = client->getInventory(inventory_location);
if (! inventory)
throw SerializationError(std::string("Attempt to access nonexistant inventory (") + location + ")");
- push_inventory(L, inventory);
+ push_inventory_lists(L, *inventory);
} catch (SerializationError &) {
lua_pushnil(L);
}
diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp
index 18622ee00..137b210be 100644
--- a/src/script/lua_api/l_craft.cpp
+++ b/src/script/lua_api/l_craft.cpp
@@ -371,8 +371,9 @@ int ModApiCraft::l_clear_craft(lua_State *L)
int ModApiCraft::l_get_craft_result(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+ IGameDef *gdef = getGameDef(L);
- int input_i = 1;
+ const int input_i = 1;
std::string method_s = getstringfield_default(L, input_i, "method", "normal");
enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method",
es_CraftMethod, CRAFT_METHOD_NORMAL);
@@ -382,10 +383,9 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
width = luaL_checkinteger(L, -1);
lua_pop(L, 1);
lua_getfield(L, input_i, "items");
- std::vector<ItemStack> items = read_items(L, -1,getServer(L));
+ std::vector<ItemStack> items = read_items(L, -1, gdef);
lua_pop(L, 1); // items
- IGameDef *gdef = getServer(L);
ICraftDefManager *cdef = gdef->cdef();
CraftInput input(method, width, items);
CraftOutput output;
@@ -465,13 +465,13 @@ static void push_craft_recipes(lua_State *L, IGameDef *gdef,
const std::vector<CraftDefinition*> &recipes,
const CraftOutput &output)
{
- lua_createtable(L, recipes.size(), 0);
-
if (recipes.empty()) {
lua_pushnil(L);
return;
}
+ lua_createtable(L, recipes.size(), 0);
+
std::vector<CraftDefinition*>::const_iterator it = recipes.begin();
for (unsigned i = 0; it != recipes.end(); ++it) {
lua_newtable(L);
@@ -487,10 +487,9 @@ int ModApiCraft::l_get_craft_recipe(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string item = luaL_checkstring(L, 1);
- Server *server = getServer(L);
+ IGameDef *gdef = getGameDef(L);
CraftOutput output(item, 0);
- std::vector<CraftDefinition*> recipes = server->cdef()
- ->getCraftRecipes(output, server, 1);
+ auto recipes = gdef->cdef()->getCraftRecipes(output, gdef, 1);
lua_createtable(L, 1, 0);
@@ -500,7 +499,7 @@ int ModApiCraft::l_get_craft_recipe(lua_State *L)
setintfield(L, -1, "width", 0);
return 1;
}
- push_craft_recipe(L, server, recipes[0], output);
+ push_craft_recipe(L, gdef, recipes[0], output);
return 1;
}
@@ -510,12 +509,11 @@ int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string item = luaL_checkstring(L, 1);
- Server *server = getServer(L);
+ IGameDef *gdef = getGameDef(L);
CraftOutput output(item, 0);
- std::vector<CraftDefinition*> recipes = server->cdef()
- ->getCraftRecipes(output, server);
+ auto recipes = gdef->cdef()->getCraftRecipes(output, gdef);
- push_craft_recipes(L, server, recipes, output);
+ push_craft_recipes(L, gdef, recipes, output);
return 1;
}
@@ -527,3 +525,11 @@ void ModApiCraft::Initialize(lua_State *L, int top)
API_FCT(register_craft);
API_FCT(clear_craft);
}
+
+void ModApiCraft::InitializeAsync(lua_State *L, int top)
+{
+ // all read-only functions
+ API_FCT(get_all_craft_recipes);
+ API_FCT(get_craft_recipe);
+ API_FCT(get_craft_result);
+}
diff --git a/src/script/lua_api/l_craft.h b/src/script/lua_api/l_craft.h
index 9002b23ef..5234af56f 100644
--- a/src/script/lua_api/l_craft.h
+++ b/src/script/lua_api/l_craft.h
@@ -45,4 +45,5 @@ private:
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 876f84d53..a489d245c 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -477,7 +477,7 @@ int ModApiEnvMod::l_place_node(lua_State *L)
return 1;
}
// Create item to place
- ItemStack item(ndef->get(n).name, 1, 0, idef);
+ Optional<ItemStack> item = ItemStack(ndef->get(n).name, 1, 0, idef);
// Make pointed position
PointedThing pointed;
pointed.type = POINTEDTHING_NODE;
@@ -1038,6 +1038,21 @@ int ModApiEnvMod::l_find_nodes_near_under_air_except(lua_State *L)
return 2;
}
+static void checkArea(v3s16 &minp, v3s16 &maxp)
+{
+ auto volume = VoxelArea(minp, maxp).getVolume();
+ // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+ if (volume > 4096000) {
+ throw LuaError("Area volume exceeds allowed value of 4096000");
+ }
+
+ // Clamp to map range to avoid problems
+#define CLAMP(arg) core::clamp(arg, (s16)-MAX_MAP_GENERATION_LIMIT, (s16)MAX_MAP_GENERATION_LIMIT)
+ minp = v3s16(CLAMP(minp.X), CLAMP(minp.Y), CLAMP(minp.Z));
+ maxp = v3s16(CLAMP(maxp.X), CLAMP(maxp.Y), CLAMP(maxp.Z));
+#undef CLAMP
+}
+
// find_nodes_in_area(minp, maxp, nodenames, [grouped])
int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
{
@@ -1057,13 +1072,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
}
#endif
- v3s16 cube = maxp - minp + 1;
- // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
- if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
- luaL_error(L, "find_nodes_in_area(): area volume"
- " exceeds allowed value of 4096000");
- return 0;
- }
+ checkArea(minp, maxp);
std::vector<content_t> filter;
collectNodeIds(L, 3, ndef, filter);
@@ -1168,13 +1177,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
}
#endif
- v3s16 cube = maxp - minp + 1;
- // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
- if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
- luaL_error(L, "find_nodes_in_area_under_air(): area volume"
- " exceeds allowed value of 4096000");
- return 0;
- }
+ checkArea(minp, maxp);
std::vector<content_t> filter;
collectNodeIds(L, 3, ndef, filter);
@@ -1541,7 +1544,7 @@ int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
GET_ENV_PTR;
v3s16 p0 = read_v3s16(L, 1);
- env->getMap().transforming_liquid_add(p0);
+ env->getServerMap().transforming_liquid_add(p0);
return 1;
}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index a5ac21e21..70a8d2398 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -114,7 +114,7 @@ private:
// get_objects_inside_radius(pos, radius)
static int l_get_objects_inside_radius(lua_State *L);
-
+
// get_objects_in_area(pos, minp, maxp)
static int l_get_objects_in_area(lua_State *L);
diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp
index 751ec9837..5566a8523 100644
--- a/src/script/lua_api/l_http.cpp
+++ b/src/script/lua_api/l_http.cpp
@@ -21,14 +21,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h"
#include "common/c_content.h"
#include "lua_api/l_http.h"
+#include "cpp_api/s_security.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); \
@@ -167,54 +166,22 @@ 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;
- }
-
- std::string mod_name = readParam<std::string>(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()) {
+ if (!ScriptApiSecurity::checkWhitelisted(L, "secure.http_mods") &&
+ !ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
lua_pushnil(L);
return 1;
}
- lua_getglobal(L, "core");
- lua_getfield(L, -1, "http_add_fetch");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_HTTP_API_LUA);
+ assert(lua_isfunction(L, -1));
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
+ // <function> <table with fetch_async, fetch_async_get>
+ // Now call it to append .fetch(request, callback) to table
lua_call(L, 1, 1);
return 1;
@@ -234,6 +201,22 @@ int ModApiHttp::l_get_http_api(lua_State *L)
#endif
+int ModApiHttp::l_set_http_api_lua(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+#if USE_CURL
+ // This is called by builtin to give us a function that will later
+ // populate the http_api table with additional method(s).
+ // We need this because access to the HTTP api is security-relevant and
+ // any mod could just mess with a global variable.
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ lua_rawseti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_HTTP_API_LUA);
+#endif
+
+ return 0;
+}
+
void ModApiHttp::Initialize(lua_State *L, int top)
{
#if USE_CURL
@@ -247,8 +230,14 @@ void ModApiHttp::Initialize(lua_State *L, int top)
API_FCT(get_http_api);
} else {
API_FCT(request_http_api);
+ API_FCT(set_http_api_lua);
}
+#else
+
+ // Define this function anyway so builtin can call it without checking
+ API_FCT(set_http_api_lua);
+
#endif
}
diff --git a/src/script/lua_api/l_http.h b/src/script/lua_api/l_http.h
index c3a2a5276..8d084ecd9 100644
--- a/src/script/lua_api/l_http.h
+++ b/src/script/lua_api/l_http.h
@@ -48,6 +48,10 @@ private:
static int l_get_http_api(lua_State *L);
#endif
+ // set_http_api_lua() [internal]
+ static int l_set_http_api_lua(lua_State *L);
+
+
public:
static void Initialize(lua_State *L, int top);
static void InitializeAsync(lua_State *L, int top);
diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h
index 672e535ca..de73ff42a 100644
--- a/src/script/lua_api/l_internal.h
+++ b/src/script/lua_api/l_internal.h
@@ -69,7 +69,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Retrieve Environment pointer as `env` (no map lock)
#define GET_PLAIN_ENV_PTR_NO_MAP_LOCK \
- Environment *env = (Environment *)getEnv(L); \
+ Environment *env = getEnv(L); \
if (env == NULL) \
return 0
diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp
index 0dd418462..175047e58 100644
--- a/src/script/lua_api/l_inventory.cpp
+++ b/src/script/lua_api/l_inventory.cpp
@@ -214,11 +214,16 @@ int InvRef::l_get_list(lua_State *L)
InvRef *ref = checkobject(L, 1);
const char *listname = luaL_checkstring(L, 2);
Inventory *inv = getinv(L, ref);
- if(inv){
- push_inventory_list(L, inv, listname);
- } else {
+ if (!inv) {
lua_pushnil(L);
+ return 1;
}
+ InventoryList *invlist = inv->getList(listname);
+ if (!invlist) {
+ lua_pushnil(L);
+ return 1;
+ }
+ push_inventory_list(L, *invlist);
return 1;
}
@@ -242,7 +247,7 @@ int InvRef::l_set_list(lua_State *L)
return 0;
}
-// get_lists(self) -> list of InventoryLists
+// get_lists(self) -> table that maps listnames to InventoryLists
int InvRef::l_get_lists(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -251,15 +256,7 @@ int InvRef::l_get_lists(lua_State *L)
if (!inv) {
return 0;
}
- std::vector<const InventoryList*> lists = inv->getLists();
- std::vector<const InventoryList*>::iterator iter = lists.begin();
- lua_createtable(L, 0, lists.size());
- for (; iter != lists.end(); iter++) {
- const char* name = (*iter)->getName().c_str();
- lua_pushstring(L, name);
- push_inventory_list(L, inv, name);
- lua_rawset(L, -3);
- }
+ push_inventory_lists(L, *inv);
return 1;
}
@@ -421,19 +418,6 @@ void InvRef::create(lua_State *L, const InventoryLocation &loc)
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
-void InvRef::createPlayer(lua_State *L, RemotePlayer *player)
-{
- NO_MAP_LOCK_REQUIRED;
- InventoryLocation loc;
- loc.setPlayer(player->getName());
- create(L, loc);
-}
-void InvRef::createNodeMeta(lua_State *L, v3s16 p)
-{
- InventoryLocation loc;
- loc.setNodeMeta(p);
- create(L, loc);
-}
void InvRef::Register(lua_State *L)
{
diff --git a/src/script/lua_api/l_inventory.h b/src/script/lua_api/l_inventory.h
index 94f670c9d..6a75bac0f 100644
--- a/src/script/lua_api/l_inventory.h
+++ b/src/script/lua_api/l_inventory.h
@@ -111,8 +111,6 @@ public:
// Creates an InvRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, const InventoryLocation &loc);
- static void createPlayer(lua_State *L, RemotePlayer *player);
- static void createNodeMeta(lua_State *L, v3s16 p);
static void Register(lua_State *L);
};
diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp
index 2ea2bd4f6..9220259ff 100644
--- a/src/script/lua_api/l_item.cpp
+++ b/src/script/lua_api/l_item.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "common/c_packer.h"
#include "itemdef.h"
#include "nodedef.h"
#include "server.h"
@@ -446,6 +447,7 @@ int LuaItemStack::create_object(lua_State *L)
lua_setmetatable(L, -2);
return 1;
}
+
// Not callable from Lua
int LuaItemStack::create(lua_State *L, const ItemStack &item)
{
@@ -462,6 +464,20 @@ LuaItemStack *LuaItemStack::checkobject(lua_State *L, int narg)
return *(LuaItemStack **)luaL_checkudata(L, narg, className);
}
+void *LuaItemStack::packIn(lua_State *L, int idx)
+{
+ LuaItemStack *o = checkobject(L, idx);
+ return new ItemStack(o->getItem());
+}
+
+void LuaItemStack::packOut(lua_State *L, void *ptr)
+{
+ ItemStack *stack = reinterpret_cast<ItemStack*>(ptr);
+ if (L)
+ create(L, *stack);
+ delete stack;
+}
+
void LuaItemStack::Register(lua_State *L)
{
lua_newtable(L);
@@ -493,6 +509,8 @@ void LuaItemStack::Register(lua_State *L)
// Can be created from Lua (ItemStack(itemstack or itemstring or table or nil))
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
const char LuaItemStack::className[] = "ItemStack";
@@ -638,8 +656,8 @@ int ModApiItemMod::l_get_content_id(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string name = luaL_checkstring(L, 1);
- const IItemDefManager *idef = getGameDef(L)->getItemDefManager();
- const NodeDefManager *ndef = getGameDef(L)->getNodeDefManager();
+ const IItemDefManager *idef = getGameDef(L)->idef();
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
// If this is called at mod load time, NodeDefManager isn't aware of
// aliases yet, so we need to handle them manually
@@ -664,7 +682,7 @@ int ModApiItemMod::l_get_name_from_content_id(lua_State *L)
NO_MAP_LOCK_REQUIRED;
content_t c = luaL_checkint(L, 1);
- const NodeDefManager *ndef = getGameDef(L)->getNodeDefManager();
+ const NodeDefManager *ndef = getGameDef(L)->ndef();
const char *name = ndef->get(c).name.c_str();
lua_pushstring(L, name);
@@ -679,3 +697,10 @@ void ModApiItemMod::Initialize(lua_State *L, int top)
API_FCT(get_content_id);
API_FCT(get_name_from_content_id);
}
+
+void ModApiItemMod::InitializeAsync(lua_State *L, int top)
+{
+ // all read-only functions
+ API_FCT(get_content_id);
+ API_FCT(get_name_from_content_id);
+}
diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h
index 16878c101..180975061 100644
--- a/src/script/lua_api/l_item.h
+++ b/src/script/lua_api/l_item.h
@@ -141,8 +141,11 @@ public:
// Not callable from Lua
static int create(lua_State *L, const ItemStack &item);
static LuaItemStack* checkobject(lua_State *L, int narg);
- static void Register(lua_State *L);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
+ static void Register(lua_State *L);
};
class ModApiItemMod : public ModApiBase {
@@ -152,6 +155,8 @@ private:
static int l_register_alias_raw(lua_State *L);
static int l_get_content_id(lua_State *L);
static int l_get_name_from_content_id(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp
index 769b3ef2b..1da0679d6 100644
--- a/src/script/lua_api/l_localplayer.cpp
+++ b/src/script/lua_api/l_localplayer.cpp
@@ -196,11 +196,11 @@ int LuaLocalPlayer::l_is_in_liquid_stable(lua_State *L)
return 1;
}
-int LuaLocalPlayer::l_get_liquid_viscosity(lua_State *L)
+int LuaLocalPlayer::l_get_move_resistance(lua_State *L)
{
LocalPlayer *player = getobject(L, 1);
- lua_pushinteger(L, player->liquid_viscosity);
+ lua_pushinteger(L, player->move_resistance);
return 1;
}
@@ -302,13 +302,15 @@ int LuaLocalPlayer::l_get_control(lua_State *L)
set("dig", c.dig);
set("place", c.place);
// Player movement in polar coordinates and non-binary speed
- set("movement_speed", c.movement_speed);
- set("movement_direction", c.movement_direction);
+ lua_pushnumber(L, c.movement_speed);
+ lua_setfield(L, -2, "movement_speed");
+ lua_pushnumber(L, c.movement_direction);
+ lua_setfield(L, -2, "movement_direction");
// Provide direction keys to ensure compatibility
- set("up", player->keyPressed & (1 << 0)); // Up, down, left, and right were removed in favor of
- set("down", player->keyPressed & (1 << 1)); // analog direction indicators and are therefore not
- set("left", player->keyPressed & (1 << 2)); // available as booleans anymore. The corresponding values
- set("right", player->keyPressed & (1 << 3)); // can still be read from the keyPressed bits though.
+ set("up", c.direction_keys & (1 << 0));
+ set("down", c.direction_keys & (1 << 1));
+ set("left", c.direction_keys & (1 << 2));
+ set("right", c.direction_keys & (1 << 3));
return 1;
}
@@ -576,7 +578,6 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, is_touching_ground),
luamethod(LuaLocalPlayer, is_in_liquid),
luamethod(LuaLocalPlayer, is_in_liquid_stable),
- luamethod(LuaLocalPlayer, get_liquid_viscosity),
luamethod(LuaLocalPlayer, is_climbing),
luamethod(LuaLocalPlayer, swimming_vertical),
luamethod(LuaLocalPlayer, get_physics_override),
@@ -602,5 +603,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = {
luamethod(LuaLocalPlayer, get_object),
luamethod(LuaLocalPlayer, get_hotbar_size),
+ luamethod(LuaLocalPlayer, get_move_resistance),
+
{0, 0}
};
diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h
index bb5a294ca..458c824e6 100644
--- a/src/script/lua_api/l_localplayer.h
+++ b/src/script/lua_api/l_localplayer.h
@@ -72,7 +72,6 @@ private:
static int l_is_touching_ground(lua_State *L);
static int l_is_in_liquid(lua_State *L);
static int l_is_in_liquid_stable(lua_State *L);
- static int l_get_liquid_viscosity(lua_State *L);
static int l_is_climbing(lua_State *L);
static int l_swimming_vertical(lua_State *L);
@@ -121,6 +120,8 @@ private:
// hud_get(self, id)
static int l_hud_get(lua_State *L);
+ static int l_get_move_resistance(lua_State *L);
+
// get_object(self)
static int l_get_object(lua_State *L);
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 8eb0e252a..2b46a4d51 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -323,9 +323,9 @@ int ModApiMainMenu::l_get_games(lua_State *L)
lua_newtable(L);
int table2 = lua_gettop(L);
int internal_index = 1;
- for (const std::string &addon_mods_path : game.addon_mods_paths) {
+ for (const auto &addon_mods_path : game.addon_mods_paths) {
lua_pushnumber(L, internal_index);
- lua_pushstring(L, addon_mods_path.c_str());
+ lua_pushstring(L, addon_mods_path.second.c_str());
lua_settable(L, table2);
internal_index++;
}
@@ -414,25 +414,53 @@ int ModApiMainMenu::l_create_world(lua_State *L)
const char *name = luaL_checkstring(L, 1);
int gameidx = luaL_checkinteger(L,2) -1;
+ StringMap use_settings;
+ luaL_checktype(L, 3, LUA_TTABLE);
+ lua_pushnil(L);
+ while (lua_next(L, 3) != 0) {
+ // key at index -2 and value at index -1
+ use_settings[luaL_checkstring(L, -2)] = luaL_checkstring(L, -1);
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+
std::string path = porting::path_user + DIR_DELIM
"worlds" + DIR_DELIM
+ sanitizeDirName(name, "world_");
std::vector<SubgameSpec> games = getAvailableGames();
+ if (gameidx < 0 || gameidx >= (int) games.size()) {
+ lua_pushstring(L, "Invalid game index");
+ return 1;
+ }
- if ((gameidx >= 0) &&
- (gameidx < (int) games.size())) {
+ // Set the settings for world creation
+ // this is a bad hack but the best we have right now..
+ StringMap backup;
+ for (auto it : use_settings) {
+ if (g_settings->existsLocal(it.first))
+ backup[it.first] = g_settings->get(it.first);
+ g_settings->set(it.first, it.second);
+ }
- // Create world if it doesn't exist
- try {
- loadGameConfAndInitWorld(path, name, games[gameidx], true);
- lua_pushnil(L);
- } catch (const BaseException &e) {
- lua_pushstring(L, (std::string("Failed to initialize world: ") + e.what()).c_str());
- }
- } else {
- lua_pushstring(L, "Invalid game index");
+ // Create world if it doesn't exist
+ try {
+ loadGameConfAndInitWorld(path, name, games[gameidx], true);
+ lua_pushnil(L);
+ } catch (const BaseException &e) {
+ auto err = std::string("Failed to initialize world: ") + e.what();
+ lua_pushstring(L, err.c_str());
+ }
+
+ // Restore previous settings
+ for (auto it : use_settings) {
+ auto it2 = backup.find(it.first);
+ if (it2 == backup.end())
+ g_settings->remove(it.first); // wasn't set before
+ else
+ g_settings->set(it.first, it2->second); // was set before
}
+
return 1;
}
@@ -503,6 +531,21 @@ int ModApiMainMenu::l_get_modpath(lua_State *L)
}
/******************************************************************************/
+int ModApiMainMenu::l_get_modpaths(lua_State *L)
+{
+ lua_newtable(L);
+
+ ModApiMainMenu::l_get_modpath(L);
+ lua_setfield(L, -2, "mods");
+
+ for (const std::string &component : getEnvModPaths()) {
+ lua_pushstring(L, component.c_str());
+ lua_setfield(L, -2, fs::AbsolutePath(component).c_str());
+ }
+ return 1;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_get_clientmodpath(lua_State *L)
{
std::string modpath = fs::RemoveRelativePathComponents(
@@ -548,7 +591,10 @@ int ModApiMainMenu::l_get_cache_path(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_temp_path(lua_State *L)
{
- lua_pushstring(L, fs::TempPath().c_str());
+ if (lua_isnoneornil(L, 1) || !lua_toboolean(L, 1))
+ lua_pushstring(L, fs::TempPath().c_str());
+ else
+ lua_pushstring(L, fs::CreateTempFile().c_str());
return 1;
}
@@ -588,26 +634,24 @@ int ModApiMainMenu::l_copy_dir(lua_State *L)
const char *destination = luaL_checkstring(L, 2);
bool keep_source = true;
+ if (!lua_isnoneornil(L, 3))
+ keep_source = readParam<bool>(L, 3);
- if ((!lua_isnone(L,3)) &&
- (!lua_isnil(L,3))) {
- keep_source = readParam<bool>(L,3);
- }
-
- std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
- std::string absolute_source = fs::RemoveRelativePathComponents(source);
+ std::string abs_destination = fs::RemoveRelativePathComponents(destination);
+ std::string abs_source = fs::RemoveRelativePathComponents(source);
- if ((ModApiMainMenu::mayModifyPath(absolute_destination))) {
- bool retval = fs::CopyDir(absolute_source,absolute_destination);
-
- if (retval && (!keep_source)) {
-
- retval &= fs::RecursiveDelete(absolute_source);
- }
- lua_pushboolean(L,retval);
+ if (!ModApiMainMenu::mayModifyPath(abs_destination) ||
+ (!keep_source && !ModApiMainMenu::mayModifyPath(abs_source))) {
+ lua_pushboolean(L, false);
return 1;
}
- lua_pushboolean(L,false);
+
+ bool retval;
+ if (keep_source)
+ retval = fs::CopyDir(abs_source, abs_destination);
+ else
+ retval = fs::MoveDir(abs_source, abs_destination);
+ lua_pushboolean(L, retval);
return 1;
}
@@ -629,9 +673,9 @@ int ModApiMainMenu::l_extract_zip(lua_State *L)
std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
if (ModApiMainMenu::mayModifyPath(absolute_destination)) {
- auto rendering_engine = getGuiEngine(L)->m_rendering_engine;
- fs::CreateAllDirs(absolute_destination);
- lua_pushboolean(L, fs::extractZipFile(rendering_engine->get_filesystem(), zipfile, destination));
+ auto fs = RenderingEngine::get_raw_device()->getFileSystem();
+ bool ok = fs::extractZipFile(fs, zipfile, destination);
+ lua_pushboolean(L, ok);
return 1;
}
@@ -759,8 +803,9 @@ int ModApiMainMenu::l_get_video_drivers(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_gettext(lua_State *L)
{
- std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
- lua_pushstring(L, text.c_str());
+ const char *srctext = luaL_checkstring(L, 1);
+ const char *text = *srctext ? gettext(srctext) : "";
+ lua_pushstring(L, text);
return 1;
}
@@ -860,6 +905,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(get_mapgen_names);
API_FCT(get_user_path);
API_FCT(get_modpath);
+ API_FCT(get_modpaths);
API_FCT(get_clientmodpath);
API_FCT(get_gamepath);
API_FCT(get_texturepath);
@@ -893,6 +939,7 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(get_mapgen_names);
API_FCT(get_user_path);
API_FCT(get_modpath);
+ API_FCT(get_modpaths);
API_FCT(get_clientmodpath);
API_FCT(get_gamepath);
API_FCT(get_texturepath);
@@ -903,10 +950,10 @@ void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
API_FCT(delete_dir);
API_FCT(copy_dir);
API_FCT(is_dir);
- //API_FCT(extract_zip); //TODO remove dependency to GuiEngine
+ API_FCT(extract_zip);
API_FCT(may_modify_path);
API_FCT(download_file);
API_FCT(get_min_supp_proto);
API_FCT(get_max_supp_proto);
- //API_FCT(gettext); (gettext lib isn't threadsafe)
+ API_FCT(gettext);
}
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index ec2d20da2..781185425 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -112,6 +112,8 @@ private:
static int l_get_modpath(lua_State *L);
+ static int l_get_modpaths(lua_State *L);
+
static int l_get_clientmodpath(lua_State *L);
static int l_get_gamepath(lua_State *L);
diff --git a/src/script/lua_api/l_metadata.cpp b/src/script/lua_api/l_metadata.cpp
index 21002e6a7..d00cb4daa 100644
--- a/src/script/lua_api/l_metadata.cpp
+++ b/src/script/lua_api/l_metadata.cpp
@@ -82,9 +82,10 @@ int MetaDataRef::l_get(lua_State *L)
std::string str;
if (meta->getStringToRef(name, str)) {
lua_pushlstring(L, str.c_str(), str.size());
- return 1;
+ } else {
+ lua_pushnil(L);
}
- return 0;
+ return 1;
}
// get_string(self, name)
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 60d14f8f2..1d052685e 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -89,7 +89,10 @@ int NodeMetaRef::l_get_inventory(lua_State *L)
NodeMetaRef *ref = checkobject(L, 1);
ref->getmeta(true); // try to ensure the metadata exists
- InvRef::createNodeMeta(L, ref->m_p);
+
+ InventoryLocation loc;
+ loc.setNodeMeta(ref->m_p);
+ InvRef::create(L, loc);
return 1;
}
@@ -124,18 +127,14 @@ void NodeMetaRef::handleToTable(lua_State *L, Metadata *_meta)
// fields
MetaDataRef::handleToTable(L, _meta);
- NodeMetadata *meta = (NodeMetadata*) _meta;
+ NodeMetadata *meta = (NodeMetadata *) _meta;
// inventory
- lua_newtable(L);
Inventory *inv = meta->getInventory();
if (inv) {
- std::vector<const InventoryList *> lists = inv->getLists();
- for(std::vector<const InventoryList *>::const_iterator
- i = lists.begin(); i != lists.end(); ++i) {
- push_inventory_list(L, inv, (*i)->getName().c_str());
- lua_setfield(L, -2, (*i)->getName().c_str());
- }
+ push_inventory_lists(L, *inv);
+ } else {
+ lua_newtable(L);
}
lua_setfield(L, -2, "inventory");
}
diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp
index f43ba837a..5561eaebf 100644
--- a/src/script/lua_api/l_noise.cpp
+++ b/src/script/lua_api/l_noise.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "common/c_packer.h"
#include "log.h"
#include "porting.h"
#include "util/numeric.h"
@@ -30,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
LuaPerlinNoise
*/
-LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
+LuaPerlinNoise::LuaPerlinNoise(const NoiseParams *params) :
np(*params)
{
}
@@ -101,6 +102,25 @@ LuaPerlinNoise *LuaPerlinNoise::checkobject(lua_State *L, int narg)
}
+void *LuaPerlinNoise::packIn(lua_State *L, int idx)
+{
+ LuaPerlinNoise *o = checkobject(L, idx);
+ return new NoiseParams(o->np);
+}
+
+void LuaPerlinNoise::packOut(lua_State *L, void *ptr)
+{
+ NoiseParams *np = reinterpret_cast<NoiseParams*>(ptr);
+ if (L) {
+ LuaPerlinNoise *o = new LuaPerlinNoise(np);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ }
+ delete np;
+}
+
+
void LuaPerlinNoise::Register(lua_State *L)
{
lua_newtable(L);
@@ -126,6 +146,8 @@ void LuaPerlinNoise::Register(lua_State *L)
lua_pop(L, 1);
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
@@ -141,12 +163,10 @@ luaL_Reg LuaPerlinNoise::methods[] = {
LuaPerlinNoiseMap
*/
-LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, s32 seed, v3s16 size)
+LuaPerlinNoiseMap::LuaPerlinNoiseMap(const NoiseParams *np, s32 seed, v3s16 size)
{
- m_is3d = size.Z > 1;
- np = *params;
try {
- noise = new Noise(&np, seed, size.X, size.Y, size.Z);
+ noise = new Noise(np, seed, size.X, size.Y, size.Z);
} catch (InvalidNoiseParamsException &e) {
throw LuaError(e.what());
}
@@ -217,7 +237,7 @@ int LuaPerlinNoiseMap::l_get_3d_map(lua_State *L)
LuaPerlinNoiseMap *o = checkobject(L, 1);
v3f p = check_v3f(L, 2);
- if (!o->m_is3d)
+ if (!o->is3D())
return 0;
Noise *n = o->noise;
@@ -248,7 +268,7 @@ int LuaPerlinNoiseMap::l_get_3d_map_flat(lua_State *L)
v3f p = check_v3f(L, 2);
bool use_buffer = lua_istable(L, 3);
- if (!o->m_is3d)
+ if (!o->is3D())
return 0;
Noise *n = o->noise;
@@ -289,7 +309,7 @@ int LuaPerlinNoiseMap::l_calc_3d_map(lua_State *L)
LuaPerlinNoiseMap *o = checkobject(L, 1);
v3f p = check_v3f(L, 2);
- if (!o->m_is3d)
+ if (!o->is3D())
return 0;
Noise *n = o->noise;
@@ -359,6 +379,35 @@ LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
}
+struct NoiseMapParams {
+ NoiseParams np;
+ s32 seed;
+ v3s16 size;
+};
+
+void *LuaPerlinNoiseMap::packIn(lua_State *L, int idx)
+{
+ LuaPerlinNoiseMap *o = checkobject(L, idx);
+ NoiseMapParams *ret = new NoiseMapParams();
+ ret->np = o->noise->np;
+ ret->seed = o->noise->seed;
+ ret->size = v3s16(o->noise->sx, o->noise->sy, o->noise->sz);
+ return ret;
+}
+
+void LuaPerlinNoiseMap::packOut(lua_State *L, void *ptr)
+{
+ NoiseMapParams *p = reinterpret_cast<NoiseMapParams*>(ptr);
+ if (L) {
+ LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&p->np, p->seed, p->size);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ }
+ delete p;
+}
+
+
void LuaPerlinNoiseMap::Register(lua_State *L)
{
lua_newtable(L);
@@ -384,6 +433,8 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
lua_pop(L, 1);
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h
index 9f50dfd3f..5d34a479b 100644
--- a/src/script/lua_api/l_noise.h
+++ b/src/script/lua_api/l_noise.h
@@ -30,6 +30,7 @@ class LuaPerlinNoise : public ModApiBase
{
private:
NoiseParams np;
+
static const char className[];
static luaL_Reg methods[];
@@ -42,7 +43,7 @@ private:
static int l_get_3d(lua_State *L);
public:
- LuaPerlinNoise(NoiseParams *params);
+ LuaPerlinNoise(const NoiseParams *params);
~LuaPerlinNoise() = default;
// LuaPerlinNoise(seed, octaves, persistence, scale)
@@ -51,6 +52,9 @@ public:
static LuaPerlinNoise *checkobject(lua_State *L, int narg);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
static void Register(lua_State *L);
};
@@ -59,9 +63,8 @@ public:
*/
class LuaPerlinNoiseMap : public ModApiBase
{
- NoiseParams np;
Noise *noise;
- bool m_is3d;
+
static const char className[];
static luaL_Reg methods[];
@@ -80,16 +83,20 @@ class LuaPerlinNoiseMap : public ModApiBase
static int l_get_map_slice(lua_State *L);
public:
- LuaPerlinNoiseMap(NoiseParams *np, s32 seed, v3s16 size);
-
+ LuaPerlinNoiseMap(const NoiseParams *np, s32 seed, v3s16 size);
~LuaPerlinNoiseMap();
+ inline bool is3D() const { return noise->sz > 1; }
+
// LuaPerlinNoiseMap(np, size)
// Creates an LuaPerlinNoiseMap and leaves it on top of stack
static int create_object(lua_State *L);
static LuaPerlinNoiseMap *checkobject(lua_State *L, int narg);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
static void Register(lua_State *L);
};
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index b7185f7ec..39b19364e 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -174,7 +174,7 @@ int ObjectRef::l_punch(lua_State *L)
v3f dir = readParam<v3f>(L, 5, sao->getBasePosition() - puncher->getBasePosition());
dir.normalize();
- u16 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch);
+ u32 wear = sao->punch(dir, &toolcap, puncher, time_from_last_punch);
lua_pushnumber(L, wear);
return 1;
@@ -420,8 +420,7 @@ int ObjectRef::l_set_local_animation(lua_State *L)
float frame_speed = readParam<float>(L, 6, 30.0f);
getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_local_animation(self)
@@ -464,8 +463,7 @@ int ObjectRef::l_set_eye_offset(lua_State *L)
offset_third.Y = rangelim(offset_third.Y,-10,15); //1.5*BS
getServer(L)->setPlayerEyeOffset(player, offset_first, offset_third);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_eye_offset(self)
@@ -737,8 +735,7 @@ int ObjectRef::l_set_nametag_attributes(lua_State *L)
prop->validate();
sao->notifyObjectPropertiesModified();
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_nametag_attributes(self)
@@ -1116,7 +1113,7 @@ int ObjectRef::l_set_look_vertical(lua_State *L)
float pitch = readParam<float>(L, 2) * core::RADTODEG;
playersao->setLookPitchAndSend(pitch);
- return 1;
+ return 0;
}
// set_look_horizontal(self, radians)
@@ -1131,7 +1128,7 @@ int ObjectRef::l_set_look_horizontal(lua_State *L)
float yaw = readParam<float>(L, 2) * core::RADTODEG;
playersao->setPlayerYawAndSend(yaw);
- return 1;
+ return 0;
}
// DEPRECATED
@@ -1151,7 +1148,7 @@ int ObjectRef::l_set_look_pitch(lua_State *L)
float pitch = readParam<float>(L, 2) * core::RADTODEG;
playersao->setLookPitchAndSend(pitch);
- return 1;
+ return 0;
}
// DEPRECATED
@@ -1171,7 +1168,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
float yaw = readParam<float>(L, 2) * core::RADTODEG;
playersao->setPlayerYawAndSend(yaw);
- return 1;
+ return 0;
}
// set_fov(self, degrees, is_multiplier, transition_time)
@@ -1310,8 +1307,7 @@ int ObjectRef::l_set_inventory_formspec(lua_State *L)
player->inventory_formspec = formspec;
getServer(L)->reportInventoryFormspecModified(player->getName());
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_inventory_formspec(self) -> formspec
@@ -1342,8 +1338,7 @@ int ObjectRef::l_set_formspec_prepend(lua_State *L)
player->formspec_prepend = formspec;
getServer(L)->reportFormspecPrependModified(player->getName());
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_formspec_prepend(self)
@@ -1367,20 +1362,19 @@ int ObjectRef::l_get_player_control(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
- if (player == nullptr) {
- lua_pushlstring(L, "", 0);
- return 1;
- }
- const PlayerControl &control = player->getPlayerControl();
lua_newtable(L);
- lua_pushboolean(L, player->keyPressed & (1 << 0));
+ if (player == nullptr)
+ return 1;
+
+ const PlayerControl &control = player->getPlayerControl();
+ lua_pushboolean(L, control.direction_keys & (1 << 0));
lua_setfield(L, -2, "up");
- lua_pushboolean(L, player->keyPressed & (1 << 1));
+ lua_pushboolean(L, control.direction_keys & (1 << 1));
lua_setfield(L, -2, "down");
- lua_pushboolean(L, player->keyPressed & (1 << 2));
+ lua_pushboolean(L, control.direction_keys & (1 << 2));
lua_setfield(L, -2, "left");
- lua_pushboolean(L, player->keyPressed & (1 << 3));
+ lua_pushboolean(L, control.direction_keys & (1 << 3));
lua_setfield(L, -2, "right");
lua_pushboolean(L, control.jump);
lua_setfield(L, -2, "jump");
@@ -1409,11 +1403,25 @@ int ObjectRef::l_get_player_control_bits(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == nullptr) {
- lua_pushlstring(L, "", 0);
+ lua_pushinteger(L, 0);
return 1;
}
- lua_pushnumber(L, player->keyPressed);
+ const auto &c = player->getPlayerControl();
+
+ // This is very close to PlayerControl::getKeysPressed() but duplicated
+ // here so the encoding in the API is not inadvertedly changed.
+ u32 keypress_bits =
+ c.direction_keys |
+ ( (u32)(c.jump & 1) << 4) |
+ ( (u32)(c.aux1 & 1) << 5) |
+ ( (u32)(c.sneak & 1) << 6) |
+ ( (u32)(c.dig & 1) << 7) |
+ ( (u32)(c.place & 1) << 8) |
+ ( (u32)(c.zoom & 1) << 9)
+ ;
+
+ lua_pushinteger(L, keypress_bits);
return 1;
}
@@ -1590,8 +1598,7 @@ int ObjectRef::l_hud_set_flags(lua_State *L)
if (!getServer(L)->hudSetFlags(player, flags, mask))
return 0;
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// hud_get_flags(self)
@@ -1604,20 +1611,11 @@ int ObjectRef::l_hud_get_flags(lua_State *L)
return 0;
lua_newtable(L);
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE);
- lua_setfield(L, -2, "hotbar");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE);
- lua_setfield(L, -2, "healthbar");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE);
- lua_setfield(L, -2, "crosshair");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE);
- lua_setfield(L, -2, "wielditem");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE);
- lua_setfield(L, -2, "breathbar");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE);
- lua_setfield(L, -2, "minimap");
- lua_pushboolean(L, player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE);
- lua_setfield(L, -2, "minimap_radar");
+ const EnumString *esp = es_HudBuiltinElement;
+ for (int i = 0; esp[i].str; i++) {
+ lua_pushboolean(L, (player->hud_flags & esp[i].num) != 0);
+ lua_setfield(L, -2, esp[i].str);
+ }
return 1;
}
@@ -1722,9 +1720,11 @@ int ObjectRef::l_set_sky(lua_State *L)
return 0;
SkyboxParams sky_params = player->getSkyParams();
- bool is_colorspec = is_color_table(L, 2);
- if (lua_istable(L, 2) && !is_colorspec) {
+ // reset if empty
+ if (lua_isnoneornil(L, 2) && lua_isnone(L, 3)) {
+ sky_params = SkyboxDefaults::getSkyDefaults();
+ } else if (lua_istable(L, 2) && !is_color_table(L, 2)) {
lua_getfield(L, 2, "base_color");
if (!lua_isnil(L, -1))
read_color(L, -1, &sky_params.bgcolor);
@@ -1748,17 +1748,11 @@ int ObjectRef::l_set_sky(lua_State *L)
}
lua_pop(L, 1);
- /*
- We want to avoid crashes, so we're checking even if we're not using them.
- However, we want to ensure that the skybox can be set to nil when
- using "regular" or "plain" skybox modes as textures aren't needed.
- */
-
- if (sky_params.textures.size() != 6 && sky_params.textures.size() > 0)
+ // Validate that we either have six or zero textures
+ if (sky_params.textures.size() != 6 && !sky_params.textures.empty())
throw LuaError("Skybox expects 6 textures!");
- sky_params.clouds = getboolfield_default(L, 2,
- "clouds", sky_params.clouds);
+ sky_params.clouds = getboolfield_default(L, 2, "clouds", sky_params.clouds);
lua_getfield(L, 2, "sky_color");
if (lua_istable(L, -1)) {
@@ -1806,7 +1800,7 @@ int ObjectRef::l_set_sky(lua_State *L)
sky_params.fog_tint_type = luaL_checkstring(L, -1);
lua_pop(L, 1);
- // Because we need to leave the "sky_color" table.
+ // pop "sky_color" table
lua_pop(L, 1);
}
} else {
@@ -1842,11 +1836,8 @@ int ObjectRef::l_set_sky(lua_State *L)
if (lua_istable(L, 4)) {
lua_pushnil(L);
while (lua_next(L, 4) != 0) {
- // Key at index -2, and value at index -1
- if (lua_isstring(L, -1))
- sky_params.textures.emplace_back(readParam<std::string>(L, -1));
- else
- sky_params.textures.emplace_back("");
+ // Key at index -2, and value at index -1
+ sky_params.textures.emplace_back(readParam<std::string>(L, -1));
// Remove the value, keep the key for the next iteration
lua_pop(L, 1);
}
@@ -1862,12 +1853,39 @@ int ObjectRef::l_set_sky(lua_State *L)
getServer(L)->setMoon(player, moon_params);
getServer(L)->setStars(player, star_params);
}
+
getServer(L)->setSky(player, sky_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
+}
+
+static void push_sky_color(lua_State *L, const SkyboxParams &params)
+{
+ lua_newtable(L);
+ if (params.type == "regular") {
+ push_ARGB8(L, params.sky_color.day_sky);
+ lua_setfield(L, -2, "day_sky");
+ push_ARGB8(L, params.sky_color.day_horizon);
+ lua_setfield(L, -2, "day_horizon");
+ push_ARGB8(L, params.sky_color.dawn_sky);
+ lua_setfield(L, -2, "dawn_sky");
+ push_ARGB8(L, params.sky_color.dawn_horizon);
+ lua_setfield(L, -2, "dawn_horizon");
+ push_ARGB8(L, params.sky_color.night_sky);
+ lua_setfield(L, -2, "night_sky");
+ push_ARGB8(L, params.sky_color.night_horizon);
+ lua_setfield(L, -2, "night_horizon");
+ push_ARGB8(L, params.sky_color.indoors);
+ lua_setfield(L, -2, "indoors");
+ }
+ push_ARGB8(L, params.fog_sun_tint);
+ lua_setfield(L, -2, "fog_sun_tint");
+ push_ARGB8(L, params.fog_moon_tint);
+ lua_setfield(L, -2, "fog_moon_tint");
+ lua_pushstring(L, params.fog_tint_type.c_str());
+ lua_setfield(L, -2, "fog_tint_type");
}
-// get_sky(self)
+// get_sky(self, as_table)
int ObjectRef::l_get_sky(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -1876,10 +1894,30 @@ int ObjectRef::l_get_sky(lua_State *L)
if (player == nullptr)
return 0;
- SkyboxParams skybox_params = player->getSkyParams();
+ const SkyboxParams &skybox_params = player->getSkyParams();
+
+ // handle the deprecated version
+ if (!readParam<bool>(L, 2, false)) {
+ log_deprecated(L, "Deprecated call to get_sky, please check lua_api.txt");
+ push_ARGB8(L, skybox_params.bgcolor);
+ lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
+
+ lua_newtable(L);
+ s16 i = 1;
+ for (const std::string &texture : skybox_params.textures) {
+ lua_pushlstring(L, texture.c_str(), texture.size());
+ lua_rawseti(L, -2, i++);
+ }
+ lua_pushboolean(L, skybox_params.clouds);
+ return 4;
+ }
+
+ lua_newtable(L);
push_ARGB8(L, skybox_params.bgcolor);
+ lua_setfield(L, -2, "base_color");
lua_pushlstring(L, skybox_params.type.c_str(), skybox_params.type.size());
+ lua_setfield(L, -2, "type");
lua_newtable(L);
s16 i = 1;
@@ -1887,44 +1925,30 @@ int ObjectRef::l_get_sky(lua_State *L)
lua_pushlstring(L, texture.c_str(), texture.size());
lua_rawseti(L, -2, i++);
}
+ lua_setfield(L, -2, "textures");
lua_pushboolean(L, skybox_params.clouds);
- return 4;
+ lua_setfield(L, -2, "clouds");
+
+ push_sky_color(L, skybox_params);
+ lua_setfield(L, -2, "sky_color");
+ return 1;
}
+// DEPRECATED
// get_sky_color(self)
int ObjectRef::l_get_sky_color(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+
+ log_deprecated(L, "Deprecated call to get_sky_color, use get_sky instead");
+
ObjectRef *ref = checkobject(L, 1);
RemotePlayer *player = getplayer(ref);
if (player == nullptr)
return 0;
const SkyboxParams &skybox_params = player->getSkyParams();
-
- lua_newtable(L);
- if (skybox_params.type == "regular") {
- push_ARGB8(L, skybox_params.sky_color.day_sky);
- lua_setfield(L, -2, "day_sky");
- push_ARGB8(L, skybox_params.sky_color.day_horizon);
- lua_setfield(L, -2, "day_horizon");
- push_ARGB8(L, skybox_params.sky_color.dawn_sky);
- lua_setfield(L, -2, "dawn_sky");
- push_ARGB8(L, skybox_params.sky_color.dawn_horizon);
- lua_setfield(L, -2, "dawn_horizon");
- push_ARGB8(L, skybox_params.sky_color.night_sky);
- lua_setfield(L, -2, "night_sky");
- push_ARGB8(L, skybox_params.sky_color.night_horizon);
- lua_setfield(L, -2, "night_horizon");
- push_ARGB8(L, skybox_params.sky_color.indoors);
- lua_setfield(L, -2, "indoors");
- }
- push_ARGB8(L, skybox_params.fog_sun_tint);
- lua_setfield(L, -2, "fog_sun_tint");
- push_ARGB8(L, skybox_params.fog_moon_tint);
- lua_setfield(L, -2, "fog_moon_tint");
- lua_pushstring(L, skybox_params.fog_tint_type.c_str());
- lua_setfield(L, -2, "fog_tint_type");
+ push_sky_color(L, skybox_params);
return 1;
}
@@ -1937,25 +1961,23 @@ int ObjectRef::l_set_sun(lua_State *L)
if (player == nullptr)
return 0;
- luaL_checktype(L, 2, LUA_TTABLE);
SunParams sun_params = player->getSunParams();
- sun_params.visible = getboolfield_default(L, 2,
- "visible", sun_params.visible);
- sun_params.texture = getstringfield_default(L, 2,
- "texture", sun_params.texture);
- sun_params.tonemap = getstringfield_default(L, 2,
- "tonemap", sun_params.tonemap);
- sun_params.sunrise = getstringfield_default(L, 2,
- "sunrise", sun_params.sunrise);
- sun_params.sunrise_visible = getboolfield_default(L, 2,
- "sunrise_visible", sun_params.sunrise_visible);
- sun_params.scale = getfloatfield_default(L, 2,
- "scale", sun_params.scale);
+ // reset if empty
+ if (lua_isnoneornil(L, 2)) {
+ sun_params = SkyboxDefaults::getSunDefaults();
+ } else {
+ luaL_checktype(L, 2, LUA_TTABLE);
+ sun_params.visible = getboolfield_default(L, 2, "visible", sun_params.visible);
+ sun_params.texture = getstringfield_default(L, 2, "texture", sun_params.texture);
+ sun_params.tonemap = getstringfield_default(L, 2, "tonemap", sun_params.tonemap);
+ sun_params.sunrise = getstringfield_default(L, 2, "sunrise", sun_params.sunrise);
+ sun_params.sunrise_visible = getboolfield_default(L, 2, "sunrise_visible", sun_params.sunrise_visible);
+ sun_params.scale = getfloatfield_default(L, 2, "scale", sun_params.scale);
+ }
getServer(L)->setSun(player, sun_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
//get_sun(self)
@@ -1994,21 +2016,21 @@ int ObjectRef::l_set_moon(lua_State *L)
if (player == nullptr)
return 0;
- luaL_checktype(L, 2, LUA_TTABLE);
MoonParams moon_params = player->getMoonParams();
- moon_params.visible = getboolfield_default(L, 2,
- "visible", moon_params.visible);
- moon_params.texture = getstringfield_default(L, 2,
- "texture", moon_params.texture);
- moon_params.tonemap = getstringfield_default(L, 2,
- "tonemap", moon_params.tonemap);
- moon_params.scale = getfloatfield_default(L, 2,
- "scale", moon_params.scale);
+ // reset if empty
+ if (lua_isnoneornil(L, 2)) {
+ moon_params = SkyboxDefaults::getMoonDefaults();
+ } else {
+ luaL_checktype(L, 2, LUA_TTABLE);
+ moon_params.visible = getboolfield_default(L, 2, "visible", moon_params.visible);
+ moon_params.texture = getstringfield_default(L, 2, "texture", moon_params.texture);
+ moon_params.tonemap = getstringfield_default(L, 2, "tonemap", moon_params.tonemap);
+ moon_params.scale = getfloatfield_default(L, 2, "scale", moon_params.scale);
+ }
getServer(L)->setMoon(player, moon_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_moon(self)
@@ -2043,25 +2065,27 @@ int ObjectRef::l_set_stars(lua_State *L)
if (player == nullptr)
return 0;
- luaL_checktype(L, 2, LUA_TTABLE);
StarParams star_params = player->getStarParams();
- star_params.visible = getboolfield_default(L, 2,
- "visible", star_params.visible);
- star_params.count = getintfield_default(L, 2,
- "count", star_params.count);
+ // reset if empty
+ if (lua_isnoneornil(L, 2)) {
+ star_params = SkyboxDefaults::getStarDefaults();
+ } else {
+ luaL_checktype(L, 2, LUA_TTABLE);
+ star_params.visible = getboolfield_default(L, 2, "visible", star_params.visible);
+ star_params.count = getintfield_default(L, 2, "count", star_params.count);
- lua_getfield(L, 2, "star_color");
- if (!lua_isnil(L, -1))
- read_color(L, -1, &star_params.starcolor);
- lua_pop(L, 1);
+ lua_getfield(L, 2, "star_color");
+ if (!lua_isnil(L, -1))
+ read_color(L, -1, &star_params.starcolor);
+ lua_pop(L, 1);
- star_params.scale = getfloatfield_default(L, 2,
- "scale", star_params.scale);
+ star_params.scale = getfloatfield_default(L, 2,
+ "scale", star_params.scale);
+ }
getServer(L)->setStars(player, star_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_stars(self)
@@ -2096,35 +2120,39 @@ int ObjectRef::l_set_clouds(lua_State *L)
if (player == nullptr)
return 0;
- luaL_checktype(L, 2, LUA_TTABLE);
CloudParams cloud_params = player->getCloudParams();
- cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
+ // reset if empty
+ if (lua_isnoneornil(L, 2)) {
+ cloud_params = SkyboxDefaults::getCloudDefaults();
+ } else {
+ luaL_checktype(L, 2, LUA_TTABLE);
+ cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density);
- lua_getfield(L, 2, "color");
- if (!lua_isnil(L, -1))
- read_color(L, -1, &cloud_params.color_bright);
- lua_pop(L, 1);
- lua_getfield(L, 2, "ambient");
- if (!lua_isnil(L, -1))
- read_color(L, -1, &cloud_params.color_ambient);
- lua_pop(L, 1);
+ lua_getfield(L, 2, "color");
+ if (!lua_isnil(L, -1))
+ read_color(L, -1, &cloud_params.color_bright);
+ lua_pop(L, 1);
+ lua_getfield(L, 2, "ambient");
+ if (!lua_isnil(L, -1))
+ read_color(L, -1, &cloud_params.color_ambient);
+ lua_pop(L, 1);
- cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height );
- cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
+ cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height);
+ cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness);
- lua_getfield(L, 2, "speed");
- if (lua_istable(L, -1)) {
- v2f new_speed;
- new_speed.X = getfloatfield_default(L, -1, "x", 0);
- new_speed.Y = getfloatfield_default(L, -1, "z", 0);
- cloud_params.speed = new_speed;
+ lua_getfield(L, 2, "speed");
+ if (lua_istable(L, -1)) {
+ v2f new_speed;
+ new_speed.X = getfloatfield_default(L, -1, "x", 0);
+ new_speed.Y = getfloatfield_default(L, -1, "z", 0);
+ cloud_params.speed = new_speed;
+ }
+ lua_pop(L, 1);
}
- lua_pop(L, 1);
getServer(L)->setClouds(player, cloud_params);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
int ObjectRef::l_get_clouds(lua_State *L)
@@ -2178,8 +2206,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
}
getServer(L)->overrideDayNightRatio(player, do_override, ratio);
- lua_pushboolean(L, true);
- return 1;
+ return 0;
}
// get_day_night_ratio(self)
@@ -2256,6 +2283,46 @@ int ObjectRef::l_set_minimap_modes(lua_State *L)
return 0;
}
+// set_lighting(self, lighting)
+int ObjectRef::l_set_lighting(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (player == nullptr)
+ return 0;
+
+ luaL_checktype(L, 2, LUA_TTABLE);
+ Lighting lighting = player->getLighting();
+ lua_getfield(L, 2, "shadows");
+ if (lua_istable(L, -1)) {
+ lighting.shadow_intensity = getfloatfield_default(L, -1, "intensity", lighting.shadow_intensity);
+ }
+ lua_pop(L, -1);
+
+ getServer(L)->setLighting(player, lighting);
+ return 0;
+}
+
+// get_lighting(self)
+int ObjectRef::l_get_lighting(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ RemotePlayer *player = getplayer(ref);
+ if (player == nullptr)
+ return 0;
+
+ const Lighting &lighting = player->getLighting();
+
+ lua_newtable(L); // result
+ lua_newtable(L); // "shadows"
+ lua_pushnumber(L, lighting.shadow_intensity);
+ lua_setfield(L, -2, "intensity");
+ lua_setfield(L, -2, "shadows");
+ return 1;
+}
+
ObjectRef::ObjectRef(ServerActiveObject *object):
m_object(object)
{}
@@ -2409,5 +2476,7 @@ luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_eye_offset),
luamethod(ObjectRef, send_mapblock),
luamethod(ObjectRef, set_minimap_modes),
+ luamethod(ObjectRef, set_lighting),
+ luamethod(ObjectRef, get_lighting),
{0,0}
};
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index db3a3a7cf..3e4e6681a 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -316,9 +316,10 @@ private:
// set_sky(self, sky_parameters)
static int l_set_sky(lua_State *L);
- // get_sky(self)
+ // get_sky(self, as_table)
static int l_get_sky(lua_State *L);
+ // DEPRECATED
// get_sky_color(self)
static int l_get_sky_color(lua_State* L);
@@ -375,4 +376,10 @@ private:
// set_minimap_modes(self, modes, wanted_mode)
static int l_set_minimap_modes(lua_State *L);
+
+ // set_lighting(self, lighting)
+ static int l_set_lighting(lua_State *L);
+
+ // get_lighting(self)
+ static int l_get_lighting(lua_State *L);
};
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index b4672fe2a..e8105dd75 100644
--- a/src/script/lua_api/l_server.cpp
+++ b/src/script/lua_api/l_server.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "common/c_packer.h"
#include "cpp_api/s_base.h"
#include "cpp_api/s_security.h"
#include "scripting_server.h"
@@ -57,6 +58,14 @@ int ModApiServer::l_get_server_uptime(lua_State *L)
return 1;
}
+// get_server_max_lag()
+int ModApiServer::l_get_server_max_lag(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ GET_ENV_PTR;
+ lua_pushnumber(L, env->getMaxLagEstimate());
+ return 1;
+}
// print(text)
int ModApiServer::l_print(lua_State *L)
@@ -282,8 +291,10 @@ int ModApiServer::l_ban_player(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- Server *server = getServer(L);
+ if (!getEnv(L))
+ throw LuaError("Can't ban player before server has started up");
+ Server *server = getServer(L);
const char *name = luaL_checkstring(L, 1);
RemotePlayer *player = server->getEnv().getPlayer(name);
if (!player) {
@@ -297,23 +308,30 @@ int ModApiServer::l_ban_player(lua_State *L)
return 1;
}
-// kick_player(name, [reason]) -> success
-int ModApiServer::l_kick_player(lua_State *L)
+// disconnect_player(name, [reason]) -> success
+int ModApiServer::l_disconnect_player(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+
+ if (!getEnv(L))
+ throw LuaError("Can't kick player before server has started up");
+
const char *name = luaL_checkstring(L, 1);
- std::string message("Kicked");
+ std::string message;
if (lua_isstring(L, 2))
- message.append(": ").append(readParam<std::string>(L, 2));
+ message.append(readParam<std::string>(L, 2));
else
- message.append(".");
+ message.append("Disconnected.");
+
+ Server *server = getServer(L);
- RemotePlayer *player = dynamic_cast<ServerEnvironment *>(getEnv(L))->getPlayer(name);
- if (player == NULL) {
+ RemotePlayer *player = server->getEnv().getPlayer(name);
+ if (!player) {
lua_pushboolean(L, false); // No such player
return 1;
}
- getServer(L)->DenyAccess_Legacy(player->getPeerId(), utf8_to_wide(message));
+
+ server->DenyAccess(player->getPeerId(), SERVER_ACCESSDENIED_CUSTOM_STRING, message);
lua_pushboolean(L, true);
return 1;
}
@@ -324,7 +342,8 @@ int ModApiServer::l_remove_player(lua_State *L)
NO_MAP_LOCK_REQUIRED;
std::string name = luaL_checkstring(L, 1);
ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L));
- assert(s_env);
+ if (!s_env)
+ throw LuaError("Can't remove player before server has started up");
RemotePlayer *player = s_env->getPlayer(name.c_str());
if (!player)
@@ -375,12 +394,11 @@ int ModApiServer::l_get_modpath(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::string modname = luaL_checkstring(L, 1);
- const ModSpec *mod = getServer(L)->getModSpec(modname);
- if (!mod) {
+ const ModSpec *mod = getGameDef(L)->getModSpec(modname);
+ if (!mod)
lua_pushnil(L);
- return 1;
- }
- lua_pushstring(L, mod->path.c_str());
+ else
+ lua_pushstring(L, mod->path.c_str());
return 1;
}
@@ -392,13 +410,14 @@ int ModApiServer::l_get_modnames(lua_State *L)
// Get a list of mods
std::vector<std::string> modlist;
- getServer(L)->getModNames(modlist);
+ for (auto &it : getGameDef(L)->getMods())
+ modlist.emplace_back(it.name);
std::sort(modlist.begin(), modlist.end());
// Package them up for Lua
lua_createtable(L, modlist.size(), 0);
- std::vector<std::string>::iterator iter = modlist.begin();
+ auto iter = modlist.begin();
for (u16 i = 0; iter != modlist.end(); ++iter) {
lua_pushstring(L, iter->c_str());
lua_rawseti(L, -2, ++i);
@@ -410,8 +429,8 @@ int ModApiServer::l_get_modnames(lua_State *L)
int ModApiServer::l_get_worldpath(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- std::string worldpath = getServer(L)->getWorldPath();
- lua_pushstring(L, worldpath.c_str());
+ const Server *srv = getServer(L);
+ lua_pushstring(L, srv->getWorldPath().c_str());
return 1;
}
@@ -479,7 +498,7 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
CHECK_SECURE_PATH(L, filepath.c_str(), false);
- u32 token = server->getScriptIface()->allocateDynamicMediaCallback(2);
+ u32 token = server->getScriptIface()->allocateDynamicMediaCallback(L, 2);
bool ok = server->dynamicAddMedia(filepath, token, to_player, ephemeral);
if (!ok)
@@ -493,7 +512,8 @@ int ModApiServer::l_dynamic_add_media(lua_State *L)
int ModApiServer::l_is_singleplayer(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- lua_pushboolean(L, getServer(L)->isSingleplayer());
+ const Server *srv = getServer(L);
+ lua_pushboolean(L, srv->isSingleplayer());
return 1;
}
@@ -508,11 +528,82 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L)
return 0;
}
+// do_async_callback(func, params, mod_origin)
+int ModApiServer::l_do_async_callback(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ServerScripting *script = getScriptApi<ServerScripting>(L);
+
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ luaL_checktype(L, 2, LUA_TTABLE);
+ luaL_checktype(L, 3, LUA_TSTRING);
+
+ call_string_dump(L, 1);
+ size_t func_length;
+ const char *serialized_func_raw = lua_tolstring(L, -1, &func_length);
+
+ PackedValue *param = script_pack(L, 2);
+
+ std::string mod_origin = readParam<std::string>(L, 3);
+
+ u32 jobId = script->queueAsync(
+ std::string(serialized_func_raw, func_length),
+ param, mod_origin);
+
+ lua_settop(L, 0);
+ lua_pushinteger(L, jobId);
+ return 1;
+}
+
+// register_async_dofile(path)
+int ModApiServer::l_register_async_dofile(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ std::string path = readParam<std::string>(L, 1);
+ CHECK_SECURE_PATH(L, path.c_str(), false);
+
+ // Find currently running mod name (only at init time)
+ lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
+ if (!lua_isstring(L, -1))
+ return 0;
+ std::string modname = readParam<std::string>(L, -1);
+
+ getServer(L)->m_async_init_files.emplace_back(modname, path);
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// serialize_roundtrip(value)
+// Meant for unit testing the packer from Lua
+int ModApiServer::l_serialize_roundtrip(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ int top = lua_gettop(L);
+ auto *pv = script_pack(L, 1);
+ if (top != lua_gettop(L))
+ throw LuaError("stack values leaked");
+
+#ifndef NDEBUG
+ script_dump_packed(pv);
+#endif
+
+ top = lua_gettop(L);
+ script_unpack(L, pv);
+ delete pv;
+ if (top + 1 != lua_gettop(L))
+ throw LuaError("stack values leaked");
+
+ return 1;
+}
+
void ModApiServer::Initialize(lua_State *L, int top)
{
API_FCT(request_shutdown);
API_FCT(get_server_status);
API_FCT(get_server_uptime);
+ API_FCT(get_server_max_lag);
API_FCT(get_worldpath);
API_FCT(is_singleplayer);
@@ -536,7 +627,22 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(get_ban_list);
API_FCT(get_ban_description);
API_FCT(ban_player);
- API_FCT(kick_player);
+ API_FCT(disconnect_player);
+ API_FCT(remove_player);
API_FCT(unban_player_or_ip);
API_FCT(notify_authentication_modified);
+
+ API_FCT(do_async_callback);
+ API_FCT(register_async_dofile);
+ API_FCT(serialize_roundtrip);
+}
+
+void ModApiServer::InitializeAsync(lua_State *L, int top)
+{
+ API_FCT(get_worldpath);
+ API_FCT(is_singleplayer);
+
+ API_FCT(get_current_modname);
+ API_FCT(get_modpath);
+ API_FCT(get_modnames);
}
diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h
index c688e494b..a4f38c34e 100644
--- a/src/script/lua_api/l_server.h
+++ b/src/script/lua_api/l_server.h
@@ -33,6 +33,9 @@ private:
// get_server_uptime()
static int l_get_server_uptime(lua_State *L);
+ // get_server_max_lag()
+ static int l_get_server_max_lag(lua_State *L);
+
// get_worldpath()
static int l_get_worldpath(lua_State *L);
@@ -94,8 +97,8 @@ private:
// unban_player_or_ip()
static int l_unban_player_or_ip(lua_State *L);
- // kick_player(name, [message]) -> success
- static int l_kick_player(lua_State *L);
+ // disconnect_player(name, [reason]) -> success
+ static int l_disconnect_player(lua_State *L);
// remove_player(name)
static int l_remove_player(lua_State *L);
@@ -103,6 +106,16 @@ private:
// notify_authentication_modified(name)
static int l_notify_authentication_modified(lua_State *L);
+ // do_async_callback(func, params, mod_origin)
+ static int l_do_async_callback(lua_State *L);
+
+ // register_async_dofile(path)
+ static int l_register_async_dofile(lua_State *L);
+
+ // serialize_roundtrip(obj)
+ static int l_serialize_roundtrip(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
+ static void InitializeAsync(lua_State *L, int top);
};
diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp
index 978b315d5..b8f4347a8 100644
--- a/src/script/lua_api/l_storage.cpp
+++ b/src/script/lua_api/l_storage.cpp
@@ -32,19 +32,23 @@ int ModApiStorage::l_get_mod_storage(lua_State *L)
std::string mod_name = readParam<std::string>(L, -1);
- ModMetadata *store = new ModMetadata(mod_name);
+ ModMetadata *store = nullptr;
+
if (IGameDef *gamedef = getGameDef(L)) {
- store->load(gamedef->getModStoragePath());
- gamedef->registerModStorage(store);
+ store = new ModMetadata(mod_name, gamedef->getModStorageDatabase());
+ if (gamedef->registerModStorage(store)) {
+ StorageRef::create(L, store);
+ int object = lua_gettop(L);
+ lua_pushvalue(L, object);
+ return 1;
+ }
} else {
- delete store;
assert(false); // this should not happen
}
- StorageRef::create(L, store);
- int object = lua_gettop(L);
+ delete store;
- lua_pushvalue(L, object);
+ lua_pushnil(L);
return 1;
}
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index d575eb603..fa749c2e5 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -41,7 +41,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/hex.h"
#include "util/sha1.h"
#include "util/png.h"
-#include <algorithm>
#include <cstdio>
// log([level,] text)
@@ -160,28 +159,33 @@ int ModApiUtil::l_write_json(lua_State *L)
return 1;
}
-// get_dig_params(groups, tool_capabilities)
+// get_dig_params(groups, tool_capabilities[, wear])
int ModApiUtil::l_get_dig_params(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ItemGroupList groups;
read_groups(L, 1, groups);
ToolCapabilities tp = read_tool_capabilities(L, 2);
- push_dig_params(L, getDigParams(groups, &tp));
+ if (lua_isnoneornil(L, 3)) {
+ push_dig_params(L, getDigParams(groups, &tp));
+ } else {
+ u16 wear = readParam<int>(L, 3);
+ push_dig_params(L, getDigParams(groups, &tp, wear));
+ }
return 1;
}
-// get_hit_params(groups, tool_capabilities[, time_from_last_punch])
+// get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]])
int ModApiUtil::l_get_hit_params(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
std::unordered_map<std::string, int> groups;
read_groups(L, 1, groups);
ToolCapabilities tp = read_tool_capabilities(L, 2);
- if(lua_isnoneornil(L, 3))
- push_hit_params(L, getHitParams(groups, &tp));
- else
- push_hit_params(L, getHitParams(groups, &tp, readParam<float>(L, 3)));
+ float time_from_last_punch = readParam<float>(L, 3, 1000000);
+ int wear = readParam<int>(L, 4, 0);
+ push_hit_params(L, getHitParams(groups, &tp,
+ time_from_last_punch, wear));
return 1;
}
@@ -344,6 +348,49 @@ int ModApiUtil::l_mkdir(lua_State *L)
return 1;
}
+// rmdir(path, recursive)
+int ModApiUtil::l_rmdir(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ const char *path = luaL_checkstring(L, 1);
+ CHECK_SECURE_PATH(L, path, true);
+
+ bool recursive = readParam<bool>(L, 2, false);
+
+ if (recursive)
+ lua_pushboolean(L, fs::RecursiveDelete(path));
+ else
+ lua_pushboolean(L, fs::DeleteSingleFileOrEmptyDirectory(path));
+
+ return 1;
+}
+
+// cpdir(source, destination)
+int ModApiUtil::l_cpdir(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ const char *source = luaL_checkstring(L, 1);
+ const char *destination = luaL_checkstring(L, 2);
+ CHECK_SECURE_PATH(L, source, false);
+ CHECK_SECURE_PATH(L, destination, true);
+
+ lua_pushboolean(L, fs::CopyDir(source, destination));
+ return 1;
+}
+
+// mpdir(source, destination)
+int ModApiUtil::l_mvdir(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ const char *source = luaL_checkstring(L, 1);
+ const char *destination = luaL_checkstring(L, 2);
+ CHECK_SECURE_PATH(L, source, true);
+ CHECK_SECURE_PATH(L, destination, true);
+
+ lua_pushboolean(L, fs::MoveDir(source, destination));
+ return 1;
+}
+
// get_dir_list(path, is_dir)
int ModApiUtil::l_get_dir_list(lua_State *L)
{
@@ -396,36 +443,7 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L)
return 1;
}
- // 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)) {
- return 0;
- }
-
- // Check secure.trusted_mods
- std::string mod_name = readParam<std::string>(L, -1);
- std::string trusted_mods = g_settings->get("secure.trusted_mods");
- trusted_mods.erase(std::remove_if(trusted_mods.begin(),
- trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)),
- 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()) {
+ if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
return 0;
}
@@ -583,6 +601,9 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(decompress);
API_FCT(mkdir);
+ API_FCT(rmdir);
+ API_FCT(cpdir);
+ API_FCT(mvdir);
API_FCT(get_dir_list);
API_FCT(safe_file_write);
@@ -651,7 +672,13 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
API_FCT(decompress);
API_FCT(mkdir);
+ API_FCT(rmdir);
+ API_FCT(cpdir);
+ API_FCT(mvdir);
API_FCT(get_dir_list);
+ API_FCT(safe_file_write);
+
+ API_FCT(request_insecure_environment);
API_FCT(encode_base64);
API_FCT(decode_base64);
@@ -661,6 +688,8 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
API_FCT(colorspec_to_colorstring);
API_FCT(colorspec_to_bytes);
+ API_FCT(encode_png);
+
API_FCT(get_last_run_mod);
API_FCT(set_last_run_mod);
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index cc91e8d39..cc5563577 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -50,10 +50,10 @@ private:
// write_json(data[, styled])
static int l_write_json(lua_State *L);
- // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
+ // get_dig_params(groups, tool_capabilities[, wear])
static int l_get_dig_params(lua_State *L);
- // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
+ // get_hit_params(groups, tool_capabilities[, time_from_last_punch[, wear]])
static int l_get_hit_params(lua_State *L);
// check_password_entry(name, entry, password)
@@ -80,6 +80,15 @@ private:
// mkdir(path)
static int l_mkdir(lua_State *L);
+ // rmdir(path, recursive)
+ static int l_rmdir(lua_State *L);
+
+ // cpdir(source, destination, remove_source)
+ static int l_cpdir(lua_State *L);
+
+ // mvdir(source, destination)
+ static int l_mvdir(lua_State *L);
+
// get_dir_list(path, is_dir)
static int l_get_dir_list(lua_State *L);
@@ -120,6 +129,4 @@ public:
static void Initialize(lua_State *L, int top);
static void InitializeAsync(lua_State *L, int top);
static void InitializeClient(lua_State *L, int top);
-
- static void InitializeAsync(AsyncEngine &engine);
};
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index e040e545b..6187a47db 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -17,11 +17,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
+#include <map>
#include "lua_api/l_vmanip.h"
#include "lua_api/l_internal.h"
#include "common/c_content.h"
#include "common/c_converter.h"
+#include "common/c_packer.h"
#include "emerge.h"
#include "environment.h"
#include "map.h"
@@ -45,6 +46,8 @@ int LuaVoxelManip::l_read_from_map(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
+ if (vm->isOrphan())
+ return 0;
v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
@@ -112,23 +115,23 @@ int LuaVoxelManip::l_write_to_map(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
bool update_light = !lua_isboolean(L, 2) || readParam<bool>(L, 2);
+
GET_ENV_PTR;
ServerMap *map = &(env->getServerMap());
+
+ std::map<v3s16, MapBlock*> modified_blocks;
if (o->is_mapgen_vm || !update_light) {
- o->vm->blitBackAll(&(o->modified_blocks));
+ o->vm->blitBackAll(&modified_blocks);
} else {
- voxalgo::blit_back_with_light(map, o->vm,
- &(o->modified_blocks));
+ voxalgo::blit_back_with_light(map, o->vm, &modified_blocks);
}
MapEditEvent event;
event.type = MEET_OTHER;
- for (const auto &modified_block : o->modified_blocks)
- event.modified_blocks.insert(modified_block.first);
-
+ for (const auto &it : modified_blocks)
+ event.modified_blocks.insert(it.first);
map->dispatchEvent(event);
- o->modified_blocks.clear();
return 0;
}
@@ -166,7 +169,7 @@ int LuaVoxelManip::l_update_liquids(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
- Map *map = &(env->getMap());
+ ServerMap *map = &(env->getServerMap());
const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
MMVManip *vm = o->vm;
@@ -429,6 +432,34 @@ LuaVoxelManip *LuaVoxelManip::checkobject(lua_State *L, int narg)
return *(LuaVoxelManip **)ud; // unbox pointer
}
+void *LuaVoxelManip::packIn(lua_State *L, int idx)
+{
+ LuaVoxelManip *o = checkobject(L, idx);
+
+ if (o->is_mapgen_vm)
+ throw LuaError("nope");
+ return o->vm->clone();
+}
+
+void LuaVoxelManip::packOut(lua_State *L, void *ptr)
+{
+ MMVManip *vm = reinterpret_cast<MMVManip*>(ptr);
+ if (!L) {
+ delete vm;
+ return;
+ }
+
+ // Associate vmanip with map if the Lua env has one
+ Environment *env = getEnv(L);
+ if (env)
+ vm->reparent(&(env->getMap()));
+
+ LuaVoxelManip *o = new LuaVoxelManip(vm, false);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+}
+
void LuaVoxelManip::Register(lua_State *L)
{
lua_newtable(L);
@@ -455,6 +486,8 @@ void LuaVoxelManip::Register(lua_State *L)
// Can be created from Lua (VoxelManip())
lua_register(L, className, create_object);
+
+ script_register_packer(L, className, packIn, packOut);
}
const char LuaVoxelManip::className[] = "VoxelManip";
diff --git a/src/script/lua_api/l_vmanip.h b/src/script/lua_api/l_vmanip.h
index 15ab9eef8..005133335 100644
--- a/src/script/lua_api/l_vmanip.h
+++ b/src/script/lua_api/l_vmanip.h
@@ -19,7 +19,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
-#include <map>
#include "irr_v3d.h"
#include "lua_api/l_base.h"
@@ -33,7 +32,6 @@ class MMVManip;
class LuaVoxelManip : public ModApiBase
{
private:
- std::map<v3s16, MapBlock *> modified_blocks;
bool is_mapgen_vm = false;
static const char className[];
@@ -77,5 +75,8 @@ public:
static LuaVoxelManip *checkobject(lua_State *L, int narg);
+ static void *packIn(lua_State *L, int idx);
+ static void packOut(lua_State *L, void *ptr);
+
static void Register(lua_State *L);
};