aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/CMakeLists.txt9
-rw-r--r--src/script/common/CMakeLists.txt5
-rw-r--r--src/script/common/c_content.cpp189
-rw-r--r--src/script/common/c_content.h69
-rw-r--r--src/script/common/c_converter.cpp300
-rw-r--r--src/script/common/c_converter.h38
-rw-r--r--src/script/common/c_internal.cpp84
-rw-r--r--src/script/common/c_internal.h17
-rw-r--r--src/script/cpp_api/CMakeLists.txt8
-rw-r--r--src/script/cpp_api/s_async.cpp15
-rw-r--r--src/script/cpp_api/s_base.cpp156
-rw-r--r--src/script/cpp_api/s_base.h39
-rw-r--r--src/script/cpp_api/s_entity.cpp35
-rw-r--r--src/script/cpp_api/s_env.cpp6
-rw-r--r--src/script/cpp_api/s_internal.h1
-rw-r--r--src/script/cpp_api/s_inventory.cpp21
-rw-r--r--src/script/cpp_api/s_item.cpp20
-rw-r--r--src/script/cpp_api/s_mainmenu.cpp22
-rw-r--r--src/script/cpp_api/s_mainmenu.h15
-rw-r--r--src/script/cpp_api/s_node.cpp34
-rw-r--r--src/script/cpp_api/s_node.h5
-rw-r--r--src/script/cpp_api/s_nodemeta.cpp24
-rw-r--r--src/script/cpp_api/s_player.cpp79
-rw-r--r--src/script/cpp_api/s_player.h16
-rw-r--r--src/script/cpp_api/s_security.cpp604
-rw-r--r--src/script/cpp_api/s_security.h70
-rw-r--r--src/script/cpp_api/s_server.cpp16
-rw-r--r--src/script/lua_api/CMakeLists.txt6
-rw-r--r--src/script/lua_api/l_areastore.cpp401
-rw-r--r--src/script/lua_api/l_areastore.h70
-rw-r--r--src/script/lua_api/l_base.cpp40
-rw-r--r--src/script/lua_api/l_base.h4
-rw-r--r--src/script/lua_api/l_craft.cpp183
-rw-r--r--src/script/lua_api/l_env.cpp147
-rw-r--r--src/script/lua_api/l_env.h8
-rw-r--r--src/script/lua_api/l_internal.h13
-rw-r--r--src/script/lua_api/l_mainmenu.cpp115
-rw-r--r--src/script/lua_api/l_mainmenu.h2
-rw-r--r--src/script/lua_api/l_mapgen.cpp986
-rw-r--r--src/script/lua_api/l_mapgen.h35
-rw-r--r--src/script/lua_api/l_nodemeta.cpp27
-rw-r--r--src/script/lua_api/l_noise.cpp338
-rw-r--r--src/script/lua_api/l_noise.h54
-rw-r--r--src/script/lua_api/l_object.cpp584
-rw-r--r--src/script/lua_api/l_object.h58
-rw-r--r--src/script/lua_api/l_particles.cpp214
-rw-r--r--src/script/lua_api/l_server.cpp63
-rw-r--r--src/script/lua_api/l_server.h8
-rw-r--r--src/script/lua_api/l_settings.cpp2
-rw-r--r--src/script/lua_api/l_util.cpp90
-rw-r--r--src/script/lua_api/l_util.h12
-rw-r--r--src/script/lua_api/l_vmanip.cpp50
-rw-r--r--src/script/scripting_game.cpp14
-rw-r--r--src/script/scripting_game.h20
-rw-r--r--src/script/scripting_mainmenu.cpp2
55 files changed, 4146 insertions, 1297 deletions
diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt
index 491c05a1e..5ef672ca9 100644
--- a/src/script/CMakeLists.txt
+++ b/src/script/CMakeLists.txt
@@ -11,9 +11,10 @@ set(common_SCRIPT_SRCS
PARENT_SCOPE)
# Used by client only
-set(minetest_SCRIPT_SRCS
+set(client_SCRIPT_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/scripting_mainmenu.cpp
- ${minetest_SCRIPT_COMMON_SRCS}
- ${minetest_SCRIPT_CPP_API_SRCS}
- ${minetest_SCRIPT_LUA_API_SRCS}
+ ${client_SCRIPT_COMMON_SRCS}
+ ${client_SCRIPT_CPP_API_SRCS}
+ ${client_SCRIPT_LUA_API_SRCS}
PARENT_SCOPE)
+
diff --git a/src/script/common/CMakeLists.txt b/src/script/common/CMakeLists.txt
index 27e2fb4d5..4a8e6bab5 100644
--- a/src/script/common/CMakeLists.txt
+++ b/src/script/common/CMakeLists.txt
@@ -1,4 +1,3 @@
-# Used by server and client
set(common_SCRIPT_COMMON_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/c_content.cpp
${CMAKE_CURRENT_SOURCE_DIR}/c_converter.cpp
@@ -6,6 +5,6 @@ set(common_SCRIPT_COMMON_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/c_internal.cpp
PARENT_SCOPE)
-# Used by client only
-set(minetest_SCRIPT_COMMON_SRCS
+set(client_SCRIPT_COMMON_SRCS
PARENT_SCOPE)
+
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index ff9aee8ed..3754fc2ff 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -162,18 +162,13 @@ void read_object_properties(lua_State *L, int index,
lua_pop(L, 1);
lua_getfield(L, -1, "colors");
- if(lua_istable(L, -1)){
- prop->colors.clear();
+ 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
- if(lua_isstring(L, -1))
- prop->colors.push_back(readARGB8(L, -1));
- else
- prop->colors.push_back(video::SColor(255, 255, 255, 255));
- // removes value, keeps key for next iteration
- lua_pop(L, 1);
+ prop->colors.clear();
+ for (lua_pushnil(L); lua_next(L, table); lua_pop(L, 1)) {
+ video::SColor color(255, 255, 255, 255);
+ read_color(L, -1, &color);
+ prop->colors.push_back(color);
}
}
lua_pop(L, 1);
@@ -205,17 +200,78 @@ void read_object_properties(lua_State *L, int index,
}
/******************************************************************************/
-TileDef read_tiledef(lua_State *L, int index)
+void push_object_properties(lua_State *L, ObjectProperties *prop)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, prop->hp_max);
+ lua_setfield(L, -2, "hp_max");
+ lua_pushboolean(L, prop->physical);
+ lua_setfield(L, -2, "physical");
+ lua_pushboolean(L, prop->collideWithObjects);
+ lua_setfield(L, -2, "collide_with_objects");
+ lua_pushnumber(L, prop->weight);
+ lua_setfield(L, -2, "weight");
+ push_aabb3f(L, prop->collisionbox);
+ lua_setfield(L, -2, "collisionbox");
+ lua_pushlstring(L, prop->visual.c_str(), prop->visual.size());
+ lua_setfield(L, -2, "visual");
+ lua_pushlstring(L, prop->mesh.c_str(), prop->mesh.size());
+ lua_setfield(L, -2, "mesh");
+ push_v2f(L, prop->visual_size);
+ lua_setfield(L, -2, "visual_size");
+
+ lua_newtable(L);
+ u16 i = 1;
+ for (std::vector<std::string>::iterator it = prop->textures.begin();
+ it != prop->textures.end(); ++it) {
+ lua_pushlstring(L, it->c_str(), it->size());
+ lua_rawseti(L, -2, i);
+ }
+ lua_setfield(L, -2, "textures");
+
+ lua_newtable(L);
+ i = 1;
+ for (std::vector<video::SColor>::iterator it = prop->colors.begin();
+ it != prop->colors.end(); ++it) {
+ push_ARGB8(L, *it);
+ lua_rawseti(L, -2, i);
+ }
+ lua_setfield(L, -2, "colors");
+
+ push_v2s16(L, prop->spritediv);
+ lua_setfield(L, -2, "spritediv");
+ push_v2s16(L, prop->initial_sprite_basepos);
+ lua_setfield(L, -2, "initial_sprite_basepos");
+ lua_pushboolean(L, prop->is_visible);
+ lua_setfield(L, -2, "is_visible");
+ lua_pushboolean(L, prop->makes_footstep_sound);
+ lua_setfield(L, -2, "makes_footstep_sound");
+ lua_pushnumber(L, prop->automatic_rotate);
+ lua_setfield(L, -2, "automatic_rotate");
+ lua_pushnumber(L, prop->stepheight / BS);
+ lua_setfield(L, -2, "stepheight");
+ if (prop->automatic_face_movement_dir)
+ lua_pushnumber(L, prop->automatic_face_movement_dir_offset);
+ else
+ lua_pushboolean(L, false);
+ lua_setfield(L, -2, "automatic_face_movement_dir");
+}
+
+/******************************************************************************/
+TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
{
if(index < 0)
index = lua_gettop(L) + 1 + index;
TileDef tiledef;
-
+ bool default_tiling = (drawtype == NDT_PLANTLIKE || drawtype == NDT_FIRELIKE)
+ ? false : true;
// 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;
}
else if(lua_istable(L, index))
{
@@ -224,20 +280,24 @@ TileDef read_tiledef(lua_State *L, int index)
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", true);
+ tiledef.tileable_horizontal = getboolfield_default(
+ L, index, "tileable_horizontal", default_tiling);
+ tiledef.tileable_vertical = getboolfield_default(
+ L, index, "tileable_vertical", default_tiling);
// animation = {}
lua_getfield(L, index, "animation");
if(lua_istable(L, -1)){
// {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
tiledef.animation.type = (TileAnimationType)
- getenumfield(L, -1, "type", es_TileAnimationType,
- TAT_NONE);
+ getenumfield(L, -1, "type", es_TileAnimationType,
+ TAT_NONE);
tiledef.animation.aspect_w =
- getintfield_default(L, -1, "aspect_w", 16);
+ getintfield_default(L, -1, "aspect_w", 16);
tiledef.animation.aspect_h =
- getintfield_default(L, -1, "aspect_h", 16);
+ getintfield_default(L, -1, "aspect_h", 16);
tiledef.animation.length =
- getfloatfield_default(L, -1, "length", 1.0);
+ getfloatfield_default(L, -1, "length", 1.0);
}
lua_pop(L, 1);
}
@@ -300,7 +360,7 @@ ContentFeatures read_content_features(lua_State *L, int index)
int i = 0;
while(lua_next(L, table) != 0){
// Read tiledef from value
- f.tiledef[i] = read_tiledef(L, -1);
+ f.tiledef[i] = read_tiledef(L, -1, f.drawtype);
// removes value, keeps key for next iteration
lua_pop(L, 1);
i++;
@@ -335,7 +395,7 @@ ContentFeatures read_content_features(lua_State *L, int index)
int i = 0;
while(lua_next(L, table) != 0){
// Read tiledef from value
- f.tiledef_special[i] = read_tiledef(L, -1);
+ f.tiledef_special[i] = read_tiledef(L, -1, f.drawtype);
// removes value, keeps key for next iteration
lua_pop(L, 1);
i++;
@@ -357,8 +417,7 @@ ContentFeatures read_content_features(lua_State *L, int index)
/* Other stuff */
lua_getfield(L, index, "post_effect_color");
- if(!lua_isnil(L, -1))
- f.post_effect_color = readARGB8(L, -1);
+ read_color(L, -1, &f.post_effect_color);
lua_pop(L, 1);
f.param_type = (ContentParamType)getenumfield(L, index, "paramtype",
@@ -546,22 +605,23 @@ NodeBox read_nodebox(lua_State *L, int index)
MapNode readnode(lua_State *L, int index, INodeDefManager *ndef)
{
lua_getfield(L, index, "name");
- const char *name = luaL_checkstring(L, -1);
+ if (!lua_isstring(L, -1))
+ throw LuaError("Node name is not set or is not a string!");
+ const char *name = lua_tostring(L, -1);
lua_pop(L, 1);
- u8 param1;
+
+ u8 param1 = 0;
lua_getfield(L, index, "param1");
- if(lua_isnil(L, -1))
- param1 = 0;
- else
+ if (!lua_isnil(L, -1))
param1 = lua_tonumber(L, -1);
lua_pop(L, 1);
- u8 param2;
+
+ u8 param2 = 0;
lua_getfield(L, index, "param2");
- if(lua_isnil(L, -1))
- param2 = 0;
- else
+ if (!lua_isnil(L, -1))
param2 = lua_tonumber(L, -1);
lua_pop(L, 1);
+
return MapNode(ndef, name, param1, param2);
}
@@ -901,6 +961,12 @@ u32 read_flags_table(lua_State *L, int table, FlagDesc *flagdesc, u32 *flagmask)
return flags;
}
+void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask)
+{
+ std::string flagstring = writeFlagString(flags, flagdesc, flagmask);
+ lua_pushlstring(L, flagstring.c_str(), flagstring.size());
+}
+
/******************************************************************************/
/* Lua Stored data! */
/******************************************************************************/
@@ -926,14 +992,23 @@ void read_groups(lua_State *L, int index,
}
/******************************************************************************/
+void push_groups(lua_State *L, const std::map<std::string, int> &groups)
+{
+ lua_newtable(L);
+ std::map<std::string, int>::const_iterator it;
+ for (it = groups.begin(); it != groups.end(); ++it) {
+ lua_pushnumber(L, it->second);
+ lua_setfield(L, -2, it->first.c_str());
+ }
+}
+
+/******************************************************************************/
void push_items(lua_State *L, const std::vector<ItemStack> &items)
{
- // Create and fill table
lua_createtable(L, items.size(), 0);
- std::vector<ItemStack>::const_iterator iter = items.begin();
- for (u32 i = 0; iter != items.end(); iter++) {
- LuaItemStack::create(L, *iter);
- lua_rawseti(L, -2, ++i);
+ for (u32 i = 0; i != items.size(); i++) {
+ LuaItemStack::create(L, items[i]);
+ lua_rawseti(L, -2, i + 1);
}
}
@@ -982,14 +1057,16 @@ bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
if (!lua_istable(L, index))
return false;
- np->offset = getfloatfield_default(L, index, "offset", 0.0);
- np->scale = getfloatfield_default(L, index, "scale", 0.0);
- np->persist = getfloatfield_default(L, index, "persist", 0.0);
- np->lacunarity = getfloatfield_default(L, index, "lacunarity", 2.0);
- np->seed = getintfield_default(L, index, "seed", 0);
- np->octaves = getintfield_default(L, index, "octaves", 0);
+ getfloatfield(L, index, "offset", np->offset);
+ getfloatfield(L, index, "scale", np->scale);
+ getfloatfield(L, index, "persist", np->persist);
+ getfloatfield(L, index, "persistence", np->persist);
+ getfloatfield(L, index, "lacunarity", np->lacunarity);
+ getintfield(L, index, "seed", np->seed);
+ getintfield(L, index, "octaves", np->octaves);
- u32 flags = 0, flagmask = 0;
+ u32 flags = 0;
+ u32 flagmask = 0;
np->flags = getflagsfield(L, index, "flags", flagdesc_noiseparams,
&flags, &flagmask) ? flags : NOISE_FLAG_DEFAULTS;
@@ -1000,6 +1077,30 @@ bool read_noiseparams(lua_State *L, int index, NoiseParams *np)
return true;
}
+void push_noiseparams(lua_State *L, NoiseParams *np)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, np->offset);
+ lua_setfield(L, -2, "offset");
+ lua_pushnumber(L, np->scale);
+ lua_setfield(L, -2, "scale");
+ lua_pushnumber(L, np->persist);
+ lua_setfield(L, -2, "persistence");
+ lua_pushnumber(L, np->lacunarity);
+ lua_setfield(L, -2, "lacunarity");
+ lua_pushnumber(L, np->seed);
+ lua_setfield(L, -2, "seed");
+ lua_pushnumber(L, np->octaves);
+ lua_setfield(L, -2, "octaves");
+
+ push_flags_string(L, flagdesc_noiseparams, np->flags,
+ np->flags);
+ lua_setfield(L, -2, "flags");
+
+ push_v3f(L, np->spread);
+ lua_setfield(L, -2, "spread");
+}
+
/******************************************************************************/
// Returns depth of json value tree
static int push_json_value_getdepth(const Json::Value &value)
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 241b1ca76..46416ad8e 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -62,59 +62,57 @@ struct NoiseParams;
class Schematic;
-ContentFeatures read_content_features (lua_State *L, int index);
-TileDef read_tiledef (lua_State *L, int index);
-void read_soundspec (lua_State *L, int index,
- SimpleSoundSpec &spec);
-NodeBox read_nodebox (lua_State *L, int index);
+ContentFeatures read_content_features (lua_State *L, int index);
+TileDef read_tiledef (lua_State *L, int index,
+ u8 drawtype);
+void read_soundspec (lua_State *L, int index,
+ SimpleSoundSpec &spec);
+NodeBox read_nodebox (lua_State *L, int index);
-void read_server_sound_params (lua_State *L, int index,
- ServerSoundParams &params);
+void read_server_sound_params (lua_State *L, int index,
+ ServerSoundParams &params);
-void push_dig_params (lua_State *L,const DigParams &params);
-void push_hit_params (lua_State *L,const HitParams &params);
+void push_dig_params (lua_State *L,
+ const DigParams &params);
+void push_hit_params (lua_State *L,
+ const HitParams &params);
-ItemStack read_item (lua_State *L, int index, Server* srv);
+ItemStack read_item (lua_State *L, int index, Server *srv);
-ToolCapabilities read_tool_capabilities (lua_State *L,
- int table);
+ToolCapabilities read_tool_capabilities (lua_State *L, int table);
void push_tool_capabilities (lua_State *L,
const ToolCapabilities &prop);
-ItemDefinition read_item_definition (lua_State *L,
- int index,
+ItemDefinition read_item_definition (lua_State *L, int index,
ItemDefinition default_def);
-void read_object_properties (lua_State *L,
- int index,
+void read_object_properties (lua_State *L, int index,
+ ObjectProperties *prop);
+void push_object_properties (lua_State *L,
ObjectProperties *prop);
void push_inventory_list (lua_State *L,
Inventory *inv,
const char *name);
-void read_inventory_list (lua_State *L,
- int tableindex,
- Inventory *inv,
- const char *name,
- Server* srv,
- int forcesize=-1);
+void read_inventory_list (lua_State *L, int tableindex,
+ Inventory *inv, const char *name,
+ Server *srv, int forcesize=-1);
-MapNode readnode (lua_State *L,
- int index,
+MapNode readnode (lua_State *L, int index,
INodeDefManager *ndef);
-void pushnode (lua_State *L,
- const MapNode &n,
+void pushnode (lua_State *L, const MapNode &n,
INodeDefManager *ndef);
NodeBox read_nodebox (lua_State *L, int index);
-void read_groups (lua_State *L,
- int index,
+void read_groups (lua_State *L, int index,
std::map<std::string, int> &result);
+void push_groups (lua_State *L,
+ const std::map<std::string, int> &groups);
+
//TODO rename to "read_enum_field"
-int getenumfield (lua_State *L,
- int table,
+int getenumfield (lua_State *L, int table,
const char *fieldname,
const EnumString *spec,
int default_);
@@ -128,6 +126,9 @@ bool read_flags (lua_State *L, int index,
FlagDesc *flagdesc,
u32 *flags, u32 *flagmask);
+void push_flags_string (lua_State *L, FlagDesc *flagdesc,
+ u32 flags, u32 flagmask);
+
u32 read_flags_table (lua_State *L, int table,
FlagDesc *flagdesc, u32 *flagmask);
@@ -142,23 +143,21 @@ void read_soundspec (lua_State *L,
int index,
SimpleSoundSpec &spec);
-
bool string_to_enum (const EnumString *spec,
int &result,
const std::string &str);
bool read_noiseparams (lua_State *L, int index,
NoiseParams *np);
+void push_noiseparams (lua_State *L, NoiseParams *np);
void luaentity_get (lua_State *L,u16 id);
bool push_json_value (lua_State *L,
const Json::Value &value,
int nullindex);
-void read_json_value (lua_State *L,
- Json::Value &root,
- int index,
- u8 recursion = 0);
+void read_json_value (lua_State *L, Json::Value &root,
+ int index, u8 recursion = 0);
extern struct EnumString es_TileAnimationType[];
diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp
index 66eeec68e..f1d3cc421 100644
--- a/src/script/common/c_converter.cpp
+++ b/src/script/common/c_converter.cpp
@@ -23,9 +23,23 @@ extern "C" {
}
#include "util/numeric.h"
+#include "util/string.h"
#include "common/c_converter.h"
#include "constants.h"
+
+#define CHECK_TYPE(index, name, type) do { \
+ int t = lua_type(L, (index)); \
+ if (t != (type)) { \
+ throw LuaError(std::string("Invalid ") + (name) + \
+ " (expected " + lua_typename(L, (type)) + \
+ " got " + lua_typename(L, t) + ")."); \
+ } \
+ } while(0)
+#define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
+#define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE)
+
+
void push_v3f(lua_State *L, v3f p)
{
lua_newtable(L);
@@ -49,7 +63,7 @@ void push_v2f(lua_State *L, v2f p)
v2s16 read_v2s16(lua_State *L, int index)
{
v2s16 p;
- luaL_checktype(L, index, LUA_TTABLE);
+ CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
p.X = lua_tonumber(L, -1);
lua_pop(L, 1);
@@ -59,10 +73,43 @@ v2s16 read_v2s16(lua_State *L, int index)
return p;
}
+v2s16 check_v2s16(lua_State *L, int index)
+{
+ v2s16 p;
+ CHECK_POS_TAB(index);
+ lua_getfield(L, index, "x");
+ CHECK_POS_COORD("x");
+ p.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "y");
+ CHECK_POS_COORD("y");
+ p.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ return p;
+}
+
+void push_v2s16(lua_State *L, v2s16 p)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, p.X);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, p.Y);
+ lua_setfield(L, -2, "y");
+}
+
+void push_v2s32(lua_State *L, v2s32 p)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, p.X);
+ lua_setfield(L, -2, "x");
+ lua_pushnumber(L, p.Y);
+ lua_setfield(L, -2, "y");
+}
+
v2s32 read_v2s32(lua_State *L, int index)
{
v2s32 p;
- luaL_checktype(L, index, LUA_TTABLE);
+ CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
p.X = lua_tonumber(L, -1);
lua_pop(L, 1);
@@ -75,11 +122,26 @@ v2s32 read_v2s32(lua_State *L, int index)
v2f read_v2f(lua_State *L, int index)
{
v2f p;
- luaL_checktype(L, index, LUA_TTABLE);
+ CHECK_POS_TAB(index);
+ lua_getfield(L, index, "x");
+ p.X = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, index, "y");
+ p.Y = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ return p;
+}
+
+v2f check_v2f(lua_State *L, int index)
+{
+ v2f p;
+ CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
+ CHECK_POS_COORD("x");
p.X = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
+ CHECK_POS_COORD("y");
p.Y = lua_tonumber(L, -1);
lua_pop(L, 1);
return p;
@@ -88,7 +150,7 @@ v2f read_v2f(lua_State *L, int index)
v3f read_v3f(lua_State *L, int index)
{
v3f pos;
- luaL_checktype(L, index, LUA_TTABLE);
+ CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
pos.X = lua_tonumber(L, -1);
lua_pop(L, 1);
@@ -104,19 +166,35 @@ v3f read_v3f(lua_State *L, int index)
v3f check_v3f(lua_State *L, int index)
{
v3f pos;
- luaL_checktype(L, index, LUA_TTABLE);
+ CHECK_POS_TAB(index);
lua_getfield(L, index, "x");
- pos.X = luaL_checknumber(L, -1);
+ CHECK_POS_COORD("x");
+ pos.X = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "y");
- pos.Y = luaL_checknumber(L, -1);
+ CHECK_POS_COORD("y");
+ pos.Y = lua_tonumber(L, -1);
lua_pop(L, 1);
lua_getfield(L, index, "z");
- pos.Z = luaL_checknumber(L, -1);
+ CHECK_POS_COORD("z");
+ pos.Z = lua_tonumber(L, -1);
lua_pop(L, 1);
return pos;
}
+void push_ARGB8(lua_State *L, video::SColor color)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, color.getAlpha());
+ lua_setfield(L, -2, "a");
+ lua_pushnumber(L, color.getRed());
+ lua_setfield(L, -2, "r");
+ lua_pushnumber(L, color.getGreen());
+ lua_setfield(L, -2, "g");
+ lua_pushnumber(L, color.getBlue());
+ lua_setfield(L, -2, "b");
+}
+
void pushFloatPos(lua_State *L, v3f p)
{
p /= BS;
@@ -153,13 +231,31 @@ v3s16 check_v3s16(lua_State *L, int index)
return floatToInt(pf, 1.0);
}
-video::SColor readARGB8(lua_State *L, int index)
+bool read_color(lua_State *L, int index, video::SColor *color)
+{
+ if (lua_istable(L, index)) {
+ *color = read_ARGB8(L, index);
+ } else if (lua_isnumber(L, index)) {
+ color->set(lua_tonumber(L, index));
+ } else if (lua_isstring(L, index)) {
+ video::SColor parsed_color;
+ if (!parseColorString(lua_tostring(L, index), parsed_color, true))
+ return false;
+
+ *color = parsed_color;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+video::SColor read_ARGB8(lua_State *L, int index)
{
video::SColor color(0);
- luaL_checktype(L, index, LUA_TTABLE);
+ CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
lua_getfield(L, index, "a");
- if(lua_isnumber(L, -1))
- color.setAlpha(lua_tonumber(L, -1));
+ color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
lua_pop(L, 1);
lua_getfield(L, index, "r");
color.setRed(lua_tonumber(L, -1));
@@ -199,6 +295,23 @@ aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
return box;
}
+void push_aabb3f(lua_State *L, aabb3f box)
+{
+ lua_newtable(L);
+ lua_pushnumber(L, box.MinEdge.X);
+ lua_rawseti(L, -2, 1);
+ lua_pushnumber(L, box.MinEdge.Y);
+ lua_rawseti(L, -2, 2);
+ lua_pushnumber(L, box.MinEdge.Z);
+ lua_rawseti(L, -2, 3);
+ lua_pushnumber(L, box.MaxEdge.X);
+ lua_rawseti(L, -2, 4);
+ lua_pushnumber(L, box.MaxEdge.Y);
+ lua_rawseti(L, -2, 5);
+ lua_pushnumber(L, box.MaxEdge.Z);
+ lua_rawseti(L, -2, 6);
+}
+
std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
{
std::vector<aabb3f> boxes;
@@ -227,24 +340,28 @@ std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
return boxes;
}
-bool read_stringlist(lua_State *L, int index, std::vector<const char *> &result)
+size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
{
if (index < 0)
index = lua_gettop(L) + 1 + index;
+ size_t num_strings = 0;
+
if (lua_istable(L, index)) {
lua_pushnil(L);
while (lua_next(L, index)) {
- if (lua_isstring(L, -1))
- result.push_back(lua_tostring(L, -1));
+ if (lua_isstring(L, -1)) {
+ result->push_back(lua_tostring(L, -1));
+ num_strings++;
+ }
lua_pop(L, 1);
}
} else if (lua_isstring(L, index)) {
- result.push_back(lua_tostring(L, index));
- } else {
- return false;
+ result->push_back(lua_tostring(L, index));
+ num_strings++;
}
- return true;
+
+ return num_strings;
}
/*
@@ -281,6 +398,45 @@ bool getintfield(lua_State *L, int table,
return got;
}
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, u8 &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, u16 &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, u32 &result)
+{
+ lua_getfield(L, table, fieldname);
+ bool got = false;
+ if(lua_isnumber(L, -1)){
+ result = lua_tonumber(L, -1);
+ got = true;
+ }
+ lua_pop(L, 1);
+ return got;
+}
+
bool getfloatfield(lua_State *L, int table,
const char *fieldname, float &result)
{
@@ -307,24 +463,26 @@ bool getboolfield(lua_State *L, int table,
return got;
}
-bool getstringlistfield(lua_State *L, int table, const char *fieldname,
- std::vector<const char *> &result)
+size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
+ std::vector<std::string> *result)
{
lua_getfield(L, table, fieldname);
- bool got = read_stringlist(L, -1, result);
+ size_t num_strings_read = read_stringlist(L, -1, result);
lua_pop(L, 1);
- return got;
+ return num_strings_read;
}
std::string checkstringfield(lua_State *L, int table,
const char *fieldname)
{
lua_getfield(L, table, fieldname);
- std::string s = luaL_checkstring(L, -1);
+ CHECK_TYPE(-1, std::string("field \"") + fieldname + '"', LUA_TSTRING);
+ size_t len;
+ const char *s = lua_tolstring(L, -1, &len);
lua_pop(L, 1);
- return s;
+ return std::string(s, len);
}
std::string getstringfield_default(lua_State *L, int table,
@@ -387,3 +545,95 @@ void setboolfield(lua_State *L, int table,
}
+////
+//// Array table slices
+////
+
+size_t write_array_slice_float(
+ lua_State *L,
+ int table_index,
+ float *data,
+ v3u16 data_size,
+ v3u16 slice_offset,
+ v3u16 slice_size)
+{
+ v3u16 pmin, pmax(data_size);
+
+ if (slice_offset.X > 0) {
+ slice_offset.X--;
+ pmin.X = slice_offset.X;
+ pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
+ }
+
+ if (slice_offset.Y > 0) {
+ slice_offset.Y--;
+ pmin.Y = slice_offset.Y;
+ pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
+ }
+
+ if (slice_offset.Z > 0) {
+ slice_offset.Z--;
+ pmin.Z = slice_offset.Z;
+ pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
+ }
+
+ const u32 ystride = data_size.X;
+ const u32 zstride = data_size.X * data_size.Y;
+
+ u32 elem_index = 1;
+ for (u32 z = pmin.Z; z != pmax.Z; z++)
+ for (u32 y = pmin.Y; y != pmax.Y; y++)
+ for (u32 x = pmin.X; x != pmax.X; x++) {
+ u32 i = z * zstride + y * ystride + x;
+ lua_pushnumber(L, data[i]);
+ lua_rawseti(L, table_index, elem_index);
+ elem_index++;
+ }
+
+ return elem_index - 1;
+}
+
+
+size_t write_array_slice_u16(
+ lua_State *L,
+ int table_index,
+ u16 *data,
+ v3u16 data_size,
+ v3u16 slice_offset,
+ v3u16 slice_size)
+{
+ v3u16 pmin, pmax(data_size);
+
+ if (slice_offset.X > 0) {
+ slice_offset.X--;
+ pmin.X = slice_offset.X;
+ pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
+ }
+
+ if (slice_offset.Y > 0) {
+ slice_offset.Y--;
+ pmin.Y = slice_offset.Y;
+ pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
+ }
+
+ if (slice_offset.Z > 0) {
+ slice_offset.Z--;
+ pmin.Z = slice_offset.Z;
+ pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
+ }
+
+ const u32 ystride = data_size.X;
+ const u32 zstride = data_size.X * data_size.Y;
+
+ u32 elem_index = 1;
+ for (u32 z = pmin.Z; z != pmax.Z; z++)
+ for (u32 y = pmin.Y; y != pmax.Y; y++)
+ for (u32 x = pmin.X; x != pmax.X; x++) {
+ u32 i = z * zstride + y * ystride + x;
+ lua_pushinteger(L, data[i]);
+ lua_rawseti(L, table_index, elem_index);
+ elem_index++;
+ }
+
+ return elem_index - 1;
+}
diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h
index 3b7eb6f7d..18a045d2a 100644
--- a/src/script/common/c_converter.h
+++ b/src/script/common/c_converter.h
@@ -48,11 +48,17 @@ int getintfield_default (lua_State *L, int table,
bool getstringfield(lua_State *L, int table,
const char *fieldname, std::string &result);
-bool getstringlistfield(lua_State *L, int table,
+size_t getstringlistfield(lua_State *L, int table,
const char *fieldname,
- std::vector<const char *> &result);
+ std::vector<std::string> *result);
bool getintfield(lua_State *L, int table,
const char *fieldname, int &result);
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, u8 &result);
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, u16 &result);
+bool getintfield(lua_State *L, int table,
+ const char *fieldname, u32 &result);
void read_groups(lua_State *L, int index,
std::map<std::string, int> &result);
bool getboolfield(lua_State *L, int table,
@@ -70,8 +76,9 @@ void setfloatfield(lua_State *L, int table,
void setboolfield(lua_State *L, int table,
const char *fieldname, bool value);
-
v3f checkFloatPos (lua_State *L, int index);
+v2f check_v2f (lua_State *L, int index);
+v2s16 check_v2s16 (lua_State *L, int index);
v3f check_v3f (lua_State *L, int index);
v3s16 check_v3s16 (lua_State *L, int index);
@@ -79,23 +86,32 @@ v3f read_v3f (lua_State *L, int index);
v2f read_v2f (lua_State *L, int index);
v2s16 read_v2s16 (lua_State *L, int index);
v2s32 read_v2s32 (lua_State *L, int index);
-video::SColor readARGB8 (lua_State *L, int index);
+video::SColor read_ARGB8 (lua_State *L, int index);
+bool read_color (lua_State *L, int index,
+ video::SColor *color);
+
aabb3f read_aabb3f (lua_State *L, int index, f32 scale);
v3s16 read_v3s16 (lua_State *L, int index);
std::vector<aabb3f> read_aabb3f_vector (lua_State *L, int index, f32 scale);
-bool read_stringlist (lua_State *L, int index,
- std::vector<const char *> &result);
+size_t read_stringlist (lua_State *L, int index,
+ std::vector<std::string> *result);
+void push_v2s16 (lua_State *L, v2s16 p);
+void push_v2s32 (lua_State *L, v2s32 p);
void push_v3s16 (lua_State *L, v3s16 p);
+void push_aabb3f (lua_State *L, aabb3f box);
+void push_ARGB8 (lua_State *L, video::SColor color);
void pushFloatPos (lua_State *L, v3f p);
void push_v3f (lua_State *L, v3f p);
void push_v2f (lua_State *L, v2f p);
+void warn_if_field_exists(lua_State *L, int table,
+ const char *fieldname,
+ const std::string &message);
-
-void warn_if_field_exists (lua_State *L,
- int table,
- const char *fieldname,
- const std::string &message);
+size_t write_array_slice_float(lua_State *L, int table_index, float *data,
+ v3u16 data_size, v3u16 slice_offset, v3u16 slice_size);
+size_t write_array_slice_u16(lua_State *L, int table_index, u16 *data,
+ v3u16 data_size, v3u16 slice_offset, v3u16 slice_size);
#endif /* C_CONVERTER_H_ */
diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp
index f811dd5d3..2a10ce0f2 100644
--- a/src/script/common/c_internal.cpp
+++ b/src/script/common/c_internal.cpp
@@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_internal.h"
#include "debug.h"
#include "log.h"
-#include "main.h"
#include "settings.h"
std::string script_get_backtrace(lua_State *L)
@@ -64,19 +63,65 @@ int script_exception_wrapper(lua_State *L, lua_CFunction f)
return f(L); // Call wrapped function and return result.
} catch (const char *s) { // Catch and convert exceptions.
lua_pushstring(L, s);
- } catch (std::exception& e) {
+ } catch (std::exception &e) {
lua_pushstring(L, e.what());
- } catch (...) {
- lua_pushliteral(L, "caught (...)");
}
return lua_error(L); // Rethrow as a Lua error.
}
-void script_error(lua_State *L)
+/*
+ * Note that we can't get tracebacks for LUA_ERRMEM or LUA_ERRERR (without
+ * hacking Lua internals). For LUA_ERRMEM, this is because memory errors will
+ * not execute the the error handler, and by the time lua_pcall returns the
+ * execution stack will have already been unwound. For LUA_ERRERR, there was
+ * another error while trying to generate a backtrace from a LUA_ERRRUN. It is
+ * presumed there is an error with the internal Lua state and thus not possible
+ * to gather a coherent backtrace. Realistically, the best we can do here is
+ * print which C function performed the failing pcall.
+ */
+void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn)
{
- const char *s = lua_tostring(L, -1);
- std::string str(s ? s : "");
- throw LuaError(str);
+ if (pcall_result == 0)
+ return;
+
+ const char *err_type;
+ switch (pcall_result) {
+ case LUA_ERRRUN:
+ err_type = "Runtime";
+ break;
+ case LUA_ERRMEM:
+ err_type = "OOM";
+ break;
+ case LUA_ERRERR:
+ err_type = "Double fault";
+ break;
+ default:
+ err_type = "Unknown";
+ }
+
+ if (!mod)
+ mod = "??";
+
+ if (!fxn)
+ fxn = "??";
+
+ const char *err_descr = lua_tostring(L, -1);
+ if (!err_descr)
+ err_descr = "<no description>";
+
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%s error from mod '%s' in callback %s(): ",
+ err_type, mod, fxn);
+
+ std::string err_msg(buf);
+ err_msg += err_descr;
+
+ if (pcall_result == LUA_ERRMEM) {
+ err_msg += "\nCurrent Lua memory usage: "
+ + itos(lua_gc(L, LUA_GCCOUNT, 0) >> 10) + " MB";
+ }
+
+ throw LuaError(err_msg);
}
// Push the list of callbacks (a lua table).
@@ -85,9 +130,10 @@ void script_error(lua_State *L)
// - runs the callbacks
// - replaces the table and arguments with the return value,
// computed depending on mode
-void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
+void script_run_callbacks_f(lua_State *L, int nargs,
+ RunCallbacksMode mode, const char *fxn)
{
- assert(lua_gettop(L) >= nargs + 1);
+ FATAL_ERROR_IF(lua_gettop(L) < nargs + 1, "Not enough arguments");
// Insert error handler
lua_pushcfunction(L, script_error_handler);
@@ -107,14 +153,14 @@ void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
// Stack now looks like this:
// ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
- if (lua_pcall(L, nargs + 2, 1, errorhandler)) {
- script_error(L);
- }
+ int result = lua_pcall(L, nargs + 2, 1, errorhandler);
+ if (result != 0)
+ script_error(L, result, NULL, fxn);
lua_remove(L, -2); // Remove error handler
}
-void log_deprecated(lua_State *L, std::string message)
+void log_deprecated(lua_State *L, const std::string &message)
{
static bool configured = false;
static bool dolog = false;
@@ -125,8 +171,7 @@ void log_deprecated(lua_State *L, std::string message)
std::string value = g_settings->get("deprecated_lua_api_handling");
if (value == "log") {
dolog = true;
- }
- if (value == "error") {
+ } else if (value == "error") {
dolog = true;
doerror = true;
}
@@ -134,11 +179,10 @@ void log_deprecated(lua_State *L, std::string message)
if (doerror) {
if (L != NULL) {
- script_error(L);
+ script_error(L, LUA_ERRRUN, NULL, NULL);
} else {
- /* As of april 2014 assert is not optimized to nop in release builds
- * therefore this is correct. */
- assert("Can't do a scripterror for this deprecated message, so exit completely!");
+ FATAL_ERROR("Can't do a scripterror for this deprecated message, "
+ "so exit completely!");
}
}
diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h
index eb9181b09..ecb514c8f 100644
--- a/src/script/common/c_internal.h
+++ b/src/script/common/c_internal.h
@@ -34,6 +34,16 @@ extern "C" {
#include "common/c_types.h"
+#define PCALL_RESL(L, RES) do { \
+ int result_ = (RES); \
+ if (result_ != 0) { \
+ script_error((L), result_, NULL, __FUNCTION__); \
+ } \
+} while (0)
+
+#define script_run_callbacks(L, nargs, mode) \
+ script_run_callbacks_f((L), (nargs), (mode), __FUNCTION__)
+
// What script_run_callbacks does with the return values of callbacks.
// Regardless of the mode, if only one callback is defined,
// its return value is the total return value.
@@ -67,8 +77,9 @@ enum RunCallbacksMode
std::string script_get_backtrace(lua_State *L);
int script_error_handler(lua_State *L);
int script_exception_wrapper(lua_State *L, lua_CFunction f);
-void script_error(lua_State *L);
-void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode);
-void log_deprecated(lua_State *L, std::string message);
+void script_error(lua_State *L, int pcall_result, const char *mod, const char *fxn);
+void script_run_callbacks_f(lua_State *L, int nargs,
+ RunCallbacksMode mode, const char *fxn);
+void log_deprecated(lua_State *L, const std::string &message);
#endif /* C_INTERNAL_H_ */
diff --git a/src/script/cpp_api/CMakeLists.txt b/src/script/cpp_api/CMakeLists.txt
index c45020055..be4d0131e 100644
--- a/src/script/cpp_api/CMakeLists.txt
+++ b/src/script/cpp_api/CMakeLists.txt
@@ -1,5 +1,5 @@
-# Used by server and client
set(common_SCRIPT_CPP_API_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/s_async.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_base.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_entity.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_env.cpp
@@ -8,11 +8,11 @@ set(common_SCRIPT_CPP_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/s_node.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_nodemeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_player.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/s_security.cpp
${CMAKE_CURRENT_SOURCE_DIR}/s_server.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/s_async.cpp
PARENT_SCOPE)
-# Used by client only
-set(minetest_SCRIPT_CPP_API_SRCS
+set(client_SCRIPT_CPP_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp
PARENT_SCOPE)
+
diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp
index de1ebc07b..c00b22f98 100644
--- a/src/script/cpp_api/s_async.cpp
+++ b/src/script/cpp_api/s_async.cpp
@@ -155,7 +155,7 @@ void AsyncEngine::step(lua_State *L, int errorhandler)
lua_getfield(L, -1, "async_event_handler");
if (lua_isnil(L, -1)) {
- assert("Async event handler does not exist!" == 0);
+ FATAL_ERROR("Async event handler does not exist!");
}
luaL_checktype(L, -1, LUA_TFUNCTION);
@@ -164,9 +164,7 @@ void AsyncEngine::step(lua_State *L, int errorhandler)
lua_pushlstring(L, jobDone.serializedResult.data(),
jobDone.serializedResult.size());
- if (lua_pcall(L, 2, 0, errorhandler)) {
- script_error(L);
- }
+ PCALL_RESL(L, lua_pcall(L, 2, 0, errorhandler));
}
resultQueueMutex.Unlock();
lua_pop(L, 1); // Pop core
@@ -237,7 +235,7 @@ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher,
/******************************************************************************/
AsyncWorkerThread::~AsyncWorkerThread()
{
- assert(IsRunning() == false);
+ sanity_check(IsRunning() == false);
}
/******************************************************************************/
@@ -257,7 +255,7 @@ void* AsyncWorkerThread::Thread()
std::string script = getServer()->getBuiltinLuaPath() + DIR_DELIM + "init.lua";
if (!loadScript(script)) {
errorstream
- << "AsyncWorkderThread execution of async base environment failed!"
+ << "AsyncWorkerThread execution of async base environment failed!"
<< std::endl;
abort();
}
@@ -293,8 +291,9 @@ void* AsyncWorkerThread::Thread()
toProcess.serializedParams.data(),
toProcess.serializedParams.size());
- if (lua_pcall(L, 2, 1, m_errorhandler)) {
- scriptError();
+ int result = lua_pcall(L, 2, 1, m_errorhandler);
+ if (result) {
+ PCALL_RES(result);
toProcess.serializedResult = "";
} else {
// Fetch result
diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp
index 1f96373dc..dcfbac4bf 100644
--- a/src/script/cpp_api/s_base.cpp
+++ b/src/script/cpp_api/s_base.cpp
@@ -19,7 +19,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_base.h"
#include "cpp_api/s_internal.h"
+#include "cpp_api/s_security.h"
#include "lua_api/l_object.h"
+#include "common/c_converter.h"
#include "serverobject.h"
#include "debug.h"
#include "filesys.h"
@@ -45,18 +47,18 @@ class ModNameStorer
private:
lua_State *L;
public:
- ModNameStorer(lua_State *L_, const std::string &modname):
+ ModNameStorer(lua_State *L_, const std::string &mod_name):
L(L_)
{
- // Store current modname in registry
- lua_pushstring(L, modname.c_str());
- lua_setfield(L, LUA_REGISTRYINDEX, "current_modname");
+ // Store current mod name in registry
+ lua_pushstring(L, mod_name.c_str());
+ lua_setfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
}
~ModNameStorer()
{
- // Clear current modname in registry
+ // Clear current mod name from registry
lua_pushnil(L);
- lua_setfield(L, LUA_REGISTRYINDEX, "current_modname");
+ lua_setfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
}
};
@@ -67,12 +69,12 @@ public:
ScriptApiBase::ScriptApiBase()
{
- #ifdef SCRIPTAPI_LOCK_DEBUG
+#ifdef SCRIPTAPI_LOCK_DEBUG
m_locked = false;
- #endif
+#endif
m_luastack = luaL_newstate();
- assert(m_luastack);
+ FATAL_ERROR_IF(!m_luastack, "luaL_newstate() failed");
luaL_openlibs(m_luastack);
@@ -102,6 +104,11 @@ ScriptApiBase::ScriptApiBase()
lua_pushstring(m_luastack, porting::getPlatformName());
lua_setglobal(m_luastack, "PLATFORM");
+ // m_secure gets set to true inside
+ // ScriptApiSecurity::initializeSecurity(), if neccessary.
+ // Default to false otherwise
+ m_secure = false;
+
m_server = NULL;
m_environment = NULL;
m_guiengine = NULL;
@@ -112,88 +119,136 @@ ScriptApiBase::~ScriptApiBase()
lua_close(m_luastack);
}
-bool ScriptApiBase::loadMod(const std::string &scriptpath,
- const std::string &modname)
+bool ScriptApiBase::loadMod(const std::string &script_path,
+ const std::string &mod_name, std::string *error)
{
- ModNameStorer modnamestorer(getStack(), modname);
-
- if (!string_allowed(modname, MODNAME_ALLOWED_CHARS)) {
- errorstream<<"Error loading mod \""<<modname
- <<"\": modname does not follow naming conventions: "
- <<"Only chararacters [a-z0-9_] are allowed."<<std::endl;
- return false;
- }
+ ModNameStorer mod_name_storer(getStack(), mod_name);
- return loadScript(scriptpath);
+ return loadScript(script_path, error);
}
-bool ScriptApiBase::loadScript(const std::string &scriptpath)
+bool ScriptApiBase::loadScript(const std::string &script_path, std::string *error)
{
- verbosestream<<"Loading and running script from "<<scriptpath<<std::endl;
+ verbosestream << "Loading and running script from " << script_path << std::endl;
lua_State *L = getStack();
- int ret = luaL_loadfile(L, scriptpath.c_str()) || lua_pcall(L, 0, 0, m_errorhandler);
- if (ret) {
- errorstream << "========== ERROR FROM LUA ===========" << std::endl;
- errorstream << "Failed to load and run script from " << std::endl;
- errorstream << scriptpath << ":" << std::endl;
- errorstream << std::endl;
- errorstream << lua_tostring(L, -1) << std::endl;
- errorstream << std::endl;
- errorstream << "======= END OF ERROR FROM LUA ========" << std::endl;
+ 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);
+ 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;
}
return true;
}
+// Push the list of callbacks (a lua table).
+// Then push nargs arguments.
+// Then call this function, which
+// - runs the callbacks
+// - replaces the table and arguments with the return value,
+// computed depending on mode
+void ScriptApiBase::runCallbacksRaw(int nargs,
+ RunCallbacksMode mode, const char *fxn)
+{
+ 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);
+
+ // 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);
+
+ // Insert mode after table
+ lua_pushnumber(L, (int)mode);
+ lua_insert(L, errorhandler + 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);
+ if (result != 0)
+ scriptError(result, fxn);
+
+ lua_remove(L, -2); // Remove error handler
+}
+
void ScriptApiBase::realityCheck()
{
int top = lua_gettop(m_luastack);
- if(top >= 30){
- dstream<<"Stack is over 30:"<<std::endl;
+ if (top >= 30) {
+ dstream << "Stack is over 30:" << std::endl;
stackDump(dstream);
std::string traceback = script_get_backtrace(m_luastack);
throw LuaError("Stack is over 30 (reality check)\n" + traceback);
}
}
-void ScriptApiBase::scriptError()
+void ScriptApiBase::scriptError(int result, const char *fxn)
{
- throw LuaError(lua_tostring(m_luastack, -1));
+ script_error(getStack(), result, m_last_run_mod.c_str(), fxn);
}
void ScriptApiBase::stackDump(std::ostream &o)
{
- int i;
int top = lua_gettop(m_luastack);
- for (i = 1; i <= top; i++) { /* repeat for each level */
+ for (int i = 1; i <= top; i++) { /* repeat for each level */
int t = lua_type(m_luastack, i);
switch (t) {
-
case LUA_TSTRING: /* strings */
- o<<"\""<<lua_tostring(m_luastack, i)<<"\"";
+ o << "\"" << lua_tostring(m_luastack, i) << "\"";
break;
-
case LUA_TBOOLEAN: /* booleans */
- o<<(lua_toboolean(m_luastack, i) ? "true" : "false");
+ o << (lua_toboolean(m_luastack, i) ? "true" : "false");
break;
-
case LUA_TNUMBER: /* numbers */ {
char buf[10];
snprintf(buf, 10, "%g", lua_tonumber(m_luastack, i));
- o<<buf;
- break; }
-
+ o << buf;
+ break;
+ }
default: /* other values */
- o<<lua_typename(m_luastack, t);
+ o << lua_typename(m_luastack, t);
break;
-
}
- o<<" ";
+ o << " ";
}
- o<<std::endl;
+ o << std::endl;
+}
+
+void ScriptApiBase::setOriginDirect(const char *origin)
+{
+ m_last_run_mod = origin ? origin : "??";
+}
+
+void ScriptApiBase::setOriginFromTableRaw(int index, const char *fxn)
+{
+#ifdef SCRIPTAPI_DEBUG
+ lua_State *L = getStack();
+
+ m_last_run_mod = lua_istable(L, index) ?
+ getstringfield_default(L, index, "mod_origin", "") : "";
+ //printf(">>>> running %s for mod: %s\n", fxn, m_last_run_mod.c_str());
+#endif
}
void ScriptApiBase::addObjectReference(ServerActiveObject *cobj)
@@ -245,7 +300,7 @@ void ScriptApiBase::removeObjectReference(ServerActiveObject *cobj)
void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
ServerActiveObject *cobj)
{
- if(cobj == NULL || cobj->getId() == 0){
+ if (cobj == NULL || cobj->getId() == 0) {
ObjectRef::create(L, cobj);
} else {
objectrefGet(L, cobj->getId());
@@ -263,4 +318,3 @@ void ScriptApiBase::objectrefGet(lua_State *L, u16 id)
lua_remove(L, -2); // object_refs
lua_remove(L, -2); // core
}
-
diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h
index 4ea3677a9..d653b5bac 100644
--- a/src/script/cpp_api/s_base.h
+++ b/src/script/cpp_api/s_base.h
@@ -34,6 +34,25 @@ extern "C" {
#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*"
+
+#define PCALL_RES(RES) do { \
+ int result_ = (RES); \
+ if (result_ != 0) { \
+ scriptError(result_, __FUNCTION__); \
+ } \
+} while (0)
+
+#define runCallbacks(nargs, mode) \
+ runCallbacksRaw((nargs), (mode), __FUNCTION__)
+
+#define setOriginFromTable(index) \
+ setOriginFromTableRaw(index, __FUNCTION__)
class Server;
class Environment;
@@ -42,17 +61,26 @@ class ServerActiveObject;
class ScriptApiBase {
public:
-
ScriptApiBase();
virtual ~ScriptApiBase();
- bool loadMod(const std::string &scriptpath, const std::string &modname);
- bool loadScript(const std::string &scriptpath);
+ 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);
+
+ void runCallbacksRaw(int nargs,
+ RunCallbacksMode mode, const char *fxn);
/* object */
void addObjectReference(ServerActiveObject *cobj);
void removeObjectReference(ServerActiveObject *cobj);
+ Server* getServer() { return m_server; }
+
+ std::string getOrigin() { return m_last_run_mod; }
+ void setOriginDirect(const char *origin);
+ void setOriginFromTableRaw(int index, const char *fxn);
+
protected:
friend class LuaABM;
friend class InvRef;
@@ -66,10 +94,9 @@ protected:
{ return m_luastack; }
void realityCheck();
- void scriptError();
+ void scriptError(int result, const char *fxn);
void stackDump(std::ostream &o);
- Server* getServer() { return m_server; }
void setServer(Server* server) { m_server = server; }
Environment* getEnv() { return m_environment; }
@@ -82,8 +109,10 @@ protected:
void objectrefGet(lua_State *L, u16 id);
JMutex 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;
#endif
diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp
index b52bde18a..0d159846a 100644
--- a/src/script/cpp_api/s_entity.cpp
+++ b/src/script/cpp_api/s_entity.cpp
@@ -91,9 +91,9 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
lua_pushvalue(L, object); // self
lua_pushlstring(L, staticdata.c_str(), staticdata.size());
lua_pushinteger(L, dtime_s);
- // Call with 3 arguments, 0 results
- if (lua_pcall(L, 3, 0, m_errorhandler))
- scriptError();
+
+ setOriginFromTable(object);
+ PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
} else {
lua_pop(L, 1);
}
@@ -136,12 +136,12 @@ std::string ScriptApiEntity::luaentity_GetStaticdata(u16 id)
lua_pop(L, 2); // Pop entity and get_staticdata
return "";
}
-
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
- // Call with 1 arguments, 1 results
- if (lua_pcall(L, 1, 1, m_errorhandler))
- scriptError();
+
+ setOriginFromTable(object);
+ PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
+
lua_remove(L, object); // Remove object
size_t len = 0;
@@ -209,9 +209,10 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime)
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
lua_pushnumber(L, dtime); // dtime
- // Call with 2 arguments, 0 results
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+
+ setOriginFromTable(object);
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+
lua_pop(L, 1); // Pop object
}
@@ -241,9 +242,10 @@ void ScriptApiEntity::luaentity_Punch(u16 id,
lua_pushnumber(L, time_from_last_punch);
push_tool_capabilities(L, *toolcap);
push_v3f(L, dir);
- // Call with 5 arguments, 0 results
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+
+ setOriginFromTable(object);
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
+
lua_pop(L, 1); // Pop object
}
@@ -268,9 +270,10 @@ void ScriptApiEntity::luaentity_Rightclick(u16 id,
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushvalue(L, object); // self
objectrefGetOrCreate(L, clicker); // Clicker reference
- // Call with 2 arguments, 0 results
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+
+ setOriginFromTable(object);
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
+
lua_pop(L, 1); // Pop object
}
diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp
index c171bbf02..9c733773a 100644
--- a/src/script/cpp_api/s_env.cpp
+++ b/src/script/cpp_api/s_env.cpp
@@ -38,7 +38,7 @@ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp,
push_v3s16(L, minp);
push_v3s16(L, maxp);
lua_pushnumber(L, blockseed);
- script_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiEnv::environment_Step(float dtime)
@@ -52,7 +52,7 @@ void ScriptApiEnv::environment_Step(float dtime)
// Call callbacks
lua_pushnumber(L, dtime);
try {
- script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
getServer()->setAsyncFatalError(e.what());
}
@@ -73,7 +73,7 @@ void ScriptApiEnv::player_event(ServerActiveObject* player, std::string type)
objectrefGetOrCreate(L, player); // player
lua_pushstring(L,type.c_str()); // event type
try {
- script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
} catch (LuaError &e) {
getServer()->setAsyncFatalError(e.what());
}
diff --git a/src/script/cpp_api/s_internal.h b/src/script/cpp_api/s_internal.h
index 10ee1a7de..9999a584a 100644
--- a/src/script/cpp_api/s_internal.h
+++ b/src/script/cpp_api/s_internal.h
@@ -61,3 +61,4 @@ bool* m_variable;
StackUnroller stack_unroller(L);
#endif /* S_INTERNAL_H_ */
+
diff --git a/src/script/cpp_api/s_inventory.cpp b/src/script/cpp_api/s_inventory.cpp
index 422faf150..019d1ccc0 100644
--- a/src/script/cpp_api/s_inventory.cpp
+++ b/src/script/cpp_api/s_inventory.cpp
@@ -48,8 +48,7 @@ int ScriptApiDetached::detached_inventory_AllowMove(
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler));
if(!lua_isnumber(L, -1))
throw LuaError("allow_move should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
@@ -77,8 +76,7 @@ int ScriptApiDetached::detached_inventory_AllowPut(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_put should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
@@ -106,8 +104,7 @@ int ScriptApiDetached::detached_inventory_AllowTake(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_take should return a number. name=" + name);
int ret = luaL_checkinteger(L, -1);
@@ -139,8 +136,7 @@ void ScriptApiDetached::detached_inventory_OnMove(
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler));
}
// Report put items
@@ -164,8 +160,7 @@ void ScriptApiDetached::detached_inventory_OnPut(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
// Report taken items
@@ -189,8 +184,7 @@ void ScriptApiDetached::detached_inventory_OnTake(
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
// Retrieves core.detached_inventories[name][callbackname]
@@ -215,6 +209,9 @@ bool ScriptApiDetached::getDetachedInventoryCallback(
lua_pop(L, 1);
return false;
}
+
+ setOriginFromTable(-1);
+
lua_getfield(L, -1, callbackname);
lua_remove(L, -2);
// Should be a function or nil
diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp
index e3a9ac7aa..4d4d416ec 100644
--- a/src/script/cpp_api/s_item.cpp
+++ b/src/script/cpp_api/s_item.cpp
@@ -42,8 +42,7 @@ bool ScriptApiItem::item_OnDrop(ItemStack &item,
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, dropper);
pushFloatPos(L, pos);
- if (lua_pcall(L, 3, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -68,8 +67,7 @@ bool ScriptApiItem::item_OnPlace(ItemStack &item,
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, placer);
pushPointedThing(pointed);
- if (lua_pcall(L, 3, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -94,8 +92,7 @@ bool ScriptApiItem::item_OnUse(ItemStack &item,
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, user);
pushPointedThing(pointed);
- if (lua_pcall(L, 3, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 1, m_errorhandler));
if(!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -116,7 +113,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
lua_getfield(L, -1, "on_craft");
LuaItemStack::create(L, item);
objectrefGetOrCreate(L, user);
-
+
// Push inventory list
std::vector<ItemStack> items;
for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
@@ -125,8 +122,7 @@ bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
push_items(L, items);
InvRef::create(L, craft_inv);
- if (lua_pcall(L, 4, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -156,8 +152,7 @@ bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
push_items(L, items);
InvRef::create(L, craft_inv);
- if (lua_pcall(L, 4, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 1, m_errorhandler));
if (!lua_isnil(L, -1)) {
try {
item = read_item(L,-1, getServer());
@@ -198,6 +193,9 @@ bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
lua_remove(L, -2);
luaL_checktype(L, -1, LUA_TTABLE);
}
+
+ setOriginFromTable(-1);
+
lua_getfield(L, -1, callbackname);
lua_remove(L, -2); // Remove item def
// Should be a function or nil
diff --git a/src/script/cpp_api/s_mainmenu.cpp b/src/script/cpp_api/s_mainmenu.cpp
index ef8cea6c9..17ceff082 100644
--- a/src/script/cpp_api/s_mainmenu.cpp
+++ b/src/script/cpp_api/s_mainmenu.cpp
@@ -21,15 +21,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_internal.h"
#include "common/c_converter.h"
-void ScriptApiMainMenu::setMainMenuErrorMessage(std::string errormessage)
+void ScriptApiMainMenu::setMainMenuData(MainMenuDataForScript *data)
{
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "gamedata");
int gamedata_idx = lua_gettop(L);
lua_pushstring(L, "errormessage");
- lua_pushstring(L, errormessage.c_str());
+ if (!data->errormessage.empty()) {
+ lua_pushstring(L, data->errormessage.c_str());
+ } else {
+ lua_pushnil(L);
+ }
lua_settable(L, gamedata_idx);
+ setboolfield(L, gamedata_idx, "reconnect_requested",
+ data->reconnect_requested);
lua_pop(L, 1);
}
@@ -49,11 +55,10 @@ void ScriptApiMainMenu::handleMainMenuEvent(std::string text)
// Call it
lua_pushstring(L, text.c_str());
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
-void ScriptApiMainMenu::handleMainMenuButtons(std::map<std::string, std::string> fields)
+void ScriptApiMainMenu::handleMainMenuButtons(const StringMap &fields)
{
SCRIPTAPI_PRECHECKHEADER
@@ -69,8 +74,8 @@ void ScriptApiMainMenu::handleMainMenuButtons(std::map<std::string, std::string>
// Convert fields to a Lua table
lua_newtable(L);
- std::map<std::string, std::string>::const_iterator it;
- for (it = fields.begin(); it != fields.end(); it++){
+ StringMap::const_iterator it;
+ for (it = fields.begin(); it != fields.end(); ++it) {
const std::string &name = it->first;
const std::string &value = it->second;
lua_pushstring(L, name.c_str());
@@ -79,7 +84,6 @@ void ScriptApiMainMenu::handleMainMenuButtons(std::map<std::string, std::string>
}
// Call it
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
diff --git a/src/script/cpp_api/s_mainmenu.h b/src/script/cpp_api/s_mainmenu.h
index 53dcd37e9..8d5895817 100644
--- a/src/script/cpp_api/s_mainmenu.h
+++ b/src/script/cpp_api/s_mainmenu.h
@@ -21,17 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define S_MAINMENU_H_
#include "cpp_api/s_base.h"
-#include <map>
+#include "util/string.h"
+#include "../guiMainMenu.h"
-class ScriptApiMainMenu
- : virtual public ScriptApiBase
-{
+class ScriptApiMainMenu : virtual public ScriptApiBase {
public:
/**
- * set gamedata.errormessage to inform lua of an error
- * @param errormessage the error message
+ * Hand over MainMenuDataForScript to lua to inform lua of the content
+ * @param data the data
*/
- void setMainMenuErrorMessage(std::string errormessage);
+ void setMainMenuData(MainMenuDataForScript *data);
/**
* process events received from formspec
@@ -43,7 +42,7 @@ public:
* process field data recieved from formspec
* @param fields data in field format
*/
- void handleMainMenuButtons(std::map<std::string, std::string> fields);
+ void handleMainMenuButtons(const StringMap &fields);
};
#endif /* S_MAINMENU_H_ */
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index e3d3fb58b..dac058b13 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -106,8 +106,7 @@ bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
pushnode(L, node, ndef);
objectrefGetOrCreate(L, puncher);
pushPointedThing(pointed);
- if (lua_pcall(L, 4, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler));
return true;
}
@@ -126,8 +125,7 @@ bool ScriptApiNode::node_on_dig(v3s16 p, MapNode node,
push_v3s16(L, p);
pushnode(L, node, ndef);
objectrefGetOrCreate(L, digger);
- if (lua_pcall(L, 3, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 3, 0, m_errorhandler));
return true;
}
@@ -143,8 +141,7 @@ void ScriptApiNode::node_on_construct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
@@ -159,8 +156,7 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
@@ -176,8 +172,7 @@ void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node)
// Call function
push_v3s16(L, p);
pushnode(L, node, ndef);
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
}
bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
@@ -193,14 +188,13 @@ bool ScriptApiNode::node_on_timer(v3s16 p, MapNode node, f32 dtime)
// Call function
push_v3s16(L, p);
lua_pushnumber(L,dtime);
- if (lua_pcall(L, 2, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true;
}
void ScriptApiNode::node_on_receive_fields(v3s16 p,
const std::string &formname,
- const std::map<std::string, std::string> &fields,
+ const StringMap &fields,
ServerActiveObject *sender)
{
SCRIPTAPI_PRECHECKHEADER
@@ -220,8 +214,8 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
push_v3s16(L, p); // pos
lua_pushstring(L, formname.c_str()); // formname
lua_newtable(L); // fields
- std::map<std::string, std::string>::const_iterator it;
- for (it = fields.begin(); it != fields.end(); it++){
+ StringMap::const_iterator it;
+ for (it = fields.begin(); it != fields.end(); it++) {
const std::string &name = it->first;
const std::string &value = it->second;
lua_pushstring(L, name.c_str());
@@ -229,8 +223,7 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
lua_settable(L, -3);
}
objectrefGetOrCreate(L, sender); // player
- if (lua_pcall(L, 4, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 4, 0, m_errorhandler));
}
void ScriptApiNode::node_falling_update(v3s16 p)
@@ -239,8 +232,7 @@ void ScriptApiNode::node_falling_update(v3s16 p)
lua_getglobal(L, "nodeupdate");
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
void ScriptApiNode::node_falling_update_single(v3s16 p)
@@ -249,7 +241,5 @@ void ScriptApiNode::node_falling_update_single(v3s16 p)
lua_getglobal(L, "nodeupdate_single");
push_v3s16(L, p);
- if (lua_pcall(L, 1, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 0, m_errorhandler));
}
-
diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h
index b3a6c83b5..fe1180cb3 100644
--- a/src/script/cpp_api/s_node.h
+++ b/src/script/cpp_api/s_node.h
@@ -20,11 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef S_NODE_H_
#define S_NODE_H_
-#include <map>
-
#include "irr_v3d.h"
#include "cpp_api/s_base.h"
#include "cpp_api/s_nodemeta.h"
+#include "util/string.h"
struct MapNode;
class ServerActiveObject;
@@ -47,7 +46,7 @@ public:
bool node_on_timer(v3s16 p, MapNode node, f32 dtime);
void node_on_receive_fields(v3s16 p,
const std::string &formname,
- const std::map<std::string, std::string> &fields,
+ const StringMap &fields,
ServerActiveObject *sender);
void node_falling_update(v3s16 p);
void node_falling_update_single(v3s16 p);
diff --git a/src/script/cpp_api/s_nodemeta.cpp b/src/script/cpp_api/s_nodemeta.cpp
index 01eee337c..638750b0e 100644
--- a/src/script/cpp_api/s_nodemeta.cpp
+++ b/src/script/cpp_api/s_nodemeta.cpp
@@ -54,8 +54,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowMove(v3s16 p,
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_move should"
" return a number, guilty node: " + nodename);
@@ -89,8 +88,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowPut(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if(!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_put should"
" return a number, guilty node: " + nodename);
@@ -124,8 +122,7 @@ int ScriptApiNodemeta::nodemeta_inventory_AllowTake(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 1, m_errorhandler));
if (!lua_isnumber(L, -1))
throw LuaError("allow_metadata_inventory_take should"
" return a number, guilty node: " + nodename);
@@ -162,8 +159,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnMove(v3s16 p,
lua_pushinteger(L, to_index + 1); // to_index
lua_pushinteger(L, count); // count
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 7, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 7, 0, m_errorhandler));
}
// Report put items
@@ -191,8 +187,7 @@ void ScriptApiNodemeta::nodemeta_inventory_OnPut(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
// Report taken items
@@ -220,13 +215,14 @@ void ScriptApiNodemeta::nodemeta_inventory_OnTake(v3s16 p,
lua_pushinteger(L, index + 1); // index
LuaItemStack::create(L, stack); // stack
objectrefGetOrCreate(L, player); // player
- if (lua_pcall(L, 5, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 5, 0, m_errorhandler));
}
-ScriptApiNodemeta::ScriptApiNodemeta() {
+ScriptApiNodemeta::ScriptApiNodemeta()
+{
}
-ScriptApiNodemeta::~ScriptApiNodemeta() {
+ScriptApiNodemeta::~ScriptApiNodemeta()
+{
}
diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp
index 81bfd4505..ef3c31cfd 100644
--- a/src/script/cpp_api/s_player.cpp
+++ b/src/script/cpp_api/s_player.cpp
@@ -19,6 +19,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_player.h"
#include "cpp_api/s_internal.h"
+#include "common/c_converter.h"
+#include "common/c_content.h"
#include "util/string.h"
void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
@@ -30,7 +32,7 @@ void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
lua_getfield(L, -1, "registered_on_newplayers");
// Call callbacks
objectrefGetOrCreate(L, player);
- script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player)
@@ -42,7 +44,47 @@ void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player)
lua_getfield(L, -1, "registered_on_dieplayers");
// Call callbacks
objectrefGetOrCreate(L, player);
- script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
+}
+
+bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
+ ServerActiveObject *hitter,
+ float time_from_last_punch,
+ const ToolCapabilities *toolcap,
+ v3f dir,
+ s16 damage)
+{
+ SCRIPTAPI_PRECHECKHEADER
+ // Get core.registered_on_punchplayers
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_punchplayers");
+ // Call callbacks
+ objectrefGetOrCreate(L, player);
+ objectrefGetOrCreate(L, hitter);
+ lua_pushnumber(L, time_from_last_punch);
+ push_tool_capabilities(L, *toolcap);
+ push_v3f(L, dir);
+ lua_pushnumber(L, damage);
+ runCallbacks(6, RUN_CALLBACKS_MODE_OR);
+ return lua_toboolean(L, -1);
+}
+
+s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
+ s16 hp_change)
+{
+ SCRIPTAPI_PRECHECKHEADER
+
+ // Get core.registered_on_player_hpchange
+ lua_getglobal(L, "core");
+ lua_getfield(L, -1, "registered_on_player_hpchange");
+ lua_remove(L, -2);
+
+ objectrefGetOrCreate(L, player);
+ lua_pushnumber(L, hp_change);
+ PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
+ hp_change = lua_tointeger(L, -1);
+ lua_pop(L, -1);
+ return hp_change;
}
bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
@@ -54,12 +96,15 @@ bool ScriptApiPlayer::on_respawnplayer(ServerActiveObject *player)
lua_getfield(L, -1, "registered_on_respawnplayers");
// Call callbacks
objectrefGetOrCreate(L, player);
- script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_OR);
+ runCallbacks(1, RUN_CALLBACKS_MODE_OR);
bool positioning_handled_by_some = lua_toboolean(L, -1);
return positioning_handled_by_some;
}
-bool ScriptApiPlayer::on_prejoinplayer(std::string name, std::string ip, std::string &reason)
+bool ScriptApiPlayer::on_prejoinplayer(
+ const std::string &name,
+ const std::string &ip,
+ std::string *reason)
{
SCRIPTAPI_PRECHECKHEADER
@@ -68,9 +113,9 @@ bool ScriptApiPlayer::on_prejoinplayer(std::string name, std::string ip, std::st
lua_getfield(L, -1, "registered_on_prejoinplayers");
lua_pushstring(L, name.c_str());
lua_pushstring(L, ip.c_str());
- script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR);
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR);
if (lua_isstring(L, -1)) {
- reason.assign(lua_tostring(L, -1));
+ reason->assign(lua_tostring(L, -1));
return true;
}
return false;
@@ -85,7 +130,7 @@ void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
lua_getfield(L, -1, "registered_on_joinplayers");
// Call callbacks
objectrefGetOrCreate(L, player);
- script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
@@ -97,7 +142,7 @@ void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
lua_getfield(L, -1, "registered_on_leaveplayers");
// Call callbacks
objectrefGetOrCreate(L, player);
- script_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
@@ -113,12 +158,12 @@ void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
lua_newtable(L);
lua_pushlstring(L, cheat_type.c_str(), cheat_type.size());
lua_setfield(L, -2, "type");
- script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
}
void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname,
- const std::map<std::string, std::string> &fields)
+ const StringMap &fields)
{
SCRIPTAPI_PRECHECKHEADER
@@ -132,17 +177,19 @@ void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
lua_pushstring(L, formname.c_str());
// param 3
lua_newtable(L);
- for(std::map<std::string, std::string>::const_iterator
- i = fields.begin(); i != fields.end(); i++){
- const std::string &name = i->first;
- const std::string &value = i->second;
+ StringMap::const_iterator it;
+ for (it = fields.begin(); it != fields.end(); ++it) {
+ const std::string &name = it->first;
+ const std::string &value = it->second;
lua_pushstring(L, name.c_str());
lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3);
}
- script_run_callbacks(L, 3, RUN_CALLBACKS_MODE_OR_SC);
+ runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
}
-ScriptApiPlayer::~ScriptApiPlayer() {
+
+ScriptApiPlayer::~ScriptApiPlayer()
+{
}
diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h
index c77d397c4..2e4dc2222 100644
--- a/src/script/cpp_api/s_player.h
+++ b/src/script/cpp_api/s_player.h
@@ -20,10 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef S_PLAYER_H_
#define S_PLAYER_H_
-#include <map>
-
#include "cpp_api/s_base.h"
+#include "irr_v3d.h"
+#include "util/string.h"
+struct ToolCapabilities;
class ScriptApiPlayer
: virtual public ScriptApiBase
@@ -34,14 +35,17 @@ public:
void on_newplayer(ServerActiveObject *player);
void on_dieplayer(ServerActiveObject *player);
bool on_respawnplayer(ServerActiveObject *player);
- bool on_prejoinplayer(std::string name, std::string ip, std::string &reason);
+ bool on_prejoinplayer(const std::string &name, const std::string &ip,
+ std::string *reason);
void on_joinplayer(ServerActiveObject *player);
void on_leaveplayer(ServerActiveObject *player);
void on_cheat(ServerActiveObject *player, const std::string &cheat_type);
-
+ bool on_punchplayer(ServerActiveObject *player,
+ ServerActiveObject *hitter, float time_from_last_punch,
+ const ToolCapabilities *toolcap, v3f dir, s16 damage);
+ s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change);
void on_playerReceiveFields(ServerActiveObject *player,
- const std::string &formname,
- const std::map<std::string, std::string> &fields);
+ const std::string &formname, const StringMap &fields);
};
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
new file mode 100644
index 000000000..6a6d40307
--- /dev/null
+++ b/src/script/cpp_api/s_security.cpp
@@ -0,0 +1,604 @@
+/*
+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 "cpp_api/s_security.h"
+
+#include "filesys.h"
+#include "porting.h"
+#include "server.h"
+#include "settings.h"
+
+#include <cerrno>
+#include <string>
+#include <iostream>
+
+
+#define SECURE_API(lib, name) \
+ lua_pushcfunction(L, sl_##lib##_##name); \
+ lua_setfield(L, -2, #name);
+
+
+static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int from=-2, int to=-1)
+{
+ if (from < 0) from = lua_gettop(L) + from + 1;
+ if (to < 0) to = lua_gettop(L) + to + 1;
+ for (unsigned i = 0; i < (len / sizeof(list[0])); i++) {
+ lua_getfield(L, from, list[i]);
+ lua_setfield(L, to, list[i]);
+ }
+}
+
+// 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_getfield(L, -1, lib);
+ lua_remove(L, -2); // Remove globals_backup
+ lua_getfield(L, -1, func);
+ lua_remove(L, -2); // Remove lib
+}
+
+
+void ScriptApiSecurity::initializeSecurity()
+{
+ static const char *whitelist[] = {
+ "assert",
+ "core",
+ "collectgarbage",
+ "DIR_DELIM",
+ "error",
+ "getfenv",
+ "getmetatable",
+ "ipairs",
+ "next",
+ "pairs",
+ "pcall",
+ "print",
+ "rawequal",
+ "rawget",
+ "rawset",
+ "select",
+ "setfenv",
+ "setmetatable",
+ "tonumber",
+ "tostring",
+ "type",
+ "unpack",
+ "_VERSION",
+ "xpcall",
+ // Completely safe libraries
+ "coroutine",
+ "string",
+ "table",
+ "math",
+ };
+ static const char *io_whitelist[] = {
+ "close",
+ "flush",
+ "read",
+ "type",
+ "write",
+ };
+ static const char *os_whitelist[] = {
+ "clock",
+ "date",
+ "difftime",
+ "exit",
+ "getenv",
+ "setlocale",
+ "time",
+ "tmpname",
+ };
+ static const char *debug_whitelist[] = {
+ "gethook",
+ "traceback",
+ "getinfo",
+ "getmetatable",
+ "setupvalue",
+ "setmetatable",
+ "upvalueid",
+ "upvaluejoin",
+ "sethook",
+ "debug",
+ "getupvalue",
+ "setlocal",
+ };
+ static const char *package_whitelist[] = {
+ "config",
+ "cpath",
+ "path",
+ "searchpath",
+ };
+ static const char *jit_whitelist[] = {
+ "arch",
+ "flush",
+ "off",
+ "on",
+ "opt",
+ "os",
+ "status",
+ "version",
+ "version_num",
+ };
+
+ m_secure = true;
+
+ lua_State *L = getStack();
+
+ // Backup globals to the registry
+ lua_getglobal(L, "_G");
+ lua_setfield(L, LUA_REGISTRYINDEX, "globals_backup");
+
+ // Replace the global environment with an empty one
+#if LUA_VERSION_NUM <= 501
+ int is_main = lua_pushthread(L); // Push the main thread
+ FATAL_ERROR_IF(!is_main, "Security: ScriptApi's Lua state "
+ "isn't the main Lua thread!");
+#endif
+ lua_newtable(L); // Create new environment
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "_G"); // Set _G of new environment
+#if LUA_VERSION_NUM >= 502 // Lua >= 5.2
+ // Set the global environment
+ lua_rawseti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
+#else // Lua <= 5.1
+ // Set the environment of the main thread
+ FATAL_ERROR_IF(!lua_setfenv(L, -2), "Security: Unable to set "
+ "environment of the main Lua thread!");
+ lua_pop(L, 1); // Pop thread
+#endif
+
+ // Get old globals
+ lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ int old_globals = lua_gettop(L);
+
+
+ // Copy safe base functions
+ lua_getglobal(L, "_G");
+ copy_safe(L, whitelist, sizeof(whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(g, dofile);
+ SECURE_API(g, load);
+ SECURE_API(g, loadfile);
+ SECURE_API(g, loadstring);
+ SECURE_API(g, require);
+ lua_pop(L, 1);
+
+
+ // Copy safe IO functions
+ lua_getfield(L, old_globals, "io");
+ lua_newtable(L);
+ copy_safe(L, io_whitelist, sizeof(io_whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(io, open);
+ SECURE_API(io, input);
+ SECURE_API(io, output);
+ SECURE_API(io, lines);
+
+ lua_setglobal(L, "io");
+ lua_pop(L, 1); // Pop old IO
+
+
+ // Copy safe OS functions
+ lua_getfield(L, old_globals, "os");
+ lua_newtable(L);
+ copy_safe(L, os_whitelist, sizeof(os_whitelist));
+
+ // And replace unsafe ones
+ SECURE_API(os, remove);
+ SECURE_API(os, rename);
+
+ lua_setglobal(L, "os");
+ lua_pop(L, 1); // Pop old OS
+
+
+ // Copy safe debug functions
+ lua_getfield(L, old_globals, "debug");
+ lua_newtable(L);
+ copy_safe(L, debug_whitelist, sizeof(debug_whitelist));
+ lua_setglobal(L, "debug");
+ lua_pop(L, 1); // Pop old debug
+
+
+ // Copy safe package fields
+ lua_getfield(L, old_globals, "package");
+ lua_newtable(L);
+ copy_safe(L, package_whitelist, sizeof(package_whitelist));
+ lua_setglobal(L, "package");
+ lua_pop(L, 1); // Pop old package
+
+
+ // Copy safe jit functions, if they exist
+ lua_getfield(L, -1, "jit");
+ if (!lua_isnil(L, -1)) {
+ lua_newtable(L);
+ copy_safe(L, jit_whitelist, sizeof(jit_whitelist));
+ lua_setglobal(L, "jit");
+ }
+ lua_pop(L, 1); // Pop old jit
+
+ lua_pop(L, 1); // Pop globals_backup
+}
+
+
+bool ScriptApiSecurity::isSecure(lua_State *L)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ bool secure = !lua_isnil(L, -1);
+ lua_pop(L, 1);
+ return secure;
+}
+
+
+#define CHECK_FILE_ERR(ret, fp) \
+ if (ret) { \
+ if (fp) std::fclose(fp); \
+ lua_pushfstring(L, "%s: %s", path, strerror(errno)); \
+ return false; \
+ }
+
+
+bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path)
+{
+ FILE *fp;
+ char *chunk_name;
+ if (path == NULL) {
+ fp = stdin;
+ chunk_name = const_cast<char *>("=stdin");
+ } else {
+ fp = fopen(path, "rb");
+ if (!fp) {
+ lua_pushfstring(L, "%s: %s", path, strerror(errno));
+ return false;
+ }
+ chunk_name = new char[strlen(path) + 2];
+ chunk_name[0] = '@';
+ chunk_name[1] = '\0';
+ strcat(chunk_name, path);
+ }
+
+ size_t start = 0;
+ int c = std::getc(fp);
+ if (c == '#') {
+ // Skip the first line
+ while ((c = std::getc(fp)) != EOF && c != '\n');
+ if (c == '\n') c = std::getc(fp);
+ start = std::ftell(fp);
+ }
+
+ if (c == LUA_SIGNATURE[0]) {
+ lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
+ return false;
+ }
+
+ // Read the file
+ int ret = std::fseek(fp, 0, SEEK_END);
+ CHECK_FILE_ERR(ret, fp);
+ if (ret) {
+ std::fclose(fp);
+ lua_pushfstring(L, "%s: %s", path, strerror(errno));
+ return false;
+ }
+ size_t size = std::ftell(fp) - start;
+ char *code = new char[size];
+ ret = std::fseek(fp, start, SEEK_SET);
+ CHECK_FILE_ERR(ret, fp);
+ if (ret) {
+ std::fclose(fp);
+ lua_pushfstring(L, "%s: %s", path, strerror(errno));
+ return false;
+ }
+ size_t num_read = std::fread(code, 1, size, fp);
+ if (path) {
+ std::fclose(fp);
+ }
+ if (num_read != size) {
+ lua_pushliteral(L, "Error reading file to load.");
+ return false;
+ }
+
+ if (luaL_loadbuffer(L, code, size, chunk_name)) {
+ return false;
+ }
+
+ if (path) {
+ delete [] chunk_name;
+ }
+ return true;
+}
+
+
+bool ScriptApiSecurity::checkPath(lua_State *L, const char *path)
+{
+ std::string str; // Transient
+
+ std::string norel_path = fs::RemoveRelativePathComponents(path);
+ std::string abs_path = fs::AbsolutePath(norel_path);
+
+ if (!abs_path.empty()) {
+ // Don't allow accessing the settings file
+ str = fs::AbsolutePath(g_settings_path);
+ if (str == abs_path) return false;
+ }
+
+ // If we couldn't find the absolute path (path doesn't exist) then
+ // try removing the last components until it works (to allow
+ // non-existent files/folders for mkdir).
+ std::string cur_path = norel_path;
+ std::string removed;
+ while (abs_path.empty() && !cur_path.empty()) {
+ std::string tmp_rmed;
+ cur_path = fs::RemoveLastPathComponent(cur_path, &tmp_rmed);
+ removed = tmp_rmed + (removed.empty() ? "" : DIR_DELIM + removed);
+ abs_path = fs::AbsolutePath(cur_path);
+ }
+ if (abs_path.empty()) return false;
+ // Add the removed parts back so that you can't, eg, create a
+ // directory in worldmods if worldmods doesn't exist.
+ if (!removed.empty()) abs_path += DIR_DELIM + removed;
+
+ // Get server from registry
+ lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
+ ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ const Server *server = script->getServer();
+
+ if (!server) return false;
+
+ // Get mod name
+ lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ if (lua_isstring(L, -1)) {
+ std::string mod_name = lua_tostring(L, -1);
+
+ // Builtin can access anything
+ if (mod_name == BUILTIN_MOD_NAME) {
+ return true;
+ }
+
+ // Allow paths in mod path
+ const ModSpec *mod = server->getModSpec(mod_name);
+ if (mod) {
+ str = fs::AbsolutePath(mod->path);
+ if (!str.empty() && fs::PathStartsWith(abs_path, str)) {
+ return true;
+ }
+ }
+ }
+ lua_pop(L, 1); // Pop mod name
+
+ str = fs::AbsolutePath(server->getWorldPath());
+ if (str.empty()) return false;
+ // Don't allow access to world mods. We add to the absolute path
+ // of the world instead of getting the absolute paths directly
+ // because that won't work if they don't exist.
+ if (fs::PathStartsWith(abs_path, str + DIR_DELIM + "worldmods") ||
+ fs::PathStartsWith(abs_path, str + DIR_DELIM + "game")) {
+ return false;
+ }
+ // Allow all other paths in world path
+ if (fs::PathStartsWith(abs_path, str)) {
+ return true;
+ }
+
+ // Default to disallowing
+ return false;
+}
+
+
+int ScriptApiSecurity::sl_g_dofile(lua_State *L)
+{
+ int nret = sl_g_loadfile(L);
+ if (nret != 1) {
+ lua_error(L);
+ // code after this function isn't executed
+ }
+ int top_precall = lua_gettop(L);
+ lua_call(L, 0, LUA_MULTRET);
+ // Return number of arguments returned by the function,
+ // adjusting for the function being poped.
+ return lua_gettop(L) - (top_precall - 1);
+}
+
+
+int ScriptApiSecurity::sl_g_load(lua_State *L)
+{
+ size_t len;
+ const char *buf;
+ std::string code;
+ const char *chunk_name = "=(load)";
+
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ if (!lua_isnone(L, 2)) {
+ luaL_checktype(L, 2, LUA_TSTRING);
+ chunk_name = lua_tostring(L, 2);
+ }
+
+ while (true) {
+ lua_pushvalue(L, 1);
+ lua_call(L, 0, 1);
+ int t = lua_type(L, -1);
+ if (t == LUA_TNIL) {
+ break;
+ } else if (t != LUA_TSTRING) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "Loader didn't return a string");
+ return 2;
+ }
+ buf = lua_tolstring(L, -1, &len);
+ code += std::string(buf, len);
+ lua_pop(L, 1); // Pop return value
+ }
+ if (code[0] == LUA_SIGNATURE[0]) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
+ return 2;
+ }
+ if (luaL_loadbuffer(L, code.data(), code.size(), chunk_name)) {
+ lua_pushnil(L);
+ lua_insert(L, lua_gettop(L) - 1);
+ return 2;
+ }
+ return 1;
+}
+
+
+int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
+{
+ const char *path = NULL;
+
+ if (lua_isstring(L, 1)) {
+ path = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path);
+ }
+
+ if (!safeLoadFile(L, path)) {
+ lua_pushnil(L);
+ lua_insert(L, -2);
+ return 2;
+ }
+
+ return 1;
+}
+
+
+int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
+{
+ const char *chunk_name = "=(load)";
+
+ luaL_checktype(L, 1, LUA_TSTRING);
+ if (!lua_isnone(L, 2)) {
+ luaL_checktype(L, 2, LUA_TSTRING);
+ chunk_name = lua_tostring(L, 2);
+ }
+
+ size_t size;
+ const char *code = lua_tolstring(L, 1, &size);
+
+ if (size > 0 && code[0] == LUA_SIGNATURE[0]) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
+ return 2;
+ }
+ if (luaL_loadbuffer(L, code, size, chunk_name)) {
+ lua_pushnil(L);
+ lua_insert(L, lua_gettop(L) - 1);
+ return 2;
+ }
+ return 1;
+}
+
+
+int ScriptApiSecurity::sl_g_require(lua_State *L)
+{
+ lua_pushliteral(L, "require() is disabled when mod security is on.");
+ return lua_error(L);
+}
+
+
+int ScriptApiSecurity::sl_io_open(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TSTRING);
+ const char *path = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path);
+
+ push_original(L, "io", "open");
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_call(L, 2, 2);
+ return 2;
+}
+
+
+int ScriptApiSecurity::sl_io_input(lua_State *L)
+{
+ if (lua_isstring(L, 1)) {
+ const char *path = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path);
+ }
+
+ push_original(L, "io", "input");
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 1);
+ return 1;
+}
+
+
+int ScriptApiSecurity::sl_io_output(lua_State *L)
+{
+ if (lua_isstring(L, 1)) {
+ const char *path = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path);
+ }
+
+ push_original(L, "io", "output");
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 1);
+ return 1;
+}
+
+
+int ScriptApiSecurity::sl_io_lines(lua_State *L)
+{
+ if (lua_isstring(L, 1)) {
+ const char *path = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path);
+ }
+
+ push_original(L, "io", "lines");
+ lua_pushvalue(L, 1);
+ int top_precall = lua_gettop(L);
+ lua_call(L, 1, LUA_MULTRET);
+ // Return number of arguments returned by the function,
+ // adjusting for the function being poped.
+ return lua_gettop(L) - (top_precall - 1);
+}
+
+
+int ScriptApiSecurity::sl_os_rename(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TSTRING);
+ const char *path1 = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path1);
+
+ luaL_checktype(L, 2, LUA_TSTRING);
+ const char *path2 = lua_tostring(L, 2);
+ CHECK_SECURE_PATH(L, path2);
+
+ push_original(L, "os", "rename");
+ lua_pushvalue(L, 1);
+ lua_pushvalue(L, 2);
+ lua_call(L, 2, 2);
+ return 2;
+}
+
+
+int ScriptApiSecurity::sl_os_remove(lua_State *L)
+{
+ luaL_checktype(L, 1, LUA_TSTRING);
+ const char *path = lua_tostring(L, 1);
+ CHECK_SECURE_PATH(L, path);
+
+ push_original(L, "os", "remove");
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 2);
+ return 2;
+}
+
diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h
new file mode 100644
index 000000000..4a4389cf5
--- /dev/null
+++ b/src/script/cpp_api/s_security.h
@@ -0,0 +1,70 @@
+/*
+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 S_SECURITY_H
+#define S_SECURITY_H
+
+#include "cpp_api/s_base.h"
+
+
+#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); \
+ }
+#define CHECK_SECURE_PATH_OPTIONAL(L, path) \
+ if (ScriptApiSecurity::isSecure(L)) { \
+ CHECK_SECURE_PATH(L, path); \
+ }
+
+
+class ScriptApiSecurity : virtual public ScriptApiBase
+{
+public:
+ // Sets up security on the ScriptApi's Lua state
+ void initializeSecurity();
+ // Checks if the Lua state has been secured
+ static bool isSecure(lua_State *L);
+ // Loads a file as Lua code safely (doesn't allow bytecode).
+ static bool safeLoadFile(lua_State *L, const char *path);
+ // Checks if mods are allowed to read and write to the path
+ static bool checkPath(lua_State *L, const char *path);
+
+private:
+ // Syntax: "sl_" <Library name or 'g' (global)> '_' <Function name>
+ // (sl stands for Secure Lua)
+
+ static int sl_g_dofile(lua_State *L);
+ static int sl_g_load(lua_State *L);
+ static int sl_g_loadfile(lua_State *L);
+ static int sl_g_loadstring(lua_State *L);
+ static int sl_g_require(lua_State *L);
+
+ static int sl_io_open(lua_State *L);
+ static int sl_io_input(lua_State *L);
+ static int sl_io_output(lua_State *L);
+ static int sl_io_lines(lua_State *L);
+
+ static int sl_os_rename(lua_State *L);
+ static int sl_os_remove(lua_State *L);
+};
+
+#endif
+
diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp
index 21fe164aa..ec2f9c0af 100644
--- a/src/script/cpp_api/s_server.cpp
+++ b/src/script/cpp_api/s_server.cpp
@@ -32,8 +32,7 @@ bool ScriptApiServer::getAuth(const std::string &playername,
if (lua_type(L, -1) != LUA_TFUNCTION)
throw LuaError("Authentication handler missing get_auth");
lua_pushstring(L, playername.c_str());
- if (lua_pcall(L, 1, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 1, 1, m_errorhandler));
lua_remove(L, -2); // Remove auth handler
// nil = login not allowed
@@ -68,6 +67,9 @@ void ScriptApiServer::getAuthHandler()
lua_pop(L, 1);
lua_getfield(L, -1, "builtin_auth_handler");
}
+
+ setOriginFromTable(-1);
+
lua_remove(L, -2); // Remove core
if (lua_type(L, -1) != LUA_TTABLE)
throw LuaError("Authentication handler table not valid");
@@ -104,8 +106,7 @@ 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());
- if (lua_pcall(L, 2, 0, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 0, m_errorhandler));
}
bool ScriptApiServer::setPassword(const std::string &playername,
@@ -120,8 +121,7 @@ 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());
- if (lua_pcall(L, 2, 1, m_errorhandler))
- scriptError();
+ PCALL_RES(lua_pcall(L, 2, 1, m_errorhandler));
return lua_toboolean(L, -1);
}
@@ -136,7 +136,7 @@ bool ScriptApiServer::on_chat_message(const std::string &name,
// Call callbacks
lua_pushstring(L, name.c_str());
lua_pushstring(L, message.c_str());
- script_run_callbacks(L, 2, RUN_CALLBACKS_MODE_OR_SC);
+ runCallbacks(2, RUN_CALLBACKS_MODE_OR_SC);
bool ate = lua_toboolean(L, -1);
return ate;
}
@@ -149,6 +149,6 @@ void ScriptApiServer::on_shutdown()
lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_shutdown");
// Call callbacks
- script_run_callbacks(L, 0, RUN_CALLBACKS_MODE_FIRST);
+ runCallbacks(0, RUN_CALLBACKS_MODE_FIRST);
}
diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt
index 08960d2ad..2501ce6d6 100644
--- a/src/script/lua_api/CMakeLists.txt
+++ b/src/script/lua_api/CMakeLists.txt
@@ -1,5 +1,5 @@
-# Used by server and client
set(common_SCRIPT_LUA_API_SRCS
+ ${CMAKE_CURRENT_SOURCE_DIR}/l_areastore.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_base.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_craft.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_env.cpp
@@ -18,7 +18,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp
PARENT_SCOPE)
-# Used by client only
-set(minetest_SCRIPT_LUA_API_SRCS
+set(client_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
PARENT_SCOPE)
+
diff --git a/src/script/lua_api/l_areastore.cpp b/src/script/lua_api/l_areastore.cpp
new file mode 100644
index 000000000..1e9075119
--- /dev/null
+++ b/src/script/lua_api/l_areastore.cpp
@@ -0,0 +1,401 @@
+/*
+Minetest
+Copyright (C) 2015 est31 <mtest31@outlook.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_areastore.h"
+#include "lua_api/l_internal.h"
+#include "common/c_converter.h"
+#include "cpp_api/s_security.h"
+#include "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,
+ bool *borders, bool *data)
+{
+ if (!lua_isboolean(L, start_i))
+ return;
+ *borders = 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)
+{
+ if (!include_borders && !include_data) {
+ lua_pushboolean(L, true);
+ }
+ lua_newtable(L);
+ if (include_borders) {
+ push_v3s16(L, a->minedge);
+ lua_setfield(L, -2, "min");
+ push_v3s16(L, a->maxedge);
+ lua_setfield(L, -2, "max");
+ }
+ if (include_data) {
+ lua_pushlstring(L, a->data.c_str(), a->data.size());
+ lua_setfield(L, -2, "data");
+ }
+}
+
+static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
+ bool borders, 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);
+ lua_settable(L, -3);
+ }
+}
+
+// garbage collector
+int LuaAreaStore::gc_object(lua_State *L)
+{
+ LuaAreaStore *o = *(LuaAreaStore **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+// get_area(id, include_borders, include_data)
+int LuaAreaStore::l_get_area(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = checkobject(L, 1);
+ AreaStore *ast = o->as;
+
+ u32 id = luaL_checknumber(L, 2);
+
+ bool include_borders = true;
+ bool include_data = false;
+ get_data_and_border_flags(L, 3, &include_borders, &include_data);
+
+ const Area *res;
+
+ res = ast->getArea(id);
+ push_area(L, res, include_borders, include_data);
+
+ return 1;
+}
+
+// get_areas_for_pos(pos, include_borders, include_data)
+int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = checkobject(L, 1);
+ AreaStore *ast = o->as;
+
+ v3s16 pos = check_v3s16(L, 2);
+
+ bool include_borders = true;
+ bool include_data = false;
+ get_data_and_border_flags(L, 3, &include_borders, &include_data);
+
+ std::vector<Area *> res;
+
+ ast->getAreasForPos(&res, pos);
+ push_areas(L, res, include_borders, include_data);
+
+ return 1;
+}
+
+// get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)
+int LuaAreaStore::l_get_areas_in_area(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = checkobject(L, 1);
+ AreaStore *ast = o->as;
+
+ v3s16 minedge = check_v3s16(L, 2);
+ v3s16 maxedge = check_v3s16(L, 3);
+
+ bool include_borders = true;
+ bool include_data = false;
+ bool accept_overlap = false;
+ if (lua_isboolean(L, 4)) {
+ accept_overlap = lua_toboolean(L, 4);
+ get_data_and_border_flags(L, 5, &include_borders, &include_data);
+ }
+ std::vector<Area *> res;
+
+ ast->getAreasInArea(&res, minedge, maxedge, accept_overlap);
+ push_areas(L, res, include_borders, include_data);
+
+ return 1;
+}
+
+// insert_area(edge1, edge2, data)
+int LuaAreaStore::l_insert_area(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ 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;
+ }
+
+ size_t d_len;
+ const char *data = luaL_checklstring(L, 4, &d_len);
+
+ a.data = std::string(data, d_len);
+
+ ast->insertArea(a);
+
+ lua_pushnumber(L, a.id);
+ return 1;
+}
+
+// reserve(count)
+int LuaAreaStore::l_reserve(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = checkobject(L, 1);
+ AreaStore *ast = o->as;
+
+ size_t count = luaL_checknumber(L, 2);
+ ast->reserve(count);
+ return 0;
+}
+
+// remove_area(id)
+int LuaAreaStore::l_remove_area(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = checkobject(L, 1);
+ AreaStore *ast = o->as;
+
+ u32 id = luaL_checknumber(L, 2);
+ bool success = ast->removeArea(id);
+
+ lua_pushboolean(L, success);
+ return 1;
+}
+
+// set_cache_params(params)
+int LuaAreaStore::l_set_cache_params(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = checkobject(L, 1);
+ AreaStore *ast = o->as;
+
+ luaL_checktype(L, 2, LUA_TTABLE);
+
+ bool enabled = getboolfield_default(L, 2, "enabled", true);
+ u8 block_radius = getintfield_default(L, 2, "block_radius", 64);
+ size_t limit = getintfield_default(L, 2, "block_radius", 1000);
+
+ ast->setCacheParams(enabled, block_radius, limit);
+
+ 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);
+ std::string str = os.str();
+
+ lua_pushlstring(L, str.c_str(), str.length());
+ return 1;
+}
+
+// to_file(filename)
+int LuaAreaStore::l_to_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::ostringstream os(std::ios_base::binary);
+ ast->serialize(os);
+
+ lua_pushboolean(L, fs::safeWriteToFile(filename, os.str()));
+ return 1;
+}
+
+// from_string(str)
+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;
+}
+
+// from_file(filename)
+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;
+}
+#endif
+
+LuaAreaStore::LuaAreaStore()
+{
+#if USE_SPATIAL
+ this->as = new SpatialAreaStore();
+#else
+ this->as = new VectorAreaStore();
+#endif
+}
+
+LuaAreaStore::LuaAreaStore(const std::string &type)
+{
+#if USE_SPATIAL
+ if (type == "LibSpatial") {
+ this->as = new SpatialAreaStore();
+ } else
+#endif
+ {
+ this->as = new VectorAreaStore();
+ }
+}
+
+LuaAreaStore::~LuaAreaStore()
+{
+ delete as;
+}
+
+// LuaAreaStore()
+// Creates an LuaAreaStore and leaves it on top of stack
+int LuaAreaStore::create_object(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaAreaStore *o = (lua_isstring(L, 1)) ?
+ new LuaAreaStore(lua_tostring(L, 1)) :
+ new LuaAreaStore();
+
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+LuaAreaStore *LuaAreaStore::checkobject(lua_State *L, int narg)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+
+ return *(LuaAreaStore **)ud; // unbox pointer
+}
+
+void LuaAreaStore::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); // hide metatable from Lua getmetatable()
+
+ 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); // drop metatable
+
+ luaL_openlib(L, 0, methods, 0); // fill methodtable
+ lua_pop(L, 1); // drop methodtable
+
+ // Can be created from Lua (AreaStore())
+ lua_register(L, className, create_object);
+}
+
+const char LuaAreaStore::className[] = "AreaStore";
+const luaL_reg LuaAreaStore::methods[] = {
+ luamethod(LuaAreaStore, get_area),
+ luamethod(LuaAreaStore, get_areas_for_pos),
+ luamethod(LuaAreaStore, get_areas_in_area),
+ luamethod(LuaAreaStore, insert_area),
+ luamethod(LuaAreaStore, reserve),
+ luamethod(LuaAreaStore, remove_area),
+ luamethod(LuaAreaStore, set_cache_params),
+ /* luamethod(LuaAreaStore, to_string),
+ luamethod(LuaAreaStore, to_file),
+ luamethod(LuaAreaStore, from_string),
+ luamethod(LuaAreaStore, from_file),*/
+ {0,0}
+};
diff --git a/src/script/lua_api/l_areastore.h b/src/script/lua_api/l_areastore.h
new file mode 100644
index 000000000..a25529627
--- /dev/null
+++ b/src/script/lua_api/l_areastore.h
@@ -0,0 +1,70 @@
+/*
+Minetest
+Copyright (C) 2015 est31 <mtest31@outlook.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_AREASTORE_H_
+#define L_AREASTORE_H_
+
+#include "lua_api/l_base.h"
+#include "irr_v3d.h"
+#include "areastore.h"
+
+/*
+ AreaStore
+ */
+class LuaAreaStore : public ModApiBase {
+private:
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ static int gc_object(lua_State *L);
+
+ static int l_get_area(lua_State *L);
+
+ static int l_get_areas_for_pos(lua_State *L);
+ static int l_get_areas_in_area(lua_State *L);
+ static int l_insert_area(lua_State *L);
+ static int l_reserve(lua_State *L);
+ static int l_remove_area(lua_State *L);
+
+ static int l_set_cache_params(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); */
+
+public:
+ AreaStore *as;
+
+ LuaAreaStore();
+ LuaAreaStore(const std::string &type);
+ ~LuaAreaStore();
+
+ // AreaStore()
+ // Creates a AreaStore and leaves it on top of stack
+ static int create_object(lua_State *L);
+
+ static LuaAreaStore *checkobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+#endif /* L_AREASTORE_H_ */
diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp
index b8d673ee4..6ad3e4ba2 100644
--- a/src/script/lua_api/l_base.cpp
+++ b/src/script/lua_api/l_base.cpp
@@ -20,8 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_base.h"
#include "lua_api/l_internal.h"
#include "cpp_api/s_base.h"
+#include <mods.h>
+#include <server.h>
-ScriptApiBase* ModApiBase::getScriptApiBase(lua_State *L) {
+ScriptApiBase *ModApiBase::getScriptApiBase(lua_State *L)
+{
// Get server from registry
lua_getfield(L, LUA_REGISTRYINDEX, "scriptapi");
ScriptApiBase *sapi_ptr = (ScriptApiBase*) lua_touserdata(L, -1);
@@ -29,23 +32,42 @@ ScriptApiBase* ModApiBase::getScriptApiBase(lua_State *L) {
return sapi_ptr;
}
-Server* ModApiBase::getServer(lua_State *L) {
+Server *ModApiBase::getServer(lua_State *L)
+{
return getScriptApiBase(L)->getServer();
}
-Environment* ModApiBase::getEnv(lua_State *L) {
+Environment *ModApiBase::getEnv(lua_State *L)
+{
return getScriptApiBase(L)->getEnv();
}
-GUIEngine* ModApiBase::getGuiEngine(lua_State *L) {
+GUIEngine *ModApiBase::getGuiEngine(lua_State *L)
+{
return getScriptApiBase(L)->getGuiEngine();
}
-bool ModApiBase::registerFunction(lua_State *L,
- const char *name,
- lua_CFunction fct,
- int top
- ) {
+std::string ModApiBase::getCurrentModPath(lua_State *L)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ const char *current_mod_name = lua_tostring(L, -1);
+ if (!current_mod_name)
+ return ".";
+
+ const ModSpec *mod = getServer(L)->getModSpec(current_mod_name);
+ if (!mod)
+ return ".";
+
+ return mod->path;
+}
+
+
+bool ModApiBase::registerFunction(
+ lua_State *L,
+ const char *name,
+ lua_CFunction fct,
+ int top)
+{
//TODO check presence first!
lua_pushstring(L,name);
diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h
index debbcd09b..641013dfd 100644
--- a/src/script/lua_api/l_base.h
+++ b/src/script/lua_api/l_base.h
@@ -35,11 +35,13 @@ class GUIEngine;
class ModApiBase {
-protected:
+public:
static ScriptApiBase* getScriptApiBase(lua_State *L);
static Server* getServer(lua_State *L);
static Environment* getEnv(lua_State *L);
static GUIEngine* getGuiEngine(lua_State *L);
+ // When we are not loading the mod, this function returns "."
+ static std::string getCurrentModPath(lua_State *L);
// Get an arbitrary subclass of ScriptApiBase
// by using dynamic_cast<> on getScriptApiBase()
diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp
index 8f8efbfbc..391a0133d 100644
--- a/src/script/lua_api/l_craft.cpp
+++ b/src/script/lua_api/l_craft.cpp
@@ -173,7 +173,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
CraftDefinition *def = new CraftDefinitionShaped(
output, width, recipe, replacements);
- craftdef->registerCraft(def);
+ craftdef->registerCraft(def, getServer(L));
}
/*
CraftDefinitionShapeless
@@ -205,7 +205,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
CraftDefinition *def = new CraftDefinitionShapeless(
output, recipe, replacements);
- craftdef->registerCraft(def);
+ craftdef->registerCraft(def, getServer(L));
}
/*
CraftDefinitionToolRepair
@@ -216,7 +216,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
CraftDefinition *def = new CraftDefinitionToolRepair(
additional_wear);
- craftdef->registerCraft(def);
+ craftdef->registerCraft(def, getServer(L));
}
/*
CraftDefinitionCooking
@@ -246,7 +246,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
CraftDefinition *def = new CraftDefinitionCooking(
output, recipe, cooktime, replacements);
- craftdef->registerCraft(def);
+ craftdef->registerCraft(def, getServer(L));
}
/*
CraftDefinitionFuel
@@ -270,7 +270,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
CraftDefinition *def = new CraftDefinitionFuel(
recipe, burntime, replacements);
- craftdef->registerCraft(def);
+ craftdef->registerCraft(def, getServer(L));
}
else
{
@@ -303,18 +303,23 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
ICraftDefManager *cdef = gdef->cdef();
CraftInput input(method, width, items);
CraftOutput output;
- bool got = cdef->getCraftResult(input, output, true, gdef);
+ std::vector<ItemStack> output_replacements;
+ bool got = cdef->getCraftResult(input, output, output_replacements, true, gdef);
lua_newtable(L); // output table
- if(got){
+ if (got) {
ItemStack item;
item.deSerialize(output.item, gdef->idef());
LuaItemStack::create(L, item);
lua_setfield(L, -2, "item");
setintfield(L, -1, "time", output.time);
+ push_items(L, output_replacements);
+ lua_setfield(L, -2, "replacements");
} else {
LuaItemStack::create(L, ItemStack());
lua_setfield(L, -2, "item");
setintfield(L, -1, "time", 0);
+ lua_newtable(L);
+ lua_setfield(L, -2, "replacements");
}
lua_newtable(L); // decremented input table
lua_pushstring(L, method_s.c_str());
@@ -326,56 +331,82 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
return 2;
}
+
+static void push_craft_recipe(lua_State *L, IGameDef *gdef,
+ const CraftDefinition *recipe,
+ const CraftOutput &tmpout)
+{
+ CraftInput input = recipe->getInput(tmpout, gdef);
+ CraftOutput output = recipe->getOutput(input, gdef);
+
+ lua_newtable(L); // items
+ std::vector<ItemStack>::const_iterator iter = input.items.begin();
+ for (u16 j = 1; iter != input.items.end(); iter++, j++) {
+ if (iter->empty())
+ continue;
+ lua_pushstring(L, iter->name.c_str());
+ lua_rawseti(L, -2, j);
+ }
+ lua_setfield(L, -2, "items");
+ setintfield(L, -1, "width", input.width);
+ switch (input.method) {
+ case CRAFT_METHOD_NORMAL:
+ lua_pushstring(L, "normal");
+ break;
+ case CRAFT_METHOD_COOKING:
+ lua_pushstring(L, "cooking");
+ break;
+ case CRAFT_METHOD_FUEL:
+ lua_pushstring(L, "fuel");
+ break;
+ default:
+ lua_pushstring(L, "unknown");
+ }
+ lua_setfield(L, -2, "type");
+ lua_pushstring(L, output.item.c_str());
+ lua_setfield(L, -2, "output");
+}
+
+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;
+ }
+
+ std::vector<CraftDefinition*>::const_iterator it = recipes.begin();
+ for (unsigned i = 0; it != recipes.end(); ++it) {
+ lua_newtable(L);
+ push_craft_recipe(L, gdef, *it, output);
+ lua_rawseti(L, -2, ++i);
+ }
+}
+
+
// get_craft_recipe(result item)
int ModApiCraft::l_get_craft_recipe(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- int k = 1;
- int input_i = 1;
- std::string o_item = luaL_checkstring(L,input_i);
+ std::string item = luaL_checkstring(L, 1);
+ Server *server = getServer(L);
+ CraftOutput output(item, 0);
+ std::vector<CraftDefinition*> recipes = server->cdef()
+ ->getCraftRecipes(output, server, 1);
- IGameDef *gdef = getServer(L);
- ICraftDefManager *cdef = gdef->cdef();
- CraftInput input;
- CraftOutput output(o_item,0);
- bool got = cdef->getCraftRecipe(input, output, gdef);
- lua_newtable(L); // output table
- if(got){
- lua_newtable(L);
- for(std::vector<ItemStack>::const_iterator
- i = input.items.begin();
- i != input.items.end(); i++, k++)
- {
- if (i->empty())
- {
- continue;
- }
- lua_pushinteger(L,k);
- lua_pushstring(L,i->name.c_str());
- lua_settable(L, -3);
- }
- lua_setfield(L, -2, "items");
- setintfield(L, -1, "width", input.width);
- switch (input.method) {
- case CRAFT_METHOD_NORMAL:
- lua_pushstring(L,"normal");
- break;
- case CRAFT_METHOD_COOKING:
- lua_pushstring(L,"cooking");
- break;
- case CRAFT_METHOD_FUEL:
- lua_pushstring(L,"fuel");
- break;
- default:
- lua_pushstring(L,"unknown");
- }
- lua_setfield(L, -2, "type");
- } else {
+ lua_createtable(L, 1, 0);
+
+ if (recipes.empty()) {
lua_pushnil(L);
lua_setfield(L, -2, "items");
setintfield(L, -1, "width", 0);
+ return 1;
}
+ push_craft_recipe(L, server, recipes[0], output);
return 1;
}
@@ -384,59 +415,13 @@ int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- std::string o_item = luaL_checkstring(L,1);
- IGameDef *gdef = getServer(L);
- ICraftDefManager *cdef = gdef->cdef();
- CraftInput input;
- CraftOutput output(o_item,0);
- std::vector<CraftDefinition*> recipes_list;
- recipes_list = cdef->getCraftRecipes(output, gdef);
- if (recipes_list.empty()) {
- lua_pushnil(L);
- return 1;
- }
+ std::string item = luaL_checkstring(L, 1);
+ Server *server = getServer(L);
+ CraftOutput output(item, 0);
+ std::vector<CraftDefinition*> recipes = server->cdef()
+ ->getCraftRecipes(output, server);
- lua_createtable(L, recipes_list.size(), 0);
- std::vector<CraftDefinition*>::const_iterator iter = recipes_list.begin();
- for (u16 i = 0; iter != recipes_list.end(); iter++) {
- CraftOutput tmpout;
- tmpout.item = "";
- tmpout.time = 0;
- tmpout = (*iter)->getOutput(input, gdef);
- std::string query = tmpout.item;
- char *fmtpos, *fmt = &query[0];
- if (strtok_r(fmt, " ", &fmtpos) == output.item) {
- input = (*iter)->getInput(output, gdef);
- lua_newtable(L);
- lua_newtable(L); // items
- std::vector<ItemStack>::const_iterator iter = input.items.begin();
- for (u16 j = 1; iter != input.items.end(); iter++, j++) {
- if (iter->empty())
- continue;
- lua_pushstring(L, iter->name.c_str());
- lua_rawseti(L, -2, j);
- }
- lua_setfield(L, -2, "items");
- setintfield(L, -1, "width", input.width);
- switch (input.method) {
- case CRAFT_METHOD_NORMAL:
- lua_pushstring(L, "normal");
- break;
- case CRAFT_METHOD_COOKING:
- lua_pushstring(L, "cooking");
- break;
- case CRAFT_METHOD_FUEL:
- lua_pushstring(L, "fuel");
- break;
- default:
- lua_pushstring(L, "unknown");
- }
- lua_setfield(L, -2, "type");
- lua_pushstring(L, &tmpout.item[0]);
- lua_setfield(L, -2, "output");
- lua_rawseti(L, -2, ++i);
- }
- }
+ push_craft_recipes(L, server, recipes, output);
return 1;
}
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index cd5d253ac..28afdd071 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -49,7 +49,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
scriptIface->realityCheck();
lua_State *L = scriptIface->getStack();
- assert(lua_checkstack(L, 20));
+ sanity_check(lua_checkstack(L, 20));
StackUnroller stack_unroller(L);
lua_pushcfunction(L, script_error_handler);
@@ -65,9 +65,11 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
lua_pushnumber(L, m_id);
lua_gettable(L, -2);
if(lua_isnil(L, -1))
- assert(0);
+ FATAL_ERROR("");
lua_remove(L, -2); // Remove registered_abms
+ scriptIface->setOriginFromTable(-1);
+
// Call action
luaL_checktype(L, -1, LUA_TTABLE);
lua_getfield(L, -1, "action");
@@ -77,8 +79,11 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
pushnode(L, n, env->getGameDef()->ndef());
lua_pushnumber(L, active_object_count);
lua_pushnumber(L, active_object_count_wider);
- if(lua_pcall(L, 4, 0, errorhandler))
- script_error(L);
+
+ int result = lua_pcall(L, 4, 0, errorhandler);
+ if (result)
+ scriptIface->scriptError(result, "LuaABM::trigger");
+
lua_pop(L, 1); // Pop error handler
}
@@ -334,6 +339,22 @@ int ModApiEnvMod::l_add_node_level(lua_State *L)
return 1;
}
+// find_nodes_with_meta(pos1, pos2)
+int ModApiEnvMod::l_find_nodes_with_meta(lua_State *L)
+{
+ GET_ENV_PTR;
+
+ std::vector<v3s16> positions = env->getMap().findNodesWithMetadata(
+ check_v3s16(L, 1), check_v3s16(L, 2));
+
+ lua_newtable(L);
+ for (size_t i = 0; i != positions.size(); i++) {
+ push_v3s16(L, positions[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+
+ return 1;
+}
// get_meta(pos)
int ModApiEnvMod::l_get_meta(lua_State *L)
@@ -402,23 +423,11 @@ int ModApiEnvMod::l_add_item(lua_State *L)
return 0;
lua_pushvalue(L, 1);
lua_pushstring(L, item.getItemString().c_str());
- if(lua_pcall(L, 2, 1, errorhandler))
- script_error(L);
+
+ PCALL_RESL(L, lua_pcall(L, 2, 1, errorhandler));
+
lua_remove(L, errorhandler); // Remove error handler
return 1;
- /*lua_pushvalue(L, 1);
- lua_pushstring(L, "__builtin:item");
- lua_pushstring(L, item.getItemString().c_str());
- return l_add_entity(L);*/
- /*// Do it
- ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
- int objectid = env->addActiveObject(obj);
- // If failed to add, return nothing (reads as nil)
- if(objectid == 0)
- return 0;
- // Return ObjectRef
- objectrefGetOrCreate(L, obj);
- return 1;*/
}
// get_player_by_name(name)
@@ -451,10 +460,11 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
// Do it
v3f pos = checkFloatPos(L, 1);
float radius = luaL_checknumber(L, 2) * BS;
- std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
+ std::vector<u16> ids;
+ env->getObjectsInsideRadius(ids, pos, radius);
ScriptApiBase *script = getScriptApiBase(L);
lua_createtable(L, ids.size(), 0);
- std::set<u16>::const_iterator iter = ids.begin();
+ std::vector<u16>::const_iterator iter = ids.begin();
for(u32 i = 0; iter != ids.end(); iter++) {
ServerActiveObject *obj = env->getActiveObject(*iter);
// Insert object reference into table
@@ -472,7 +482,7 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L)
// Do it
float timeofday_f = luaL_checknumber(L, 1);
- assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
+ sanity_check(timeofday_f >= 0.0 && timeofday_f <= 1.0);
int timeofday_mh = (int)(timeofday_f * 24000.0);
// This should be set directly in the environment but currently
// such changes aren't immediately sent to the clients, so call
@@ -530,9 +540,8 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
}
for(int d=1; d<=radius; d++){
- std::list<v3s16> list;
- getFacePositions(list, d);
- for(std::list<v3s16>::iterator i = list.begin();
+ std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
+ for(std::vector<v3s16>::iterator i = list.begin();
i != list.end(); ++i){
v3s16 p = pos + (*i);
content_t c = env->getMap().getNodeNoEx(p).getContent();
@@ -555,30 +564,92 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
v3s16 minp = read_v3s16(L, 1);
v3s16 maxp = read_v3s16(L, 2);
std::set<content_t> filter;
- if(lua_istable(L, 3)){
+ if(lua_istable(L, 3)) {
int table = 3;
lua_pushnil(L);
- while(lua_next(L, table) != 0){
+ while(lua_next(L, table) != 0) {
// key at index -2 and value at index -1
luaL_checktype(L, -1, LUA_TSTRING);
ndef->getIds(lua_tostring(L, -1), filter);
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
- } else if(lua_isstring(L, 3)){
+ } else if(lua_isstring(L, 3)) {
+ ndef->getIds(lua_tostring(L, 3), filter);
+ }
+
+ std::map<content_t, u16> individual_count;
+
+ lua_newtable(L);
+ u64 i = 0;
+ for (s16 x = minp.X; x <= maxp.X; x++)
+ for (s16 y = minp.Y; y <= maxp.Y; y++)
+ for (s16 z = minp.Z; z <= maxp.Z; z++) {
+ v3s16 p(x, y, z);
+ content_t c = env->getMap().getNodeNoEx(p).getContent();
+ if (filter.count(c) != 0) {
+ push_v3s16(L, p);
+ lua_rawseti(L, -2, ++i);
+ individual_count[c]++;
+ }
+ }
+ lua_newtable(L);
+ for (std::set<content_t>::iterator it = filter.begin();
+ it != filter.end(); ++it) {
+ lua_pushnumber(L, individual_count[*it]);
+ lua_setfield(L, -2, ndef->get(*it).name.c_str());
+ }
+ return 2;
+}
+
+// find_nodes_in_area_under_air(minp, maxp, nodenames) -> list of positions
+// nodenames: e.g. {"ignore", "group:tree"} or "default:dirt"
+int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
+{
+ /* Note: A similar but generalized (and therefore slower) version of this
+ * function could be created -- e.g. find_nodes_in_area_under -- which
+ * would accept a node name (or ID?) or list of names that the "above node"
+ * should be.
+ * TODO
+ */
+
+ GET_ENV_PTR;
+
+ INodeDefManager *ndef = getServer(L)->ndef();
+ v3s16 minp = read_v3s16(L, 1);
+ v3s16 maxp = read_v3s16(L, 2);
+ std::set<content_t> filter;
+
+ if (lua_istable(L, 3)) {
+ int table = 3;
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0) {
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ ndef->getIds(lua_tostring(L, -1), filter);
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if (lua_isstring(L, 3)) {
ndef->getIds(lua_tostring(L, 3), filter);
}
lua_newtable(L);
u64 i = 0;
- for(s16 x = minp.X; x <= maxp.X; x++)
- for(s16 y = minp.Y; y <= maxp.Y; y++)
- for(s16 z = minp.Z; z <= maxp.Z; z++) {
+ for (s16 x = minp.X; x <= maxp.X; x++)
+ for (s16 z = minp.Z; z <= maxp.Z; z++) {
+ s16 y = minp.Y;
v3s16 p(x, y, z);
content_t c = env->getMap().getNodeNoEx(p).getContent();
- if(filter.count(c) != 0) {
- push_v3s16(L, p);
- lua_rawseti(L, -2, ++i);
+ for (; y <= maxp.Y; y++) {
+ v3s16 psurf(x, y + 1, z);
+ content_t csurf = env->getMap().getNodeNoEx(psurf).getContent();
+ if(c != CONTENT_AIR && csurf == CONTENT_AIR &&
+ filter.count(c) != 0) {
+ push_v3s16(L, v3s16(x, y, z));
+ lua_rawseti(L, -2, ++i);
+ }
+ c = csurf;
}
}
return 1;
@@ -702,10 +773,12 @@ int ModApiEnvMod::l_delete_area(lua_State *L)
for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
for (s16 x = bpmin.X; x <= bpmax.X; x++) {
v3s16 bp(x, y, z);
- if (map.deleteBlock(bp))
+ if (map.deleteBlock(bp)) {
+ env->setStaticForActiveObjectsInBlock(bp, false);
event.modified_blocks.insert(bp);
- else
+ } else {
success = false;
+ }
}
map.dispatchEvent(&event);
@@ -872,6 +945,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(set_node_level);
API_FCT(add_node_level);
API_FCT(add_entity);
+ API_FCT(find_nodes_with_meta);
API_FCT(get_meta);
API_FCT(get_node_timer);
API_FCT(get_player_by_name);
@@ -881,6 +955,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
API_FCT(get_gametime);
API_FCT(find_node_near);
API_FCT(find_nodes_in_area);
+ API_FCT(find_nodes_in_area_under_air);
API_FCT(delete_area);
API_FCT(get_perlin);
API_FCT(get_perlin_map);
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index bfaea1c4d..0d4ca788e 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -64,7 +64,6 @@ private:
// pos = {x=num, y=num, z=num}
static int l_punch_node(lua_State *L);
-
// get_node_max_level(pos)
// pos = {x=num, y=num, z=num}
static int l_get_node_max_level(lua_State *L);
@@ -81,6 +80,9 @@ private:
// pos = {x=num, y=num, z=num}
static int l_add_node_level(lua_State *L);
+ // find_nodes_with_meta(pos1, pos2)
+ static int l_find_nodes_with_meta(lua_State *L);
+
// get_meta(pos)
static int l_get_meta(lua_State *L);
@@ -119,6 +121,10 @@ private:
// nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
static int l_find_nodes_in_area(lua_State *L);
+ // find_surface_nodes_in_area(minp, maxp, nodenames) -> list of positions
+ // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+ static int l_find_nodes_in_area_under_air(lua_State *L);
+
// delete_area(p1, p2) -> true/false
static int l_delete_area(lua_State *L);
diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h
index 5936ac046..1e40c5c4a 100644
--- a/src/script/lua_api/l_internal.h
+++ b/src/script/lua_api/l_internal.h
@@ -33,13 +33,16 @@ 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)
-#if (defined(WIN32) || defined(_WIN32_WCE))
#define NO_MAP_LOCK_REQUIRED
+
+/*
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ #define NO_MAP_LOCK_REQUIRED
#else
-#include "main.h"
-#include "profiler.h"
-#define NO_MAP_LOCK_REQUIRED \
- ScopeProfiler nolocktime(g_profiler,"Scriptapi: unlockable time",SPT_ADD)
+ #include "profiler.h"
+ #define NO_MAP_LOCK_REQUIRED \
+ ScopeProfiler nolocktime(g_profiler,"Scriptapi: unlockable time",SPT_ADD)
#endif
+*/
#endif /* L_INTERNAL_H_ */
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 2bed2a255..92311d6fc 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -34,7 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "sound.h"
#include "settings.h"
-#include "main.h" // for g_settings
#include "log.h"
#include "EDriverTypes.h"
@@ -90,7 +89,7 @@ int ModApiMainMenu::getBoolData(lua_State *L, std::string name,bool& valid)
int ModApiMainMenu::l_update_formspec(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
if (engine->m_startgame)
return 0;
@@ -109,21 +108,25 @@ int ModApiMainMenu::l_update_formspec(lua_State *L)
int ModApiMainMenu::l_start(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
//update c++ gamedata from lua table
bool valid = false;
+ MainMenuData *data = engine->m_data;
- engine->m_data->selected_world = getIntegerData(L, "selected_world",valid) -1;
- engine->m_data->simple_singleplayer_mode = getBoolData(L,"singleplayer",valid);
- engine->m_data->name = getTextData(L,"playername");
- engine->m_data->password = getTextData(L,"password");
- engine->m_data->address = getTextData(L,"address");
- engine->m_data->port = getTextData(L,"port");
- engine->m_data->serverdescription = getTextData(L,"serverdescription");
- engine->m_data->servername = getTextData(L,"servername");
+ data->selected_world = getIntegerData(L, "selected_world",valid) -1;
+ data->simple_singleplayer_mode = getBoolData(L,"singleplayer",valid);
+ data->do_reconnect = getBoolData(L, "do_reconnect", valid);
+ if (!data->do_reconnect) {
+ data->name = getTextData(L,"playername");
+ data->password = getTextData(L,"password");
+ data->address = getTextData(L,"address");
+ data->port = getTextData(L,"port");
+ }
+ data->serverdescription = getTextData(L,"serverdescription");
+ data->servername = getTextData(L,"servername");
//close menu next time
engine->m_startgame = true;
@@ -134,7 +137,7 @@ int ModApiMainMenu::l_start(lua_State *L)
int ModApiMainMenu::l_close(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
engine->m_kill = true;
return 0;
@@ -144,7 +147,7 @@ int ModApiMainMenu::l_close(lua_State *L)
int ModApiMainMenu::l_set_background(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
std::string backgroundlevel(luaL_checkstring(L, 1));
std::string texturename(luaL_checkstring(L, 2));
@@ -189,7 +192,7 @@ int ModApiMainMenu::l_set_background(lua_State *L)
int ModApiMainMenu::l_set_clouds(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
bool value = lua_toboolean(L,1);
@@ -209,9 +212,9 @@ int ModApiMainMenu::l_get_textlist_index(lua_State *L)
int ModApiMainMenu::l_get_table_index(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
- std::wstring tablename(narrow_to_wide(luaL_checkstring(L, 1)));
+ std::string tablename(luaL_checkstring(L, 1));
GUITable *table = engine->m_menu->getTable(tablename);
s32 selection = table ? table->getSelected() : 0;
@@ -617,7 +620,7 @@ int ModApiMainMenu::l_delete_favorite(lua_State *L)
int ModApiMainMenu::l_show_keys_menu(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
GUIKeyChangeMenu *kmenu
= new GUIKeyChangeMenu( engine->m_device->getGUIEnvironment(),
@@ -644,15 +647,12 @@ int ModApiMainMenu::l_create_world(lua_State *L)
(gameidx < (int) games.size())) {
// Create world if it doesn't exist
- if(!initializeWorld(path, games[gameidx].id)){
+ if (!loadGameConfAndInitWorld(path, games[gameidx])) {
lua_pushstring(L, "Failed to initialize world");
-
- }
- else {
- lua_pushnil(L);
+ } else {
+ lua_pushnil(L);
}
- }
- else {
+ } else {
lua_pushstring(L, "Invalid game index");
}
return 1;
@@ -692,7 +692,7 @@ int ModApiMainMenu::l_delete_world(lua_State *L)
int ModApiMainMenu::l_set_topleft_text(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
std::string text = "";
@@ -758,30 +758,6 @@ int ModApiMainMenu::l_get_texturepath_share(lua_State *L)
}
/******************************************************************************/
-int ModApiMainMenu::l_get_dirlist(lua_State *L)
-{
- const char *path = luaL_checkstring(L, 1);
- bool dironly = lua_toboolean(L, 2);
-
- std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
-
- unsigned int index = 1;
- lua_newtable(L);
- int table = lua_gettop(L);
-
- for (unsigned int i=0;i< dirlist.size(); i++) {
- if ((dirlist[i].dir) || (dironly == false)) {
- lua_pushnumber(L,index);
- lua_pushstring(L,dirlist[i].name.c_str());
- lua_settable(L, table);
- index++;
- }
- }
-
- return 1;
-}
-
-/******************************************************************************/
int ModApiMainMenu::l_create_dir(lua_State *L) {
const char *path = luaL_checkstring(L, 1);
@@ -843,7 +819,7 @@ int ModApiMainMenu::l_copy_dir(lua_State *L)
int ModApiMainMenu::l_extract_zip(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine);
const char *zipfile = luaL_checkstring(L, 1);
const char *destination = luaL_checkstring(L, 2);
@@ -860,7 +836,7 @@ int ModApiMainMenu::l_extract_zip(lua_State *L)
return 1;
}
- assert(fs->getFileArchiveCount() > 0);
+ sanity_check(fs->getFileArchiveCount() > 0);
/**********************************************************************/
/* WARNING this is not threadsafe!! */
@@ -931,7 +907,7 @@ int ModApiMainMenu::l_extract_zip(lua_State *L)
int ModApiMainMenu::l_get_mainmenu_path(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
lua_pushstring(L,engine->getScriptDir().c_str());
return 1;
@@ -963,7 +939,7 @@ bool ModApiMainMenu::isMinetestPath(std::string path)
int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
{
GUIEngine* engine = getGuiEngine(L);
- assert(engine != 0);
+ sanity_check(engine != NULL);
const char *formname= luaL_checkstring(L, 1);
const char *title = luaL_checkstring(L, 2);
@@ -983,7 +959,7 @@ int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
/******************************************************************************/
int ModApiMainMenu::l_get_version(lua_State *L)
{
- lua_pushstring(L, minetest_version_simple);
+ lua_pushstring(L, g_version_string);
return 1;
}
@@ -1060,10 +1036,32 @@ int ModApiMainMenu::l_get_video_drivers(lua_State *L)
}
/******************************************************************************/
+int ModApiMainMenu::l_get_video_modes(lua_State *L)
+{
+ std::vector<core::vector3d<u32> > videomodes
+ = porting::getSupportedVideoModes();
+
+ lua_newtable(L);
+ for (u32 i = 0; i != videomodes.size(); i++) {
+ lua_newtable(L);
+ lua_pushnumber(L, videomodes[i].X);
+ lua_setfield(L, -2, "w");
+ lua_pushnumber(L, videomodes[i].Y);
+ lua_setfield(L, -2, "h");
+ lua_pushnumber(L, videomodes[i].Z);
+ lua_setfield(L, -2, "depth");
+
+ lua_rawseti(L, -2, i + 1);
+ }
+
+ return 1;
+}
+
+/******************************************************************************/
int ModApiMainMenu::l_gettext(lua_State *L)
{
std::wstring wtext = wstrgettext((std::string) luaL_checkstring(L, 1));
- lua_pushstring(L, wide_to_narrow(wtext).c_str());
+ lua_pushstring(L, wide_to_utf8(wtext).c_str());
return 1;
}
@@ -1118,8 +1116,8 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L)
const char* serialized_param_raw = luaL_checklstring(L, 2, &param_length);
- assert(serialized_func_raw != NULL);
- assert(serialized_param_raw != NULL);
+ sanity_check(serialized_func_raw != NULL);
+ sanity_check(serialized_param_raw != NULL);
std::string serialized_func = std::string(serialized_func_raw, func_length);
std::string serialized_param = std::string(serialized_param_raw, param_length);
@@ -1152,7 +1150,6 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(get_gamepath);
API_FCT(get_texturepath);
API_FCT(get_texturepath_share);
- API_FCT(get_dirlist);
API_FCT(create_dir);
API_FCT(delete_dir);
API_FCT(copy_dir);
@@ -1167,6 +1164,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(sound_stop);
API_FCT(gettext);
API_FCT(get_video_drivers);
+ API_FCT(get_video_modes);
API_FCT(get_screen_info);
API_FCT(get_min_supp_proto);
API_FCT(get_max_supp_proto);
@@ -1185,7 +1183,6 @@ void ModApiMainMenu::InitializeAsync(AsyncEngine& engine)
ASYNC_API_FCT(get_gamepath);
ASYNC_API_FCT(get_texturepath);
ASYNC_API_FCT(get_texturepath_share);
- ASYNC_API_FCT(get_dirlist);
ASYNC_API_FCT(create_dir);
ASYNC_API_FCT(delete_dir);
ASYNC_API_FCT(copy_dir);
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index 8b21a93aa..9c1fed272 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -137,6 +137,8 @@ private:
static int l_get_video_drivers(lua_State *L);
+ static int l_get_video_modes(lua_State *L);
+
//version compatibility
static int l_get_min_supp_proto(lua_State *L);
diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp
index d470cef88..d30b68054 100644
--- a/src/script/lua_api/l_mapgen.cpp
+++ b/src/script/lua_api/l_mapgen.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_vmanip.h"
#include "common/c_converter.h"
#include "common/c_content.h"
+#include "cpp_api/s_security.h"
#include "util/serialize.h"
#include "server.h"
#include "environment.h"
@@ -32,18 +33,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mg_schematic.h"
#include "mapgen_v5.h"
#include "mapgen_v7.h"
+#include "filesys.h"
#include "settings.h"
-#include "main.h"
#include "log.h"
-
struct EnumString ModApiMapgen::es_BiomeTerrainType[] =
{
- {BIOME_TYPE_NORMAL, "normal"},
- {BIOME_TYPE_LIQUID, "liquid"},
- {BIOME_TYPE_NETHER, "nether"},
- {BIOME_TYPE_AETHER, "aether"},
- {BIOME_TYPE_FLAT, "flat"},
+ {BIOME_NORMAL, "normal"},
+ {BIOME_LIQUID, "liquid"},
+ {BIOME_NETHER, "nether"},
+ {BIOME_AETHER, "aether"},
+ {BIOME_FLAT, "flat"},
{0, NULL},
};
@@ -68,10 +68,10 @@ struct EnumString ModApiMapgen::es_MapgenObject[] =
struct EnumString ModApiMapgen::es_OreType[] =
{
- {ORE_TYPE_SCATTER, "scatter"},
- {ORE_TYPE_SHEET, "sheet"},
- {ORE_TYPE_BLOB, "blob"},
- {ORE_TYPE_VEIN, "vein"},
+ {ORE_SCATTER, "scatter"},
+ {ORE_SHEET, "sheet"},
+ {ORE_BLOB, "blob"},
+ {ORE_VEIN, "vein"},
{0, NULL},
};
@@ -85,116 +85,238 @@ struct EnumString ModApiMapgen::es_Rotation[] =
{0, NULL},
};
+struct EnumString ModApiMapgen::es_SchematicFormatType[] =
+{
+ {SCHEM_FMT_HANDLE, "handle"},
+ {SCHEM_FMT_MTS, "mts"},
+ {SCHEM_FMT_LUA, "lua"},
+ {0, NULL},
+};
+
+ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr);
+
+Biome *get_or_load_biome(lua_State *L, int index,
+ BiomeManager *biomemgr);
+Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef);
+size_t get_biome_list(lua_State *L, int index,
+ BiomeManager *biomemgr, std::set<u8> *biome_id_list);
+
+Schematic *get_or_load_schematic(lua_State *L, int index,
+ SchematicManager *schemmgr, StringMap *replace_names);
+Schematic *load_schematic(lua_State *L, int index, INodeDefManager *ndef,
+ StringMap *replace_names);
+Schematic *load_schematic_from_def(lua_State *L, int index,
+ INodeDefManager *ndef, StringMap *replace_names);
+bool read_schematic_def(lua_State *L, int index,
+ Schematic *schem, std::vector<std::string> *names);
+
+bool read_deco_simple(lua_State *L, DecoSimple *deco);
+bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco);
+
///////////////////////////////////////////////////////////////////////////////
+ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
-bool read_schematic(lua_State *L, int index, Schematic *schem,
- INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
+ // If a number, assume this is a handle to an object def
+ if (lua_isnumber(L, index))
+ return objmgr->get(lua_tointeger(L, index));
+
+ // If a string, assume a name is given instead
+ if (lua_isstring(L, index))
+ return objmgr->getByName(lua_tostring(L, index));
+
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+Schematic *get_or_load_schematic(lua_State *L, int index,
+ SchematicManager *schemmgr, StringMap *replace_names)
{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ Schematic *schem = (Schematic *)get_objdef(L, index, schemmgr);
+ if (schem)
+ return schem;
+
+ schem = load_schematic(L, index, schemmgr->getNodeDef(),
+ replace_names);
+ if (!schem)
+ return NULL;
+
+ if (schemmgr->add(schem) == OBJDEF_INVALID_HANDLE) {
+ delete schem;
+ return NULL;
+ }
+
+ return schem;
+}
+
+
+Schematic *load_schematic(lua_State *L, int index, INodeDefManager *ndef,
+ StringMap *replace_names)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ Schematic *schem = NULL;
+
+ if (lua_istable(L, index)) {
+ schem = load_schematic_from_def(L, index, ndef,
+ replace_names);
+ if (!schem) {
+ delete schem;
+ return NULL;
+ }
+ } else if (lua_isnumber(L, index)) {
+ return NULL;
+ } else if (lua_isstring(L, index)) {
+ schem = SchematicManager::create(SCHEMATIC_NORMAL);
+
+ std::string filepath = lua_tostring(L, index);
+ if (!fs::IsPathAbsolute(filepath))
+ filepath = ModApiBase::getCurrentModPath(L) + DIR_DELIM + filepath;
+
+ if (!schem->loadSchematicFromFile(filepath, ndef,
+ replace_names)) {
+ delete schem;
+ return NULL;
+ }
+ }
+
+ return schem;
+}
+
+
+Schematic *load_schematic_from_def(lua_State *L, int index,
+ INodeDefManager *ndef, StringMap *replace_names)
+{
+ Schematic *schem = SchematicManager::create(SCHEMATIC_NORMAL);
+
+ if (!read_schematic_def(L, index, schem, &schem->m_nodenames)) {
+ delete schem;
+ return NULL;
+ }
+
+ size_t num_nodes = schem->m_nodenames.size();
+
+ schem->m_nnlistsizes.push_back(num_nodes);
+
+ if (replace_names) {
+ for (size_t i = 0; i != num_nodes; i++) {
+ StringMap::iterator it = replace_names->find(schem->m_nodenames[i]);
+ if (it != replace_names->end())
+ schem->m_nodenames[i] = it->second;
+ }
+ }
+
+ if (ndef)
+ ndef->pendNodeResolve(schem);
+
+ return schem;
+}
+
+
+bool read_schematic_def(lua_State *L, int index,
+ Schematic *schem, std::vector<std::string> *names)
+{
+ if (!lua_istable(L, index))
+ return false;
+
//// Get schematic size
lua_getfield(L, index, "size");
- v3s16 size = read_v3s16(L, -1);
+ v3s16 size = check_v3s16(L, -1);
lua_pop(L, 1);
+ schem->size = size;
+
//// Get schematic data
lua_getfield(L, index, "data");
luaL_checktype(L, -1, LUA_TTABLE);
- int numnodes = size.X * size.Y * size.Z;
- MapNode *schemdata = new MapNode[numnodes];
- int i = 0;
+ u32 numnodes = size.X * size.Y * size.Z;
+ schem->schemdata = new MapNode[numnodes];
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (i >= numnodes) {
- i++;
- lua_pop(L, 1);
+ size_t names_base = names->size();
+ std::map<std::string, content_t> name_id_map;
+
+ u32 i = 0;
+ for (lua_pushnil(L); lua_next(L, -2); i++, lua_pop(L, 1)) {
+ if (i >= numnodes)
continue;
- }
- // same as readnode, except param1 default is MTSCHEM_PROB_CONST
- lua_getfield(L, -1, "name");
- std::string name = luaL_checkstring(L, -1);
- lua_pop(L, 1);
+ //// Read name
+ std::string name;
+ if (!getstringfield(L, -1, "name", name))
+ throw LuaError("Schematic data definition with missing name field");
+ //// Read param1/prob
u8 param1;
- lua_getfield(L, -1, "param1");
- param1 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : MTSCHEM_PROB_ALWAYS;
- lua_pop(L, 1);
-
- u8 param2;
- lua_getfield(L, -1, "param2");
- param2 = !lua_isnil(L, -1) ? lua_tonumber(L, -1) : 0;
- lua_pop(L, 1);
-
- std::map<std::string, std::string>::iterator it;
- it = replace_names.find(name);
- if (it != replace_names.end())
- name = it->second;
+ if (!getintfield(L, -1, "param1", param1) &&
+ !getintfield(L, -1, "prob", param1))
+ param1 = MTSCHEM_PROB_ALWAYS_OLD;
+
+ //// Read param2
+ u8 param2 = getintfield_default(L, -1, "param2", 0);
+
+ //// Find or add new nodename-to-ID mapping
+ std::map<std::string, content_t>::iterator it = name_id_map.find(name);
+ content_t name_index;
+ if (it != name_id_map.end()) {
+ name_index = it->second;
+ } else {
+ name_index = names->size() - names_base;
+ name_id_map[name] = name_index;
+ names->push_back(name);
+ }
- schemdata[i] = MapNode(ndef, name, param1, param2);
+ //// Perform probability/force_place fixup on param1
+ param1 >>= 1;
+ if (getboolfield_default(L, -1, "force_place", false))
+ param1 |= MTSCHEM_FORCE_PLACE;
- i++;
- lua_pop(L, 1);
+ //// Actually set the node in the schematic
+ schem->schemdata[i] = MapNode(name_index, param1, param2);
}
if (i != numnodes) {
- errorstream << "read_schematic: incorrect number of "
+ errorstream << "read_schematic_def: incorrect number of "
"nodes provided in raw schematic data (got " << i <<
", expected " << numnodes << ")." << std::endl;
- delete schemdata;
return false;
}
//// Get Y-slice probability values (if present)
- u8 *slice_probs = new u8[size.Y];
- for (i = 0; i != size.Y; i++)
- slice_probs[i] = MTSCHEM_PROB_ALWAYS;
+ schem->slice_probs = new u8[size.Y];
+ for (i = 0; i != (u32) size.Y; i++)
+ schem->slice_probs[i] = MTSCHEM_PROB_ALWAYS;
lua_getfield(L, index, "yslice_prob");
if (lua_istable(L, -1)) {
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (getintfield(L, -1, "ypos", i) && i >= 0 && i < size.Y) {
- slice_probs[i] = getintfield_default(L, -1,
- "prob", MTSCHEM_PROB_ALWAYS);
- }
- lua_pop(L, 1);
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
+ u16 ypos;
+ if (!getintfield(L, -1, "ypos", ypos) || (ypos >= size.Y) ||
+ !getintfield(L, -1, "prob", schem->slice_probs[ypos]))
+ continue;
+
+ schem->slice_probs[ypos] >>= 1;
}
}
- // Here, we read the nodes directly from the INodeDefManager - there is no
- // need for pending node resolutions so we'll mark this schematic as updated
- schem->flags = SCHEM_CIDS_UPDATED;
-
- schem->size = size;
- schem->schemdata = schemdata;
- schem->slice_probs = slice_probs;
return true;
}
-bool get_schematic(lua_State *L, int index, Schematic *schem,
- INodeDefManager *ndef, std::map<std::string, std::string> &replace_names)
+void read_schematic_replacements(lua_State *L, int index, StringMap *replace_names)
{
if (index < 0)
index = lua_gettop(L) + 1 + index;
- if (lua_istable(L, index)) {
- return read_schematic(L, index, schem, ndef, replace_names);
- } else if (lua_isstring(L, index)) {
- const char *filename = lua_tostring(L, index);
- return schem->loadSchematicFromFile(filename, ndef, replace_names);
- } else {
- return false;
- }
-}
-
-
-void read_schematic_replacements(lua_State *L,
- std::map<std::string, std::string> &replace_names, int index)
-{
lua_pushnil(L);
while (lua_next(L, index)) {
std::string replace_from;
@@ -213,11 +335,119 @@ void read_schematic_replacements(lua_State *L,
replace_to = lua_tostring(L, -1);
}
- replace_names[replace_from] = replace_to;
+ replace_names->insert(std::make_pair(replace_from, replace_to));
lua_pop(L, 1);
}
}
+///////////////////////////////////////////////////////////////////////////////
+
+Biome *get_or_load_biome(lua_State *L, int index, BiomeManager *biomemgr)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ Biome *biome = (Biome *)get_objdef(L, index, biomemgr);
+ if (biome)
+ return biome;
+
+ biome = read_biome_def(L, index, biomemgr->getNodeDef());
+ if (!biome)
+ return NULL;
+
+ if (biomemgr->add(biome) == OBJDEF_INVALID_HANDLE) {
+ delete biome;
+ return NULL;
+ }
+
+ return biome;
+}
+
+
+Biome *read_biome_def(lua_State *L, int index, INodeDefManager *ndef)
+{
+ if (!lua_istable(L, index))
+ return NULL;
+
+ BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
+ ModApiMapgen::es_BiomeTerrainType, BIOME_NORMAL);
+ Biome *b = BiomeManager::create(biometype);
+
+ b->name = getstringfield_default(L, index, "name", "");
+ b->depth_top = getintfield_default(L, index, "depth_top", 0);
+ b->depth_filler = getintfield_default(L, index, "depth_filler", -31000);
+ b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0);
+ b->y_min = getintfield_default(L, index, "y_min", -31000);
+ b->y_max = getintfield_default(L, index, "y_max", 31000);
+ b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f);
+ b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f);
+ b->flags = 0; //reserved
+
+ std::vector<std::string> &nn = b->m_nodenames;
+ nn.push_back(getstringfield_default(L, index, "node_top", ""));
+ nn.push_back(getstringfield_default(L, index, "node_filler", ""));
+ nn.push_back(getstringfield_default(L, index, "node_stone", ""));
+ nn.push_back(getstringfield_default(L, index, "node_water_top", ""));
+ nn.push_back(getstringfield_default(L, index, "node_water", ""));
+ nn.push_back(getstringfield_default(L, index, "node_river_water", ""));
+ nn.push_back(getstringfield_default(L, index, "node_dust", ""));
+ ndef->pendNodeResolve(b);
+
+ return b;
+}
+
+
+size_t get_biome_list(lua_State *L, int index,
+ BiomeManager *biomemgr, std::set<u8> *biome_id_list)
+{
+ if (index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ if (lua_isnil(L, index))
+ return 0;
+
+ bool is_single = true;
+ if (lua_istable(L, index)) {
+ lua_getfield(L, index, "name");
+ is_single = !lua_isnil(L, -1);
+ lua_pop(L, 1);
+ }
+
+ if (is_single) {
+ Biome *biome = get_or_load_biome(L, index, biomemgr);
+ if (!biome) {
+ errorstream << "get_biome_list: failed to get biome '"
+ << (lua_isstring(L, index) ? lua_tostring(L, index) : "")
+ << "'." << std::endl;
+ return 1;
+ }
+
+ biome_id_list->insert(biome->index);
+ return 0;
+ }
+
+ // returns number of failed resolutions
+ size_t fail_count = 0;
+ size_t count = 0;
+
+ for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1)) {
+ count++;
+ Biome *biome = get_or_load_biome(L, -1, biomemgr);
+ if (!biome) {
+ fail_count++;
+ errorstream << "get_biome_list: failed to get biome '"
+ << (lua_isstring(L, -1) ? lua_tostring(L, -1) : "")
+ << "'" << std::endl;
+ continue;
+ }
+
+ biome_id_list->insert(biome->index);
+ }
+
+ return fail_count;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// get_mapgen_object(objectname)
// returns the requested object used during map generation
@@ -239,92 +469,98 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L)
size_t maplen = mg->csize.X * mg->csize.Z;
switch (mgobj) {
- case MGOBJ_VMANIP: {
- MMVManip *vm = mg->vm;
+ case MGOBJ_VMANIP: {
+ MMVManip *vm = mg->vm;
- // VoxelManip object
- LuaVoxelManip *o = new LuaVoxelManip(vm, true);
- *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
- luaL_getmetatable(L, "VoxelManip");
- lua_setmetatable(L, -2);
+ // VoxelManip object
+ LuaVoxelManip *o = new LuaVoxelManip(vm, true);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, "VoxelManip");
+ lua_setmetatable(L, -2);
- // emerged min pos
- push_v3s16(L, vm->m_area.MinEdge);
+ // emerged min pos
+ push_v3s16(L, vm->m_area.MinEdge);
- // emerged max pos
- push_v3s16(L, vm->m_area.MaxEdge);
+ // emerged max pos
+ push_v3s16(L, vm->m_area.MaxEdge);
- return 3;
+ return 3;
+ }
+ case MGOBJ_HEIGHTMAP: {
+ if (!mg->heightmap)
+ return 0;
+
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushinteger(L, mg->heightmap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_HEIGHTMAP: {
- if (!mg->heightmap)
- return 0;
-
- lua_newtable(L);
- for (size_t i = 0; i != maplen; i++) {
- lua_pushinteger(L, mg->heightmap[i]);
- lua_rawseti(L, -2, i + 1);
- }
- return 1;
+ return 1;
+ }
+ case MGOBJ_BIOMEMAP: {
+ if (!mg->biomemap)
+ return 0;
+
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushinteger(L, mg->biomemap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_BIOMEMAP: {
- if (!mg->biomemap)
- return 0;
- lua_newtable(L);
- for (size_t i = 0; i != maplen; i++) {
- lua_pushinteger(L, mg->biomemap[i]);
- lua_rawseti(L, -2, i + 1);
- }
-
- return 1;
+ return 1;
+ }
+ case MGOBJ_HEATMAP: {
+ if (!mg->heatmap)
+ return 0;
+
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushnumber(L, mg->heatmap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_HEATMAP: { // Mapgen V7 specific objects
- case MGOBJ_HUMIDMAP:
- if (strcmp(emerge->params.mg_name.c_str(), "v7"))
- return 0;
-
- MapgenV7 *mgv7 = (MapgenV7 *)mg;
- float *arr = (mgobj == MGOBJ_HEATMAP) ?
- mgv7->noise_heat->result : mgv7->noise_humidity->result;
- if (!arr)
- return 0;
+ return 1;
+ }
- lua_newtable(L);
- for (size_t i = 0; i != maplen; i++) {
- lua_pushnumber(L, arr[i]);
- lua_rawseti(L, -2, i + 1);
- }
+ case MGOBJ_HUMIDMAP: {
+ if (!mg->humidmap)
+ return 0;
- return 1;
+ lua_newtable(L);
+ for (size_t i = 0; i != maplen; i++) {
+ lua_pushnumber(L, mg->humidmap[i]);
+ lua_rawseti(L, -2, i + 1);
}
- case MGOBJ_GENNOTIFY: {
- std::map<std::string, std::vector<v3s16> >event_map;
- std::map<std::string, std::vector<v3s16> >::iterator it;
- mg->gennotify.getEvents(event_map);
+ return 1;
+ }
+ case MGOBJ_GENNOTIFY: {
+ std::map<std::string, std::vector<v3s16> >event_map;
+ std::map<std::string, std::vector<v3s16> >::iterator it;
- lua_newtable(L);
- for (it = event_map.begin(); it != event_map.end(); ++it) {
- lua_newtable(L);
+ mg->gennotify.getEvents(event_map);
- for (size_t j = 0; j != it->second.size(); j++) {
- push_v3s16(L, it->second[j]);
- lua_rawseti(L, -2, j + 1);
- }
+ lua_newtable(L);
+ for (it = event_map.begin(); it != event_map.end(); ++it) {
+ lua_newtable(L);
- lua_setfield(L, -2, it->first.c_str());
+ for (size_t j = 0; j != it->second.size(); j++) {
+ push_v3s16(L, it->second[j]);
+ lua_rawseti(L, -2, j + 1);
}
- return 1;
+ lua_setfield(L, -2, it->first.c_str());
}
+
+ return 1;
+ }
}
return 0;
}
+
int ModApiMapgen::l_get_mapgen_params(lua_State *L)
{
MapgenParams *params = &getServer(L)->getEmergeManager()->params;
@@ -350,6 +586,7 @@ int ModApiMapgen::l_get_mapgen_params(lua_State *L)
return 1;
}
+
// set_mapgen_params(params)
// set mapgen parameters
int ModApiMapgen::l_set_mapgen_params(lua_State *L)
@@ -389,6 +626,7 @@ int ModApiMapgen::l_set_mapgen_params(lua_State *L)
return 0;
}
+
// set_noiseparams(name, noiseparams, set_default)
// set global config values for noise parameters
int ModApiMapgen::l_set_noiseparams(lua_State *L)
@@ -406,6 +644,21 @@ int ModApiMapgen::l_set_noiseparams(lua_State *L)
return 0;
}
+
+// get_noiseparams(name)
+int ModApiMapgen::l_get_noiseparams(lua_State *L)
+{
+ std::string name = luaL_checkstring(L, 1);
+
+ NoiseParams np;
+ if (!g_settings->getNoiseParams(name, np))
+ return 0;
+
+ push_noiseparams(L, &np);
+ return 1;
+}
+
+
// set_gen_notify(flags, {deco_id_table})
int ModApiMapgen::l_set_gen_notify(lua_State *L)
{
@@ -421,7 +674,7 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L)
lua_pushnil(L);
while (lua_next(L, 2)) {
if (lua_isnumber(L, -1))
- emerge->gen_notify_on_deco_ids.insert(lua_tonumber(L, -1));
+ emerge->gen_notify_on_deco_ids.insert((u32)lua_tonumber(L, -1));
lua_pop(L, 1);
}
}
@@ -429,6 +682,26 @@ int ModApiMapgen::l_set_gen_notify(lua_State *L)
return 0;
}
+
+// get_gen_notify()
+int ModApiMapgen::l_get_gen_notify(lua_State *L)
+{
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+ push_flags_string(L, flagdesc_gennotify, emerge->gen_notify_on,
+ emerge->gen_notify_on);
+
+ lua_newtable(L);
+ int i = 1;
+ for (std::set<u32>::iterator it = emerge->gen_notify_on_deco_ids.begin();
+ it != emerge->gen_notify_on_deco_ids.end(); ++it) {
+ lua_pushnumber(L, *it);
+ lua_rawseti(L, -2, i);
+ i++;
+ }
+ return 2;
+}
+
+
// register_biome({lots of stuff})
int ModApiMapgen::l_register_biome(lua_State *L)
{
@@ -438,66 +711,20 @@ int ModApiMapgen::l_register_biome(lua_State *L)
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
- enum BiomeType biometype = (BiomeType)getenumfield(L, index, "type",
- es_BiomeTerrainType, BIOME_TYPE_NORMAL);
- Biome *b = bmgr->create(biometype);
-
- b->name = getstringfield_default(L, index, "name", "");
- b->depth_top = getintfield_default(L, index, "depth_top", 1);
- b->depth_filler = getintfield_default(L, index, "depth_filler", 3);
- b->height_shore = getintfield_default(L, index, "height_shore", 3);
- b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0);
- b->y_min = getintfield_default(L, index, "y_min", -31000);
- b->y_max = getintfield_default(L, index, "y_max", 31000);
- b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f);
- b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f);
- b->flags = 0; //reserved
+ Biome *biome = read_biome_def(L, index, ndef);
+ if (!biome)
+ return 0;
- u32 id = bmgr->add(b);
- if (id == (u32)-1) {
- delete b;
+ ObjDefHandle handle = bmgr->add(biome);
+ if (handle == OBJDEF_INVALID_HANDLE) {
+ delete biome;
return 0;
}
- NodeResolveInfo *nri = new NodeResolveInfo(b);
- std::list<std::string> &nnames = nri->nodenames;
- nnames.push_back(getstringfield_default(L, index, "node_top", ""));
- nnames.push_back(getstringfield_default(L, index, "node_filler", ""));
- nnames.push_back(getstringfield_default(L, index, "node_shore_top", ""));
- nnames.push_back(getstringfield_default(L, index, "node_shore_filler", ""));
- nnames.push_back(getstringfield_default(L, index, "node_underwater", ""));
- nnames.push_back(getstringfield_default(L, index, "node_stone", ""));
- nnames.push_back(getstringfield_default(L, index, "node_water_top", ""));
- nnames.push_back(getstringfield_default(L, index, "node_water", ""));
- nnames.push_back(getstringfield_default(L, index, "node_dust", ""));
- ndef->pendNodeResolve(nri);
-
- verbosestream << "register_biome: " << b->name << std::endl;
-
- lua_pushinteger(L, id);
+ lua_pushinteger(L, handle);
return 1;
}
-int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
-{
- BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
- bmgr->clear();
- return 0;
-}
-
-int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
-{
- DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
- dmgr->clear();
- return 0;
-}
-
-int ModApiMapgen::l_clear_registered_ores(lua_State *L)
-{
- OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
- omgr->clear();
- return 0;
-}
// register_decoration({lots of stuff})
int ModApiMapgen::l_register_decoration(lua_State *L)
@@ -508,6 +735,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr;
BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr;
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
enum DecorationType decotype = (DecorationType)getenumfield(L, index,
"deco_type", es_DecorationType, -1);
@@ -515,7 +743,7 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
Decoration *deco = decomgr->create(decotype);
if (!deco) {
errorstream << "register_decoration: decoration placement type "
- << decotype << " not implemented";
+ << decotype << " not implemented" << std::endl;
return 0;
}
@@ -531,15 +759,11 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
return 0;
}
- NodeResolveInfo *nri = new NodeResolveInfo(deco);
-
//// Get node name(s) to place decoration on
- std::vector<const char *> place_on_names;
- getstringlistfield(L, index, "place_on", place_on_names);
- nri->nodelistinfo.push_back(NodeListInfo(place_on_names.size()));
- for (size_t i = 0; i != place_on_names.size(); i++)
- nri->nodenames.push_back(place_on_names[i]);
+ size_t nread = getstringlistfield(L, index, "place_on", &deco->m_nodenames);
+ deco->m_nnlistsizes.push_back(nread);
+ //// Get decoration flags
getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL);
//// Get NoiseParams to define how decoration is placed
@@ -549,51 +773,45 @@ int ModApiMapgen::l_register_decoration(lua_State *L)
lua_pop(L, 1);
//// Get biomes associated with this decoration (if any)
- std::vector<const char *> biome_list;
- getstringlistfield(L, index, "biomes", biome_list);
- for (size_t i = 0; i != biome_list.size(); i++) {
- Biome *b = (Biome *)biomemgr->getByName(biome_list[i]);
- if (!b)
- continue;
-
- deco->biomes.insert(b->id);
- }
+ lua_getfield(L, index, "biomes");
+ if (get_biome_list(L, -1, biomemgr, &deco->biomes))
+ errorstream << "register_decoration: couldn't get all biomes " << std::endl;
+ lua_pop(L, 1);
//// Handle decoration type-specific parameters
bool success = false;
switch (decotype) {
- case DECO_SIMPLE:
- success = regDecoSimple(L, nri, (DecoSimple *)deco);
- break;
- case DECO_SCHEMATIC:
- success = regDecoSchematic(L, ndef, (DecoSchematic *)deco);
- break;
- case DECO_LSYSTEM:
- break;
+ case DECO_SIMPLE:
+ success = read_deco_simple(L, (DecoSimple *)deco);
+ break;
+ case DECO_SCHEMATIC:
+ success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco);
+ break;
+ case DECO_LSYSTEM:
+ break;
}
- ndef->pendNodeResolve(nri);
-
if (!success) {
delete deco;
return 0;
}
- u32 id = decomgr->add(deco);
- if (id == (u32)-1) {
+ ndef->pendNodeResolve(deco);
+
+ ObjDefHandle handle = decomgr->add(deco);
+ if (handle == OBJDEF_INVALID_HANDLE) {
delete deco;
return 0;
}
- verbosestream << "register_decoration: " << deco->name << std::endl;
-
- lua_pushinteger(L, id);
+ lua_pushinteger(L, handle);
return 1;
}
-bool ModApiMapgen::regDecoSimple(lua_State *L,
- NodeResolveInfo *nri, DecoSimple *deco)
+
+bool read_deco_simple(lua_State *L, DecoSimple *deco)
{
+ size_t nnames;
int index = 1;
deco->deco_height = getintfield_default(L, index, "height", 1);
@@ -606,60 +824,48 @@ bool ModApiMapgen::regDecoSimple(lua_State *L,
return false;
}
- std::vector<const char *> deco_names;
- getstringlistfield(L, index, "decoration", deco_names);
- if (deco_names.size() == 0) {
+ nnames = getstringlistfield(L, index, "decoration", &deco->m_nodenames);
+ deco->m_nnlistsizes.push_back(nnames);
+ if (nnames == 0) {
errorstream << "register_decoration: no decoration nodes "
"defined" << std::endl;
return false;
}
- nri->nodelistinfo.push_back(NodeListInfo(deco_names.size()));
- for (size_t i = 0; i != deco_names.size(); i++)
- nri->nodenames.push_back(deco_names[i]);
- std::vector<const char *> spawnby_names;
- getstringlistfield(L, index, "spawn_by", spawnby_names);
- if (deco->nspawnby != -1 && spawnby_names.size() == 0) {
+ nnames = getstringlistfield(L, index, "spawn_by", &deco->m_nodenames);
+ deco->m_nnlistsizes.push_back(nnames);
+ if (nnames == 0 && deco->nspawnby != -1) {
errorstream << "register_decoration: no spawn_by nodes defined,"
" but num_spawn_by specified" << std::endl;
return false;
}
- nri->nodelistinfo.push_back(NodeListInfo(spawnby_names.size()));
- for (size_t i = 0; i != spawnby_names.size(); i++)
- nri->nodenames.push_back(spawnby_names[i]);
return true;
}
-bool ModApiMapgen::regDecoSchematic(lua_State *L, INodeDefManager *ndef,
- DecoSchematic *deco)
+
+bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic *deco)
{
int index = 1;
deco->rotation = (Rotation)getenumfield(L, index, "rotation",
- es_Rotation, ROTATE_0);
+ ModApiMapgen::es_Rotation, ROTATE_0);
- std::map<std::string, std::string> replace_names;
+ StringMap replace_names;
lua_getfield(L, index, "replacements");
if (lua_istable(L, -1))
- read_schematic_replacements(L, replace_names, lua_gettop(L));
+ read_schematic_replacements(L, -1, &replace_names);
lua_pop(L, 1);
- // TODO(hmmmm): get a ref from registered schematics
- Schematic *schem = new Schematic;
lua_getfield(L, index, "schematic");
- if (!get_schematic(L, -1, schem, ndef, replace_names)) {
- lua_pop(L, 1);
- delete schem;
- return false;
- }
+ Schematic *schem = get_or_load_schematic(L, -1, schemmgr, &replace_names);
lua_pop(L, 1);
deco->schematic = schem;
-
- return true;
+ return schem != NULL;
}
+
// register_ore({lots of stuff})
int ModApiMapgen::l_register_ore(lua_State *L)
{
@@ -667,10 +873,11 @@ int ModApiMapgen::l_register_ore(lua_State *L)
luaL_checktype(L, index, LUA_TTABLE);
INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr;
enum OreType oretype = (OreType)getenumfield(L, index,
- "ore_type", es_OreType, ORE_TYPE_SCATTER);
+ "ore_type", es_OreType, ORE_SCATTER);
Ore *ore = oremgr->create(oretype);
if (!ore) {
errorstream << "register_ore: ore_type " << oretype << " not implemented";
@@ -686,6 +893,7 @@ int ModApiMapgen::l_register_ore(lua_State *L)
ore->noise = NULL;
ore->flags = 0;
+ //// Get y_min/y_max
warn_if_field_exists(L, index, "height_min",
"Deprecated: new name is \"y_min\".");
warn_if_field_exists(L, index, "height_max",
@@ -708,8 +916,16 @@ int ModApiMapgen::l_register_ore(lua_State *L)
return 0;
}
+ //// Get flags
getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL);
+ //// Get biomes associated with this decoration (if any)
+ lua_getfield(L, index, "biomes");
+ if (get_biome_list(L, -1, bmgr, &ore->biomes))
+ errorstream << "register_ore: couldn't get all biomes " << std::endl;
+ lua_pop(L, 1);
+
+ //// Get noise parameters if needed
lua_getfield(L, index, "noise_params");
if (read_noiseparams(L, -1, &ore->np)) {
ore->flags |= OREFLAG_USE_NOISE;
@@ -721,45 +937,152 @@ int ModApiMapgen::l_register_ore(lua_State *L)
}
lua_pop(L, 1);
- if (oretype == ORE_TYPE_VEIN) {
+ if (oretype == ORE_VEIN) {
OreVein *orevein = (OreVein *)ore;
orevein->random_factor = getfloatfield_default(L, index,
"random_factor", 1.f);
}
- u32 id = oremgr->add(ore);
- if (id == (u32)-1) {
+ ObjDefHandle handle = oremgr->add(ore);
+ if (handle == OBJDEF_INVALID_HANDLE) {
delete ore;
return 0;
}
- NodeResolveInfo *nri = new NodeResolveInfo(ore);
- nri->nodenames.push_back(getstringfield_default(L, index, "ore", ""));
+ ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", ""));
+
+ size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames);
+ ore->m_nnlistsizes.push_back(nnames);
+
+ ndef->pendNodeResolve(ore);
+
+ lua_pushinteger(L, handle);
+ return 1;
+}
+
- std::vector<const char *> wherein_names;
- getstringlistfield(L, index, "wherein", wherein_names);
- nri->nodelistinfo.push_back(NodeListInfo(wherein_names.size()));
- for (size_t i = 0; i != wherein_names.size(); i++)
- nri->nodenames.push_back(wherein_names[i]);
+// register_schematic({schematic}, replacements={})
+int ModApiMapgen::l_register_schematic(lua_State *L)
+{
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
+
+ StringMap replace_names;
+ if (lua_istable(L, 2))
+ read_schematic_replacements(L, 2, &replace_names);
- ndef->pendNodeResolve(nri);
+ Schematic *schem = load_schematic(L, 1, schemmgr->getNodeDef(),
+ &replace_names);
+ if (!schem)
+ return 0;
- verbosestream << "register_ore: " << ore->name << std::endl;
+ ObjDefHandle handle = schemmgr->add(schem);
+ if (handle == OBJDEF_INVALID_HANDLE) {
+ delete schem;
+ return 0;
+ }
- lua_pushinteger(L, id);
+ lua_pushinteger(L, handle);
return 1;
}
-// create_schematic(p1, p2, probability_list, filename)
+
+// clear_registered_biomes()
+int ModApiMapgen::l_clear_registered_biomes(lua_State *L)
+{
+ BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr;
+ bmgr->clear();
+ return 0;
+}
+
+
+// clear_registered_decorations()
+int ModApiMapgen::l_clear_registered_decorations(lua_State *L)
+{
+ DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr;
+ dmgr->clear();
+ return 0;
+}
+
+
+// clear_registered_ores()
+int ModApiMapgen::l_clear_registered_ores(lua_State *L)
+{
+ OreManager *omgr = getServer(L)->getEmergeManager()->oremgr;
+ omgr->clear();
+ return 0;
+}
+
+
+// clear_registered_schematics()
+int ModApiMapgen::l_clear_registered_schematics(lua_State *L)
+{
+ SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr;
+ smgr->clear();
+ return 0;
+}
+
+
+// generate_ores(vm, p1, p2, [ore_id])
+int ModApiMapgen::l_generate_ores(lua_State *L)
+{
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+
+ Mapgen mg;
+ mg.seed = emerge->params.seed;
+ mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
+ mg.ndef = getServer(L)->getNodeDefManager();
+
+ v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
+ mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
+ v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
+ mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
+ sortBoxVerticies(pmin, pmax);
+
+ u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
+
+ emerge->oremgr->placeAllOres(&mg, blockseed, pmin, pmax);
+
+ return 0;
+}
+
+
+// generate_decorations(vm, p1, p2, [deco_id])
+int ModApiMapgen::l_generate_decorations(lua_State *L)
+{
+ EmergeManager *emerge = getServer(L)->getEmergeManager();
+
+ Mapgen mg;
+ mg.seed = emerge->params.seed;
+ mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
+ mg.ndef = getServer(L)->getNodeDefManager();
+
+ v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) :
+ mg.vm->m_area.MinEdge + v3s16(1,1,1) * MAP_BLOCKSIZE;
+ v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) :
+ mg.vm->m_area.MaxEdge - v3s16(1,1,1) * MAP_BLOCKSIZE;
+ sortBoxVerticies(pmin, pmax);
+
+ u32 blockseed = Mapgen::getBlockSeed(pmin, mg.seed);
+
+ emerge->decomgr->placeAllDecos(&mg, blockseed, pmin, pmax);
+
+ return 0;
+}
+
+
+// create_schematic(p1, p2, probability_list, filename, y_slice_prob_list)
int ModApiMapgen::l_create_schematic(lua_State *L)
{
- Schematic schem;
+ INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+
+ const char *filename = luaL_checkstring(L, 4);
+ CHECK_SECURE_PATH_OPTIONAL(L, filename);
Map *map = &(getEnv(L)->getMap());
- INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ Schematic schem;
- v3s16 p1 = read_v3s16(L, 1);
- v3s16 p2 = read_v3s16(L, 2);
+ v3s16 p1 = check_v3s16(L, 1);
+ v3s16 p2 = check_v3s16(L, 2);
sortBoxVerticies(p1, p2);
std::vector<std::pair<v3s16, u8> > prob_list;
@@ -768,7 +1091,7 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
while (lua_next(L, 3)) {
if (lua_istable(L, -1)) {
lua_getfield(L, -1, "pos");
- v3s16 pos = read_v3s16(L, -1);
+ v3s16 pos = check_v3s16(L, -1);
lua_pop(L, 1);
u8 prob = getintfield_default(L, -1, "prob", MTSCHEM_PROB_ALWAYS);
@@ -793,8 +1116,6 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
}
}
- const char *filename = luaL_checkstring(L, 4);
-
if (!schem.getSchematicFromMap(map, p1, p2)) {
errorstream << "create_schematic: failed to get schematic "
"from map" << std::endl;
@@ -807,60 +1128,25 @@ int ModApiMapgen::l_create_schematic(lua_State *L)
actionstream << "create_schematic: saved schematic file '"
<< filename << "'." << std::endl;
+ lua_pushboolean(L, true);
return 1;
}
-// generate_ores(vm, [ore_id])
-int ModApiMapgen::l_generate_ores(lua_State *L)
-{
- EmergeManager *emerge = getServer(L)->getEmergeManager();
-
- Mapgen mg;
- mg.seed = emerge->params.seed;
- mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
- mg.ndef = getServer(L)->getNodeDefManager();
-
- u32 blockseed = Mapgen::getBlockSeed(mg.vm->m_area.MinEdge, mg.seed);
-
- emerge->oremgr->placeAllOres(&mg, blockseed,
- mg.vm->m_area.MinEdge, mg.vm->m_area.MaxEdge);
-
- return 0;
-}
-
-// generate_decorations(vm, [deco_id])
-int ModApiMapgen::l_generate_decorations(lua_State *L)
-{
- EmergeManager *emerge = getServer(L)->getEmergeManager();
-
- Mapgen mg;
- mg.seed = emerge->params.seed;
- mg.vm = LuaVoxelManip::checkobject(L, 1)->vm;
- mg.ndef = getServer(L)->getNodeDefManager();
-
- u32 blockseed = Mapgen::getBlockSeed(mg.vm->m_area.MinEdge, mg.seed);
-
- emerge->decomgr->placeAllDecos(&mg, blockseed,
- mg.vm->m_area.MinEdge, mg.vm->m_area.MaxEdge);
-
- return 0;
-}
// place_schematic(p, schematic, rotation, replacement)
int ModApiMapgen::l_place_schematic(lua_State *L)
{
- Schematic schem;
-
Map *map = &(getEnv(L)->getMap());
- INodeDefManager *ndef = getServer(L)->getNodeDefManager();
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
//// Read position
- v3s16 p = read_v3s16(L, 1);
+ v3s16 p = check_v3s16(L, 1);
//// Read rotation
int rot = ROTATE_0;
- if (lua_isstring(L, 3))
- string_to_enum(es_Rotation, rot, std::string(lua_tostring(L, 3)));
+ const char *enumstr = lua_tostring(L, 3);
+ if (enumstr)
+ string_to_enum(es_Rotation, rot, std::string(enumstr));
//// Read force placement
bool force_placement = true;
@@ -868,21 +1154,73 @@ int ModApiMapgen::l_place_schematic(lua_State *L)
force_placement = lua_toboolean(L, 5);
//// Read node replacements
- std::map<std::string, std::string> replace_names;
+ StringMap replace_names;
if (lua_istable(L, 4))
- read_schematic_replacements(L, replace_names, 4);
+ read_schematic_replacements(L, 4, &replace_names);
//// Read schematic
- if (!get_schematic(L, 2, &schem, ndef, replace_names)) {
+ Schematic *schem = get_or_load_schematic(L, 2, schemmgr, &replace_names);
+ if (!schem) {
errorstream << "place_schematic: failed to get schematic" << std::endl;
return 0;
}
- schem.placeStructure(map, p, 0, (Rotation)rot, force_placement, ndef);
+ schem->placeStructure(map, p, 0, (Rotation)rot, force_placement);
+
+ lua_pushboolean(L, true);
+ return 1;
+}
+
+// serialize_schematic(schematic, format, options={...})
+int ModApiMapgen::l_serialize_schematic(lua_State *L)
+{
+ SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr;
+
+ //// Read options
+ bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false);
+ u32 indent_spaces = getintfield_default(L, 3, "lua_num_indent_spaces", 0);
+
+ //// Get schematic
+ bool was_loaded = false;
+ Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr);
+ if (!schem) {
+ schem = load_schematic(L, 1, NULL, NULL);
+ was_loaded = true;
+ }
+ if (!schem) {
+ errorstream << "serialize_schematic: failed to get schematic" << std::endl;
+ return 0;
+ }
+
+ //// Read format of definition to save as
+ int schem_format = SCHEM_FMT_MTS;
+ const char *enumstr = lua_tostring(L, 2);
+ if (enumstr)
+ string_to_enum(es_SchematicFormatType, schem_format, std::string(enumstr));
+
+ //// Serialize to binary string
+ std::ostringstream os(std::ios_base::binary);
+ switch (schem_format) {
+ case SCHEM_FMT_MTS:
+ schem->serializeToMts(&os, schem->m_nodenames);
+ break;
+ case SCHEM_FMT_LUA:
+ schem->serializeToLua(&os, schem->m_nodenames,
+ use_comments, indent_spaces);
+ break;
+ default:
+ return 0;
+ }
+
+ if (was_loaded)
+ delete schem;
+ std::string ser = os.str();
+ lua_pushlstring(L, ser.c_str(), ser.length());
return 1;
}
+
void ModApiMapgen::Initialize(lua_State *L, int top)
{
API_FCT(get_mapgen_object);
@@ -890,19 +1228,23 @@ void ModApiMapgen::Initialize(lua_State *L, int top)
API_FCT(get_mapgen_params);
API_FCT(set_mapgen_params);
API_FCT(set_noiseparams);
+ API_FCT(get_noiseparams);
API_FCT(set_gen_notify);
+ API_FCT(get_gen_notify);
API_FCT(register_biome);
API_FCT(register_decoration);
API_FCT(register_ore);
+ API_FCT(register_schematic);
API_FCT(clear_registered_biomes);
API_FCT(clear_registered_decorations);
API_FCT(clear_registered_ores);
+ API_FCT(clear_registered_schematics);
API_FCT(generate_ores);
API_FCT(generate_decorations);
-
API_FCT(create_schematic);
API_FCT(place_schematic);
+ API_FCT(serialize_schematic);
}
diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h
index e17d1b85a..7440d1285 100644
--- a/src/script/lua_api/l_mapgen.h
+++ b/src/script/lua_api/l_mapgen.h
@@ -22,11 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_base.h"
-class INodeDefManager;
-struct NodeResolveInfo;
-class DecoSimple;
-class DecoSchematic;
-
class ModApiMapgen : public ModApiBase {
private:
// get_mapgen_object(objectname)
@@ -44,9 +39,15 @@ private:
// set_noiseparam_defaults(name, noiseparams, set_default)
static int l_set_noiseparams(lua_State *L);
+ // get_noiseparam_defaults(name)
+ static int l_get_noiseparams(lua_State *L);
+
// set_gen_notify(flagstring)
static int l_set_gen_notify(lua_State *L);
+ // set_gen_notify(flagstring)
+ static int l_get_gen_notify(lua_State *L);
+
// register_biome({lots of stuff})
static int l_register_biome(lua_State *L);
@@ -56,16 +57,22 @@ private:
// register_ore({lots of stuff})
static int l_register_ore(lua_State *L);
+ // register_schematic({schematic}, replacements={})
+ static int l_register_schematic(lua_State *L);
+
// clear_registered_biomes()
static int l_clear_registered_biomes(lua_State *L);
// clear_registered_decorations()
static int l_clear_registered_decorations(lua_State *L);
- // generate_ores(vm)
+ // clear_registered_schematics()
+ static int l_clear_registered_schematics(lua_State *L);
+
+ // generate_ores(vm, p1, p2)
static int l_generate_ores(lua_State *L);
- // generate_decorations(vm)
+ // generate_decorations(vm, p1, p2)
static int l_generate_decorations(lua_State *L);
// clear_registered_ores
@@ -77,19 +84,19 @@ private:
// place_schematic(p, schematic, rotation, replacement)
static int l_place_schematic(lua_State *L);
- static bool regDecoSimple(lua_State *L,
- NodeResolveInfo *nri, DecoSimple *deco);
- static bool regDecoSchematic(lua_State *L,
- INodeDefManager *ndef, DecoSchematic *deco);
+ // serialize_schematic(schematic, format, options={...})
+ static int l_serialize_schematic(lua_State *L);
+
+public:
+ static void Initialize(lua_State *L, int top);
static struct EnumString es_BiomeTerrainType[];
static struct EnumString es_DecorationType[];
static struct EnumString es_MapgenObject[];
static struct EnumString es_OreType[];
static struct EnumString es_Rotation[];
-
-public:
- static void Initialize(lua_State *L, int top);
+ static struct EnumString es_SchematicFormatType[];
+ static struct EnumString es_NodeResolveMethod[];
};
#endif /* L_MAPGEN_H_ */
diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp
index 4f20e56f9..6cdbe5c68 100644
--- a/src/script/lua_api/l_nodemeta.cpp
+++ b/src/script/lua_api/l_nodemeta.cpp
@@ -63,9 +63,10 @@ void NodeMetaRef::reportMetadataChange(NodeMetaRef *ref)
ref->m_env->getMap().dispatchEvent(&event);
// Set the block to be saved
MapBlock *block = ref->m_env->getMap().getBlockNoCreateNoEx(blockpos);
- if(block)
+ if (block) {
block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "NodeMetaRef::reportMetadataChange");
+ MOD_REASON_REPORT_META_CHANGE);
+ }
}
// Exported functions
@@ -189,32 +190,34 @@ int NodeMetaRef::l_to_table(lua_State *L)
NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref, true);
- if(meta == NULL){
+ if (meta == NULL) {
lua_pushnil(L);
return 1;
}
lua_newtable(L);
+
// fields
lua_newtable(L);
{
- std::map<std::string, std::string> fields = meta->getStrings();
- for(std::map<std::string, std::string>::const_iterator
- i = fields.begin(); i != fields.end(); i++){
- const std::string &name = i->first;
- const std::string &value = i->second;
+ StringMap fields = meta->getStrings();
+ for (StringMap::const_iterator
+ it = fields.begin(); it != fields.end(); ++it) {
+ const std::string &name = it->first;
+ const std::string &value = it->second;
lua_pushlstring(L, name.c_str(), name.size());
lua_pushlstring(L, value.c_str(), value.size());
lua_settable(L, -3);
}
}
lua_setfield(L, -2, "fields");
+
// 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++){
+ 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());
}
diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp
index 5a82b6485..c8dc2d2dc 100644
--- a/src/script/lua_api/l_noise.cpp
+++ b/src/script/lua_api/l_noise.cpp
@@ -23,12 +23,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_content.h"
#include "log.h"
-// garbage collector
-int LuaPerlinNoise::gc_object(lua_State *L)
+///////////////////////////////////////
+/*
+ LuaPerlinNoise
+*/
+
+LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
+ np(*params)
+{
+}
+
+
+LuaPerlinNoise::~LuaPerlinNoise()
{
- LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
- delete o;
- return 0;
}
@@ -36,7 +43,7 @@ int LuaPerlinNoise::l_get2d(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaPerlinNoise *o = checkobject(L, 1);
- v2f p = read_v2f(L, 2);
+ v2f p = check_v2f(L, 2);
lua_Number val = NoisePerlin2D(&o->np, p.X, p.Y, 0);
lua_pushnumber(L, val);
return 1;
@@ -47,26 +54,13 @@ int LuaPerlinNoise::l_get3d(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaPerlinNoise *o = checkobject(L, 1);
- v3f p = read_v3f(L, 2);
+ v3f p = check_v3f(L, 2);
lua_Number val = NoisePerlin3D(&o->np, p.X, p.Y, p.Z, 0);
lua_pushnumber(L, val);
return 1;
}
-LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
- np(*params)
-{
-}
-
-
-LuaPerlinNoise::~LuaPerlinNoise()
-{
-}
-
-
-// LuaPerlinNoise(seed, octaves, persistence, scale)
-// Creates an LuaPerlinNoise and leaves it on top of stack
int LuaPerlinNoise::create_object(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
@@ -91,14 +85,22 @@ int LuaPerlinNoise::create_object(lua_State *L)
}
-LuaPerlinNoise* LuaPerlinNoise::checkobject(lua_State *L, int narg)
+int LuaPerlinNoise::gc_object(lua_State *L)
+{
+ LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+
+LuaPerlinNoise *LuaPerlinNoise::checkobject(lua_State *L, int narg)
{
NO_MAP_LOCK_REQUIRED;
luaL_checktype(L, narg, LUA_TUSERDATA);
void *ud = luaL_checkudata(L, narg, className);
if (!ud)
luaL_typerror(L, narg, className);
- return *(LuaPerlinNoise**)ud; // unbox pointer
+ return *(LuaPerlinNoise **)ud;
}
@@ -111,7 +113,7 @@ void LuaPerlinNoise::Register(lua_State *L)
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+ lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
@@ -121,12 +123,11 @@ void LuaPerlinNoise::Register(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
- lua_pop(L, 1); // drop metatable
+ lua_pop(L, 1);
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
- // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
lua_register(L, className, create_object);
}
@@ -138,16 +139,26 @@ const luaL_reg LuaPerlinNoise::methods[] = {
{0,0}
};
-
+///////////////////////////////////////
/*
- PerlinNoiseMap
- */
+ LuaPerlinNoiseMap
+*/
-int LuaPerlinNoiseMap::gc_object(lua_State *L)
+LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, int seed, v3s16 size)
{
- LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
- delete o;
- return 0;
+ m_is3d = size.Z > 1;
+ np = *params;
+ try {
+ noise = new Noise(&np, seed, size.X, size.Y, size.Z);
+ } catch (InvalidNoiseParamsException &e) {
+ throw LuaError(e.what());
+ }
+}
+
+
+LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
+{
+ delete noise;
}
@@ -157,15 +168,15 @@ int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
size_t i = 0;
LuaPerlinNoiseMap *o = checkobject(L, 1);
- v2f p = read_v2f(L, 2);
+ v2f p = check_v2f(L, 2);
Noise *n = o->noise;
n->perlinMap2D(p.X, p.Y);
lua_newtable(L);
- for (int y = 0; y != n->sy; y++) {
+ for (u32 y = 0; y != n->sy; y++) {
lua_newtable(L);
- for (int x = 0; x != n->sx; x++) {
+ for (u32 x = 0; x != n->sx; x++) {
lua_pushnumber(L, n->result[i++]);
lua_rawseti(L, -2, x + 1);
}
@@ -180,14 +191,19 @@ int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaPerlinNoiseMap *o = checkobject(L, 1);
- v2f p = read_v2f(L, 2);
+ v2f p = check_v2f(L, 2);
+ bool use_buffer = lua_istable(L, 3);
Noise *n = o->noise;
n->perlinMap2D(p.X, p.Y);
size_t maplen = n->sx * n->sy;
- lua_newtable(L);
+ if (use_buffer)
+ lua_pushvalue(L, 3);
+ else
+ lua_newtable(L);
+
for (size_t i = 0; i != maplen; i++) {
lua_pushnumber(L, n->result[i]);
lua_rawseti(L, -2, i + 1);
@@ -202,7 +218,7 @@ int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
size_t i = 0;
LuaPerlinNoiseMap *o = checkobject(L, 1);
- v3f p = read_v3f(L, 2);
+ v3f p = check_v3f(L, 2);
if (!o->m_is3d)
return 0;
@@ -211,11 +227,11 @@ int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
n->perlinMap3D(p.X, p.Y, p.Z);
lua_newtable(L);
- for (int z = 0; z != n->sz; z++) {
+ for (u32 z = 0; z != n->sz; z++) {
lua_newtable(L);
- for (int y = 0; y != n->sy; y++) {
+ for (u32 y = 0; y != n->sy; y++) {
lua_newtable(L);
- for (int x = 0; x != n->sx; x++) {
+ for (u32 x = 0; x != n->sx; x++) {
lua_pushnumber(L, n->result[i++]);
lua_rawseti(L, -2, x + 1);
}
@@ -232,7 +248,8 @@ int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaPerlinNoiseMap *o = checkobject(L, 1);
- v3f p = read_v3f(L, 2);
+ v3f p = check_v3f(L, 2);
+ bool use_buffer = lua_istable(L, 3);
if (!o->m_is3d)
return 0;
@@ -242,7 +259,11 @@ int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
size_t maplen = n->sx * n->sy * n->sz;
- lua_newtable(L);
+ if (use_buffer)
+ lua_pushvalue(L, 3);
+ else
+ lua_newtable(L);
+
for (size_t i = 0; i != maplen; i++) {
lua_pushnumber(L, n->result[i]);
lua_rawseti(L, -2, i + 1);
@@ -251,26 +272,61 @@ int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
}
-LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, int seed, v3s16 size)
+int LuaPerlinNoiseMap::l_calc2dMap(lua_State *L)
{
- m_is3d = size.Z > 1;
- np = *params;
- try {
- noise = new Noise(&np, seed, size.X, size.Y, size.Z);
- } catch (InvalidNoiseParamsException &e) {
- throw LuaError(e.what());
- }
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaPerlinNoiseMap *o = checkobject(L, 1);
+ v2f p = check_v2f(L, 2);
+
+ Noise *n = o->noise;
+ n->perlinMap2D(p.X, p.Y);
+
+ return 0;
}
+int LuaPerlinNoiseMap::l_calc3dMap(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
-LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
+ LuaPerlinNoiseMap *o = checkobject(L, 1);
+ v3f p = check_v3f(L, 2);
+
+ if (!o->m_is3d)
+ return 0;
+
+ Noise *n = o->noise;
+ n->perlinMap3D(p.X, p.Y, p.Z);
+
+ return 0;
+}
+
+
+int LuaPerlinNoiseMap::l_getMapSlice(lua_State *L)
{
- delete noise;
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaPerlinNoiseMap *o = checkobject(L, 1);
+ v3s16 slice_offset = read_v3s16(L, 2);
+ v3s16 slice_size = read_v3s16(L, 3);
+ bool use_buffer = lua_istable(L, 4);
+
+ Noise *n = o->noise;
+
+ if (use_buffer)
+ lua_pushvalue(L, 3);
+ else
+ lua_newtable(L);
+
+ write_array_slice_float(L, lua_gettop(L), n->result,
+ v3u16(n->sx, n->sy, n->sz),
+ v3u16(slice_offset.X, slice_offset.Y, slice_offset.Z),
+ v3u16(slice_size.X, slice_size.Y, slice_size.Z));
+
+ return 1;
}
-// LuaPerlinNoiseMap(np, size)
-// Creates an LuaPerlinNoiseMap and leaves it on top of stack
int LuaPerlinNoiseMap::create_object(lua_State *L)
{
NoiseParams np;
@@ -286,6 +342,14 @@ int LuaPerlinNoiseMap::create_object(lua_State *L)
}
+int LuaPerlinNoiseMap::gc_object(lua_State *L)
+{
+ LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+
LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
@@ -294,7 +358,7 @@ LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
if (!ud)
luaL_typerror(L, narg, className);
- return *(LuaPerlinNoiseMap **)ud; // unbox pointer
+ return *(LuaPerlinNoiseMap **)ud;
}
@@ -307,7 +371,7 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+ lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
@@ -317,12 +381,11 @@ void LuaPerlinNoiseMap::Register(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
- lua_pop(L, 1); // drop metatable
+ lua_pop(L, 1);
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
- // Can be created from Lua (PerlinNoiseMap(np, size)
lua_register(L, className, create_object);
}
@@ -331,37 +394,31 @@ const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
const luaL_reg LuaPerlinNoiseMap::methods[] = {
luamethod(LuaPerlinNoiseMap, get2dMap),
luamethod(LuaPerlinNoiseMap, get2dMap_flat),
+ luamethod(LuaPerlinNoiseMap, calc2dMap),
luamethod(LuaPerlinNoiseMap, get3dMap),
luamethod(LuaPerlinNoiseMap, get3dMap_flat),
+ luamethod(LuaPerlinNoiseMap, calc3dMap),
+ luamethod(LuaPerlinNoiseMap, getMapSlice),
{0,0}
};
+///////////////////////////////////////
/*
LuaPseudoRandom
*/
-// garbage collector
-int LuaPseudoRandom::gc_object(lua_State *L)
-{
- LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
- delete o;
- return 0;
-}
-
-
-// next(self, min=0, max=32767) -> get next value
int LuaPseudoRandom::l_next(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
LuaPseudoRandom *o = checkobject(L, 1);
int min = 0;
int max = 32767;
- lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
- if(!lua_isnil(L, 2))
+ lua_settop(L, 3);
+ if (lua_isnumber(L, 2))
min = luaL_checkinteger(L, 2);
- if(!lua_isnil(L, 3))
+ if (lua_isnumber(L, 3))
max = luaL_checkinteger(L, 3);
- if(max < min){
+ if (max < min) {
errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
throw LuaError("PseudoRandom.next(): max < min");
}
@@ -378,34 +435,107 @@ int LuaPseudoRandom::l_next(lua_State *L)
}
-LuaPseudoRandom::LuaPseudoRandom(int seed):
- m_pseudo(seed)
+int LuaPseudoRandom::create_object(lua_State *L)
{
+ int seed = luaL_checknumber(L, 1);
+ LuaPseudoRandom *o = new LuaPseudoRandom(seed);
+ *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+ luaL_getmetatable(L, className);
+ lua_setmetatable(L, -2);
+ return 1;
}
-LuaPseudoRandom::~LuaPseudoRandom()
+int LuaPseudoRandom::gc_object(lua_State *L)
{
+ LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
}
-const PseudoRandom& LuaPseudoRandom::getItem() const
+LuaPseudoRandom *LuaPseudoRandom::checkobject(lua_State *L, int narg)
{
- return m_pseudo;
+ luaL_checktype(L, narg, LUA_TUSERDATA);
+ void *ud = luaL_checkudata(L, narg, className);
+ if (!ud)
+ luaL_typerror(L, narg, className);
+ return *(LuaPseudoRandom **)ud;
}
-PseudoRandom& LuaPseudoRandom::getItem()
+
+void LuaPseudoRandom::Register(lua_State *L)
{
- return m_pseudo;
+ 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);
}
-// LuaPseudoRandom(seed)
-// Creates an LuaPseudoRandom and leaves it on top of stack
-int LuaPseudoRandom::create_object(lua_State *L)
+const char LuaPseudoRandom::className[] = "PseudoRandom";
+const luaL_reg LuaPseudoRandom::methods[] = {
+ luamethod(LuaPseudoRandom, next),
+ {0,0}
+};
+
+///////////////////////////////////////
+/*
+ LuaPcgRandom
+*/
+
+int LuaPcgRandom::l_next(lua_State *L)
{
- int seed = luaL_checknumber(L, 1);
- LuaPseudoRandom *o = new LuaPseudoRandom(seed);
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaPcgRandom *o = checkobject(L, 1);
+ u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
+ u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
+
+ lua_pushinteger(L, o->m_rnd.range(min, max));
+ return 1;
+}
+
+
+int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ LuaPcgRandom *o = checkobject(L, 1);
+ u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
+ u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
+ int num_trials = lua_isnumber(L, 4) ? lua_tointeger(L, 4) : 6;
+
+ lua_pushinteger(L, o->m_rnd.randNormalDist(min, max, num_trials));
+ return 1;
+}
+
+
+int LuaPcgRandom::create_object(lua_State *L)
+{
+ lua_Integer 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;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
@@ -413,17 +543,25 @@ int LuaPseudoRandom::create_object(lua_State *L)
}
-LuaPseudoRandom* LuaPseudoRandom::checkobject(lua_State *L, int narg)
+int LuaPcgRandom::gc_object(lua_State *L)
+{
+ LuaPcgRandom *o = *(LuaPcgRandom **)(lua_touserdata(L, 1));
+ delete o;
+ return 0;
+}
+
+
+LuaPcgRandom *LuaPcgRandom::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 *(LuaPseudoRandom**)ud; // unbox pointer
+ return *(LuaPcgRandom **)ud;
}
-void LuaPseudoRandom::Register(lua_State *L)
+void LuaPcgRandom::Register(lua_State *L)
{
lua_newtable(L);
int methodtable = lua_gettop(L);
@@ -432,7 +570,7 @@ void LuaPseudoRandom::Register(lua_State *L)
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
- lua_settable(L, metatable); // hide metatable from Lua getmetatable()
+ lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
@@ -442,18 +580,18 @@ void LuaPseudoRandom::Register(lua_State *L)
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
- lua_pop(L, 1); // drop metatable
+ lua_pop(L, 1);
- luaL_openlib(L, 0, methods, 0); // fill methodtable
- lua_pop(L, 1); // drop methodtable
+ luaL_openlib(L, 0, methods, 0);
+ lua_pop(L, 1);
- // Can be created from Lua (LuaPseudoRandom(seed))
lua_register(L, className, create_object);
}
-const char LuaPseudoRandom::className[] = "PseudoRandom";
-const luaL_reg LuaPseudoRandom::methods[] = {
- luamethod(LuaPseudoRandom, next),
+const char LuaPcgRandom::className[] = "PcgRandom";
+const luaL_reg LuaPcgRandom::methods[] = {
+ luamethod(LuaPcgRandom, next),
+ luamethod(LuaPcgRandom, rand_normal_dist),
{0,0}
};
diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h
index 3e22ac7a0..e958c5a23 100644
--- a/src/script/lua_api/l_noise.h
+++ b/src/script/lua_api/l_noise.h
@@ -64,6 +64,9 @@ class LuaPerlinNoiseMap : public ModApiBase {
static const char className[];
static const luaL_reg methods[];
+ // Exported functions
+
+ // garbage collector
static int gc_object(lua_State *L);
static int l_get2dMap(lua_State *L);
@@ -71,6 +74,10 @@ class LuaPerlinNoiseMap : public ModApiBase {
static int l_get3dMap(lua_State *L);
static int l_get3dMap_flat(lua_State *L);
+ static int l_calc2dMap(lua_State *L);
+ static int l_calc3dMap(lua_State *L);
+ static int l_getMapSlice(lua_State *L);
+
public:
LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size);
@@ -104,18 +111,51 @@ private:
static int l_next(lua_State *L);
public:
- LuaPseudoRandom(int seed);
-
- ~LuaPseudoRandom();
-
- const PseudoRandom& getItem() const;
- PseudoRandom& getItem();
+ LuaPseudoRandom(int seed) :
+ m_pseudo(seed) {}
// LuaPseudoRandom(seed)
// Creates an LuaPseudoRandom and leaves it on top of stack
static int create_object(lua_State *L);
- static LuaPseudoRandom* checkobject(lua_State *L, int narg);
+ static LuaPseudoRandom *checkobject(lua_State *L, int narg);
+
+ static void Register(lua_State *L);
+};
+
+/*
+ LuaPcgRandom
+*/
+class LuaPcgRandom : public ModApiBase {
+private:
+ PcgRandom m_rnd;
+
+ static const char className[];
+ static const luaL_reg methods[];
+
+ // Exported functions
+
+ // garbage collector
+ static int gc_object(lua_State *L);
+
+ // next(self, min=-2147483648, max=2147483647) -> get next value
+ static int l_next(lua_State *L);
+
+ // rand_normal_dist(self, min=-2147483648, max=2147483647, num_trials=6) ->
+ // get next normally distributed random value
+ static int l_rand_normal_dist(lua_State *L);
+
+public:
+ LuaPcgRandom(u64 seed) :
+ m_rnd(seed) {}
+ LuaPcgRandom(u64 seed, u64 seq) :
+ m_rnd(seed, seq) {}
+
+ // LuaPcgRandom(seed)
+ // Creates an LuaPcgRandom and leaves it on top of stack
+ static int create_object(lua_State *L);
+
+ static LuaPcgRandom *checkobject(lua_State *L, int narg);
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 4286840fe..3ac8eeefb 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -26,11 +26,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "tool.h"
#include "serverobject.h"
-#include "content_object.h"
#include "content_sao.h"
#include "server.h"
#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[] =
{
@@ -65,6 +68,7 @@ struct EnumString es_HudBuiltinElement[] =
{HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"},
{HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"},
{HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"},
+ {HUD_FLAG_MINIMAP_VISIBLE, "minimap"},
{0, NULL},
};
@@ -77,7 +81,7 @@ ObjectRef* ObjectRef::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);
+ if (!ud) luaL_typerror(L, narg, className);
return *(ObjectRef**)ud; // unbox pointer
}
@@ -90,9 +94,9 @@ ServerActiveObject* ObjectRef::getobject(ObjectRef *ref)
LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
{
ServerActiveObject *obj = getobject(ref);
- if(obj == NULL)
+ if (obj == NULL)
return NULL;
- if(obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
+ if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY)
return NULL;
return (LuaEntitySAO*)obj;
}
@@ -100,9 +104,9 @@ LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref)
PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
{
ServerActiveObject *obj = getobject(ref);
- if(obj == NULL)
+ if (obj == NULL)
return NULL;
- if(obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
+ if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER)
return NULL;
return (PlayerSAO*)obj;
}
@@ -110,7 +114,7 @@ PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref)
Player* ObjectRef::getplayer(ObjectRef *ref)
{
PlayerSAO *playersao = getplayersao(ref);
- if(playersao == NULL)
+ if (playersao == NULL)
return NULL;
return playersao->getPlayer();
}
@@ -129,9 +133,22 @@ int ObjectRef::gc_object(lua_State *L) {
int ObjectRef::l_remove(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+ GET_ENV_PTR;
+
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL)
+ return 0;
+ if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+ return 0;
+
+ std::set<int> child_ids = co->getAttachmentChildIds();
+ std::set<int>::iterator it;
+ for (it = child_ids.begin(); it != child_ids.end(); ++it) {
+ ServerActiveObject *child = env->getActiveObject(*it);
+ child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
+ }
+
verbosestream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl;
co->m_removed = true;
return 0;
@@ -144,7 +161,7 @@ int ObjectRef::l_getpos(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
v3f pos = co->getBasePosition() / BS;
lua_newtable(L);
lua_pushnumber(L, pos.X);
@@ -163,7 +180,7 @@ int ObjectRef::l_setpos(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
//LuaEntitySAO *co = getluaobject(ref);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// pos
v3f pos = checkFloatPos(L, 2);
// Do it
@@ -178,7 +195,7 @@ int ObjectRef::l_moveto(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
//LuaEntitySAO *co = getluaobject(ref);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// pos
v3f pos = checkFloatPos(L, 2);
// continuous
@@ -196,20 +213,36 @@ int ObjectRef::l_punch(lua_State *L)
ObjectRef *puncher_ref = checkobject(L, 2);
ServerActiveObject *co = getobject(ref);
ServerActiveObject *puncher = getobject(puncher_ref);
- if(co == NULL) return 0;
- if(puncher == NULL) return 0;
+ if (co == NULL) return 0;
+ if (puncher == NULL) return 0;
v3f dir;
- if(lua_type(L, 5) != LUA_TTABLE)
+ if (lua_type(L, 5) != LUA_TTABLE)
dir = co->getBasePosition() - puncher->getBasePosition();
else
dir = read_v3f(L, 5);
float time_from_last_punch = 1000000;
- if(lua_isnumber(L, 3))
+ if (lua_isnumber(L, 3))
time_from_last_punch = lua_tonumber(L, 3);
ToolCapabilities toolcap = read_tool_capabilities(L, 4);
dir.normalize();
+
+ s16 src_original_hp = co->getHP();
+ s16 dst_origin_hp = puncher->getHP();
+
// Do it
co->punch(dir, &toolcap, puncher, time_from_last_punch);
+
+ // If the punched is a player, and its HP changed
+ if (src_original_hp != co->getHP() &&
+ co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
+ }
+
+ // If the puncher is a player, and its HP changed
+ if (dst_origin_hp != puncher->getHP() &&
+ puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher);
+ }
return 0;
}
@@ -221,8 +254,8 @@ int ObjectRef::l_right_click(lua_State *L)
ObjectRef *ref2 = checkobject(L, 2);
ServerActiveObject *co = getobject(ref);
ServerActiveObject *co2 = getobject(ref2);
- if(co == NULL) return 0;
- if(co2 == NULL) return 0;
+ if (co == NULL) return 0;
+ if (co2 == NULL) return 0;
// Do it
co->rightClick(co2);
return 0;
@@ -237,12 +270,15 @@ int ObjectRef::l_set_hp(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
luaL_checknumber(L, 2);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
int hp = lua_tonumber(L, 2);
/*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
<<" hp="<<hp<<std::endl;*/
// Do it
co->setHP(hp);
+ if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+ getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
+
// Return
return 0;
}
@@ -255,7 +291,7 @@ int ObjectRef::l_get_hp(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL){
+ if (co == NULL) {
// Default hp is 1
lua_pushnumber(L, 1);
return 1;
@@ -274,10 +310,10 @@ int ObjectRef::l_get_inventory(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
InventoryLocation loc = co->getInventoryLocation();
- if(getServer(L)->getInventory(loc) != NULL)
+ if (getServer(L)->getInventory(loc) != NULL)
InvRef::create(L, loc);
else
lua_pushnil(L); // An object may have no inventory (nil)
@@ -290,7 +326,7 @@ int ObjectRef::l_get_wield_list(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
lua_pushstring(L, co->getWieldList().c_str());
return 1;
@@ -302,7 +338,7 @@ int ObjectRef::l_get_wield_index(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
lua_pushinteger(L, co->getWieldIndex() + 1);
return 1;
@@ -314,7 +350,7 @@ int ObjectRef::l_get_wielded_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL){
+ if (co == NULL) {
// Empty ItemStack
LuaItemStack::create(L, ItemStack());
return 1;
@@ -330,10 +366,13 @@ int ObjectRef::l_set_wielded_item(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
ItemStack item = read_item(L, 2, getServer(L));
bool success = co->setWieldedItem(item);
+ if (success && co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ getServer(L)->SendInventory(((PlayerSAO*)co));
+ }
lua_pushboolean(L, success);
return 1;
}
@@ -344,7 +383,7 @@ int ObjectRef::l_set_armor_groups(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
ItemGroupList groups;
read_groups(L, 2, groups);
@@ -352,13 +391,27 @@ int ObjectRef::l_set_armor_groups(lua_State *L)
return 0;
}
+// get_armor_groups(self)
+int ObjectRef::l_get_armor_groups(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if (co == NULL)
+ return 0;
+ // Do it
+ ItemGroupList groups = co->getArmorGroups();
+ push_groups(L, groups);
+ return 1;
+}
+
// set_physics_override(self, physics_override_speed, physics_override_jump,
// physics_override_gravity, sneak, sneak_glitch)
int ObjectRef::l_set_physics_override(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
PlayerSAO *co = (PlayerSAO *) getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
if (lua_istable(L, 2)) {
co->m_physics_override_speed = getfloatfield_default(L, 2, "speed", co->m_physics_override_speed);
@@ -369,15 +422,15 @@ int ObjectRef::l_set_physics_override(lua_State *L)
co->m_physics_override_sent = false;
} else {
// old, non-table format
- if(!lua_isnil(L, 2)){
+ if (!lua_isnil(L, 2)) {
co->m_physics_override_speed = lua_tonumber(L, 2);
co->m_physics_override_sent = false;
}
- if(!lua_isnil(L, 3)){
+ if (!lua_isnil(L, 3)) {
co->m_physics_override_jump = lua_tonumber(L, 3);
co->m_physics_override_sent = false;
}
- if(!lua_isnil(L, 4)){
+ if (!lua_isnil(L, 4)) {
co->m_physics_override_gravity = lua_tonumber(L, 4);
co->m_physics_override_sent = false;
}
@@ -385,27 +438,74 @@ int ObjectRef::l_set_physics_override(lua_State *L)
return 0;
}
-// set_animation(self, frame_range, frame_speed, frame_blend)
+// get_physics_override(self)
+int ObjectRef::l_get_physics_override(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO *co = (PlayerSAO *)getobject(ref);
+ if (co == NULL)
+ return 0;
+ // Do it
+ lua_newtable(L);
+ lua_pushnumber(L, co->m_physics_override_speed);
+ lua_setfield(L, -2, "speed");
+ lua_pushnumber(L, co->m_physics_override_jump);
+ lua_setfield(L, -2, "jump");
+ lua_pushnumber(L, co->m_physics_override_gravity);
+ lua_setfield(L, -2, "gravity");
+ lua_pushboolean(L, co->m_physics_override_sneak);
+ lua_setfield(L, -2, "sneak");
+ lua_pushboolean(L, co->m_physics_override_sneak_glitch);
+ lua_setfield(L, -2, "sneak_glitch");
+ return 1;
+}
+
+// set_animation(self, frame_range, frame_speed, frame_blend, frame_loop)
int ObjectRef::l_set_animation(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
v2f frames = v2f(1, 1);
- if(!lua_isnil(L, 2))
+ if (!lua_isnil(L, 2))
frames = read_v2f(L, 2);
float frame_speed = 15;
- if(!lua_isnil(L, 3))
+ if (!lua_isnil(L, 3))
frame_speed = lua_tonumber(L, 3);
float frame_blend = 0;
- if(!lua_isnil(L, 4))
+ if (!lua_isnil(L, 4))
frame_blend = lua_tonumber(L, 4);
- co->setAnimation(frames, frame_speed, frame_blend);
+ bool frame_loop = true;
+ if (lua_isboolean(L, 5))
+ frame_loop = lua_toboolean(L, 5);
+ co->setAnimation(frames, frame_speed, frame_blend, frame_loop);
return 0;
}
+// get_animation(self)
+int ObjectRef::l_get_animation(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if (co == NULL)
+ return 0;
+ // Do it
+ v2f frames = v2f(1,1);
+ float frame_speed = 15;
+ float frame_blend = 0;
+ bool frame_loop = true;
+ co->getAnimation(&frames, &frame_speed, &frame_blend, &frame_loop);
+
+ push_v2f(L, frames);
+ lua_pushnumber(L, frame_speed);
+ lua_pushnumber(L, frame_blend);
+ lua_pushboolean(L, frame_loop);
+ return 4;
+}
+
// set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed)
int ObjectRef::l_set_local_animation(lua_State *L)
{
@@ -417,11 +517,11 @@ int ObjectRef::l_set_local_animation(lua_State *L)
// Do it
v2s32 frames[4];
for (int i=0;i<4;i++) {
- if(!lua_isnil(L, 2+1))
+ if (!lua_isnil(L, 2+1))
frames[i] = read_v2s32(L, 2+i);
}
float frame_speed = 30;
- if(!lua_isnil(L, 6))
+ if (!lua_isnil(L, 6))
frame_speed = lua_tonumber(L, 6);
if (!getServer(L)->setLocalPlayerAnimations(player, frames, frame_speed))
@@ -431,6 +531,27 @@ int ObjectRef::l_set_local_animation(lua_State *L)
return 0;
}
+// get_local_animation(self)
+int ObjectRef::l_get_local_animation(lua_State *L)
+{
+ //NO_MAP_LOCK_REQUIRED
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+
+ v2s32 frames[4];
+ float frame_speed;
+ player->getLocalAnimations(frames, &frame_speed);
+
+ for (int i = 0; i < 4; i++) {
+ push_v2s32(L, frames[i]);
+ }
+
+ lua_pushnumber(L, frame_speed);
+ return 5;
+}
+
// set_eye_offset(self, v3f first pv, v3f third pv)
int ObjectRef::l_set_eye_offset(lua_State *L)
{
@@ -443,9 +564,9 @@ int ObjectRef::l_set_eye_offset(lua_State *L)
v3f offset_first = v3f(0, 0, 0);
v3f offset_third = v3f(0, 0, 0);
- if(!lua_isnil(L, 2))
+ if (!lua_isnil(L, 2))
offset_first = read_v3f(L, 2);
- if(!lua_isnil(L, 3))
+ if (!lua_isnil(L, 3))
offset_third = read_v3f(L, 3);
// Prevent abuse of offset values (keep player always visible)
@@ -461,60 +582,154 @@ int ObjectRef::l_set_eye_offset(lua_State *L)
return 0;
}
+// get_eye_offset(self)
+int ObjectRef::l_get_eye_offset(lua_State *L)
+{
+ //NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+ // Do it
+ push_v3f(L, player->eye_offset_first);
+ push_v3f(L, player->eye_offset_third);
+ return 2;
+}
+
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
int ObjectRef::l_set_bone_position(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
std::string bone = "";
- if(!lua_isnil(L, 2))
+ if (!lua_isnil(L, 2))
bone = lua_tostring(L, 2);
v3f position = v3f(0, 0, 0);
- if(!lua_isnil(L, 3))
+ if (!lua_isnil(L, 3))
position = read_v3f(L, 3);
v3f rotation = v3f(0, 0, 0);
- if(!lua_isnil(L, 4))
+ if (!lua_isnil(L, 4))
rotation = read_v3f(L, 4);
co->setBonePosition(bone, position, rotation);
return 0;
}
+// get_bone_position(self, bone)
+int ObjectRef::l_get_bone_position(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if (co == NULL)
+ return 0;
+ // Do it
+ std::string bone = "";
+ if (!lua_isnil(L, 2))
+ bone = lua_tostring(L, 2);
+
+ v3f position = v3f(0, 0, 0);
+ v3f rotation = v3f(0, 0, 0);
+ co->getBonePosition(bone, &position, &rotation);
+
+ push_v3f(L, position);
+ push_v3f(L, rotation);
+ return 2;
+}
+
// 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);
ObjectRef *parent_ref = checkobject(L, 2);
ServerActiveObject *co = getobject(ref);
ServerActiveObject *parent = getobject(parent_ref);
- if(co == NULL) return 0;
- if(parent == NULL) return 0;
+ if (co == NULL)
+ return 0;
+ if (parent == NULL)
+ return 0;
// Do it
+ int parent_id = 0;
std::string bone = "";
- if(!lua_isnil(L, 3))
- bone = lua_tostring(L, 3);
v3f position = v3f(0, 0, 0);
- if(!lua_isnil(L, 4))
- position = read_v3f(L, 4);
v3f rotation = v3f(0, 0, 0);
- if(!lua_isnil(L, 5))
+ co->getAttachment(&parent_id, &bone, &position, &rotation);
+ if (parent_id) {
+ ServerActiveObject *old_parent = env->getActiveObject(parent_id);
+ old_parent->removeAttachmentChild(co->getId());
+ }
+
+ bone = "";
+ if (!lua_isnil(L, 3))
+ bone = lua_tostring(L, 3);
+ position = v3f(0, 0, 0);
+ if (!lua_isnil(L, 4))
+ position = read_v3f(L, 4);
+ rotation = v3f(0, 0, 0);
+ if (!lua_isnil(L, 5))
rotation = read_v3f(L, 5);
co->setAttachment(parent->getId(), bone, position, rotation);
+ parent->addAttachmentChild(co->getId());
return 0;
}
+// get_attach(self)
+int ObjectRef::l_get_attach(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ GET_ENV_PTR;
+
+ ObjectRef *ref = checkobject(L, 1);
+ ServerActiveObject *co = getobject(ref);
+ if (co == NULL)
+ return 0;
+
+ // Do it
+ int parent_id = 0;
+ std::string bone = "";
+ v3f position = v3f(0, 0, 0);
+ v3f rotation = v3f(0, 0, 0);
+ co->getAttachment(&parent_id, &bone, &position, &rotation);
+ if (!parent_id)
+ return 0;
+ ServerActiveObject *parent = env->getActiveObject(parent_id);
+
+ getScriptApiBase(L)->objectrefGetOrCreate(L, parent);
+ lua_pushlstring(L, bone.c_str(), bone.size());
+ push_v3f(L, position);
+ push_v3f(L, rotation);
+ return 4;
+}
+
// set_detach(self)
int ObjectRef::l_set_detach(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
+ GET_ENV_PTR;
+
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL)
+ return 0;
+
+ int parent_id = 0;
+ std::string bone = "";
+ v3f position;
+ v3f rotation;
+ co->getAttachment(&parent_id, &bone, &position, &rotation);
+ ServerActiveObject *parent = NULL;
+ if (parent_id)
+ parent = env->getActiveObject(parent_id);
+
// Do it
co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0));
+ if (parent != NULL)
+ parent->removeAttachmentChild(co->getId());
return 0;
}
@@ -524,15 +739,40 @@ int ObjectRef::l_set_properties(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
ServerActiveObject *co = getobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
ObjectProperties *prop = co->accessObjectProperties();
- if(!prop)
+ if (!prop)
return 0;
read_object_properties(L, 2, prop);
co->notifyObjectPropertiesModified();
return 0;
}
+// get_properties(self)
+int ObjectRef::l_get_properties(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;
+ push_object_properties(L, prop);
+ return 1;
+}
+
+// is_player(self)
+int ObjectRef::l_is_player(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ lua_pushboolean(L, (player != NULL));
+ return 1;
+}
+
/* LuaEntitySAO-only */
// setvelocity(self, {x=num, y=num, z=num})
@@ -541,7 +781,7 @@ int ObjectRef::l_setvelocity(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
v3f pos = checkFloatPos(L, 2);
// Do it
co->setVelocity(pos);
@@ -554,7 +794,7 @@ int ObjectRef::l_getvelocity(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
v3f v = co->getVelocity();
pushFloatPos(L, v);
@@ -567,7 +807,7 @@ int ObjectRef::l_setacceleration(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// pos
v3f pos = checkFloatPos(L, 2);
// Do it
@@ -581,7 +821,7 @@ int ObjectRef::l_getacceleration(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
v3f v = co->getAcceleration();
pushFloatPos(L, v);
@@ -594,7 +834,7 @@ int ObjectRef::l_setyaw(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
// Do it
co->setYaw(yaw);
@@ -607,7 +847,7 @@ int ObjectRef::l_getyaw(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
float yaw = co->getYaw() * core::DEGTORAD;
lua_pushnumber(L, yaw);
@@ -620,7 +860,7 @@ int ObjectRef::l_settexturemod(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
std::string mod = luaL_checkstring(L, 2);
co->setTextureMod(mod);
@@ -634,19 +874,19 @@ int ObjectRef::l_setsprite(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
v2s16 p(0,0);
- if(!lua_isnil(L, 2))
+ if (!lua_isnil(L, 2))
p = read_v2s16(L, 2);
int num_frames = 1;
- if(!lua_isnil(L, 3))
+ if (!lua_isnil(L, 3))
num_frames = lua_tonumber(L, 3);
float framelength = 0.2;
- if(!lua_isnil(L, 4))
+ if (!lua_isnil(L, 4))
framelength = lua_tonumber(L, 4);
bool select_horiz_by_yawpitch = false;
- if(!lua_isnil(L, 5))
+ if (!lua_isnil(L, 5))
select_horiz_by_yawpitch = lua_toboolean(L, 5);
co->setSprite(p, num_frames, framelength, select_horiz_by_yawpitch);
return 0;
@@ -660,7 +900,7 @@ int ObjectRef::l_get_entity_name(lua_State *L)
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
log_deprecated(L,"Deprecated call to \"get_entity_name");
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
std::string name = co->getName();
lua_pushstring(L, name.c_str());
@@ -673,7 +913,7 @@ int ObjectRef::l_get_luaentity(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
LuaEntitySAO *co = getluaobject(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
luaentity_get(L, co->getId());
return 1;
@@ -681,16 +921,6 @@ int ObjectRef::l_get_luaentity(lua_State *L)
/* Player-only */
-// is_player(self)
-int ObjectRef::l_is_player(lua_State *L)
-{
- NO_MAP_LOCK_REQUIRED;
- ObjectRef *ref = checkobject(L, 1);
- Player *player = getplayer(ref);
- lua_pushboolean(L, (player != NULL));
- return 1;
-}
-
// is_player_connected(self)
int ObjectRef::l_is_player_connected(lua_State *L)
{
@@ -707,7 +937,7 @@ int ObjectRef::l_get_player_name(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL){
+ if (player == NULL) {
lua_pushlstring(L, "", 0);
return 1;
}
@@ -716,13 +946,28 @@ int ObjectRef::l_get_player_name(lua_State *L)
return 1;
}
+// get_player_velocity(self)
+int ObjectRef::l_get_player_velocity(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL) {
+ lua_pushnil(L);
+ return 1;
+ }
+ // Do it
+ push_v3f(L, player->getSpeed() / BS);
+ return 1;
+}
+
// get_look_dir(self)
int ObjectRef::l_get_look_dir(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL) return 0;
+ if (player == NULL) return 0;
// Do it
float pitch = player->getRadPitch();
float yaw = player->getRadYaw();
@@ -737,7 +982,7 @@ int ObjectRef::l_get_look_pitch(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL) return 0;
+ if (player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadPitch());
return 1;
@@ -749,7 +994,7 @@ int ObjectRef::l_get_look_yaw(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL) return 0;
+ if (player == NULL) return 0;
// Do it
lua_pushnumber(L, player->getRadYaw());
return 1;
@@ -761,7 +1006,7 @@ int ObjectRef::l_set_look_pitch(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
float pitch = luaL_checknumber(L, 2) * core::RADTODEG;
// Do it
co->setPitch(pitch);
@@ -774,7 +1019,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
float yaw = luaL_checknumber(L, 2) * core::RADTODEG;
// Do it
co->setYaw(yaw);
@@ -787,11 +1032,15 @@ int ObjectRef::l_set_breath(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
u16 breath = luaL_checknumber(L, 2);
// Do it
co->setBreath(breath);
- co->m_breath_not_sent = true;
+
+ // If the object is a player sent the breath to client
+ if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+ getServer(L)->SendPlayerBreath(((PlayerSAO*)co)->getPeerID());
+
return 0;
}
@@ -801,7 +1050,7 @@ int ObjectRef::l_get_breath(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
- if(co == NULL) return 0;
+ if (co == NULL) return 0;
// Do it
u16 breath = co->getBreath();
lua_pushinteger (L, breath);
@@ -814,7 +1063,7 @@ int ObjectRef::l_set_inventory_formspec(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL) return 0;
+ if (player == NULL) return 0;
std::string formspec = luaL_checkstring(L, 2);
player->inventory_formspec = formspec;
@@ -829,7 +1078,7 @@ int ObjectRef::l_get_inventory_formspec(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL) return 0;
+ if (player == NULL) return 0;
std::string formspec = player->inventory_formspec;
lua_pushlstring(L, formspec.c_str(), formspec.size());
@@ -842,7 +1091,7 @@ int ObjectRef::l_get_player_control(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL){
+ if (player == NULL) {
lua_pushlstring(L, "", 0);
return 1;
}
@@ -876,7 +1125,7 @@ int ObjectRef::l_get_player_control_bits(lua_State *L)
NO_MAP_LOCK_REQUIRED;
ObjectRef *ref = checkobject(L, 1);
Player *player = getplayer(ref);
- if(player == NULL){
+ if (player == NULL) {
lua_pushlstring(L, "", 0);
return 1;
}
@@ -1136,6 +1385,8 @@ int ObjectRef::l_hud_get_flags(lua_State *L)
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");
return 1;
}
@@ -1157,6 +1408,20 @@ int ObjectRef::l_hud_set_hotbar_itemcount(lua_State *L)
return 1;
}
+// hud_get_hotbar_itemcount(self)
+int ObjectRef::l_hud_get_hotbar_itemcount(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+
+ s32 hotbar_itemcount = getServer(L)->hudGetHotbarItemcount(player);
+
+ lua_pushnumber(L, hotbar_itemcount);
+ return 1;
+}
+
// hud_set_hotbar_image(self, name)
int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
{
@@ -1171,6 +1436,19 @@ int ObjectRef::l_hud_set_hotbar_image(lua_State *L)
return 1;
}
+// hud_get_hotbar_image(self)
+int ObjectRef::l_hud_get_hotbar_image(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+
+ std::string name = getServer(L)->hudGetHotbarImage(player);
+ lua_pushlstring(L, name.c_str(), name.size());
+ return 1;
+}
+
// hud_set_hotbar_selected_image(self, name)
int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
{
@@ -1185,6 +1463,19 @@ int ObjectRef::l_hud_set_hotbar_selected_image(lua_State *L)
return 1;
}
+// hud_get_hotbar_selected_image(self)
+int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+
+ std::string name = getServer(L)->hudGetHotbarSelectedImage(player);
+ lua_pushlstring(L, name.c_str(), name.size());
+ return 1;
+}
+
// set_sky(self, bgcolor, type, list)
int ObjectRef::l_set_sky(lua_State *L)
{
@@ -1194,8 +1485,7 @@ int ObjectRef::l_set_sky(lua_State *L)
return 0;
video::SColor bgcolor(255,255,255,255);
- if (!lua_isnil(L, 2))
- bgcolor = readARGB8(L, 2);
+ read_color(L, 2, &bgcolor);
std::string type = luaL_checkstring(L, 3);
@@ -1224,6 +1514,33 @@ int ObjectRef::l_set_sky(lua_State *L)
return 1;
}
+// get_sky(self)
+int ObjectRef::l_get_sky(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+ video::SColor bgcolor(255, 255, 255, 255);
+ std::string type;
+ std::vector<std::string> params;
+
+ player->getSky(&bgcolor, &type, &params);
+ type = type == "" ? "regular" : type;
+
+ push_ARGB8(L, bgcolor);
+ lua_pushlstring(L, type.c_str(), type.size());
+ lua_newtable(L);
+ s16 i = 1;
+ for (std::vector<std::string>::iterator it = params.begin();
+ it != params.end(); ++it) {
+ lua_pushlstring(L, it->c_str(), it->size());
+ lua_rawseti(L, -2, i);
+ i++;
+ }
+ return 3;
+}
+
// override_day_night_ratio(self, brightness=0...1)
int ObjectRef::l_override_day_night_ratio(lua_State *L)
{
@@ -1234,7 +1551,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
bool do_override = false;
float ratio = 0.0f;
- if (!lua_isnil(L, 2)){
+ if (!lua_isnil(L, 2)) {
do_override = true;
ratio = luaL_checknumber(L, 2);
}
@@ -1246,6 +1563,65 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L)
return 1;
}
+// get_day_night_ratio(self)
+int ObjectRef::l_get_day_night_ratio(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ Player *player = getplayer(ref);
+ if (player == NULL)
+ return 0;
+
+ bool do_override;
+ float ratio;
+ player->getDayNightRatio(&do_override, &ratio);
+
+ if (do_override)
+ lua_pushnumber(L, ratio);
+ else
+ lua_pushnil(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)
{
@@ -1254,7 +1630,7 @@ ObjectRef::ObjectRef(ServerActiveObject *object):
ObjectRef::~ObjectRef()
{
- /*if(m_object)
+ /*if (m_object)
infostream<<"ObjectRef destructing for id="
<<m_object->getId()<<std::endl;
else
@@ -1323,12 +1699,16 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_wielded_item),
luamethod(ObjectRef, set_wielded_item),
luamethod(ObjectRef, set_armor_groups),
- luamethod(ObjectRef, set_physics_override),
+ luamethod(ObjectRef, get_armor_groups),
luamethod(ObjectRef, set_animation),
+ luamethod(ObjectRef, get_animation),
luamethod(ObjectRef, set_bone_position),
+ luamethod(ObjectRef, get_bone_position),
luamethod(ObjectRef, set_attach),
+ luamethod(ObjectRef, get_attach),
luamethod(ObjectRef, set_detach),
luamethod(ObjectRef, set_properties),
+ luamethod(ObjectRef, get_properties),
// LuaEntitySAO-only
luamethod(ObjectRef, setvelocity),
luamethod(ObjectRef, getvelocity),
@@ -1344,6 +1724,7 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, is_player),
luamethod(ObjectRef, is_player_connected),
luamethod(ObjectRef, get_player_name),
+ luamethod(ObjectRef, get_player_velocity),
luamethod(ObjectRef, get_look_dir),
luamethod(ObjectRef, get_look_pitch),
luamethod(ObjectRef, get_look_yaw),
@@ -1355,6 +1736,8 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, get_inventory_formspec),
luamethod(ObjectRef, get_player_control),
luamethod(ObjectRef, get_player_control_bits),
+ luamethod(ObjectRef, set_physics_override),
+ luamethod(ObjectRef, get_physics_override),
luamethod(ObjectRef, hud_add),
luamethod(ObjectRef, hud_remove),
luamethod(ObjectRef, hud_change),
@@ -1362,11 +1745,20 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, hud_set_flags),
luamethod(ObjectRef, hud_get_flags),
luamethod(ObjectRef, hud_set_hotbar_itemcount),
+ luamethod(ObjectRef, hud_get_hotbar_itemcount),
luamethod(ObjectRef, hud_set_hotbar_image),
+ luamethod(ObjectRef, hud_get_hotbar_image),
luamethod(ObjectRef, hud_set_hotbar_selected_image),
+ luamethod(ObjectRef, hud_get_hotbar_selected_image),
luamethod(ObjectRef, set_sky),
+ luamethod(ObjectRef, get_sky),
luamethod(ObjectRef, override_day_night_ratio),
+ luamethod(ObjectRef, get_day_night_ratio),
luamethod(ObjectRef, set_local_animation),
+ 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_object.h b/src/script/lua_api/l_object.h
index d51ca379f..a4457cc05 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -101,25 +101,46 @@ private:
// set_armor_groups(self, groups)
static int l_set_armor_groups(lua_State *L);
+ // get_armor_groups(self)
+ static int l_get_armor_groups(lua_State *L);
+
// set_physics_override(self, physics_override_speed, physics_override_jump,
// physics_override_gravity, sneak, sneak_glitch)
static int l_set_physics_override(lua_State *L);
- // set_animation(self, frame_range, frame_speed, frame_blend)
+ // get_physics_override(self)
+ static int l_get_physics_override(lua_State *L);
+
+ // set_animation(self, frame_range, frame_speed, frame_blend, frame_loop)
static int l_set_animation(lua_State *L);
+ // get_animation(self)
+ static int l_get_animation(lua_State *L);
+
// set_bone_position(self, std::string bone, v3f position, v3f rotation)
static int l_set_bone_position(lua_State *L);
+ // get_bone_position(self, bone)
+ static int l_get_bone_position(lua_State *L);
+
// set_attach(self, parent, bone, position, rotation)
static int l_set_attach(lua_State *L);
+ // get_attach(self)
+ static int l_get_attach(lua_State *L);
+
// set_detach(self)
static int l_set_detach(lua_State *L);
// set_properties(self, properties)
static int l_set_properties(lua_State *L);
+ // get_properties(self)
+ static int l_get_properties(lua_State *L);
+
+ // is_player(self)
+ static int l_is_player(lua_State *L);
+
/* LuaEntitySAO-only */
// setvelocity(self, {x=num, y=num, z=num})
@@ -156,15 +177,15 @@ private:
/* Player-only */
- // is_player(self)
- static int l_is_player(lua_State *L);
-
// is_player_connected(self)
static int l_is_player_connected(lua_State *L);
// get_player_name(self)
static int l_get_player_name(lua_State *L);
+ // get_player_velocity(self)
+ static int l_get_player_velocity(lua_State *L);
+
// get_look_dir(self)
static int l_get_look_dir(lua_State *L);
@@ -222,24 +243,51 @@ private:
// hud_set_hotbar_itemcount(self, hotbar_itemcount)
static int l_hud_set_hotbar_itemcount(lua_State *L);
+ // hud_get_hotbar_itemcount(self)
+ static int l_hud_get_hotbar_itemcount(lua_State *L);
+
// hud_set_hotbar_image(self, name)
static int l_hud_set_hotbar_image(lua_State *L);
+ // hud_get_hotbar_image(self)
+ static int l_hud_get_hotbar_image(lua_State *L);
+
// hud_set_hotbar_selected_image(self, name)
static int l_hud_set_hotbar_selected_image(lua_State *L);
+ // hud_get_hotbar_selected_image(self)
+ static int l_hud_get_hotbar_selected_image(lua_State *L);
+
// set_sky(self, type, list)
static int l_set_sky(lua_State *L);
- // override_day_night_ratio(self, type, list)
+ // get_sky(self, type, list)
+ static int l_get_sky(lua_State *L);
+
+ // override_day_night_ratio(self, type)
static int l_override_day_night_ratio(lua_State *L);
+ // get_day_night_ratio(self)
+ static int l_get_day_night_ratio(lua_State *L);
+
// set_local_animation(self, {stand/idle}, {walk}, {dig}, {walk+dig}, frame_speed)
static int l_set_local_animation(lua_State *L);
+ // get_local_animation(self)
+ static int l_get_local_animation(lua_State *L);
+
// set_eye_offset(self, v3f first pv, v3f third pv)
static int l_set_eye_offset(lua_State *L);
+ // get_eye_offset(self)
+ static int l_get_eye_offset(lua_State *L);
+
+ // set_nametag_attributes(self, attributes)
+ static int l_set_nametag_attributes(lua_State *L);
+
+ // get_nametag_attributes(self)
+ static int l_get_nametag_attributes(lua_State *L);
+
public:
ObjectRef(ServerActiveObject *object);
diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp
index 6769f5c23..2532b2b08 100644
--- a/src/script/lua_api/l_particles.cpp
+++ b/src/script/lua_api/l_particles.cpp
@@ -34,17 +34,20 @@ int ModApiParticles::l_add_particle(lua_State *L)
{
// Get parameters
v3f pos, vel, acc;
- pos= vel= acc= v3f(0, 0, 0);
+ pos = vel = acc = v3f(0, 0, 0);
+
float expirationtime, size;
- expirationtime= size= 1;
+ expirationtime = size = 1;
+
bool collisiondetection, vertical;
- collisiondetection= vertical= false;
+ collisiondetection = vertical = false;
+
std::string texture = "";
- const char *playername = "";
+ std::string playername = "";
if (lua_gettop(L) > 1) // deprecated
{
- log_deprecated(L,"Deprecated add_particle call with individual parameters instead of definition");
+ log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition");
pos = check_v3f(L, 1);
vel = check_v3f(L, 2);
acc = check_v3f(L, 3);
@@ -57,44 +60,44 @@ int ModApiParticles::l_add_particle(lua_State *L)
}
else if (lua_istable(L, 1))
{
- int table = lua_gettop(L);
- lua_pushnil(L);
- while (lua_next(L, table) != 0)
- {
- const char *key = lua_tostring(L, -2);
- if(strcmp(key,"pos")==0){
- pos=check_v3f(L, -1);
- }else if(strcmp(key,"vel")==0){
- vel=check_v3f(L, -1);
- }else if(strcmp(key,"acc")==0){
- acc=check_v3f(L, -1);
- }else if(strcmp(key,"expirationtime")==0){
- expirationtime=luaL_checknumber(L, -1);
- }else if(strcmp(key,"size")==0){
- size=luaL_checknumber(L, -1);
- }else if(strcmp(key,"collisiondetection")==0){
- collisiondetection=lua_toboolean(L, -1);
- }else if(strcmp(key,"vertical")==0){
- vertical=lua_toboolean(L, -1);
- }else if(strcmp(key,"texture")==0){
- texture=luaL_checkstring(L, -1);
- }else if(strcmp(key,"playername")==0){
- playername=luaL_checkstring(L, -1);
- }
- lua_pop(L, 1);
+ lua_getfield(L, 1, "pos");
+ pos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f();
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "vel");
+ if (lua_istable(L, -1)) {
+ vel = check_v3f(L, -1);
+ log_deprecated(L, "The use of vel is deprecated. "
+ "Use velocity instead");
}
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "velocity");
+ vel = lua_istable(L, -1) ? check_v3f(L, -1) : vel;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "acc");
+ if (lua_istable(L, -1)) {
+ acc = check_v3f(L, -1);
+ log_deprecated(L, "The use of acc is deprecated. "
+ "Use acceleration instead");
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "acceleration");
+ acc = lua_istable(L, -1) ? check_v3f(L, -1) : acc;
+ lua_pop(L, 1);
+
+ expirationtime = getfloatfield_default(L, 1, "expirationtime", 1);
+ size = getfloatfield_default(L, 1, "size", 1);
+ collisiondetection = getboolfield_default(L, 1,
+ "collisiondetection", collisiondetection);
+ vertical = getboolfield_default(L, 1, "vertical", vertical);
+ texture = getstringfield_default(L, 1, "texture", "");
+ playername = getstringfield_default(L, 1, "playername", "");
}
- if (strcmp(playername, "")==0) // spawn for all players
- {
- getServer(L)->spawnParticleAll(pos, vel, acc,
+ getServer(L)->spawnParticle(playername, pos, vel, acc,
expirationtime, size, collisiondetection, vertical, texture);
- }
- else
- {
- getServer(L)->spawnParticle(playername,
- pos, vel, acc, expirationtime,
- size, collisiondetection, vertical, texture);
- }
return 1;
}
@@ -125,7 +128,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
bool collisiondetection, vertical;
collisiondetection= vertical= false;
std::string texture = "";
- const char *playername = "";
+ std::string playername = "";
if (lua_gettop(L) > 1) //deprecated
{
@@ -149,74 +152,55 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
}
else if (lua_istable(L, 1))
{
- int table = lua_gettop(L);
- lua_pushnil(L);
- while (lua_next(L, table) != 0)
- {
- const char *key = lua_tostring(L, -2);
- if(strcmp(key,"amount")==0){
- amount=luaL_checknumber(L, -1);
- }else if(strcmp(key,"time")==0){
- time=luaL_checknumber(L, -1);
- }else if(strcmp(key,"minpos")==0){
- minpos=check_v3f(L, -1);
- }else if(strcmp(key,"maxpos")==0){
- maxpos=check_v3f(L, -1);
- }else if(strcmp(key,"minvel")==0){
- minvel=check_v3f(L, -1);
- }else if(strcmp(key,"maxvel")==0){
- maxvel=check_v3f(L, -1);
- }else if(strcmp(key,"minacc")==0){
- minacc=check_v3f(L, -1);
- }else if(strcmp(key,"maxacc")==0){
- maxacc=check_v3f(L, -1);
- }else if(strcmp(key,"minexptime")==0){
- minexptime=luaL_checknumber(L, -1);
- }else if(strcmp(key,"maxexptime")==0){
- maxexptime=luaL_checknumber(L, -1);
- }else if(strcmp(key,"minsize")==0){
- minsize=luaL_checknumber(L, -1);
- }else if(strcmp(key,"maxsize")==0){
- maxsize=luaL_checknumber(L, -1);
- }else if(strcmp(key,"collisiondetection")==0){
- collisiondetection=lua_toboolean(L, -1);
- }else if(strcmp(key,"vertical")==0){
- vertical=lua_toboolean(L, -1);
- }else if(strcmp(key,"texture")==0){
- texture=luaL_checkstring(L, -1);
- }else if(strcmp(key,"playername")==0){
- playername=luaL_checkstring(L, -1);
- }
- lua_pop(L, 1);
- }
- }
- if (strcmp(playername, "")==0) //spawn for all players
- {
- u32 id = getServer(L)->addParticleSpawnerAll( amount, time,
- minpos, maxpos,
- minvel, maxvel,
- minacc, maxacc,
- minexptime, maxexptime,
- minsize, maxsize,
- collisiondetection,
- vertical,
- texture);
- lua_pushnumber(L, id);
- }
- else
- {
- u32 id = getServer(L)->addParticleSpawner(playername,
- amount, time,
- minpos, maxpos,
- minvel, maxvel,
- minacc, maxacc,
- minexptime, maxexptime,
- minsize, maxsize,
- collisiondetection,
- vertical,
- texture);
- lua_pushnumber(L, id);
+ amount = getintfield_default(L, 1, "amount", amount);
+ time = getfloatfield_default(L, 1, "time", time);
+
+ lua_getfield(L, 1, "minpos");
+ minpos = lua_istable(L, -1) ? check_v3f(L, -1) : minpos;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "maxpos");
+ maxpos = lua_istable(L, -1) ? check_v3f(L, -1) : maxpos;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "minvel");
+ minvel = lua_istable(L, -1) ? check_v3f(L, -1) : minvel;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "maxvel");
+ maxvel = lua_istable(L, -1) ? check_v3f(L, -1) : maxvel;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "minacc");
+ minacc = lua_istable(L, -1) ? check_v3f(L, -1) : minacc;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "maxacc");
+ maxacc = lua_istable(L, -1) ? check_v3f(L, -1) : maxacc;
+ lua_pop(L, 1);
+
+ minexptime = getfloatfield_default(L, 1, "minexptime", minexptime);
+ maxexptime = getfloatfield_default(L, 1, "maxexptime", maxexptime);
+ minsize = getfloatfield_default(L, 1, "minsize", minsize);
+ maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
+ collisiondetection = getboolfield_default(L, 1,
+ "collisiondetection", collisiondetection);
+ vertical = getboolfield_default(L, 1, "vertical", vertical);
+ texture = getstringfield_default(L, 1, "texture", "");
+ playername = getstringfield_default(L, 1, "playername", "");
}
+
+ u32 id = getServer(L)->addParticleSpawner(amount, time,
+ minpos, maxpos,
+ minvel, maxvel,
+ minacc, maxacc,
+ minexptime, maxexptime,
+ minsize, maxsize,
+ collisiondetection,
+ vertical,
+ texture, playername);
+ lua_pushnumber(L, id);
+
return 1;
}
@@ -226,16 +210,12 @@ int ModApiParticles::l_delete_particlespawner(lua_State *L)
{
// Get parameters
u32 id = luaL_checknumber(L, 1);
-
- if (lua_gettop(L) == 2) // only delete for one player
- {
- const char *playername = luaL_checkstring(L, 2);
- getServer(L)->deleteParticleSpawner(playername, id);
- }
- else // delete for all players
- {
- getServer(L)->deleteParticleSpawnerAll(id);
+ std::string playername = "";
+ if (lua_gettop(L) == 2) {
+ playername = luaL_checkstring(L, 2);
}
+
+ getServer(L)->deleteParticleSpawner(playername, id);
return 1;
}
diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp
index 8d7f6512e..73eca9d60 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 "cpp_api/s_base.h"
#include "server.h"
#include "environment.h"
#include "player.h"
@@ -29,7 +30,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// request_shutdown()
int ModApiServer::l_request_shutdown(lua_State *L)
{
- getServer(L)->requestShutdown();
+ const char *msg = lua_tolstring(L, 1, NULL);
+ bool reconnect = lua_toboolean(L, 2);
+ getServer(L)->requestShutdown(msg ? msg : "", reconnect);
return 0;
}
@@ -306,7 +309,7 @@ int ModApiServer::l_kick_player(lua_State *L)
lua_pushboolean(L, false); // No such player
return 1;
}
- getServer(L)->DenyAccess(player->peer_id, narrow_to_wide(message));
+ getServer(L)->DenyAccess_Legacy(player->peer_id, utf8_to_wide(message));
lua_pushboolean(L, true);
return 1;
}
@@ -342,7 +345,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, "current_modname");
+ lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
return 1;
}
@@ -367,33 +370,18 @@ int ModApiServer::l_get_modnames(lua_State *L)
NO_MAP_LOCK_REQUIRED;
// Get a list of mods
- std::list<std::string> mods_unsorted, mods_sorted;
- getServer(L)->getModNames(mods_unsorted);
+ std::vector<std::string> modlist;
+ getServer(L)->getModNames(modlist);
// Take unsorted items from mods_unsorted and sort them into
// mods_sorted; not great performance but the number of mods on a
// server will likely be small.
- for(std::list<std::string>::iterator i = mods_unsorted.begin();
- i != mods_unsorted.end(); ++i) {
- bool added = false;
- for(std::list<std::string>::iterator x = mods_sorted.begin();
- x != mods_sorted.end(); ++x) {
- // I doubt anybody using Minetest will be using
- // anything not ASCII based :)
- if(i->compare(*x) <= 0) {
- mods_sorted.insert(x, *i);
- added = true;
- break;
- }
- }
- if(!added)
- mods_sorted.push_back(*i);
- }
+ std::sort(modlist.begin(), modlist.end());
// Package them up for Lua
- lua_createtable(L, mods_sorted.size(), 0);
- std::list<std::string>::iterator iter = mods_sorted.begin();
- for (u16 i = 0; iter != mods_sorted.end(); iter++) {
+ lua_createtable(L, modlist.size(), 0);
+ std::vector<std::string>::iterator iter = modlist.begin();
+ for (u16 i = 0; iter != modlist.end(); iter++) {
lua_pushstring(L, iter->c_str());
lua_rawseti(L, -2, ++i);
}
@@ -450,6 +438,31 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L)
return 0;
}
+// get_last_run_mod()
+int ModApiServer::l_get_last_run_mod(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ const char *current_mod = lua_tostring(L, -1);
+ if (current_mod == NULL || current_mod[0] == '\0') {
+ lua_pop(L, 1);
+ lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
+ }
+ return 1;
+}
+
+// set_last_run_mod(modname)
+int ModApiServer::l_set_last_run_mod(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+#ifdef SCRIPTAPI_DEBUG
+ const char *mod = lua_tostring(L, 1);
+ getScriptApiBase(L)->setOriginDirect(mod);
+ //printf(">>>> last mod set from Lua: %s\n", mod);
+#endif
+ return 0;
+}
+
#ifndef NDEBUG
// cause_error(type_of_error)
int ModApiServer::l_cause_error(lua_State *L)
@@ -507,6 +520,8 @@ void ModApiServer::Initialize(lua_State *L, int top)
API_FCT(unban_player_or_ip);
API_FCT(notify_authentication_modified);
+ API_FCT(get_last_run_mod);
+ API_FCT(set_last_run_mod);
#ifndef NDEBUG
API_FCT(cause_error);
#endif
diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h
index fd85a8975..df31f325f 100644
--- a/src/script/lua_api/l_server.h
+++ b/src/script/lua_api/l_server.h
@@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class ModApiServer : public ModApiBase {
private:
- // request_shutdown()
+ // request_shutdown([message], [reconnect])
static int l_request_shutdown(lua_State *L);
// get_server_status()
@@ -88,6 +88,12 @@ private:
// notify_authentication_modified(name)
static int l_notify_authentication_modified(lua_State *L);
+ // get_last_run_mod()
+ static int l_get_last_run_mod(lua_State *L);
+
+ // set_last_run_mod(modname)
+ static int l_set_last_run_mod(lua_State *L);
+
#ifndef NDEBUG
// cause_error(type_of_error)
static int l_cause_error(lua_State *L);
diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp
index 9c88a3e05..35b82b435 100644
--- a/src/script/lua_api/l_settings.cpp
+++ b/src/script/lua_api/l_settings.cpp
@@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_settings.h"
#include "lua_api/l_internal.h"
+#include "cpp_api/s_security.h"
#include "settings.h"
#include "log.h"
@@ -188,6 +189,7 @@ int LuaSettings::create_object(lua_State* L)
{
NO_MAP_LOCK_REQUIRED;
const char* filename = luaL_checkstring(L, 1);
+ CHECK_SECURE_PATH_OPTIONAL(L, filename);
LuaSettings* o = new LuaSettings(filename);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index eb6c1835d..12146e80a 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -24,13 +24,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_async.h"
#include "serialization.h"
#include "json/json.h"
+#include "cpp_api/s_security.h"
+#include "areastore.h"
#include "debug.h"
#include "porting.h"
#include "log.h"
#include "tool.h"
#include "filesys.h"
#include "settings.h"
-#include "main.h" //required for g_settings, g_settings_path
+#include "util/auth.h"
+#include <algorithm>
// debug(...)
// Writes a line to dstream
@@ -92,12 +95,19 @@ int ModApiUtil::l_log(lua_State *L)
return 0;
}
+#define CHECK_SECURE_SETTING(L, name) \
+ if (name.compare(0, 7, "secure.") == 0) {\
+ lua_pushliteral(L, "Attempt to set secure setting.");\
+ lua_error(L);\
+ }
+
// setting_set(name, value)
int ModApiUtil::l_setting_set(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- const char *name = luaL_checkstring(L, 1);
- const char *value = luaL_checkstring(L, 2);
+ std::string name = luaL_checkstring(L, 1);
+ std::string value = luaL_checkstring(L, 2);
+ CHECK_SECURE_SETTING(L, name);
g_settings->set(name, value);
return 0;
}
@@ -120,8 +130,9 @@ int ModApiUtil::l_setting_get(lua_State *L)
int ModApiUtil::l_setting_setbool(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
- const char *name = luaL_checkstring(L, 1);
+ std::string name = luaL_checkstring(L, 1);
bool value = lua_toboolean(L, 2);
+ CHECK_SECURE_SETTING(L, name);
g_settings->setBool(name, value);
return 0;
}
@@ -256,8 +267,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,
- narrow_to_wide(raw_password));
+ std::string hash = translatePassword(name, raw_password);
lua_pushstring(L, hash.c_str());
return 1;
}
@@ -308,7 +318,7 @@ int ModApiUtil::l_compress(lua_State *L)
int ModApiUtil::l_decompress(lua_State *L)
{
size_t size;
- const char * data = luaL_checklstring(L, 1, &size);
+ const char *data = luaL_checklstring(L, 1, &size);
std::istringstream is(std::string(data, size));
std::ostringstream os;
@@ -320,6 +330,64 @@ int ModApiUtil::l_decompress(lua_State *L)
return 1;
}
+// mkdir(path)
+int ModApiUtil::l_mkdir(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ const char *path = luaL_checkstring(L, 1);
+ CHECK_SECURE_PATH_OPTIONAL(L, path);
+ lua_pushboolean(L, fs::CreateAllDirs(path));
+ return 1;
+}
+
+// get_dir_list(path, is_dir)
+int ModApiUtil::l_get_dir_list(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ const char *path = luaL_checkstring(L, 1);
+ short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1;
+
+ CHECK_SECURE_PATH_OPTIONAL(L, path);
+
+ std::vector<fs::DirListNode> list = fs::GetDirListing(path);
+
+ int index = 0;
+ lua_newtable(L);
+
+ for (size_t i = 0; i < list.size(); i++) {
+ if (is_dir == -1 || is_dir == list[i].dir) {
+ lua_pushstring(L, list[i].name.c_str());
+ lua_rawseti(L, -2, ++index);
+ }
+ }
+
+ return 1;
+}
+
+int ModApiUtil::l_request_insecure_environment(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+ if (!ScriptApiSecurity::isSecure(L)) {
+ lua_getglobal(L, "_G");
+ return 1;
+ }
+ lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
+ if (!lua_isstring(L, -1)) {
+ lua_pushnil(L);
+ return 1;
+ }
+ const char *mod_name = lua_tostring(L, -1);
+ std::string trusted_mods = g_settings->get("secure.trusted_mods");
+ 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;
+ }
+ lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
+ return 1;
+}
+
+
void ModApiUtil::Initialize(lua_State *L, int top)
{
API_FCT(debug);
@@ -345,6 +413,11 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(compress);
API_FCT(decompress);
+
+ API_FCT(mkdir);
+ API_FCT(get_dir_list);
+
+ API_FCT(request_insecure_environment);
}
void ModApiUtil::InitializeAsync(AsyncEngine& engine)
@@ -367,5 +440,8 @@ void ModApiUtil::InitializeAsync(AsyncEngine& engine)
ASYNC_API_FCT(compress);
ASYNC_API_FCT(decompress);
+
+ ASYNC_API_FCT(mkdir);
+ ASYNC_API_FCT(get_dir_list);
}
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index e82432381..e75aa28cb 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -78,7 +78,7 @@ private:
// is_yes(arg)
static int l_is_yes(lua_State *L);
- // get_scriptdir()
+ // get_builtin_path()
static int l_get_builtin_path(lua_State *L);
// compress(data, method, ...)
@@ -87,6 +87,15 @@ private:
// decompress(data, method, ...)
static int l_decompress(lua_State *L);
+ // mkdir(path)
+ static int l_mkdir(lua_State *L);
+
+ // get_dir_list(path, is_dir)
+ static int l_get_dir_list(lua_State *L);
+
+ // request_insecure_environment()
+ static int l_request_insecure_environment(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
@@ -95,3 +104,4 @@ public:
};
#endif /* L_UTIL_H_ */
+
diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp
index de7612115..ac6c10303 100644
--- a/src/script/lua_api/l_vmanip.cpp
+++ b/src/script/lua_api/l_vmanip.cpp
@@ -46,8 +46,8 @@ int LuaVoxelManip::l_read_from_map(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
- v3s16 bp1 = getNodeBlockPos(read_v3s16(L, 2));
- v3s16 bp2 = getNodeBlockPos(read_v3s16(L, 3));
+ v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
+ v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
sortBoxVerticies(bp1, bp2);
vm->initialEmerge(bp1, bp2);
@@ -63,12 +63,18 @@ int LuaVoxelManip::l_get_data(lua_State *L)
NO_MAP_LOCK_REQUIRED;
LuaVoxelManip *o = checkobject(L, 1);
+ bool use_buffer = lua_istable(L, 2);
+
MMVManip *vm = o->vm;
- int volume = vm->m_area.getVolume();
+ u32 volume = vm->m_area.getVolume();
- lua_newtable(L);
- for (int i = 0; i != volume; i++) {
+ if (use_buffer)
+ lua_pushvalue(L, 2);
+ else
+ lua_newtable(L);
+
+ for (u32 i = 0; i != volume; i++) {
lua_Integer cid = vm->m_data[i].getContent();
lua_pushinteger(L, cid);
lua_rawseti(L, -2, i + 1);
@@ -87,8 +93,8 @@ int LuaVoxelManip::l_set_data(lua_State *L)
if (!lua_istable(L, 2))
return 0;
- int volume = vm->m_area.getVolume();
- for (int i = 0; i != volume; i++) {
+ u32 volume = vm->m_area.getVolume();
+ for (u32 i = 0; i != volume; i++) {
lua_rawgeti(L, 2, i + 1);
content_t c = lua_tointeger(L, -1);
@@ -116,7 +122,7 @@ int LuaVoxelManip::l_get_node_at(lua_State *L)
GET_ENV_PTR;
LuaVoxelManip *o = checkobject(L, 1);
- v3s16 pos = read_v3s16(L, 2);
+ v3s16 pos = check_v3s16(L, 2);
pushnode(L, o->vm->getNodeNoExNoEmerge(pos), env->getGameDef()->ndef());
return 1;
@@ -128,7 +134,7 @@ int LuaVoxelManip::l_set_node_at(lua_State *L)
GET_ENV_PTR;
LuaVoxelManip *o = checkobject(L, 1);
- v3s16 pos = read_v3s16(L, 2);
+ v3s16 pos = check_v3s16(L, 2);
MapNode n = readnode(L, 3, env->getGameDef()->ndef());
o->vm->setNodeNoEmerge(pos, n);
@@ -171,8 +177,8 @@ int LuaVoxelManip::l_calc_lighting(lua_State *L)
v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
v3s16 fpmin = vm->m_area.MinEdge;
v3s16 fpmax = vm->m_area.MaxEdge;
- v3s16 pmin = lua_istable(L, 2) ? read_v3s16(L, 2) : fpmin + yblock;
- v3s16 pmax = lua_istable(L, 3) ? read_v3s16(L, 3) : fpmax - yblock;
+ v3s16 pmin = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
+ v3s16 pmax = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
sortBoxVerticies(pmin, pmax);
if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
@@ -206,8 +212,8 @@ int LuaVoxelManip::l_set_lighting(lua_State *L)
MMVManip *vm = o->vm;
v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
- v3s16 pmin = lua_istable(L, 3) ? read_v3s16(L, 3) : vm->m_area.MinEdge + yblock;
- v3s16 pmax = lua_istable(L, 4) ? read_v3s16(L, 4) : vm->m_area.MaxEdge - yblock;
+ v3s16 pmin = lua_istable(L, 3) ? check_v3s16(L, 3) : vm->m_area.MinEdge + yblock;
+ v3s16 pmax = lua_istable(L, 4) ? check_v3s16(L, 4) : vm->m_area.MaxEdge - yblock;
sortBoxVerticies(pmin, pmax);
if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
@@ -228,10 +234,10 @@ int LuaVoxelManip::l_get_light_data(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
- int volume = vm->m_area.getVolume();
+ u32 volume = vm->m_area.getVolume();
lua_newtable(L);
- for (int i = 0; i != volume; i++) {
+ for (u32 i = 0; i != volume; i++) {
lua_Integer light = vm->m_data[i].param1;
lua_pushinteger(L, light);
lua_rawseti(L, -2, i + 1);
@@ -250,8 +256,8 @@ int LuaVoxelManip::l_set_light_data(lua_State *L)
if (!lua_istable(L, 2))
return 0;
- int volume = vm->m_area.getVolume();
- for (int i = 0; i != volume; i++) {
+ u32 volume = vm->m_area.getVolume();
+ for (u32 i = 0; i != volume; i++) {
lua_rawgeti(L, 2, i + 1);
u8 light = lua_tointeger(L, -1);
@@ -270,10 +276,10 @@ int LuaVoxelManip::l_get_param2_data(lua_State *L)
LuaVoxelManip *o = checkobject(L, 1);
MMVManip *vm = o->vm;
- int volume = vm->m_area.getVolume();
+ u32 volume = vm->m_area.getVolume();
lua_newtable(L);
- for (int i = 0; i != volume; i++) {
+ for (u32 i = 0; i != volume; i++) {
lua_Integer param2 = vm->m_data[i].param2;
lua_pushinteger(L, param2);
lua_rawseti(L, -2, i + 1);
@@ -292,8 +298,8 @@ int LuaVoxelManip::l_set_param2_data(lua_State *L)
if (!lua_istable(L, 2))
return 0;
- int volume = vm->m_area.getVolume();
- for (int i = 0; i != volume; i++) {
+ u32 volume = vm->m_area.getVolume();
+ for (u32 i = 0; i != volume; i++) {
lua_rawgeti(L, 2, i + 1);
u8 param2 = lua_tointeger(L, -1);
@@ -402,7 +408,7 @@ int LuaVoxelManip::create_object(lua_State *L)
Map *map = &(env->getMap());
LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
- new LuaVoxelManip(map, read_v3s16(L, 1), read_v3s16(L, 2)) :
+ new LuaVoxelManip(map, check_v3s16(L, 1), check_v3s16(L, 2)) :
new LuaVoxelManip(map);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
diff --git a/src/script/scripting_game.cpp b/src/script/scripting_game.cpp
index e716bc979..4f0350d41 100644
--- a/src/script/scripting_game.cpp
+++ b/src/script/scripting_game.cpp
@@ -20,7 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "scripting_game.h"
#include "server.h"
#include "log.h"
+#include "settings.h"
#include "cpp_api/s_internal.h"
+#include "lua_api/l_areastore.h"
#include "lua_api/l_base.h"
#include "lua_api/l_craft.h"
#include "lua_api/l_env.h"
@@ -49,10 +51,12 @@ GameScripting::GameScripting(Server* server)
// setEnv(env) is called by ScriptApiEnv::initializeEnvironment()
// once the environment has been created
- //TODO add security
-
SCRIPTAPI_PRECHECKHEADER
+ if (g_settings->getBool("secure.enable_security")) {
+ initializeSecurity();
+ }
+
lua_getglobal(L, "core");
int top = lua_gettop(L);
@@ -88,10 +92,12 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
// Register reference classes (userdata)
InvRef::Register(L);
+ LuaAreaStore::Register(L);
LuaItemStack::Register(L);
LuaPerlinNoise::Register(L);
LuaPerlinNoiseMap::Register(L);
LuaPseudoRandom::Register(L);
+ LuaPcgRandom::Register(L);
LuaVoxelManip::Register(L);
NodeMetaRef::Register(L);
NodeTimerRef::Register(L);
@@ -99,7 +105,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top)
LuaSettings::Register(L);
}
-void log_deprecated(std::string message)
+void log_deprecated(const std::string &message)
{
- log_deprecated(NULL,message);
+ log_deprecated(NULL, message);
}
diff --git a/src/script/scripting_game.h b/src/script/scripting_game.h
index 14dbd9170..970b3e80d 100644
--- a/src/script/scripting_game.h
+++ b/src/script/scripting_game.h
@@ -27,19 +27,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cpp_api/s_node.h"
#include "cpp_api/s_player.h"
#include "cpp_api/s_server.h"
+#include "cpp_api/s_security.h"
/*****************************************************************************/
/* Scripting <-> Game Interface */
/*****************************************************************************/
-class GameScripting
- : virtual public ScriptApiBase,
- public ScriptApiDetached,
- public ScriptApiEntity,
- public ScriptApiEnv,
- public ScriptApiNode,
- public ScriptApiPlayer,
- public ScriptApiServer
+class GameScripting :
+ virtual public ScriptApiBase,
+ public ScriptApiDetached,
+ public ScriptApiEntity,
+ public ScriptApiEnv,
+ public ScriptApiNode,
+ public ScriptApiPlayer,
+ public ScriptApiServer,
+ public ScriptApiSecurity
{
public:
GameScripting(Server* server);
@@ -50,6 +52,6 @@ private:
void InitializeModApi(lua_State *L, int top);
};
-void log_deprecated(std::string message);
+void log_deprecated(const std::string &message);
#endif /* SCRIPTING_GAME_H_ */
diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp
index 54b3133c5..c74c18edc 100644
--- a/src/script/scripting_mainmenu.cpp
+++ b/src/script/scripting_mainmenu.cpp
@@ -38,8 +38,6 @@ MainMenuScripting::MainMenuScripting(GUIEngine* guiengine)
{
setGuiEngine(guiengine);
- //TODO add security
-
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L, "core");