diff options
Diffstat (limited to 'src/script')
55 files changed, 1136 insertions, 697 deletions
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index accbb1a87..3dfd7ce61 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_types.h" #include "nodedef.h" #include "object_properties.h" -#include "content_sao.h" +#include "collision.h" #include "cpp_api/s_node.h" #include "lua_api/l_object.h" #include "lua_api/l_item.h" @@ -29,10 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server.h" #include "log.h" #include "tool.h" -#include "serverobject.h" #include "porting.h" #include "mapgen/mg_schematic.h" #include "noise.h" +#include "server/player_sao.h" #include "util/pointedthing.h" #include "debug.h" // For FATAL_ERROR #include <json/json.h> @@ -103,7 +103,8 @@ void read_item_definition(lua_State* L, int index, lua_pop(L, 1); lua_getfield(L, index, "sounds"); - if(lua_istable(L, -1)){ + if (!lua_isnil(L, -1)) { + luaL_checktype(L, -1, LUA_TTABLE); lua_getfield(L, -1, "place"); read_soundspec(L, -1, def.sound_place); lua_pop(L, 1); @@ -163,7 +164,7 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i) lua_setfield(L, -2, "usable"); lua_pushboolean(L, i.liquids_pointable); lua_setfield(L, -2, "liquids_pointable"); - if (i.type == ITEM_TOOL) { + if (i.tool_capabilities) { push_tool_capabilities(L, *i.tool_capabilities); lua_setfield(L, -2, "tool_capabilities"); } @@ -183,9 +184,11 @@ void read_object_properties(lua_State *L, int index, { if(index < 0) index = lua_gettop(L) + 1 + index; - if(!lua_istable(L, index)) + if (lua_isnil(L, index)) return; + luaL_checktype(L, -1, LUA_TTABLE); + int hp_max = 0; if (getintfield(L, -1, "hp_max", hp_max)) { prop->hp_max = (u16)rangelim(hp_max, 0, U16_MAX); @@ -324,6 +327,9 @@ void read_object_properties(lua_State *L, int index, getfloatfield(L, -1, "zoom_fov", prop->zoom_fov); getboolfield(L, -1, "use_texture_alpha", prop->use_texture_alpha); + getboolfield(L, -1, "shaded", prop->shaded); + + getstringfield(L, -1, "damage_texture_modifier", prop->damage_texture_modifier); } /******************************************************************************/ @@ -351,7 +357,7 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) push_v3f(L, prop->visual_size); lua_setfield(L, -2, "visual_size"); - lua_newtable(L); + lua_createtable(L, prop->textures.size(), 0); u16 i = 1; for (const std::string &texture : prop->textures) { lua_pushlstring(L, texture.c_str(), texture.size()); @@ -359,7 +365,7 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) } lua_setfield(L, -2, "textures"); - lua_newtable(L); + lua_createtable(L, prop->colors.size(), 0); i = 1; for (const video::SColor &color : prop->colors) { push_ARGB8(L, color); @@ -406,6 +412,10 @@ void push_object_properties(lua_State *L, ObjectProperties *prop) lua_setfield(L, -2, "zoom_fov"); lua_pushboolean(L, prop->use_texture_alpha); lua_setfield(L, -2, "use_texture_alpha"); + lua_pushboolean(L, prop->shaded); + lua_setfield(L, -2, "shaded"); + lua_pushlstring(L, prop->damage_texture_modifier.c_str(), prop->damage_texture_modifier.size()); + lua_setfield(L, -2, "damage_texture_modifier"); } /******************************************************************************/ @@ -687,6 +697,8 @@ ContentFeatures read_content_features(lua_State *L, int index) f.liquid_range = getintfield_default(L, index, "liquid_range", f.liquid_range); f.leveled = getintfield_default(L, index, "leveled", f.leveled); + f.leveled_max = getintfield_default(L, index, + "leveled_max", f.leveled_max); getboolfield(L, index, "liquid_renewable", f.liquid_renewable); f.drowning = getintfield_default(L, index, @@ -841,7 +853,7 @@ void push_content_features(lua_State *L, const ContentFeatures &c) lua_pushnumber(L, c.connect_sides); lua_setfield(L, -2, "connect_sides"); - lua_newtable(L); + lua_createtable(L, c.connects_to.size(), 0); u16 i = 1; for (const std::string &it : c.connects_to) { lua_pushlstring(L, it.c_str(), it.size()); @@ -853,6 +865,8 @@ void push_content_features(lua_State *L, const ContentFeatures &c) lua_setfield(L, -2, "post_effect_color"); lua_pushnumber(L, c.leveled); lua_setfield(L, -2, "leveled"); + lua_pushnumber(L, c.leveled_max); + lua_setfield(L, -2, "leveled_max"); lua_pushboolean(L, c.sunlight_propagates); lua_setfield(L, -2, "sunlight_propagates"); lua_pushnumber(L, c.light_source); @@ -964,7 +978,7 @@ void push_nodebox(lua_State *L, const NodeBox &box) void push_box(lua_State *L, const std::vector<aabb3f> &box) { - lua_newtable(L); + lua_createtable(L, box.size(), 0); u8 i = 1; for (const aabb3f &it : box) { push_aabb3f(L, it); @@ -1028,20 +1042,22 @@ void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec) { if(index < 0) index = lua_gettop(L) + 1 + index; - if(lua_isnil(L, index)){ - } else if(lua_istable(L, index)){ + if (lua_isnil(L, index)) + return; + + if (lua_istable(L, index)) { getstringfield(L, index, "name", spec.name); getfloatfield(L, index, "gain", spec.gain); getfloatfield(L, index, "fade", spec.fade); getfloatfield(L, index, "pitch", spec.pitch); - } else if(lua_isstring(L, index)){ + } else if (lua_isstring(L, index)) { spec.name = lua_tostring(L, index); } } void push_soundspec(lua_State *L, const SimpleSoundSpec &spec) { - lua_newtable(L); + lua_createtable(L, 0, 3); lua_pushstring(L, spec.name.c_str()); lua_setfield(L, -2, "name"); lua_pushnumber(L, spec.gain); @@ -1056,9 +1072,13 @@ void push_soundspec(lua_State *L, const SimpleSoundSpec &spec) NodeBox read_nodebox(lua_State *L, int index) { NodeBox nodebox; - if(lua_istable(L, -1)){ - nodebox.type = (NodeBoxType)getenumfield(L, index, "type", - ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR); + if (lua_isnil(L, -1)) + return nodebox; + + luaL_checktype(L, -1, LUA_TTABLE); + + nodebox.type = (NodeBoxType)getenumfield(L, index, "type", + ScriptApiNode::es_NodeBoxType, NODEBOX_REGULAR); #define NODEBOXREAD(n, s){ \ lua_getfield(L, index, (s)); \ @@ -1068,30 +1088,30 @@ NodeBox read_nodebox(lua_State *L, int index) } #define NODEBOXREADVEC(n, s) \ - lua_getfield(L, index, (s)); \ - if (lua_istable(L, -1)) \ - (n) = read_aabb3f_vector(L, -1, BS); \ - lua_pop(L, 1); + lua_getfield(L, index, (s)); \ + if (lua_istable(L, -1)) \ + (n) = read_aabb3f_vector(L, -1, BS); \ + lua_pop(L, 1); + + NODEBOXREADVEC(nodebox.fixed, "fixed"); + NODEBOXREAD(nodebox.wall_top, "wall_top"); + NODEBOXREAD(nodebox.wall_bottom, "wall_bottom"); + NODEBOXREAD(nodebox.wall_side, "wall_side"); + NODEBOXREADVEC(nodebox.connect_top, "connect_top"); + NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom"); + NODEBOXREADVEC(nodebox.connect_front, "connect_front"); + NODEBOXREADVEC(nodebox.connect_left, "connect_left"); + NODEBOXREADVEC(nodebox.connect_back, "connect_back"); + NODEBOXREADVEC(nodebox.connect_right, "connect_right"); + NODEBOXREADVEC(nodebox.disconnected_top, "disconnected_top"); + NODEBOXREADVEC(nodebox.disconnected_bottom, "disconnected_bottom"); + NODEBOXREADVEC(nodebox.disconnected_front, "disconnected_front"); + NODEBOXREADVEC(nodebox.disconnected_left, "disconnected_left"); + NODEBOXREADVEC(nodebox.disconnected_back, "disconnected_back"); + NODEBOXREADVEC(nodebox.disconnected_right, "disconnected_right"); + NODEBOXREADVEC(nodebox.disconnected, "disconnected"); + NODEBOXREADVEC(nodebox.disconnected_sides, "disconnected_sides"); - NODEBOXREADVEC(nodebox.fixed, "fixed"); - NODEBOXREAD(nodebox.wall_top, "wall_top"); - NODEBOXREAD(nodebox.wall_bottom, "wall_bottom"); - NODEBOXREAD(nodebox.wall_side, "wall_side"); - NODEBOXREADVEC(nodebox.connect_top, "connect_top"); - NODEBOXREADVEC(nodebox.connect_bottom, "connect_bottom"); - NODEBOXREADVEC(nodebox.connect_front, "connect_front"); - NODEBOXREADVEC(nodebox.connect_left, "connect_left"); - NODEBOXREADVEC(nodebox.connect_back, "connect_back"); - NODEBOXREADVEC(nodebox.connect_right, "connect_right"); - NODEBOXREADVEC(nodebox.disconnected_top, "disconnected_top"); - NODEBOXREADVEC(nodebox.disconnected_bottom, "disconnected_bottom"); - NODEBOXREADVEC(nodebox.disconnected_front, "disconnected_front"); - NODEBOXREADVEC(nodebox.disconnected_left, "disconnected_left"); - NODEBOXREADVEC(nodebox.disconnected_back, "disconnected_back"); - NODEBOXREADVEC(nodebox.disconnected_right, "disconnected_right"); - NODEBOXREADVEC(nodebox.disconnected, "disconnected"); - NODEBOXREADVEC(nodebox.disconnected_sides, "disconnected_sides"); - } return nodebox; } @@ -1126,12 +1146,12 @@ MapNode readnode(lua_State *L, int index, const NodeDefManager *ndef) /******************************************************************************/ void pushnode(lua_State *L, const MapNode &n, const NodeDefManager *ndef) { - lua_newtable(L); + lua_createtable(L, 0, 3); lua_pushstring(L, ndef->get(n).name.c_str()); lua_setfield(L, -2, "name"); - lua_pushnumber(L, n.getParam1()); + lua_pushinteger(L, n.getParam1()); lua_setfield(L, -2, "param1"); - lua_pushnumber(L, n.getParam2()); + lua_pushinteger(L, n.getParam2()); lua_setfield(L, -2, "param2"); } @@ -1164,7 +1184,7 @@ bool string_to_enum(const EnumString *spec, int &result, { const EnumString *esp = spec; while(esp->str){ - if(str == std::string(esp->str)){ + if (!strcmp(str.c_str(), esp->str)) { result = esp->num; return true; } @@ -1439,7 +1459,7 @@ ToolCapabilities read_tool_capabilities( /******************************************************************************/ void push_dig_params(lua_State *L,const DigParams ¶ms) { - lua_newtable(L); + lua_createtable(L, 0, 3); setboolfield(L, -1, "diggable", params.diggable); setfloatfield(L, -1, "time", params.time); setintfield(L, -1, "wear", params.wear); @@ -1448,7 +1468,7 @@ void push_dig_params(lua_State *L,const DigParams ¶ms) /******************************************************************************/ void push_hit_params(lua_State *L,const HitParams ¶ms) { - lua_newtable(L); + lua_createtable(L, 0, 3); setintfield(L, -1, "hp", params.hp); setintfield(L, -1, "wear", params.wear); } @@ -1520,8 +1540,11 @@ void push_flags_string(lua_State *L, FlagDesc *flagdesc, u32 flags, u32 flagmask /******************************************************************************/ void read_groups(lua_State *L, int index, ItemGroupList &result) { - if (!lua_istable(L,index)) + if (lua_isnil(L, index)) return; + + luaL_checktype(L, index, LUA_TTABLE); + result.clear(); lua_pushnil(L); if (index < 0) @@ -1541,9 +1564,9 @@ void read_groups(lua_State *L, int index, ItemGroupList &result) /******************************************************************************/ void push_groups(lua_State *L, const ItemGroupList &groups) { - lua_newtable(L); + lua_createtable(L, 0, groups.size()); for (const auto &group : groups) { - lua_pushnumber(L, group.second); + lua_pushinteger(L, group.second); lua_setfield(L, -2, group.first.c_str()); } } @@ -1588,7 +1611,7 @@ void luaentity_get(lua_State *L, u16 id) lua_getglobal(L, "core"); lua_getfield(L, -1, "luaentities"); luaL_checktype(L, -1, LUA_TTABLE); - lua_pushnumber(L, id); + lua_pushinteger(L, id); lua_gettable(L, -2); lua_remove(L, -2); // Remove luaentities lua_remove(L, -2); // Remove core @@ -1672,10 +1695,10 @@ static bool push_json_value_helper(lua_State *L, const Json::Value &value, lua_pushvalue(L, nullindex); break; case Json::intValue: - lua_pushinteger(L, value.asInt()); + lua_pushinteger(L, value.asLargestInt()); break; case Json::uintValue: - lua_pushinteger(L, value.asUInt()); + lua_pushinteger(L, value.asLargestUInt()); break; case Json::realValue: lua_pushnumber(L, value.asDouble()); @@ -1690,7 +1713,7 @@ static bool push_json_value_helper(lua_State *L, const Json::Value &value, lua_pushboolean(L, value.asInt()); break; case Json::arrayValue: - lua_newtable(L); + lua_createtable(L, value.size(), 0); for (Json::Value::const_iterator it = value.begin(); it != value.end(); ++it) { push_json_value_helper(L, *it, nullindex); @@ -1698,10 +1721,10 @@ static bool push_json_value_helper(lua_State *L, const Json::Value &value, } break; case Json::objectValue: - lua_newtable(L); + lua_createtable(L, 0, value.size()); for (Json::Value::const_iterator it = value.begin(); it != value.end(); ++it) { -#ifndef JSONCPP_STRING +#if !defined(JSONCPP_STRING) && (JSONCPP_VERSION_MAJOR < 1 || JSONCPP_VERSION_MINOR < 9) const char *str = it.memberName(); lua_pushstring(L, str ? str : ""); #else @@ -1825,7 +1848,7 @@ void push_objectRef(lua_State *L, const u16 id) lua_getglobal(L, "core"); lua_getfield(L, -1, "object_refs"); luaL_checktype(L, -1, LUA_TTABLE); - lua_pushnumber(L, id); + lua_pushinteger(L, id); lua_gettable(L, -2); lua_remove(L, -2); // object_refs lua_remove(L, -2); // core @@ -1851,10 +1874,15 @@ void read_hud_element(lua_State *L, HudElement *elem) elem->name = getstringfield_default(L, 2, "name", ""); elem->text = getstringfield_default(L, 2, "text", ""); elem->number = getintfield_default(L, 2, "number", 0); - elem->item = getintfield_default(L, 2, "item", 0); + if (elem->type == HUD_ELEM_WAYPOINT) + // waypoints reuse the item field to store precision, item = precision + 1 + elem->item = getintfield_default(L, 2, "precision", -1) + 1; + else + elem->item = getintfield_default(L, 2, "item", 0); elem->dir = getintfield_default(L, 2, "direction", 0); elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, getintfield_default(L, 2, "z_index", 0))); + elem->text2 = getstringfield_default(L, 2, "text2", ""); // Deprecated, only for compatibility's sake if (elem->dir == 0) @@ -1923,6 +1951,9 @@ void push_hud_element(lua_State *L, HudElement *elem) lua_pushnumber(L, elem->z_index); lua_setfield(L, -2, "z_index"); + + lua_pushstring(L, elem->text2.c_str()); + lua_setfield(L, -2, "text2"); } HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) @@ -1984,6 +2015,66 @@ HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX, luaL_checknumber(L, 4))); *value = &elem->z_index; break; + case HUD_STAT_TEXT2: + elem->text2 = luaL_checkstring(L, 4); + *value = &elem->text2; + break; } return stat; } + +/******************************************************************************/ + +// Indices must match values in `enum CollisionType` exactly!! +static const char *collision_type_str[] = { + "node", + "object", +}; + +// Indices must match values in `enum CollisionAxis` exactly!! +static const char *collision_axis_str[] = { + "x", + "y", + "z", +}; + +void push_collision_move_result(lua_State *L, const collisionMoveResult &res) +{ + lua_createtable(L, 0, 4); + + setboolfield(L, -1, "touching_ground", res.touching_ground); + setboolfield(L, -1, "collides", res.collides); + setboolfield(L, -1, "standing_on_object", res.standing_on_object); + + /* collisions */ + lua_createtable(L, res.collisions.size(), 0); + int i = 1; + for (const auto &c : res.collisions) { + lua_createtable(L, 0, 5); + + lua_pushstring(L, collision_type_str[c.type]); + lua_setfield(L, -2, "type"); + + assert(c.axis != COLLISION_AXIS_NONE); + lua_pushstring(L, collision_axis_str[c.axis]); + lua_setfield(L, -2, "axis"); + + if (c.type == COLLISION_NODE) { + push_v3s16(L, c.node_p); + lua_setfield(L, -2, "node_pos"); + } else if (c.type == COLLISION_OBJECT) { + push_objectRef(L, c.object->getId()); + lua_setfield(L, -2, "object"); + } + + push_v3f(L, c.old_speed / BS); + lua_setfield(L, -2, "old_velocity"); + + push_v3f(L, c.new_speed / BS); + lua_setfield(L, -2, "new_velocity"); + + lua_rawseti(L, -2, i++); + } + lua_setfield(L, -2, "collisions"); + /**/ +} diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 9e755682f..8f32e58eb 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -63,7 +63,9 @@ struct EnumString; struct NoiseParams; class Schematic; class ServerActiveObject; +struct collisionMoveResult; +extern struct EnumString es_TileAnimationType[]; ContentFeatures read_content_features (lua_State *L, int index); void push_content_features (lua_State *L, @@ -196,4 +198,4 @@ void push_hud_element (lua_State *L, HudElement *elem); HudElementStat read_hud_change (lua_State *L, HudElement *elem, void **value); -extern struct EnumString es_TileAnimationType[]; +void push_collision_move_result(lua_State *L, const collisionMoveResult &res); diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index 3c2f75641..eb6ab5331 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -28,15 +28,15 @@ extern "C" { #include "common/c_converter.h" #include "common/c_internal.h" #include "constants.h" +#include <set> #define CHECK_TYPE(index, name, type) { \ int t = lua_type(L, (index)); \ if (t != (type)) { \ - std::string traceback = script_get_backtrace(L); \ throw LuaError(std::string("Invalid ") + (name) + \ " (expected " + lua_typename(L, (type)) + \ - " got " + lua_typename(L, t) + ").\n" + traceback); \ + " got " + lua_typename(L, t) + ")."); \ } \ } #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER) @@ -62,7 +62,7 @@ void push_float_string(lua_State *L, float value) void push_v3f(lua_State *L, v3f p) { - lua_newtable(L); + lua_createtable(L, 0, 3); lua_pushnumber(L, p.X); lua_setfield(L, -2, "x"); lua_pushnumber(L, p.Y); @@ -73,7 +73,7 @@ void push_v3f(lua_State *L, v3f p) void push_v2f(lua_State *L, v2f p) { - lua_newtable(L); + lua_createtable(L, 0, 2); lua_pushnumber(L, p.X); lua_setfield(L, -2, "x"); lua_pushnumber(L, p.Y); @@ -82,7 +82,7 @@ void push_v2f(lua_State *L, v2f p) void push_v3_float_string(lua_State *L, v3f p) { - lua_newtable(L); + lua_createtable(L, 0, 3); push_float_string(L, p.X); lua_setfield(L, -2, "x"); push_float_string(L, p.Y); @@ -93,7 +93,7 @@ void push_v3_float_string(lua_State *L, v3f p) void push_v2_float_string(lua_State *L, v2f p) { - lua_newtable(L); + lua_createtable(L, 0, 2); push_float_string(L, p.X); lua_setfield(L, -2, "x"); push_float_string(L, p.Y); @@ -115,19 +115,19 @@ v2s16 read_v2s16(lua_State *L, int index) void push_v2s16(lua_State *L, v2s16 p) { - lua_newtable(L); - lua_pushnumber(L, p.X); + lua_createtable(L, 0, 2); + lua_pushinteger(L, p.X); lua_setfield(L, -2, "x"); - lua_pushnumber(L, p.Y); + lua_pushinteger(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_createtable(L, 0, 2); + lua_pushinteger(L, p.X); lua_setfield(L, -2, "x"); - lua_pushnumber(L, p.Y); + lua_pushinteger(L, p.Y); lua_setfield(L, -2, "y"); } @@ -250,14 +250,14 @@ v3d check_v3d(lua_State *L, int index) void push_ARGB8(lua_State *L, video::SColor color) { - lua_newtable(L); - lua_pushnumber(L, color.getAlpha()); + lua_createtable(L, 0, 4); + lua_pushinteger(L, color.getAlpha()); lua_setfield(L, -2, "a"); - lua_pushnumber(L, color.getRed()); + lua_pushinteger(L, color.getRed()); lua_setfield(L, -2, "r"); - lua_pushnumber(L, color.getGreen()); + lua_pushinteger(L, color.getGreen()); lua_setfield(L, -2, "g"); - lua_pushnumber(L, color.getBlue()); + lua_pushinteger(L, color.getBlue()); lua_setfield(L, -2, "b"); } @@ -274,12 +274,12 @@ v3f checkFloatPos(lua_State *L, int index) void push_v3s16(lua_State *L, v3s16 p) { - lua_newtable(L); - lua_pushnumber(L, p.X); + lua_createtable(L, 0, 3); + lua_pushinteger(L, p.X); lua_setfield(L, -2, "x"); - lua_pushnumber(L, p.Y); + lua_pushinteger(L, p.Y); lua_setfield(L, -2, "y"); - lua_pushnumber(L, p.Z); + lua_pushinteger(L, p.Z); lua_setfield(L, -2, "z"); } @@ -386,7 +386,7 @@ aabb3f read_aabb3f(lua_State *L, int index, f32 scale) void push_aabb3f(lua_State *L, aabb3f box) { - lua_newtable(L); + lua_createtable(L, 6, 0); lua_pushnumber(L, box.MinEdge.X); lua_rawseti(L, -2, 1); lua_pushnumber(L, box.MinEdge.Y); @@ -457,12 +457,55 @@ size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result Table field getters */ +#if defined(__MINGW32__) && !defined(__MINGW64__) +/* MinGW 32-bit somehow crashes in the std::set destructor when this + * variable is thread-local, so just don't do that. */ +static std::set<u64> warned_msgs; +#endif + +bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname) +{ +#if !defined(__MINGW32__) || defined(__MINGW64__) + thread_local std::set<u64> warned_msgs; +#endif + + int t = lua_type(L, index); + if (t == LUA_TNIL) + return false; + + if (t == type) + return true; + + // Check coercion types + if (type == LUA_TNUMBER) { + if (lua_isnumber(L, index)) + return true; + } else if (type == LUA_TSTRING) { + if (lua_isstring(L, index)) + return true; + } + + // Types mismatch. Log unique line. + std::string backtrace = std::string("Invalid field ") + fieldname + + " (expected " + lua_typename(L, type) + + " got " + lua_typename(L, t) + ").\n" + script_get_backtrace(L); + + u64 hash = murmur_hash_64_ua(backtrace.data(), backtrace.length(), 0xBADBABE); + if (warned_msgs.find(hash) == warned_msgs.end()) { + errorstream << backtrace << std::endl; + warned_msgs.insert(hash); + } + + return false; +} + bool getstringfield(lua_State *L, int table, const char *fieldname, std::string &result) { lua_getfield(L, table, fieldname); bool got = false; - if(lua_isstring(L, -1)){ + + if (check_field_or_nil(L, -1, LUA_TSTRING, fieldname)) { size_t len = 0; const char *ptr = lua_tolstring(L, -1, &len); if (ptr) { @@ -479,7 +522,8 @@ bool getfloatfield(lua_State *L, int table, { lua_getfield(L, table, fieldname); bool got = false; - if(lua_isnumber(L, -1)){ + + if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)) { result = lua_tonumber(L, -1); got = true; } @@ -492,7 +536,8 @@ bool getboolfield(lua_State *L, int table, { lua_getfield(L, table, fieldname); bool got = false; - if(lua_isboolean(L, -1)){ + + if (check_field_or_nil(L, -1, LUA_TBOOLEAN, fieldname)){ result = lua_toboolean(L, -1); got = true; } @@ -511,17 +556,6 @@ size_t getstringlistfield(lua_State *L, int table, const char *fieldname, return num_strings_read; } -std::string checkstringfield(lua_State *L, int table, - const char *fieldname) -{ - lua_getfield(L, table, fieldname); - 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 std::string(s, len); -} - std::string getstringfield_default(lua_State *L, int table, const char *fieldname, const std::string &default_) { diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h index 9620bf75a..a4a7079fd 100644 --- a/src/script/common/c_converter.h +++ b/src/script/common/c_converter.h @@ -45,13 +45,15 @@ float getfloatfield_default(lua_State *L, int table, int getintfield_default(lua_State *L, int table, const char *fieldname, int default_); +bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname); + template<typename T> bool getintfield(lua_State *L, int table, const char *fieldname, T &result) { lua_getfield(L, table, fieldname); bool got = false; - if (lua_isnumber(L, -1)){ + if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)){ result = lua_tointeger(L, -1); got = true; } @@ -87,8 +89,6 @@ bool getboolfield(lua_State *L, int table, const char *fieldname, bool &result); bool getfloatfield(lua_State *L, int table, const char *fieldname, float &result); -std::string checkstringfield(lua_State *L, int table, - const char *fieldname); void setstringfield(lua_State *L, int table, const char *fieldname, const std::string &value); diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index b19af9f82..6df1f8b7b 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -157,9 +157,9 @@ static void script_log(lua_State *L, const std::string &message, void log_deprecated(lua_State *L, const std::string &message, int stack_depth) { - static bool configured = false; - static bool do_log = false; - static bool do_error = false; + static thread_local bool configured = false; + static thread_local bool do_log = false; + static thread_local bool do_error = false; // Only read settings on first call if (!configured) { @@ -167,9 +167,10 @@ void log_deprecated(lua_State *L, const std::string &message, int stack_depth) if (value == "log") { do_log = true; } else if (value == "error") { - do_log = true; + do_log = true; do_error = true; } + configured = true; } if (do_log) diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h index d8cf3fe76..442546332 100644 --- a/src/script/common/c_internal.h +++ b/src/script/common/c_internal.h @@ -31,6 +31,7 @@ extern "C" { #include <lauxlib.h> } +#include "config.h" #include "common/c_types.h" @@ -54,6 +55,15 @@ extern "C" { #define CUSTOM_RIDX_CURRENT_MOD_NAME (CUSTOM_RIDX_BASE + 2) #define CUSTOM_RIDX_BACKTRACE (CUSTOM_RIDX_BASE + 3) +// Determine if CUSTOM_RIDX_SCRIPTAPI will hold a light or full userdata +#if defined(__aarch64__) && USE_LUAJIT +/* LuaJIT has a 47-bit limit for lightuserdata on this platform and we cannot + * assume that the ScriptApi class was allocated at a fitting address. */ +#define INDIRECT_SCRIPTAPI_RIDX 1 +#else +#define INDIRECT_SCRIPTAPI_RIDX 0 +#endif + // Pushes the error handler onto the stack and returns its index #define PUSH_ERROR_HANDLER(L) \ (lua_rawgeti((L), LUA_REGISTRYINDEX, CUSTOM_RIDX_BACKTRACE), lua_gettop((L))) diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index ecb1ba39b..f965975a3 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_security.h" #include "lua_api/l_object.h" #include "common/c_converter.h" -#include "serverobject.h" +#include "server/player_sao.h" #include "filesys.h" #include "content/mods.h" #include "porting.h" @@ -43,7 +43,6 @@ extern "C" { #include <cstdio> #include <cstdarg> #include "script/common/c_content.h" -#include "content_sao.h" #include <sstream> @@ -90,7 +89,11 @@ ScriptApiBase::ScriptApiBase(ScriptingType type): luaL_openlibs(m_luastack); // Make the ScriptApiBase* accessible to ModApiBase +#if INDIRECT_SCRIPTAPI_RIDX + *(void **)(lua_newuserdata(m_luastack, sizeof(void *))) = this; +#else lua_pushlightuserdata(m_luastack, this); +#endif lua_rawseti(m_luastack, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); // Add and save an error handler @@ -184,7 +187,9 @@ void ScriptApiBase::loadScript(const std::string &script_path) } ok = ok && !lua_pcall(L, 0, 0, error_handler); if (!ok) { - std::string error_msg = readParam<std::string>(L, -1); + const char *error_msg = lua_tostring(L, -1); + if (!error_msg) + error_msg = "(error object is not a string)"; lua_pop(L, 2); // Pop error message and error handler throw ModError("Failed to load and run script from " + script_path + ":\n" + error_msg); @@ -216,7 +221,9 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name) if (ok) ok = !lua_pcall(L, 0, 0, error_handler); if (!ok) { - std::string error_msg = luaL_checkstring(L, -1); + const char *error_msg = lua_tostring(L, -1); + if (!error_msg) + error_msg = "(error object is not a string)"; lua_pop(L, 2); // Pop error message and error handler throw ModError("Failed to load and run mod \"" + mod_name + "\":\n" + error_msg); diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index 697e5f556..86f7f7bac 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -136,8 +136,10 @@ protected: Environment* getEnv() { return m_environment; } void setEnv(Environment* env) { m_environment = env; } +#ifndef SERVER GUIEngine* getGuiEngine() { return m_guiengine; } void setGuiEngine(GUIEngine* guiengine) { m_guiengine = guiengine; } +#endif void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj); @@ -158,6 +160,8 @@ private: IGameDef *m_gamedef = nullptr; Environment *m_environment = nullptr; +#ifndef SERVER GUIEngine *m_guiengine = nullptr; +#endif ScriptingType m_type; }; diff --git a/src/script/cpp_api/s_entity.cpp b/src/script/cpp_api/s_entity.cpp index 26c7e8cd4..ea9320051 100644 --- a/src/script/cpp_api/s_entity.cpp +++ b/src/script/cpp_api/s_entity.cpp @@ -178,12 +178,11 @@ void ScriptApiEntity::luaentity_GetProperties(u16 id, lua_pop(L, 1); } -void ScriptApiEntity::luaentity_Step(u16 id, float dtime) +void ScriptApiEntity::luaentity_Step(u16 id, float dtime, + const collisionMoveResult *moveresult) { SCRIPTAPI_PRECHECKHEADER - //infostream<<"scriptapi_luaentity_step: id="<<id<<std::endl; - int error_handler = PUSH_ERROR_HANDLER(L); // Get core.luaentities[id] @@ -199,9 +198,14 @@ void ScriptApiEntity::luaentity_Step(u16 id, float dtime) luaL_checktype(L, -1, LUA_TFUNCTION); lua_pushvalue(L, object); // self lua_pushnumber(L, dtime); // dtime + /* moveresult */ + if (moveresult) + push_collision_move_result(L, *moveresult); + else + lua_pushnil(L); setOriginFromTable(object); - PCALL_RES(lua_pcall(L, 2, 0, error_handler)); + PCALL_RES(lua_pcall(L, 3, 0, error_handler)); lua_pop(L, 2); // Pop object and error handler } diff --git a/src/script/cpp_api/s_entity.h b/src/script/cpp_api/s_entity.h index cc08c46e8..b5f7a6586 100644 --- a/src/script/cpp_api/s_entity.h +++ b/src/script/cpp_api/s_entity.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., struct ObjectProperties; struct ToolCapabilities; +struct collisionMoveResult; class ScriptApiEntity : virtual public ScriptApiBase @@ -36,7 +37,8 @@ public: std::string luaentity_GetStaticdata(u16 id); void luaentity_GetProperties(u16 id, ServerActiveObject *self, ObjectProperties *prop); - void luaentity_Step(u16 id, float dtime); + void luaentity_Step(u16 id, float dtime, + const collisionMoveResult *moveresult); bool luaentity_Punch(u16 id, ServerActiveObject *puncher, float time_from_last_punch, const ToolCapabilities *toolcap, v3f dir, s16 damage); diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index ab3b5fe46..8da5debaa 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -86,7 +86,7 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) { SCRIPTAPI_PRECHECKHEADER - verbosestream << "scriptapi_add_environment" << std::endl; + verbosestream << "ScriptApiEnv: Environment initialized" << std::endl; setEnv(env); /* diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp index d93a4c3ad..e0f9bcd78 100644 --- a/src/script/cpp_api/s_node.cpp +++ b/src/script/cpp_api/s_node.cpp @@ -94,7 +94,7 @@ struct EnumString ScriptApiNode::es_NodeBoxType[] = }; bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node, - ServerActiveObject *puncher, PointedThing pointed) + ServerActiveObject *puncher, const PointedThing &pointed) { SCRIPTAPI_PRECHECKHEADER diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h index e7c0c01d1..81b44f0f0 100644 --- a/src/script/cpp_api/s_node.h +++ b/src/script/cpp_api/s_node.h @@ -36,7 +36,7 @@ public: virtual ~ScriptApiNode() = default; bool node_on_punch(v3s16 p, MapNode node, - ServerActiveObject *puncher, PointedThing pointed); + ServerActiveObject *puncher, const PointedThing &pointed); bool node_on_dig(v3s16 p, MapNode node, ServerActiveObject *digger); void node_on_construct(v3s16 p, MapNode node); diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp index df67ea00c..712120c61 100644 --- a/src/script/cpp_api/s_player.cpp +++ b/src/script/cpp_api/s_player.cpp @@ -147,7 +147,7 @@ bool ScriptApiPlayer::can_bypass_userlimit(const std::string &name, const std::s return lua_toboolean(L, -1); } -void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player) +void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player, s64 last_login) { SCRIPTAPI_PRECHECKHEADER @@ -156,7 +156,11 @@ void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player) lua_getfield(L, -1, "registered_on_joinplayers"); // Call callbacks objectrefGetOrCreate(L, player); - runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); + if (last_login != -1) + lua_pushinteger(L, last_login); + else + lua_pushnil(L); + runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); } void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player, @@ -216,16 +220,19 @@ void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player, runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC); } -void ScriptApiPlayer::on_auth_failure(const std::string &name, const std::string &ip) +void ScriptApiPlayer::on_authplayer(const std::string &name, const std::string &ip, bool is_success) { SCRIPTAPI_PRECHECKHEADER - // Get core.registered_on_auth_failure + // Get core.registered_on_authplayers lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_on_auth_fail"); + lua_getfield(L, -1, "registered_on_authplayers"); + + // Call callbacks lua_pushstring(L, name.c_str()); lua_pushstring(L, ip.c_str()); - runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); + lua_pushboolean(L, is_success); + runCallbacks(3, RUN_CALLBACKS_MODE_FIRST); } void ScriptApiPlayer::pushMoveArguments( diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h index cf24ddc73..a337f975b 100644 --- a/src/script/cpp_api/s_player.h +++ b/src/script/cpp_api/s_player.h @@ -28,6 +28,7 @@ struct InventoryLocation; struct ItemStack; struct ToolCapabilities; struct PlayerHPChangeReason; +class ServerActiveObject; class ScriptApiPlayer : virtual public ScriptApiBase { @@ -40,7 +41,7 @@ public: bool on_prejoinplayer(const std::string &name, const std::string &ip, std::string *reason); bool can_bypass_userlimit(const std::string &name, const std::string &ip); - void on_joinplayer(ServerActiveObject *player); + void on_joinplayer(ServerActiveObject *player, s64 last_login); void on_leaveplayer(ServerActiveObject *player, bool timeout); void on_cheat(ServerActiveObject *player, const std::string &cheat_type); bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter, @@ -50,7 +51,7 @@ public: const PlayerHPChangeReason &reason); void on_playerReceiveFields(ServerActiveObject *player, const std::string &formname, const StringMap &fields); - void on_auth_failure(const std::string &name, const std::string &ip); + void on_authplayer(const std::string &name, const std::string &ip, bool is_success); // Player inventory callbacks // Return number of accepted items to be moved diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index b5abcfb5d..2afa3a191 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -499,7 +499,12 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, // Get server from registry lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); - ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1); + ScriptApiBase *script; +#if INDIRECT_SCRIPTAPI_RIDX + script = (ScriptApiBase *) *(void**)(lua_touserdata(L, -1)); +#else + script = (ScriptApiBase *) lua_touserdata(L, -1); +#endif lua_pop(L, 1); const IGameDef *gamedef = script->getGameDef(); if (!gamedef) diff --git a/src/script/cpp_api/s_server.cpp b/src/script/cpp_api/s_server.cpp index 1ce2f9d45..96cb28b28 100644 --- a/src/script/cpp_api/s_server.cpp +++ b/src/script/cpp_api/s_server.cpp @@ -23,7 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc., bool ScriptApiServer::getAuth(const std::string &playername, std::string *dst_password, - std::set<std::string> *dst_privs) + std::set<std::string> *dst_privs, + s64 *dst_last_login) { SCRIPTAPI_PRECHECKHEADER @@ -43,8 +44,7 @@ bool ScriptApiServer::getAuth(const std::string &playername, luaL_checktype(L, -1, LUA_TTABLE); std::string password; - bool found = getstringfield(L, -1, "password", password); - if (!found) + if (!getstringfield(L, -1, "password", password)) throw LuaError("Authentication handler didn't return password"); if (dst_password) *dst_password = password; @@ -54,7 +54,13 @@ bool ScriptApiServer::getAuth(const std::string &playername, throw LuaError("Authentication handler didn't return privilege table"); if (dst_privs) readPrivileges(-1, *dst_privs); - lua_pop(L, 1); + lua_pop(L, 1); // Remove key from privs table + + s64 last_login; + if(!getintfield(L, -1, "last_login", last_login)) + throw LuaError("Authentication handler didn't return last_login"); + if (dst_last_login) + *dst_last_login = (s64)last_login; return true; } diff --git a/src/script/cpp_api/s_server.h b/src/script/cpp_api/s_server.h index a4cede84d..d8639cba7 100644 --- a/src/script/cpp_api/s_server.h +++ b/src/script/cpp_api/s_server.h @@ -43,7 +43,8 @@ public: /* auth */ bool getAuth(const std::string &playername, std::string *dst_password, - std::set<std::string> *dst_privs); + std::set<std::string> *dst_privs, + s64 *dst_last_login = nullptr); void createAuth(const std::string &playername, const std::string &password); bool setPassword(const std::string &playername, diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp index 8486fc7bc..2bee09436 100644 --- a/src/script/lua_api/l_base.cpp +++ b/src/script/lua_api/l_base.cpp @@ -30,7 +30,12 @@ ScriptApiBase *ModApiBase::getScriptApiBase(lua_State *L) { // Get server from registry lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); - ScriptApiBase *sapi_ptr = (ScriptApiBase*) lua_touserdata(L, -1); + ScriptApiBase *sapi_ptr; +#if INDIRECT_SCRIPTAPI_RIDX + sapi_ptr = (ScriptApiBase*) *(void**)(lua_touserdata(L, -1)); +#else + sapi_ptr = (ScriptApiBase*) lua_touserdata(L, -1); +#endif lua_pop(L, 1); return sapi_ptr; } @@ -40,6 +45,11 @@ Server *ModApiBase::getServer(lua_State *L) return getScriptApiBase(L)->getServer(); } +ServerInventoryManager *ModApiBase::getServerInventoryMgr(lua_State *L) +{ + return getScriptApiBase(L)->getServer()->getInventoryMgr(); +} + #ifndef SERVER Client *ModApiBase::getClient(lua_State *L) { @@ -57,10 +67,12 @@ Environment *ModApiBase::getEnv(lua_State *L) return getScriptApiBase(L)->getEnv(); } +#ifndef SERVER GUIEngine *ModApiBase::getGuiEngine(lua_State *L) { return getScriptApiBase(L)->getGuiEngine(); } +#endif std::string ModApiBase::getCurrentModPath(lua_State *L) { diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h index b46b5b567..65fce8481 100644 --- a/src/script/lua_api/l_base.h +++ b/src/script/lua_api/l_base.h @@ -32,26 +32,29 @@ extern "C" { #ifndef SERVER class Client; +class GUIEngine; #endif class ScriptApiBase; class Server; class Environment; -class GUIEngine; +class ServerInventoryManager; class ModApiBase : protected LuaHelper { public: static ScriptApiBase* getScriptApiBase(lua_State *L); static Server* getServer(lua_State *L); + static ServerInventoryManager *getServerInventoryMgr(lua_State *L); #ifndef SERVER static Client* getClient(lua_State *L); + static GUIEngine* getGuiEngine(lua_State *L); #endif // !SERVER static IGameDef* getGameDef(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); diff --git a/src/script/lua_api/l_camera.cpp b/src/script/lua_api/l_camera.cpp index 9c1470284..bfa60be67 100644 --- a/src/script/lua_api/l_camera.cpp +++ b/src/script/lua_api/l_camera.cpp @@ -51,6 +51,7 @@ void LuaCamera::create(lua_State *L, Camera *m) lua_setfield(L, objectstable, "camera"); } +// set_camera_mode(self, mode) int LuaCamera::l_set_camera_mode(lua_State *L) { Camera *camera = getobject(L, 1); @@ -67,17 +68,19 @@ int LuaCamera::l_set_camera_mode(lua_State *L) return 0; } +// get_camera_mode(self) int LuaCamera::l_get_camera_mode(lua_State *L) { Camera *camera = getobject(L, 1); if (!camera) return 0; - lua_pushnumber(L, (int)camera->getCameraMode()); + lua_pushinteger(L, (int)camera->getCameraMode()); return 1; } +// get_fov(self) int LuaCamera::l_get_fov(lua_State *L) { Camera *camera = getobject(L, 1); @@ -85,9 +88,9 @@ int LuaCamera::l_get_fov(lua_State *L) return 0; lua_newtable(L); - lua_pushnumber(L, camera->getFovX() * core::DEGTORAD); + lua_pushnumber(L, camera->getFovX() * core::RADTODEG); lua_setfield(L, -2, "x"); - lua_pushnumber(L, camera->getFovY() * core::DEGTORAD); + lua_pushnumber(L, camera->getFovY() * core::RADTODEG); lua_setfield(L, -2, "y"); lua_pushnumber(L, camera->getCameraNode()->getFOV() * core::RADTODEG); lua_setfield(L, -2, "actual"); @@ -96,16 +99,18 @@ int LuaCamera::l_get_fov(lua_State *L) return 1; } +// get_pos(self) int LuaCamera::l_get_pos(lua_State *L) { Camera *camera = getobject(L, 1); if (!camera) return 0; - push_v3f(L, camera->getPosition()); + push_v3f(L, camera->getPosition() / BS); return 1; } +// get_offset(self) int LuaCamera::l_get_offset(lua_State *L) { LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer(); @@ -115,38 +120,40 @@ int LuaCamera::l_get_offset(lua_State *L) return 1; } +// get_look_dir(self) int LuaCamera::l_get_look_dir(lua_State *L) { - LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer(); - sanity_check(player); - - float pitch = -1.0 * player->getPitch() * core::DEGTORAD; - float yaw = (player->getYaw() + 90.) * core::DEGTORAD; - v3f v(std::cos(pitch) * std::cos(yaw), std::sin(pitch), - std::cos(pitch) * std::sin(yaw)); + Camera *camera = getobject(L, 1); + if (!camera) + return 0; - push_v3f(L, v); + push_v3f(L, camera->getDirection()); return 1; } +// get_look_horizontal(self) +// FIXME: wouldn't localplayer be a better place for this? int LuaCamera::l_get_look_horizontal(lua_State *L) { LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer(); sanity_check(player); - lua_pushnumber(L, (player->getYaw() + 90.) * core::DEGTORAD); + lua_pushnumber(L, (player->getYaw() + 90.f) * core::DEGTORAD); return 1; } +// get_look_vertical(self) +// FIXME: wouldn't localplayer be a better place for this? int LuaCamera::l_get_look_vertical(lua_State *L) { LocalPlayer *player = getClient(L)->getEnv().getLocalPlayer(); sanity_check(player); - lua_pushnumber(L, -1.0 * player->getPitch() * core::DEGTORAD); + lua_pushnumber(L, -1.0f * player->getPitch() * core::DEGTORAD); return 1; } +// get_aspect_ratio(self) int LuaCamera::l_get_aspect_ratio(lua_State *L) { Camera *camera = getobject(L, 1); @@ -215,13 +222,19 @@ void LuaCamera::Register(lua_State *L) lua_pop(L, 1); } +// clang-format off const char LuaCamera::className[] = "Camera"; -const luaL_Reg LuaCamera::methods[] = {luamethod(LuaCamera, set_camera_mode), - luamethod(LuaCamera, get_camera_mode), luamethod(LuaCamera, get_fov), - luamethod(LuaCamera, get_pos), luamethod(LuaCamera, get_offset), - luamethod(LuaCamera, get_look_dir), - luamethod(LuaCamera, get_look_vertical), - luamethod(LuaCamera, get_look_horizontal), - luamethod(LuaCamera, get_aspect_ratio), - - {0, 0}}; +const luaL_Reg LuaCamera::methods[] = { + luamethod(LuaCamera, set_camera_mode), + luamethod(LuaCamera, get_camera_mode), + luamethod(LuaCamera, get_fov), + luamethod(LuaCamera, get_pos), + luamethod(LuaCamera, get_offset), + luamethod(LuaCamera, get_look_dir), + luamethod(LuaCamera, get_look_vertical), + luamethod(LuaCamera, get_look_horizontal), + luamethod(LuaCamera, get_aspect_ratio), + + {0, 0} +}; +// clang-format on diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index fba182492..aaced7cd0 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -29,7 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/s_base.h" #include "gettext.h" #include "l_internal.h" -#include "lua_api/l_item.h" #include "lua_api/l_nodemeta.h" #include "gui/mainmenumanager.h" #include "map.h" @@ -209,7 +208,7 @@ int ModApiClient::l_gettext(lua_State *L) return 1; } -// get_node(pos) +// get_node_or_nil(pos) // pos = {x=num, y=num, z=num} int ModApiClient::l_get_node_or_nil(lua_State *L) { @@ -228,6 +227,7 @@ int ModApiClient::l_get_node_or_nil(lua_State *L) return 1; } +// get_langauge() int ModApiClient::l_get_language(lua_State *L) { #ifdef _WIN32 @@ -244,34 +244,30 @@ int ModApiClient::l_get_language(lua_State *L) return 2; } -int ModApiClient::l_get_wielded_item(lua_State *L) -{ - Client *client = getClient(L); - LocalPlayer *player = client->getEnv().getLocalPlayer(); - if (!player) - return 0; - - ItemStack selected_item; - player->getWieldedItem(&selected_item, nullptr); - LuaItemStack::create(L, selected_item); - return 1; -} - // get_meta(pos) int ModApiClient::l_get_meta(lua_State *L) { v3s16 p = read_v3s16(L, 1); - NodeMetadata *meta = getClient(L)->getEnv().getMap().getNodeMetadata(p); + + // check restrictions first + bool pos_ok; + getClient(L)->CSMGetNode(p, &pos_ok); + if (!pos_ok) + return 0; + + NodeMetadata *meta = getEnv(L)->getMap().getNodeMetadata(p); NodeMetaRef::createClient(L, meta); return 1; } +// sound_play(spec, parameters) int ModApiClient::l_sound_play(lua_State *L) { ISoundManager *sound = getClient(L)->getSoundManager(); SimpleSoundSpec spec; read_soundspec(L, 1, spec); + float gain = 1.0f; float pitch = 1.0f; bool looped = false; @@ -293,21 +289,32 @@ int ModApiClient::l_sound_play(lua_State *L) } } - handle = sound->playSound(spec.name, looped, gain * spec.gain, 0.0f, pitch); + handle = sound->playSound(spec.name, looped, gain * spec.gain, spec.fade, pitch); lua_pushinteger(L, handle); return 1; } +// sound_stop(handle) int ModApiClient::l_sound_stop(lua_State *L) { - u32 handle = luaL_checkinteger(L, 1); + s32 handle = luaL_checkinteger(L, 1); getClient(L)->getSoundManager()->stopSound(handle); return 0; } +// sound_fade(handle, step, gain) +int ModApiClient::l_sound_fade(lua_State *L) +{ + s32 handle = luaL_checkinteger(L, 1); + float step = readParam<float>(L, 2); + float gain = readParam<float>(L, 3); + getClient(L)->getSoundManager()->fadeSound(handle, step, gain); + return 0; +} + // get_server_info() int ModApiClient::l_get_server_info(lua_State *L) { @@ -375,6 +382,7 @@ int ModApiClient::l_get_node_def(lua_State *L) return 1; } +// get_privilege_list() int ModApiClient::l_get_privilege_list(lua_State *L) { const Client *client = getClient(L); @@ -421,11 +429,11 @@ void ModApiClient::Initialize(lua_State *L, int top) API_FCT(send_respawn); API_FCT(gettext); API_FCT(get_node_or_nil); - API_FCT(get_wielded_item); API_FCT(disconnect); API_FCT(get_meta); API_FCT(sound_play); API_FCT(sound_stop); + API_FCT(sound_fade); API_FCT(get_server_info); API_FCT(get_item_def); API_FCT(get_node_def); diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h index 6d1f70b1d..5dc3efdad 100644 --- a/src/script/lua_api/l_client.h +++ b/src/script/lua_api/l_client.h @@ -69,6 +69,7 @@ private: // get_node(pos) static int l_get_node_or_nil(lua_State *L); + // get_language() static int l_get_language(lua_State *L); // get_wielded_item() @@ -77,10 +78,15 @@ private: // get_meta(pos) static int l_get_meta(lua_State *L); + // sound_play(spec, parameters) static int l_sound_play(lua_State *L); + // sound_stop(handle) static int l_sound_stop(lua_State *L); + // sound_fade(handle, step, gain) + static int l_sound_fade(lua_State *L); + // get_server_info() static int l_get_server_info(lua_State *L); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 3169fa4cf..89ec9dc7e 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include <algorithm> #include "lua_api/l_env.h" #include "lua_api/l_internal.h" #include "lua_api/l_nodemeta.h" @@ -25,7 +26,6 @@ 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 <algorithm> #include "scripting_server.h" #include "environment.h" #include "mapblock.h" @@ -33,12 +33,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "daynightratio.h" #include "util/pointedthing.h" -#include "content_sao.h" #include "mapgen/treegen.h" #include "emerge.h" #include "pathfinder.h" #include "face_position_cache.h" #include "remoteplayer.h" +#include "server/luaentity_sao.h" +#include "server/player_sao.h" +#include "util/string.h" +#include "translation.h" #ifndef SERVER #include "client/client.h" #endif @@ -72,7 +75,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, lua_remove(L, -2); // Remove core // Get registered_abms[m_id] - lua_pushnumber(L, m_id); + lua_pushinteger(L, m_id); lua_gettable(L, -2); if(lua_isnil(L, -1)) FATAL_ERROR(""); @@ -115,7 +118,7 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) lua_remove(L, -2); // Remove core // Get registered_lbms[m_id] - lua_pushnumber(L, m_id); + lua_pushinteger(L, m_id); lua_gettable(L, -2); FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); lua_remove(L, -2); // Remove registered_lbms @@ -139,8 +142,7 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) int LuaRaycast::l_next(lua_State *L) { - MAP_LOCK_REQUIRED; - GET_ENV_PTR; + GET_PLAIN_ENV_PTR; bool csm = false; #ifndef SERVER @@ -384,7 +386,7 @@ int ModApiEnvMod::l_get_node_or_nil(lua_State *L) // timeofday: nil = current time, 0 = night, 0.5 = day int ModApiEnvMod::l_get_node_light(lua_State *L) { - GET_ENV_PTR; + GET_PLAIN_ENV_PTR; // Do it v3s16 pos = read_v3s16(L, 1); @@ -488,10 +490,7 @@ int ModApiEnvMod::l_punch_node(lua_State *L) // pos = {x=num, y=num, z=num} int ModApiEnvMod::l_get_node_max_level(lua_State *L) { - Environment *env = getEnv(L); - if (!env) { - return 0; - } + GET_PLAIN_ENV_PTR; v3s16 pos = read_v3s16(L, 1); MapNode n = env->getMap().getNode(pos); @@ -503,10 +502,7 @@ int ModApiEnvMod::l_get_node_max_level(lua_State *L) // pos = {x=num, y=num, z=num} int ModApiEnvMod::l_get_node_level(lua_State *L) { - Environment *env = getEnv(L); - if (!env) { - return 0; - } + GET_PLAIN_ENV_PTR; v3s16 pos = read_v3s16(L, 1); MapNode n = env->getMap().getNode(pos); @@ -533,13 +529,13 @@ int ModApiEnvMod::l_set_node_level(lua_State *L) // add_node_level(pos, level) // pos = {x=num, y=num, z=num} -// level: 0..63 +// level: -127..127 int ModApiEnvMod::l_add_node_level(lua_State *L) { GET_ENV_PTR; v3s16 pos = read_v3s16(L, 1); - u8 level = 1; + s16 level = 1; if(lua_isnumber(L, 2)) level = lua_tonumber(L, 2); MapNode n = env->getMap().getNode(pos); @@ -551,12 +547,12 @@ int ModApiEnvMod::l_add_node_level(lua_State *L) // find_nodes_with_meta(pos1, pos2) int ModApiEnvMod::l_find_nodes_with_meta(lua_State *L) { - GET_ENV_PTR; + GET_PLAIN_ENV_PTR; std::vector<v3s16> positions = env->getMap().findNodesWithMetadata( check_v3s16(L, 1), check_v3s16(L, 2)); - lua_newtable(L); + lua_createtable(L, positions.size(), 0); for (size_t i = 0; i != positions.size(); i++) { push_v3s16(L, positions[i]); lua_rawseti(L, -2, i + 1); @@ -583,7 +579,7 @@ int ModApiEnvMod::l_get_node_timer(lua_State *L) // Do it v3s16 p = read_v3s16(L, 1); - NodeTimerRef::create(L, p, env); + NodeTimerRef::create(L, p, &env->getServerMap()); return 1; } @@ -593,19 +589,19 @@ int ModApiEnvMod::l_add_entity(lua_State *L) { GET_ENV_PTR; - // pos v3f pos = checkFloatPos(L, 1); - // content const char *name = luaL_checkstring(L, 2); - // staticdata const char *staticdata = luaL_optstring(L, 3, ""); - // Do it + ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, staticdata); int objectid = env->addActiveObject(obj); // If failed to add, return nothing (reads as nil) if(objectid == 0) return 0; - // Return ObjectRef + + // If already deleted (can happen in on_activate), return nil + if (obj->isGone()) + return 0; getScriptApiBase(L)->objectrefGetOrCreate(L, obj); return 1; } @@ -687,22 +683,22 @@ int ModApiEnvMod::l_get_player_by_name(lua_State *L) int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L) { GET_ENV_PTR; + ScriptApiBase *script = getScriptApiBase(L); // Do it v3f pos = checkFloatPos(L, 1); float radius = readParam<float>(L, 2) * BS; - std::vector<u16> ids; - env->getObjectsInsideRadius(ids, pos, radius); - ScriptApiBase *script = getScriptApiBase(L); - lua_createtable(L, ids.size(), 0); - std::vector<u16>::const_iterator iter = ids.begin(); - for(u32 i = 0; iter != ids.end(); ++iter) { - ServerActiveObject *obj = env->getActiveObject(*iter); - if (!obj->isGone()) { - // Insert object reference into table - script->objectrefGetOrCreate(L, obj); - lua_rawseti(L, -2, ++i); - } + std::vector<ServerActiveObject *> objs; + + auto include_obj_cb = [](ServerActiveObject *obj){ return !obj->isGone(); }; + env->getObjectsInsideRadius(objs, pos, radius, include_obj_cb); + + int i = 0; + lua_createtable(L, objs.size(), 0); + for (const auto obj : objs) { + // Insert object reference into table + script->objectrefGetOrCreate(L, obj); + lua_rawseti(L, -2, ++i); } return 1; } @@ -728,10 +724,7 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L) // get_timeofday() -> 0...1 int ModApiEnvMod::l_get_timeofday(lua_State *L) { - Environment *env = getEnv(L); - if (!env) { - return 0; - } + GET_PLAIN_ENV_PTR; // Do it int timeofday_mh = env->getTimeOfDay(); @@ -743,10 +736,7 @@ int ModApiEnvMod::l_get_timeofday(lua_State *L) // get_day_count() -> int int ModApiEnvMod::l_get_day_count(lua_State *L) { - Environment *env = getEnv(L); - if (!env) { - return 0; - } + GET_PLAIN_ENV_PTR; lua_pushnumber(L, env->getDayCount()); return 1; @@ -767,12 +757,9 @@ int ModApiEnvMod::l_get_gametime(lua_State *L) // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" int ModApiEnvMod::l_find_node_near(lua_State *L) { - Environment *env = getEnv(L); - if (!env) { - return 0; - } + GET_PLAIN_ENV_PTR; - const NodeDefManager *ndef = getGameDef(L)->ndef(); + const NodeDefManager *ndef = env->getGameDef()->ndef(); v3s16 pos = read_v3s16(L, 1); int radius = luaL_checkinteger(L, 2); std::vector<content_t> filter; @@ -793,8 +780,8 @@ int ModApiEnvMod::l_find_node_near(lua_State *L) #ifndef SERVER // Client API limitations - if (getClient(L)) - radius = getClient(L)->CSMClampRadius(pos, radius); + if (Client *client = getClient(L)) + radius = client->CSMClampRadius(pos, radius); #endif for (int d = start_radius; d <= radius; d++) { @@ -815,20 +802,19 @@ int ModApiEnvMod::l_find_node_near(lua_State *L) // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) { - GET_ENV_PTR; + GET_PLAIN_ENV_PTR; v3s16 minp = read_v3s16(L, 1); v3s16 maxp = read_v3s16(L, 2); sortBoxVerticies(minp, maxp); + const NodeDefManager *ndef = env->getGameDef()->ndef(); + #ifndef SERVER - const NodeDefManager *ndef = getClient(L) ? getClient(L)->ndef() : getServer(L)->ndef(); - if (getClient(L)) { - minp = getClient(L)->CSMClampPos(minp); - maxp = getClient(L)->CSMClampPos(maxp); + if (Client *client = getClient(L)) { + minp = client->CSMClampPos(minp); + maxp = client->CSMClampPos(maxp); } -#else - const NodeDefManager *ndef = getServer(L)->ndef(); #endif v3s16 cube = maxp - minp + 1; @@ -892,20 +878,19 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) * TODO */ - GET_ENV_PTR; + GET_PLAIN_ENV_PTR; v3s16 minp = read_v3s16(L, 1); v3s16 maxp = read_v3s16(L, 2); sortBoxVerticies(minp, maxp); + const NodeDefManager *ndef = env->getGameDef()->ndef(); + #ifndef SERVER - const NodeDefManager *ndef = getClient(L) ? getClient(L)->ndef() : getServer(L)->ndef(); - if (getClient(L)) { - minp = getClient(L)->CSMClampPos(minp); - maxp = getClient(L)->CSMClampPos(maxp); + if (Client *client = getClient(L)) { + minp = client->CSMClampPos(minp); + maxp = client->CSMClampPos(maxp); } -#else - const NodeDefManager *ndef = getServer(L)->ndef(); #endif v3s16 cube = maxp - minp + 1; @@ -1034,7 +1019,7 @@ int ModApiEnvMod::l_clear_objects(lua_State *L) // line_of_sight(pos1, pos2) -> true/false, pos int ModApiEnvMod::l_line_of_sight(lua_State *L) { - GET_ENV_PTR; + GET_PLAIN_ENV_PTR; // read position 1 from lua v3f pos1 = checkFloatPos(L, 1); @@ -1210,11 +1195,11 @@ int ModApiEnvMod::l_find_path(lua_State *L) algo = PA_DIJKSTRA; } - std::vector<v3s16> path = get_path(env, pos1, pos2, + std::vector<v3s16> path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2, searchdistance, max_jump, max_drop, algo); if (!path.empty()) { - lua_newtable(L); + lua_createtable(L, path.size(), 0); int top = lua_gettop(L); unsigned int index = 1; for (const v3s16 &i : path) { @@ -1274,8 +1259,9 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) else return 0; + ServerMap *map = &env->getServerMap(); treegen::error e; - if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) { + if ((e = treegen::spawn_ltree (map, p0, ndef, tree_def)) != treegen::SUCCESS) { if (e == treegen::UNBALANCED_BRACKETS) { luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); } else { @@ -1318,6 +1304,19 @@ int ModApiEnvMod::l_forceload_free_block(lua_State *L) return 0; } +// get_translated_string(lang_code, string) +int ModApiEnvMod::l_get_translated_string(lua_State * L) +{ + GET_ENV_PTR; + std::string lang_code = luaL_checkstring(L, 1); + std::string string = luaL_checkstring(L, 2); + getServer(L)->loadTranslationLanguage(lang_code); + string = wide_to_utf8(translate_string(utf8_to_wide(string), + &(*g_server_translations)[lang_code])); + lua_pushstring(L, string.c_str()); + return 1; +} + void ModApiEnvMod::Initialize(lua_State *L, int top) { API_FCT(set_node); @@ -1365,6 +1364,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(transforming_liquid_add); API_FCT(forceload_block); API_FCT(forceload_free_block); + API_FCT(get_translated_string); } void ModApiEnvMod::InitializeClient(lua_State *L, int top) diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index ac2f8b588..9050b4306 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -187,6 +187,9 @@ private: // stops forceloading a position static int l_forceload_free_block(lua_State *L); + // Get a string translated server side + static int l_get_translated_string(lua_State * L); + public: static void Initialize(lua_State *L, int top); static void InitializeClient(lua_State *L, int top); diff --git a/src/script/lua_api/l_http.cpp b/src/script/lua_api/l_http.cpp index 2ff651cb5..ec43bf174 100644 --- a/src/script/lua_api/l_http.cpp +++ b/src/script/lua_api/l_http.cpp @@ -83,6 +83,24 @@ void ModApiHttp::push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool setstringfield(L, -1, "data", res.data); } +// http_api.fetch_sync(HTTPRequest definition) +int ModApiHttp::l_http_fetch_sync(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + HTTPFetchRequest req; + read_http_fetch_request(L, req); + + infostream << "Mod performs HTTP request with URL " << req.url << std::endl; + + HTTPFetchResult res; + httpfetch_sync(req, res); + + push_http_fetch_result(L, res, true); + + return 1; +} + // http_api.fetch_async(HTTPRequest definition) int ModApiHttp::l_http_fetch_async(lua_State *L) { @@ -180,11 +198,42 @@ int ModApiHttp::l_request_http_api(lua_State *L) return 1; } + +int ModApiHttp::l_get_http_api(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + lua_newtable(L); + HTTP_API(fetch_async); + HTTP_API(fetch_async_get); + HTTP_API(fetch_sync); + + return 1; +} + #endif void ModApiHttp::Initialize(lua_State *L, int top) { #if USE_CURL - API_FCT(request_http_api); + + bool isMainmenu = false; +#ifndef SERVER + isMainmenu = ModApiBase::getGuiEngine(L) != nullptr; +#endif + + if (isMainmenu) { + API_FCT(get_http_api); + } else { + API_FCT(request_http_api); + } + +#endif +} + +void ModApiHttp::InitializeAsync(lua_State *L, int top) +{ +#if USE_CURL + API_FCT(get_http_api); #endif } diff --git a/src/script/lua_api/l_http.h b/src/script/lua_api/l_http.h index 3d9cdad29..de6e51b37 100644 --- a/src/script/lua_api/l_http.h +++ b/src/script/lua_api/l_http.h @@ -32,6 +32,9 @@ private: static void read_http_fetch_request(lua_State *L, HTTPFetchRequest &req); static void push_http_fetch_result(lua_State *L, HTTPFetchResult &res, bool completed = true); + // http_fetch_sync({url=, timeout=, post_data=}) + static int l_http_fetch_sync(lua_State *L); + // http_fetch_async({url=, timeout=, post_data=}) static int l_http_fetch_async(lua_State *L); @@ -40,8 +43,12 @@ private: // request_http_api() static int l_request_http_api(lua_State *L); + + // get_http_api() + static int l_get_http_api(lua_State *L); #endif public: static void Initialize(lua_State *L, int top); + static void InitializeAsync(lua_State *L, int top); }; diff --git a/src/script/lua_api/l_internal.h b/src/script/lua_api/l_internal.h index bbedfe46e..a86eeaf79 100644 --- a/src/script/lua_api/l_internal.h +++ b/src/script/lua_api/l_internal.h @@ -32,14 +32,39 @@ with this program; if not, write to the Free Software Foundation, Inc., #define luamethod_aliased(class, name, alias) {#name, class::l_##name}, {#alias, class::l_##name} #define API_FCT(name) registerFunction(L, #name, l_##name, top) -#define MAP_LOCK_REQUIRED -#define NO_MAP_LOCK_REQUIRED +// For future use +#define MAP_LOCK_REQUIRED ((void)0) +#define NO_MAP_LOCK_REQUIRED ((void)0) +/* In debug mode ensure no code tries to retrieve the server env when it isn't + * actually available (in CSM) */ +#if !defined(SERVER) && !defined(NDEBUG) +#define DEBUG_ASSERT_NO_CLIENTAPI \ + FATAL_ERROR_IF(getClient(L) != nullptr, "Tried " \ + "to retrieve ServerEnvironment on client") +#else +#define DEBUG_ASSERT_NO_CLIENTAPI ((void)0) +#endif + +// Retrieve ServerEnvironment pointer as `env` (no map lock) #define GET_ENV_PTR_NO_MAP_LOCK \ + DEBUG_ASSERT_NO_CLIENTAPI; \ ServerEnvironment *env = (ServerEnvironment *)getEnv(L); \ if (env == NULL) \ return 0 +// Retrieve ServerEnvironment pointer as `env` #define GET_ENV_PTR \ MAP_LOCK_REQUIRED; \ GET_ENV_PTR_NO_MAP_LOCK + +// Retrieve Environment pointer as `env` (no map lock) +#define GET_PLAIN_ENV_PTR_NO_MAP_LOCK \ + Environment *env = (Environment *)getEnv(L); \ + if (env == NULL) \ + return 0 + +// Retrieve Environment pointer as `env` +#define GET_PLAIN_ENV_PTR \ + MAP_LOCK_REQUIRED; \ + GET_PLAIN_ENV_PTR_NO_MAP_LOCK diff --git a/src/script/lua_api/l_inventory.cpp b/src/script/lua_api/l_inventory.cpp index 6e7afa4a4..e41b5cb41 100644 --- a/src/script/lua_api/l_inventory.cpp +++ b/src/script/lua_api/l_inventory.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_converter.h" #include "common/c_content.h" #include "server.h" +#include "server/serverinventorymgr.h" #include "remoteplayer.h" /* @@ -38,7 +39,7 @@ InvRef* InvRef::checkobject(lua_State *L, int narg) Inventory* InvRef::getinv(lua_State *L, InvRef *ref) { - return getServer(L)->getInventory(ref->m_loc); + return getServerInventoryMgr(L)->getInventory(ref->m_loc); } InventoryList* InvRef::getlist(lua_State *L, InvRef *ref, @@ -54,7 +55,7 @@ InventoryList* InvRef::getlist(lua_State *L, InvRef *ref, void InvRef::reportInventoryChange(lua_State *L, InvRef *ref) { // Inform other things that the inventory has changed - getServer(L)->setInventoryModified(ref->m_loc); + getServerInventoryMgr(L)->setInventoryModified(ref->m_loc); } // Exported functions @@ -487,7 +488,9 @@ int ModApiInventory::l_get_inventory(lua_State *L) { InventoryLocation loc; - std::string type = checkstringfield(L, 1, "type"); + lua_getfield(L, 1, "type"); + std::string type = luaL_checkstring(L, -1); + lua_pop(L, 1); if(type == "node"){ MAP_LOCK_REQUIRED; @@ -495,7 +498,7 @@ int ModApiInventory::l_get_inventory(lua_State *L) v3s16 pos = check_v3s16(L, -1); loc.setNodeMeta(pos); - if (getServer(L)->getInventory(loc) != NULL) + if (getServerInventoryMgr(L)->getInventory(loc) != NULL) InvRef::create(L, loc); else lua_pushnil(L); @@ -504,14 +507,16 @@ int ModApiInventory::l_get_inventory(lua_State *L) NO_MAP_LOCK_REQUIRED; if (type == "player") { - std::string name = checkstringfield(L, 1, "name"); - loc.setPlayer(name); + lua_getfield(L, 1, "name"); + loc.setPlayer(luaL_checkstring(L, -1)); + lua_pop(L, 1); } else if (type == "detached") { - std::string name = checkstringfield(L, 1, "name"); - loc.setDetached(name); + lua_getfield(L, 1, "name"); + loc.setDetached(luaL_checkstring(L, -1)); + lua_pop(L, 1); } - if (getServer(L)->getInventory(loc) != NULL) + if (getServerInventoryMgr(L)->getInventory(loc) != NULL) InvRef::create(L, loc); else lua_pushnil(L); @@ -526,7 +531,7 @@ int ModApiInventory::l_create_detached_inventory_raw(lua_State *L) NO_MAP_LOCK_REQUIRED; const char *name = luaL_checkstring(L, 1); std::string player = readParam<std::string>(L, 2, ""); - if (getServer(L)->createDetachedInventory(name, player) != NULL) { + if (getServerInventoryMgr(L)->createDetachedInventory(name, getServer(L)->idef(), player) != NULL) { InventoryLocation loc; loc.setDetached(name); InvRef::create(L, loc); @@ -541,7 +546,7 @@ int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L) { NO_MAP_LOCK_REQUIRED; const std::string &name = luaL_checkstring(L, 1); - lua_pushboolean(L, getServer(L)->removeDetachedInventory(name)); + lua_pushboolean(L, getServerInventoryMgr(L)->removeDetachedInventory(name)); return 1; } diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 0c174feca..d67cab76f 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemdef.h" #include "nodedef.h" #include "server.h" -#include "content_sao.h" #include "inventory.h" #include "log.h" @@ -38,6 +37,15 @@ int LuaItemStack::gc_object(lua_State *L) return 0; } +// __tostring metamethod +int LuaItemStack::mt_tostring(lua_State *L) +{ + LuaItemStack *o = checkobject(L, 1); + std::string itemstring = o->m_stack.getItemString(false); + lua_pushfstring(L, "ItemStack(\"%s\")", itemstring.c_str()); + return 1; +} + // is_empty(self) -> true/false int LuaItemStack::l_is_empty(lua_State *L) { @@ -434,12 +442,9 @@ int LuaItemStack::create(lua_State *L, const ItemStack &item) return 1; } -LuaItemStack* LuaItemStack::checkobject(lua_State *L, int narg) +LuaItemStack *LuaItemStack::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 *(LuaItemStack**)ud; // unbox pointer + return *(LuaItemStack **)luaL_checkudata(L, narg, className); } void LuaItemStack::Register(lua_State *L) @@ -449,9 +454,10 @@ void LuaItemStack::Register(lua_State *L) luaL_newmetatable(L, className); int metatable = lua_gettop(L); + // hide metatable from Lua getmetatable() 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); @@ -461,12 +467,16 @@ void LuaItemStack::Register(lua_State *L) lua_pushcfunction(L, gc_object); lua_settable(L, metatable); + lua_pushliteral(L, "__tostring"); + lua_pushcfunction(L, mt_tostring); + 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 (LuaItemStack(itemstack or itemstring or table or nil)) + // Can be created from Lua (ItemStack(itemstack or itemstring or table or nil)) lua_register(L, className, create_object); } @@ -522,7 +532,6 @@ int ModApiItemMod::l_register_item_raw(lua_State *L) lua_getfield(L, table, "name"); if(lua_isstring(L, -1)){ name = readParam<std::string>(L, -1); - verbosestream<<"register_item_raw: "<<name<<std::endl; } else { throw LuaError("register_item_raw: name is not defined or not a string"); } @@ -611,10 +620,21 @@ int ModApiItemMod::l_get_content_id(lua_State *L) NO_MAP_LOCK_REQUIRED; std::string name = luaL_checkstring(L, 1); + const IItemDefManager *idef = getGameDef(L)->getItemDefManager(); const NodeDefManager *ndef = getGameDef(L)->getNodeDefManager(); + + // If this is called at mod load time, NodeDefManager isn't aware of + // aliases yet, so we need to handle them manually + std::string alias_name = idef->getAlias(name); + content_t content_id; - if (!ndef->getId(name, content_id)) + if (alias_name != name) { + if (!ndef->getId(alias_name, content_id)) + throw LuaError("Unknown node: " + alias_name + + " (from alias " + name + ")"); + } else if (!ndef->getId(name, content_id)) { throw LuaError("Unknown node: " + name); + } lua_pushinteger(L, content_id); return 1; /* number of results */ diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h index 6fab58045..98744c071 100644 --- a/src/script/lua_api/l_item.h +++ b/src/script/lua_api/l_item.h @@ -34,6 +34,9 @@ private: // garbage collector static int gc_object(lua_State *L); + // __tostring metamethod + static int mt_tostring(lua_State *L); + // is_empty(self) -> true/false static int l_is_empty(lua_State *L); diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index 821b1cb66..851ede535 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -19,10 +19,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "l_localplayer.h" #include "l_internal.h" +#include "lua_api/l_item.h" #include "script/common/c_converter.h" #include "client/localplayer.h" #include "hud.h" #include "common/c_content.h" +#include "client/content_cao.h" LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m) { @@ -74,6 +76,26 @@ int LuaLocalPlayer::l_get_name(lua_State *L) return 1; } +// get_wield_index(self) +int LuaLocalPlayer::l_get_wield_index(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + + lua_pushinteger(L, player->getWieldIndex()); + return 1; +} + +// get_wielded_item(self) +int LuaLocalPlayer::l_get_wielded_item(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + + ItemStack selected_item; + player->getWieldedItem(&selected_item, nullptr); + LuaItemStack::create(L, selected_item); + return 1; +} + int LuaLocalPlayer::l_is_attached(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -130,6 +152,7 @@ int LuaLocalPlayer::l_swimming_vertical(lua_State *L) return 1; } +// get_physics_override(self) int LuaLocalPlayer::l_get_physics_override(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -150,14 +173,9 @@ int LuaLocalPlayer::l_get_physics_override(lua_State *L) lua_pushboolean(L, player->physics_override_sneak_glitch); lua_setfield(L, -2, "sneak_glitch"); - return 1; -} - -int LuaLocalPlayer::l_get_override_pos(lua_State *L) -{ - LocalPlayer *player = getobject(L, 1); + lua_pushboolean(L, player->physics_override_new_move); + lua_setfield(L, -2, "new_move"); - push_v3f(L, player->getPosition()); return 1; } @@ -193,14 +211,33 @@ int LuaLocalPlayer::l_get_last_look_horizontal(lua_State *L) return 1; } -int LuaLocalPlayer::l_get_key_pressed(lua_State *L) +// get_control(self) +int LuaLocalPlayer::l_get_control(lua_State *L) { LocalPlayer *player = getobject(L, 1); + const PlayerControl &c = player->getPlayerControl(); + + auto set = [L] (const char *name, bool value) { + lua_pushboolean(L, value); + lua_setfield(L, -2, name); + }; + + lua_createtable(L, 0, 12); + set("up", c.up); + set("down", c.down); + set("left", c.left); + set("right", c.right); + set("jump", c.jump); + set("aux1", c.aux1); + set("sneak", c.sneak); + set("zoom", c.zoom); + set("LMB", c.LMB); + set("RMB", c.RMB); - lua_pushinteger(L, player->last_keyPressed); return 1; } +// get_breath(self) int LuaLocalPlayer::l_get_breath(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -209,6 +246,7 @@ int LuaLocalPlayer::l_get_breath(lua_State *L) return 1; } +// get_pos(self) int LuaLocalPlayer::l_get_pos(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -217,6 +255,7 @@ int LuaLocalPlayer::l_get_pos(lua_State *L) return 1; } +// get_movement_acceleration(self) int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -234,6 +273,7 @@ int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L) return 1; } +// get_movement_speed(self) int LuaLocalPlayer::l_get_movement_speed(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -257,6 +297,7 @@ int LuaLocalPlayer::l_get_movement_speed(lua_State *L) return 1; } +// get_movement(self) int LuaLocalPlayer::l_get_movement(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -278,6 +319,13 @@ int LuaLocalPlayer::l_get_movement(lua_State *L) return 1; } +// get_armor_groups(self) +int LuaLocalPlayer::l_get_armor_groups(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + push_groups(L, player->getCAO()->getGroups()); + return 1; +} // hud_add(self, form) int LuaLocalPlayer::l_hud_add(lua_State *L) @@ -407,6 +455,8 @@ const luaL_Reg LuaLocalPlayer::methods[] = { luamethod(LuaLocalPlayer, get_velocity), luamethod(LuaLocalPlayer, get_hp), luamethod(LuaLocalPlayer, get_name), + luamethod(LuaLocalPlayer, get_wield_index), + luamethod(LuaLocalPlayer, get_wielded_item), luamethod(LuaLocalPlayer, is_attached), luamethod(LuaLocalPlayer, is_touching_ground), luamethod(LuaLocalPlayer, is_in_liquid), @@ -415,17 +465,19 @@ const luaL_Reg LuaLocalPlayer::methods[] = { luamethod(LuaLocalPlayer, is_climbing), luamethod(LuaLocalPlayer, swimming_vertical), luamethod(LuaLocalPlayer, get_physics_override), - luamethod(LuaLocalPlayer, get_override_pos), + // TODO: figure our if these are useful in any way luamethod(LuaLocalPlayer, get_last_pos), luamethod(LuaLocalPlayer, get_last_velocity), luamethod(LuaLocalPlayer, get_last_look_horizontal), luamethod(LuaLocalPlayer, get_last_look_vertical), - luamethod(LuaLocalPlayer, get_key_pressed), + // + luamethod(LuaLocalPlayer, get_control), luamethod(LuaLocalPlayer, get_breath), luamethod(LuaLocalPlayer, get_pos), luamethod(LuaLocalPlayer, get_movement_acceleration), luamethod(LuaLocalPlayer, get_movement_speed), luamethod(LuaLocalPlayer, get_movement), + luamethod(LuaLocalPlayer, get_armor_groups), luamethod(LuaLocalPlayer, hud_add), luamethod(LuaLocalPlayer, hud_remove), luamethod(LuaLocalPlayer, hud_change), diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h index 01de2ed4e..4413f2bdb 100644 --- a/src/script/lua_api/l_localplayer.h +++ b/src/script/lua_api/l_localplayer.h @@ -32,12 +32,21 @@ private: // garbage collector static int gc_object(lua_State *L); + // get_velocity(self) static int l_get_velocity(lua_State *L); + // get_hp(self) static int l_get_hp(lua_State *L); + // get_name(self) static int l_get_name(lua_State *L); + // get_wield_index(self) + static int l_get_wield_index(lua_State *L); + + // get_wielded_item(self) + static int l_get_wielded_item(lua_State *L); + static int l_is_attached(lua_State *L); static int l_is_touching_ground(lua_State *L); static int l_is_in_liquid(lua_State *L); @@ -54,18 +63,28 @@ private: static int l_get_last_velocity(lua_State *L); static int l_get_last_look_vertical(lua_State *L); static int l_get_last_look_horizontal(lua_State *L); - static int l_get_key_pressed(lua_State *L); + // get_control(self) + static int l_get_control(lua_State *L); + + // get_breath(self) static int l_get_breath(lua_State *L); + // get_pos(self) static int l_get_pos(lua_State *L); + // get_movement_acceleration(self) static int l_get_movement_acceleration(lua_State *L); + // get_movement_speed(self) static int l_get_movement_speed(lua_State *L); + // get_movement(self) static int l_get_movement(lua_State *L); + // get_armor_groups(self) + static int l_get_armor_groups(lua_State *L); + // hud_add(self, id, form) static int l_hud_add(lua_State *L); diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 76db7ed13..f32c477c2 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -280,8 +280,8 @@ int ModApiMainMenu::l_get_favorites(lua_State *L) { std::string listtype = "local"; - if (!lua_isnone(L,1)) { - listtype = luaL_checkstring(L,1); + if (!lua_isnone(L, 1)) { + listtype = luaL_checkstring(L, 1); } std::vector<ServerListSpec> servers; @@ -298,7 +298,7 @@ int ModApiMainMenu::l_get_favorites(lua_State *L) for (const Json::Value &server : servers) { - lua_pushnumber(L,index); + lua_pushnumber(L, index); lua_newtable(L); int top_lvl2 = lua_gettop(L); @@ -306,11 +306,11 @@ int ModApiMainMenu::l_get_favorites(lua_State *L) if (!server["clients"].asString().empty()) { std::string clients_raw = server["clients"].asString(); char* endptr = 0; - int numbervalue = strtol(clients_raw.c_str(),&endptr,10); + int numbervalue = strtol(clients_raw.c_str(), &endptr,10); if ((!clients_raw.empty()) && (*endptr == 0)) { - lua_pushstring(L,"clients"); - lua_pushnumber(L,numbervalue); + lua_pushstring(L, "clients"); + lua_pushnumber(L, numbervalue); lua_settable(L, top_lvl2); } } @@ -319,83 +319,83 @@ int ModApiMainMenu::l_get_favorites(lua_State *L) std::string clients_max_raw = server["clients_max"].asString(); char* endptr = 0; - int numbervalue = strtol(clients_max_raw.c_str(),&endptr,10); + int numbervalue = strtol(clients_max_raw.c_str(), &endptr,10); if ((!clients_max_raw.empty()) && (*endptr == 0)) { - lua_pushstring(L,"clients_max"); - lua_pushnumber(L,numbervalue); + lua_pushstring(L, "clients_max"); + lua_pushnumber(L, numbervalue); lua_settable(L, top_lvl2); } } if (!server["version"].asString().empty()) { - lua_pushstring(L,"version"); + lua_pushstring(L, "version"); std::string topush = server["version"].asString(); - lua_pushstring(L,topush.c_str()); + lua_pushstring(L, topush.c_str()); lua_settable(L, top_lvl2); } if (!server["proto_min"].asString().empty()) { - lua_pushstring(L,"proto_min"); + lua_pushstring(L, "proto_min"); lua_pushinteger(L, server["proto_min"].asInt()); lua_settable(L, top_lvl2); } if (!server["proto_max"].asString().empty()) { - lua_pushstring(L,"proto_max"); + lua_pushstring(L, "proto_max"); lua_pushinteger(L, server["proto_max"].asInt()); lua_settable(L, top_lvl2); } if (!server["password"].asString().empty()) { - lua_pushstring(L,"password"); + lua_pushstring(L, "password"); lua_pushboolean(L, server["password"].asBool()); lua_settable(L, top_lvl2); } if (!server["creative"].asString().empty()) { - lua_pushstring(L,"creative"); + lua_pushstring(L, "creative"); lua_pushboolean(L, server["creative"].asBool()); lua_settable(L, top_lvl2); } if (!server["damage"].asString().empty()) { - lua_pushstring(L,"damage"); + lua_pushstring(L, "damage"); lua_pushboolean(L, server["damage"].asBool()); lua_settable(L, top_lvl2); } if (!server["pvp"].asString().empty()) { - lua_pushstring(L,"pvp"); + lua_pushstring(L, "pvp"); lua_pushboolean(L, server["pvp"].asBool()); lua_settable(L, top_lvl2); } if (!server["description"].asString().empty()) { - lua_pushstring(L,"description"); + lua_pushstring(L, "description"); std::string topush = server["description"].asString(); - lua_pushstring(L,topush.c_str()); + lua_pushstring(L, topush.c_str()); lua_settable(L, top_lvl2); } if (!server["name"].asString().empty()) { - lua_pushstring(L,"name"); + lua_pushstring(L, "name"); std::string topush = server["name"].asString(); - lua_pushstring(L,topush.c_str()); + lua_pushstring(L, topush.c_str()); lua_settable(L, top_lvl2); } if (!server["address"].asString().empty()) { - lua_pushstring(L,"address"); + lua_pushstring(L, "address"); std::string topush = server["address"].asString(); - lua_pushstring(L,topush.c_str()); + lua_pushstring(L, topush.c_str()); lua_settable(L, top_lvl2); } if (!server["port"].asString().empty()) { - lua_pushstring(L,"port"); + lua_pushstring(L, "port"); std::string topush = server["port"].asString(); - lua_pushstring(L,topush.c_str()); + lua_pushstring(L, topush.c_str()); lua_settable(L, top_lvl2); } @@ -406,6 +406,37 @@ int ModApiMainMenu::l_get_favorites(lua_State *L) lua_settable(L, top_lvl2); } + if (server["clients_list"].isArray()) { + unsigned int index_lvl2 = 1; + lua_pushstring(L, "clients_list"); + lua_newtable(L); + int top_lvl3 = lua_gettop(L); + for (const Json::Value &client : server["clients_list"]) { + lua_pushnumber(L, index_lvl2); + std::string topush = client.asString(); + lua_pushstring(L, topush.c_str()); + lua_settable(L, top_lvl3); + index_lvl2++; + } + lua_settable(L, top_lvl2); + } + + if (server["mods"].isArray()) { + unsigned int index_lvl2 = 1; + lua_pushstring(L, "mods"); + lua_newtable(L); + int top_lvl3 = lua_gettop(L); + for (const Json::Value &mod : server["mods"]) { + + lua_pushnumber(L, index_lvl2); + std::string topush = mod.asString(); + lua_pushstring(L, topush.c_str()); + lua_settable(L, top_lvl3); + index_lvl2++; + } + lua_settable(L, top_lvl2); + } + lua_settable(L, top); index++; } @@ -571,9 +602,10 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L) sanity_check(engine != NULL); GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(RenderingEngine::get_gui_env(), - engine->m_parent, - -1, - engine->m_menumanager); + engine->m_parent, + -1, + engine->m_menumanager, + engine->m_texture_source); kmenu->drop(); return 0; } @@ -904,12 +936,12 @@ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L) GUIFileSelectMenu* fileOpenMenu = new GUIFileSelectMenu(RenderingEngine::get_gui_env(), - engine->m_parent, - -1, - engine->m_menumanager, - title, - formname, - is_file_select); + engine->m_parent, + -1, + engine->m_menumanager, + title, + formname, + is_file_select); fileOpenMenu->setTextDest(engine->m_buttonhandler); fileOpenMenu->drop(); return 0; @@ -1032,6 +1064,14 @@ int ModApiMainMenu::l_get_max_supp_proto(lua_State *L) } /******************************************************************************/ +int ModApiMainMenu::l_open_url(lua_State *L) +{ + std::string url = luaL_checkstring(L, 1); + lua_pushboolean(L, porting::openURL(url)); + return 1; +} + +/******************************************************************************/ int ModApiMainMenu::l_do_async_callback(lua_State *L) { GUIEngine* engine = getGuiEngine(L); @@ -1093,6 +1133,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(get_screen_info); API_FCT(get_min_supp_proto); API_FCT(get_max_supp_proto); + API_FCT(open_url); API_FCT(do_async_callback); } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index b2ca49320..5a16b3bfe 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -145,6 +145,9 @@ private: static int l_get_max_supp_proto(lua_State *L); + // other + static int l_open_url(lua_State *L); + // async static int l_do_async_callback(lua_State *L); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index cb0d6ac95..834938e56 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -91,13 +91,13 @@ struct EnumString ModApiMapgen::es_SchematicFormatType[] = {0, NULL}, }; -ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr); +ObjDef *get_objdef(lua_State *L, int index, const ObjDefManager *objmgr); Biome *get_or_load_biome(lua_State *L, int index, BiomeManager *biomemgr); Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef); size_t get_biome_list(lua_State *L, int index, - BiomeManager *biomemgr, std::unordered_set<u8> *biome_id_list); + BiomeManager *biomemgr, std::unordered_set<biome_t> *biome_id_list); Schematic *get_or_load_schematic(lua_State *L, int index, SchematicManager *schemmgr, StringMap *replace_names); @@ -114,7 +114,7 @@ bool read_deco_schematic(lua_State *L, SchematicManager *schemmgr, DecoSchematic /////////////////////////////////////////////////////////////////////////////// -ObjDef *get_objdef(lua_State *L, int index, ObjDefManager *objmgr) +ObjDef *get_objdef(lua_State *L, int index, const ObjDefManager *objmgr) { if (index < 0) index = lua_gettop(L) + 1 + index; @@ -425,7 +425,7 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef) size_t get_biome_list(lua_State *L, int index, - BiomeManager *biomemgr, std::unordered_set<u8> *biome_id_list) + BiomeManager *biomemgr, std::unordered_set<biome_t> *biome_id_list) { if (index < 0) index = lua_gettop(L) + 1 + index; @@ -486,11 +486,11 @@ int ModApiMapgen::l_get_biome_id(lua_State *L) if (!biome_str) return 0; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; - Biome *biome = (Biome *)bmgr->getByName(biome_str); + const Biome *biome = (Biome *)bmgr->getByName(biome_str); if (!biome || biome->index == OBJDEF_INVALID_INDEX) return 0; @@ -508,11 +508,11 @@ int ModApiMapgen::l_get_biome_name(lua_State *L) int biome_id = luaL_checkinteger(L, 1); - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; - Biome *b = (Biome *)bmgr->getRaw(biome_id); + const Biome *b = (Biome *)bmgr->getRaw(biome_id); lua_pushstring(L, b->name.c_str()); return 1; @@ -546,13 +546,11 @@ int ModApiMapgen::l_get_heat(lua_State *L) u64 seed; ss >> seed; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; float heat = bmgr->getHeatAtPosOriginal(pos, np_heat, np_heat_blend, seed); - if (!heat) - return 0; lua_pushnumber(L, heat); @@ -587,14 +585,12 @@ int ModApiMapgen::l_get_humidity(lua_State *L) u64 seed; ss >> seed; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; float humidity = bmgr->getHumidityAtPosOriginal(pos, np_humidity, np_humidity_blend, seed); - if (!humidity) - return 0; lua_pushnumber(L, humidity); @@ -635,7 +631,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L) u64 seed; ss >> seed; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + const BiomeManager *bmgr = getServer(L)->getEmergeManager()->getBiomeManager(); if (!bmgr) return 0; @@ -648,7 +644,7 @@ int ModApiMapgen::l_get_biome_data(lua_State *L) if (!humidity) return 0; - Biome *biome = (Biome *)bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos); + const Biome *biome = bmgr->getBiomeFromNoiseOriginal(heat, humidity, pos); if (!biome || biome->index == OBJDEF_INVALID_INDEX) return 0; @@ -710,7 +706,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) if (!mg->heightmap) return 0; - lua_newtable(L); + lua_createtable(L, maplen, 0); for (size_t i = 0; i != maplen; i++) { lua_pushinteger(L, mg->heightmap[i]); lua_rawseti(L, -2, i + 1); @@ -722,7 +718,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) if (!mg->biomegen) return 0; - lua_newtable(L); + lua_createtable(L, maplen, 0); for (size_t i = 0; i != maplen; i++) { lua_pushinteger(L, mg->biomegen->biomemap[i]); lua_rawseti(L, -2, i + 1); @@ -736,7 +732,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen; - lua_newtable(L); + lua_createtable(L, maplen, 0); for (size_t i = 0; i != maplen; i++) { lua_pushnumber(L, bg->heatmap[i]); lua_rawseti(L, -2, i + 1); @@ -751,7 +747,7 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) BiomeGenOriginal *bg = (BiomeGenOriginal *)mg->biomegen; - lua_newtable(L); + lua_createtable(L, maplen, 0); for (size_t i = 0; i != maplen; i++) { lua_pushnumber(L, bg->humidmap[i]); lua_rawseti(L, -2, i + 1); @@ -761,13 +757,12 @@ int ModApiMapgen::l_get_mapgen_object(lua_State *L) } 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); - lua_newtable(L); - for (it = event_map.begin(); it != event_map.end(); ++it) { - lua_newtable(L); + lua_createtable(L, 0, event_map.size()); + for (auto it = event_map.begin(); it != event_map.end(); ++it) { + lua_createtable(L, it->second.size(), 0); for (size_t j = 0; j != it->second.size(); j++) { push_v3s16(L, it->second[j]); @@ -1067,7 +1062,8 @@ int ModApiMapgen::l_get_decoration_id(lua_State *L) if (!deco_str) return 0; - DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr; + const DecorationManager *dmgr = + getServer(L)->getEmergeManager()->getDecorationManager(); if (!dmgr) return 0; @@ -1092,7 +1088,7 @@ int ModApiMapgen::l_register_biome(lua_State *L) luaL_checktype(L, index, LUA_TTABLE); const NodeDefManager *ndef = getServer(L)->getNodeDefManager(); - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + BiomeManager *bmgr = getServer(L)->getEmergeManager()->getWritableBiomeManager(); Biome *biome = read_biome_def(L, index, ndef); if (!biome) @@ -1118,9 +1114,10 @@ int ModApiMapgen::l_register_decoration(lua_State *L) luaL_checktype(L, index, LUA_TTABLE); const NodeDefManager *ndef = getServer(L)->getNodeDefManager(); - DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr; - BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + EmergeManager *emerge = getServer(L)->getEmergeManager(); + DecorationManager *decomgr = emerge->getWritableDecorationManager(); + BiomeManager *biomemgr = emerge->getWritableBiomeManager(); + SchematicManager *schemmgr = emerge->getWritableSchematicManager(); enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); @@ -1275,8 +1272,9 @@ int ModApiMapgen::l_register_ore(lua_State *L) luaL_checktype(L, index, LUA_TTABLE); const NodeDefManager *ndef = getServer(L)->getNodeDefManager(); - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; - OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; + EmergeManager *emerge = getServer(L)->getEmergeManager(); + BiomeManager *bmgr = emerge->getWritableBiomeManager(); + OreManager *oremgr = emerge->getWritableOreManager(); enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); @@ -1423,7 +1421,8 @@ int ModApiMapgen::l_register_schematic(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + SchematicManager *schemmgr = + getServer(L)->getEmergeManager()->getWritableSchematicManager(); StringMap replace_names; if (lua_istable(L, 2)) @@ -1450,7 +1449,8 @@ int ModApiMapgen::l_clear_registered_biomes(lua_State *L) { NO_MAP_LOCK_REQUIRED; - BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; + BiomeManager *bmgr = + getServer(L)->getEmergeManager()->getWritableBiomeManager(); bmgr->clear(); return 0; } @@ -1461,7 +1461,8 @@ int ModApiMapgen::l_clear_registered_decorations(lua_State *L) { NO_MAP_LOCK_REQUIRED; - DecorationManager *dmgr = getServer(L)->getEmergeManager()->decomgr; + DecorationManager *dmgr = + getServer(L)->getEmergeManager()->getWritableDecorationManager(); dmgr->clear(); return 0; } @@ -1472,7 +1473,8 @@ int ModApiMapgen::l_clear_registered_ores(lua_State *L) { NO_MAP_LOCK_REQUIRED; - OreManager *omgr = getServer(L)->getEmergeManager()->oremgr; + OreManager *omgr = + getServer(L)->getEmergeManager()->getWritableOreManager(); omgr->clear(); return 0; } @@ -1483,7 +1485,8 @@ int ModApiMapgen::l_clear_registered_schematics(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *smgr = getServer(L)->getEmergeManager()->schemmgr; + SchematicManager *smgr = + getServer(L)->getEmergeManager()->getWritableSchematicManager(); smgr->clear(); return 0; } @@ -1708,7 +1711,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + const SchematicManager *schemmgr = getServer(L)->getEmergeManager()->getSchematicManager(); //// Read options bool use_comments = getboolfield_default(L, 3, "lua_use_comments", false); @@ -1716,7 +1719,7 @@ int ModApiMapgen::l_serialize_schematic(lua_State *L) //// Get schematic bool was_loaded = false; - Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr); + const Schematic *schem = (Schematic *)get_objdef(L, 1, schemmgr); if (!schem) { schem = load_schematic(L, 1, NULL, NULL); was_loaded = true; @@ -1759,7 +1762,8 @@ int ModApiMapgen::l_read_schematic(lua_State *L) { NO_MAP_LOCK_REQUIRED; - SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; + const SchematicManager *schemmgr = + getServer(L)->getEmergeManager()->getSchematicManager(); //// Read options std::string write_yslice = getstringfield_default(L, 2, "write_yslice_prob", "all"); diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index 4a6a9ccf4..0bdc56fc5 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_base.h" +typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include + class ModApiMapgen : public ModApiBase { private: diff --git a/src/script/lua_api/l_metadata.cpp b/src/script/lua_api/l_metadata.cpp index 21002e6a7..61a25a761 100644 --- a/src/script/lua_api/l_metadata.cpp +++ b/src/script/lua_api/l_metadata.cpp @@ -153,7 +153,9 @@ int MetaDataRef::l_set_int(lua_State *L) MetaDataRef *ref = checkobject(L, 1); std::string name = luaL_checkstring(L, 2); int a = luaL_checkint(L, 3); - std::string str = itos(a); + std::string str; + if (a != 0) + str = itos(a); Metadata *meta = ref->getmeta(true); if (meta == NULL || str == meta->getString(name)) @@ -191,7 +193,9 @@ int MetaDataRef::l_set_float(lua_State *L) MetaDataRef *ref = checkobject(L, 1); std::string name = luaL_checkstring(L, 2); float a = readParam<float>(L, 3); - std::string str = ftos(a); + std::string str; + if (a != 0) + str = ftos(a); Metadata *meta = ref->getmeta(true); if (meta == NULL || str == meta->getString(name)) diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 229ce73db..57052cb42 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -55,11 +55,13 @@ Metadata* NodeMetaRef::getmeta(bool auto_create) void NodeMetaRef::clearMeta() { + SANITY_CHECK(!m_is_local); m_env->getMap().removeNodeMetadata(m_p); } void NodeMetaRef::reportMetadataChange(const std::string *name) { + SANITY_CHECK(!m_is_local); // NOTE: This same code is in rollback_interface.cpp // Inform other things that the metadata has changed NodeMetadata *meta = dynamic_cast<NodeMetadata*>(m_meta); diff --git a/src/script/lua_api/l_nodetimer.cpp b/src/script/lua_api/l_nodetimer.cpp index 15a59744f..c2df52c05 100644 --- a/src/script/lua_api/l_nodetimer.cpp +++ b/src/script/lua_api/l_nodetimer.cpp @@ -41,11 +41,9 @@ int NodeTimerRef::l_set(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; f32 t = readParam<float>(L,2); f32 e = readParam<float>(L,3); - env->getMap().setNodeTimer(NodeTimer(t, e, o->m_p)); + o->m_map->setNodeTimer(NodeTimer(t, e, o->m_p)); return 0; } @@ -53,10 +51,8 @@ int NodeTimerRef::l_start(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; f32 t = readParam<float>(L,2); - env->getMap().setNodeTimer(NodeTimer(t, 0, o->m_p)); + o->m_map->setNodeTimer(NodeTimer(t, 0, o->m_p)); return 0; } @@ -64,9 +60,7 @@ int NodeTimerRef::l_stop(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - env->getMap().removeNodeTimer(o->m_p); + o->m_map->removeNodeTimer(o->m_p); return 0; } @@ -74,10 +68,7 @@ int NodeTimerRef::l_is_started(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - - NodeTimer t = env->getMap().getNodeTimer(o->m_p); + NodeTimer t = o->m_map->getNodeTimer(o->m_p); lua_pushboolean(L,(t.timeout != 0)); return 1; } @@ -86,10 +77,7 @@ int NodeTimerRef::l_get_timeout(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - - NodeTimer t = env->getMap().getNodeTimer(o->m_p); + NodeTimer t = o->m_map->getNodeTimer(o->m_p); lua_pushnumber(L,t.timeout); return 1; } @@ -98,37 +86,21 @@ int NodeTimerRef::l_get_elapsed(lua_State *L) { MAP_LOCK_REQUIRED; NodeTimerRef *o = checkobject(L, 1); - ServerEnvironment *env = o->m_env; - if(env == NULL) return 0; - - NodeTimer t = env->getMap().getNodeTimer(o->m_p); + NodeTimer t = o->m_map->getNodeTimer(o->m_p); lua_pushnumber(L,t.elapsed); return 1; } - -NodeTimerRef::NodeTimerRef(v3s16 p, ServerEnvironment *env): - m_p(p), - m_env(env) -{ -} - // Creates an NodeTimerRef and leaves it on top of stack // Not callable from Lua; all references are created on the C side. -void NodeTimerRef::create(lua_State *L, v3s16 p, ServerEnvironment *env) +void NodeTimerRef::create(lua_State *L, v3s16 p, ServerMap *map) { - NodeTimerRef *o = new NodeTimerRef(p, env); + NodeTimerRef *o = new NodeTimerRef(p, map); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, className); lua_setmetatable(L, -2); } -void NodeTimerRef::set_null(lua_State *L) -{ - NodeTimerRef *o = checkobject(L, -1); - o->m_env = NULL; -} - void NodeTimerRef::Register(lua_State *L) { lua_newtable(L); diff --git a/src/script/lua_api/l_nodetimer.h b/src/script/lua_api/l_nodetimer.h index b894c5c8c..bbc975fd2 100644 --- a/src/script/lua_api/l_nodetimer.h +++ b/src/script/lua_api/l_nodetimer.h @@ -22,13 +22,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irr_v3d.h" #include "lua_api/l_base.h" -class ServerEnvironment; +class ServerMap; class NodeTimerRef : public ModApiBase { private: v3s16 m_p; - ServerEnvironment *m_env = nullptr; + ServerMap *m_map; static const char className[]; static const luaL_Reg methods[]; @@ -50,14 +50,12 @@ private: static int l_get_elapsed(lua_State *L); public: - NodeTimerRef(v3s16 p, ServerEnvironment *env); + NodeTimerRef(v3s16 p, ServerMap *map) : m_p(p), m_map(map) {} ~NodeTimerRef() = default; // Creates an NodeTimerRef and leaves it on top of stack // Not callable from Lua; all references are created on the C side. - static void create(lua_State *L, v3s16 p, ServerEnvironment *env); - - static void set_null(lua_State *L); + static void create(lua_State *L, v3s16 p, ServerMap *map); static void Register(lua_State *L); }; diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index e38d319f4..9aeb15709 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -171,9 +171,9 @@ int LuaPerlinNoiseMap::l_get_2d_map(lua_State *L) Noise *n = o->noise; n->perlinMap2D(p.X, p.Y); - lua_newtable(L); + lua_createtable(L, n->sy, 0); for (u32 y = 0; y != n->sy; y++) { - lua_newtable(L); + lua_createtable(L, n->sx, 0); for (u32 x = 0; x != n->sx; x++) { lua_pushnumber(L, n->result[i++]); lua_rawseti(L, -2, x + 1); @@ -200,7 +200,7 @@ int LuaPerlinNoiseMap::l_get_2d_map_flat(lua_State *L) if (use_buffer) lua_pushvalue(L, 3); else - lua_newtable(L); + lua_createtable(L, maplen, 0); for (size_t i = 0; i != maplen; i++) { lua_pushnumber(L, n->result[i]); @@ -224,11 +224,11 @@ int LuaPerlinNoiseMap::l_get_3d_map(lua_State *L) Noise *n = o->noise; n->perlinMap3D(p.X, p.Y, p.Z); - lua_newtable(L); + lua_createtable(L, n->sz, 0); for (u32 z = 0; z != n->sz; z++) { - lua_newtable(L); + lua_createtable(L, n->sy, 0); for (u32 y = 0; y != n->sy; y++) { - lua_newtable(L); + lua_createtable(L, n->sx, 0); for (u32 x = 0; x != n->sx; x++) { lua_pushnumber(L, n->result[i++]); lua_rawseti(L, -2, x + 1); @@ -260,7 +260,7 @@ int LuaPerlinNoiseMap::l_get_3d_map_flat(lua_State *L) if (use_buffer) lua_pushvalue(L, 3); else - lua_newtable(L); + lua_createtable(L, maplen, 0); for (size_t i = 0; i != maplen; i++) { lua_pushnumber(L, n->result[i]); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 23ed1ffe0..e7394133a 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -27,12 +27,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "log.h" #include "tool.h" -#include "serverobject.h" -#include "content_sao.h" #include "remoteplayer.h" #include "server.h" #include "hud.h" #include "scripting_server.h" +#include "server/luaentity_sao.h" +#include "server/player_sao.h" +#include "server/serverinventorymgr.h" /* ObjectRef @@ -50,6 +51,8 @@ ObjectRef* ObjectRef::checkobject(lua_State *L, int narg) ServerActiveObject* ObjectRef::getobject(ObjectRef *ref) { ServerActiveObject *co = ref->m_object; + if (co && co->isGone()) + return NULL; return co; } @@ -60,8 +63,6 @@ LuaEntitySAO* ObjectRef::getluaobject(ObjectRef *ref) return NULL; if (obj->getType() != ACTIVEOBJECT_TYPE_LUAENTITY) return NULL; - if (obj->isGone()) - return NULL; return (LuaEntitySAO*)obj; } @@ -72,8 +73,6 @@ PlayerSAO* ObjectRef::getplayersao(ObjectRef *ref) return NULL; if (obj->getType() != ACTIVEOBJECT_TYPE_PLAYER) return NULL; - if (obj->isGone()) - return NULL; return (PlayerSAO*)obj; } @@ -123,14 +122,7 @@ int ObjectRef::l_get_pos(lua_State *L) ObjectRef *ref = checkobject(L, 1); ServerActiveObject *co = getobject(ref); if (co == NULL) return 0; - v3f pos = co->getBasePosition() / BS; - lua_newtable(L); - lua_pushnumber(L, pos.X); - lua_setfield(L, -2, "x"); - lua_pushnumber(L, pos.Y); - lua_setfield(L, -2, "y"); - lua_pushnumber(L, pos.Z); - lua_setfield(L, -2, "z"); + push_v3f(L, co->getBasePosition() / BS); return 1; } @@ -139,7 +131,6 @@ int ObjectRef::l_set_pos(lua_State *L) { NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); - //LuaEntitySAO *co = getluaobject(ref); ServerActiveObject *co = getobject(ref); if (co == NULL) return 0; // pos @@ -154,7 +145,6 @@ int ObjectRef::l_move_to(lua_State *L) { NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); - //LuaEntitySAO *co = getluaobject(ref); ServerActiveObject *co = getobject(ref); if (co == NULL) return 0; // pos @@ -300,7 +290,7 @@ int ObjectRef::l_get_inventory(lua_State *L) if (co == NULL) return 0; // Do it InventoryLocation loc = co->getInventoryLocation(); - if (getServer(L)->getInventory(loc) != NULL) + if (getServerInventoryMgr(L)->getInventory(loc) != NULL) InvRef::create(L, loc); else lua_pushnil(L); // An object may have no inventory (nil) @@ -533,7 +523,7 @@ int ObjectRef::l_set_local_animation(lua_State *L) // get_local_animation(self) int ObjectRef::l_get_local_animation(lua_State *L) { - NO_MAP_LOCK_REQUIRED + NO_MAP_LOCK_REQUIRED; ObjectRef *ref = checkobject(L, 1); RemotePlayer *player = getplayer(ref); if (player == NULL) @@ -685,8 +675,13 @@ int ObjectRef::l_set_attach(lua_State *L) ServerActiveObject *parent = getobject(parent_ref); if (co == NULL) return 0; + if (parent == NULL) return 0; + + if (co == parent) + throw LuaError("ObjectRef::set_attach: attaching object to itself is not allowed."); + // Do it int parent_id = 0; std::string bone; @@ -1109,17 +1104,13 @@ int ObjectRef::l_add_player_velocity(lua_State *L) ObjectRef *ref = checkobject(L, 1); v3f vel = checkFloatPos(L, 2); - RemotePlayer *player = getplayer(ref); PlayerSAO *co = getplayersao(ref); - if (!player || !co) + if (!co) return 0; - session_t peer_id = player->getPeerId(); - if (peer_id == PEER_ID_INEXISTENT) - return 0; // Do it co->setMaxSpeedOverride(vel); - getServer(L)->SendPlayerSpeed(peer_id, vel); + getServer(L)->SendPlayerSpeed(co->getPeerID(), vel); return 0; } @@ -1259,7 +1250,7 @@ int ObjectRef::l_set_look_yaw(lua_State *L) return 1; } -// set_fov(self, degrees[, is_multiplier]) +// set_fov(self, degrees[, is_multiplier, transition_time]) int ObjectRef::l_set_fov(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -1268,7 +1259,11 @@ int ObjectRef::l_set_fov(lua_State *L) if (!player) return 0; - player->setFov({ static_cast<f32>(luaL_checknumber(L, 2)), readParam<bool>(L, 3) }); + player->setFov({ + static_cast<f32>(luaL_checknumber(L, 2)), + readParam<bool>(L, 3, false), + lua_isnumber(L, 4) ? static_cast<f32>(luaL_checknumber(L, 4)) : 0.0f + }); getServer(L)->SendPlayerFov(player->getPeerId()); return 0; @@ -1286,8 +1281,9 @@ int ObjectRef::l_get_fov(lua_State *L) PlayerFovSpec fov_spec = player->getFov(); lua_pushnumber(L, fov_spec.fov); lua_pushboolean(L, fov_spec.is_multiplier); + lua_pushnumber(L, fov_spec.transition_time); - return 2; + return 3; } // set_breath(self, breath) @@ -1463,6 +1459,8 @@ int ObjectRef::l_get_player_control(lua_State *L) lua_setfield(L, -2, "LMB"); lua_pushboolean(L, control.RMB); lua_setfield(L, -2, "RMB"); + lua_pushboolean(L, control.zoom); + lua_setfield(L, -2, "zoom"); return 1; } @@ -1787,19 +1785,19 @@ int ObjectRef::l_set_sky(lua_State *L) lua_pop(L, 1); // Prevent flickering clouds at dawn/dusk: - skybox_params.sun_tint = video::SColor(255, 255, 255, 255); + skybox_params.fog_sun_tint = video::SColor(255, 255, 255, 255); lua_getfield(L, -1, "fog_sun_tint"); - read_color(L, -1, &skybox_params.sun_tint); + read_color(L, -1, &skybox_params.fog_sun_tint); lua_pop(L, 1); - skybox_params.moon_tint = video::SColor(255, 255, 255, 255); + skybox_params.fog_moon_tint = video::SColor(255, 255, 255, 255); lua_getfield(L, -1, "fog_moon_tint"); - read_color(L, -1, &skybox_params.moon_tint); + read_color(L, -1, &skybox_params.fog_moon_tint); lua_pop(L, 1); lua_getfield(L, -1, "fog_tint_type"); if (!lua_isnil(L, -1)) - skybox_params.tint_type = luaL_checkstring(L, -1); + skybox_params.fog_tint_type = luaL_checkstring(L, -1); lua_pop(L, 1); // Because we need to leave the "sky_color" table. @@ -1917,12 +1915,12 @@ int ObjectRef::l_get_sky_color(lua_State *L) push_ARGB8(L, skybox_params.sky_color.indoors); lua_setfield(L, -2, "indoors"); } - push_ARGB8(L, skybox_params.sun_tint); - lua_setfield(L, -2, "sun_tint"); - push_ARGB8(L, skybox_params.moon_tint); - lua_setfield(L, -2, "moon_tint"); - lua_pushstring(L, skybox_params.tint_type.c_str()); - lua_setfield(L, -2, "tint_type"); + push_ARGB8(L, skybox_params.fog_sun_tint); + lua_setfield(L, -2, "fog_sun_tint"); + push_ARGB8(L, skybox_params.fog_moon_tint); + lua_setfield(L, -2, "fog_moon_tint"); + lua_pushstring(L, skybox_params.fog_tint_type.c_str()); + lua_setfield(L, -2, "fog_tint_type"); return 1; } @@ -2177,9 +2175,7 @@ int ObjectRef::l_override_day_night_ratio(lua_State *L) ratio = readParam<float>(L, 2); } - if (!getServer(L)->overrideDayNightRatio(player, do_override, ratio)) - return 0; - + getServer(L)->overrideDayNightRatio(player, do_override, ratio); lua_pushboolean(L, true); return 1; } diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp index 340903ebf..a51c4fe20 100644 --- a/src/script/lua_api/l_particles.cpp +++ b/src/script/lua_api/l_particles.cpp @@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_converter.h" #include "common/c_content.h" #include "server.h" -#include "client/particles.h" +#include "particles.h" // add_particle({pos=, velocity=, acceleration=, expirationtime=, // size=, collisiondetection=, collision_removal=, object_collision=, @@ -40,85 +40,88 @@ with this program; if not, write to the Free Software Foundation, Inc., // glow = num int ModApiParticles::l_add_particle(lua_State *L) { - MAP_LOCK_REQUIRED; + NO_MAP_LOCK_REQUIRED; // Get parameters - v3f pos, vel, acc; - float expirationtime, size; - expirationtime = size = 1; - bool collisiondetection, vertical, collision_removal, object_collision; - collisiondetection = vertical = collision_removal = object_collision = false; - struct TileAnimationParams animation; - animation.type = TAT_NONE; - std::string texture; + struct ParticleParameters p; std::string playername; - u8 glow = 0; if (lua_gettop(L) > 1) // deprecated { - 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); - expirationtime = luaL_checknumber(L, 4); - size = luaL_checknumber(L, 5); - collisiondetection = readParam<bool>(L, 6); - texture = luaL_checkstring(L, 7); + log_deprecated(L, "Deprecated add_particle call with " + "individual parameters instead of definition"); + p.pos = check_v3f(L, 1); + p.vel = check_v3f(L, 2); + p.acc = check_v3f(L, 3); + p.expirationtime = luaL_checknumber(L, 4); + p.size = luaL_checknumber(L, 5); + p.collisiondetection = readParam<bool>(L, 6); + p.texture = luaL_checkstring(L, 7); if (lua_gettop(L) == 8) // only spawn for a single player playername = luaL_checkstring(L, 8); } else if (lua_istable(L, 1)) { lua_getfield(L, 1, "pos"); - pos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(); + if (lua_istable(L, -1)) + p.pos = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "vel"); if (lua_istable(L, -1)) { - vel = check_v3f(L, -1); + p.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; + if (lua_istable(L, -1)) + p.vel = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "acc"); if (lua_istable(L, -1)) { - acc = check_v3f(L, -1); + p.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; + if (lua_istable(L, -1)) + p.acc = check_v3f(L, -1); 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); - collision_removal = getboolfield_default(L, 1, - "collision_removal", collision_removal); - object_collision = getboolfield_default(L, 1, - "object_collision", object_collision); - vertical = getboolfield_default(L, 1, "vertical", vertical); + p.expirationtime = getfloatfield_default(L, 1, "expirationtime", + p.expirationtime); + p.size = getfloatfield_default(L, 1, "size", p.size); + p.collisiondetection = getboolfield_default(L, 1, + "collisiondetection", p.collisiondetection); + p.collision_removal = getboolfield_default(L, 1, + "collision_removal", p.collision_removal); + p.object_collision = getboolfield_default(L, 1, + "object_collision", p.object_collision); + p.vertical = getboolfield_default(L, 1, "vertical", p.vertical); lua_getfield(L, 1, "animation"); - animation = read_animation_definition(L, -1); + p.animation = read_animation_definition(L, -1); lua_pop(L, 1); - texture = getstringfield_default(L, 1, "texture", ""); - playername = getstringfield_default(L, 1, "playername", ""); + p.texture = getstringfield_default(L, 1, "texture", p.texture); + p.glow = getintfield_default(L, 1, "glow", p.glow); + + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); - glow = getintfield_default(L, 1, "glow", 0); + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); + + playername = getstringfield_default(L, 1, "playername", ""); } - getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size, - collisiondetection, collision_removal, object_collision, vertical, - texture, animation, glow); + + getServer(L)->spawnParticle(playername, p); return 1; } @@ -146,84 +149,82 @@ int ModApiParticles::l_add_particle(lua_State *L) // glow = num int ModApiParticles::l_add_particlespawner(lua_State *L) { - MAP_LOCK_REQUIRED; + NO_MAP_LOCK_REQUIRED; // Get parameters - u16 amount = 1; - v3f minpos, maxpos, minvel, maxvel, minacc, maxacc; - float time, minexptime, maxexptime, minsize, maxsize; - time = minexptime = maxexptime = minsize = maxsize = 1; - bool collisiondetection, vertical, collision_removal, object_collision; - collisiondetection = vertical = collision_removal = object_collision = false; - struct TileAnimationParams animation; - animation.type = TAT_NONE; + ParticleSpawnerParameters p; ServerActiveObject *attached = NULL; - std::string texture; std::string playername; - u8 glow = 0; if (lua_gettop(L) > 1) //deprecated { - log_deprecated(L,"Deprecated add_particlespawner call with individual parameters instead of definition"); - amount = luaL_checknumber(L, 1); - time = luaL_checknumber(L, 2); - minpos = check_v3f(L, 3); - maxpos = check_v3f(L, 4); - minvel = check_v3f(L, 5); - maxvel = check_v3f(L, 6); - minacc = check_v3f(L, 7); - maxacc = check_v3f(L, 8); - minexptime = luaL_checknumber(L, 9); - maxexptime = luaL_checknumber(L, 10); - minsize = luaL_checknumber(L, 11); - maxsize = luaL_checknumber(L, 12); - collisiondetection = readParam<bool>(L, 13); - texture = luaL_checkstring(L, 14); + log_deprecated(L, "Deprecated add_particlespawner call with " + "individual parameters instead of definition"); + p.amount = luaL_checknumber(L, 1); + p.time = luaL_checknumber(L, 2); + p.minpos = check_v3f(L, 3); + p.maxpos = check_v3f(L, 4); + p.minvel = check_v3f(L, 5); + p.maxvel = check_v3f(L, 6); + p.minacc = check_v3f(L, 7); + p.maxacc = check_v3f(L, 8); + p.minexptime = luaL_checknumber(L, 9); + p.maxexptime = luaL_checknumber(L, 10); + p.minsize = luaL_checknumber(L, 11); + p.maxsize = luaL_checknumber(L, 12); + p.collisiondetection = readParam<bool>(L, 13); + p.texture = luaL_checkstring(L, 14); if (lua_gettop(L) == 15) // only spawn for a single player playername = luaL_checkstring(L, 15); } else if (lua_istable(L, 1)) { - amount = getintfield_default(L, 1, "amount", amount); - time = getfloatfield_default(L, 1, "time", time); + p.amount = getintfield_default(L, 1, "amount", p.amount); + p.time = getfloatfield_default(L, 1, "time", p.time); lua_getfield(L, 1, "minpos"); - minpos = lua_istable(L, -1) ? check_v3f(L, -1) : minpos; + if (lua_istable(L, -1)) + p.minpos = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "maxpos"); - maxpos = lua_istable(L, -1) ? check_v3f(L, -1) : maxpos; + if (lua_istable(L, -1)) + p.maxpos = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "minvel"); - minvel = lua_istable(L, -1) ? check_v3f(L, -1) : minvel; + if (lua_istable(L, -1)) + p.minvel = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "maxvel"); - maxvel = lua_istable(L, -1) ? check_v3f(L, -1) : maxvel; + if (lua_istable(L, -1)) + p.maxvel = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "minacc"); - minacc = lua_istable(L, -1) ? check_v3f(L, -1) : minacc; + if (lua_istable(L, -1)) + p.minacc = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "maxacc"); - maxacc = lua_istable(L, -1) ? check_v3f(L, -1) : maxacc; + if (lua_istable(L, -1)) + p.maxacc = check_v3f(L, -1); 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); - collision_removal = getboolfield_default(L, 1, - "collision_removal", collision_removal); - object_collision = getboolfield_default(L, 1, - "object_collision", object_collision); + p.minexptime = getfloatfield_default(L, 1, "minexptime", p.minexptime); + p.maxexptime = getfloatfield_default(L, 1, "maxexptime", p.maxexptime); + p.minsize = getfloatfield_default(L, 1, "minsize", p.minsize); + p.maxsize = getfloatfield_default(L, 1, "maxsize", p.maxsize); + p.collisiondetection = getboolfield_default(L, 1, + "collisiondetection", p.collisiondetection); + p.collision_removal = getboolfield_default(L, 1, + "collision_removal", p.collision_removal); + p.object_collision = getboolfield_default(L, 1, + "object_collision", p.object_collision); lua_getfield(L, 1, "animation"); - animation = read_animation_definition(L, -1); + p.animation = read_animation_definition(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "attached"); @@ -233,25 +234,20 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) attached = ObjectRef::getobject(ref); } - vertical = getboolfield_default(L, 1, "vertical", vertical); - texture = getstringfield_default(L, 1, "texture", ""); + p.vertical = getboolfield_default(L, 1, "vertical", p.vertical); + p.texture = getstringfield_default(L, 1, "texture", p.texture); playername = getstringfield_default(L, 1, "playername", ""); - glow = getintfield_default(L, 1, "glow", 0); + p.glow = getintfield_default(L, 1, "glow", p.glow); + + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); + + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); } - u32 id = getServer(L)->addParticleSpawner(amount, time, - minpos, maxpos, - minvel, maxvel, - minacc, maxacc, - minexptime, maxexptime, - minsize, maxsize, - collisiondetection, - collision_removal, - object_collision, - attached, - vertical, - texture, playername, - animation, glow); + u32 id = getServer(L)->addParticleSpawner(p, attached, playername); lua_pushnumber(L, id); return 1; @@ -261,7 +257,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) // player (string) is optional int ModApiParticles::l_delete_particlespawner(lua_State *L) { - MAP_LOCK_REQUIRED; + NO_MAP_LOCK_REQUIRED; // Get parameters u32 id = luaL_checknumber(L, 1); diff --git a/src/script/lua_api/l_particles_local.cpp b/src/script/lua_api/l_particles_local.cpp index a9bf55665..cc68b13a5 100644 --- a/src/script/lua_api/l_particles_local.cpp +++ b/src/script/lua_api/l_particles_local.cpp @@ -32,56 +32,51 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); // Get parameters - v3f pos, vel, acc; - float expirationtime, size; - bool collisiondetection, vertical, collision_removal; - - struct TileAnimationParams animation; - animation.type = TAT_NONE; - - std::string texture; - - u8 glow; + ParticleParameters p; lua_getfield(L, 1, "pos"); - pos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.pos = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "velocity"); - vel = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.vel = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "acceleration"); - acc = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.acc = check_v3f(L, -1); lua_pop(L, 1); - expirationtime = getfloatfield_default(L, 1, "expirationtime", 1); - size = getfloatfield_default(L, 1, "size", 1); - collisiondetection = getboolfield_default(L, 1, "collisiondetection", false); - collision_removal = getboolfield_default(L, 1, "collision_removal", false); - vertical = getboolfield_default(L, 1, "vertical", false); + p.expirationtime = getfloatfield_default(L, 1, "expirationtime", + p.expirationtime); + p.size = getfloatfield_default(L, 1, "size", p.size); + p.collisiondetection = getboolfield_default(L, 1, + "collisiondetection", p.collisiondetection); + p.collision_removal = getboolfield_default(L, 1, + "collision_removal", p.collision_removal); + p.object_collision = getboolfield_default(L, 1, + "object_collision", p.object_collision); + p.vertical = getboolfield_default(L, 1, "vertical", p.vertical); lua_getfield(L, 1, "animation"); - animation = read_animation_definition(L, -1); + p.animation = read_animation_definition(L, -1); lua_pop(L, 1); - texture = getstringfield_default(L, 1, "texture", ""); + p.texture = getstringfield_default(L, 1, "texture", p.texture); + p.glow = getintfield_default(L, 1, "glow", p.glow); + + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); - glow = getintfield_default(L, 1, "glow", 0); + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); ClientEvent *event = new ClientEvent(); - event->type = CE_SPAWN_PARTICLE; - event->spawn_particle.pos = new v3f (pos); - event->spawn_particle.vel = new v3f (vel); - event->spawn_particle.acc = new v3f (acc); - event->spawn_particle.expirationtime = expirationtime; - event->spawn_particle.size = size; - event->spawn_particle.collisiondetection = collisiondetection; - event->spawn_particle.collision_removal = collision_removal; - event->spawn_particle.vertical = vertical; - event->spawn_particle.texture = new std::string(texture); - event->spawn_particle.animation = animation; - event->spawn_particle.glow = glow; + event->type = CE_SPAWN_PARTICLE; + event->spawn_particle = new ParticleParameters(p); getClient(L)->pushToEventQueue(event); return 0; @@ -90,94 +85,76 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L) int ModApiParticlesLocal::l_add_particlespawner(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - // Get parameters - u16 amount; - v3f minpos, maxpos, minvel, maxvel, minacc, maxacc; - float time, minexptime, maxexptime, minsize, maxsize; - bool collisiondetection, vertical, collision_removal; - struct TileAnimationParams animation; - animation.type = TAT_NONE; - // TODO: Implement this when there is a way to get an objectref. - // ServerActiveObject *attached = NULL; - std::string texture; - u8 glow; + // Get parameters + ParticleSpawnerParameters p; - amount = getintfield_default(L, 1, "amount", 1); - time = getfloatfield_default(L, 1, "time", 1); + p.amount = getintfield_default(L, 1, "amount", p.amount); + p.time = getfloatfield_default(L, 1, "time", p.time); lua_getfield(L, 1, "minpos"); - minpos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.minpos = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "maxpos"); - maxpos = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.maxpos = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "minvel"); - minvel = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.minvel = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "maxvel"); - maxvel = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.maxvel = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "minacc"); - minacc = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.minacc = check_v3f(L, -1); lua_pop(L, 1); lua_getfield(L, 1, "maxacc"); - maxacc = lua_istable(L, -1) ? check_v3f(L, -1) : v3f(0, 0, 0); + if (lua_istable(L, -1)) + p.maxacc = check_v3f(L, -1); lua_pop(L, 1); - minexptime = getfloatfield_default(L, 1, "minexptime", 1); - maxexptime = getfloatfield_default(L, 1, "maxexptime", 1); - minsize = getfloatfield_default(L, 1, "minsize", 1); - maxsize = getfloatfield_default(L, 1, "maxsize", 1); - - collisiondetection = getboolfield_default(L, 1, "collisiondetection", false); - collision_removal = getboolfield_default(L, 1, "collision_removal", false); - vertical = getboolfield_default(L, 1, "vertical", false); + p.minexptime = getfloatfield_default(L, 1, "minexptime", p.minexptime); + p.maxexptime = getfloatfield_default(L, 1, "maxexptime", p.maxexptime); + p.minsize = getfloatfield_default(L, 1, "minsize", p.minsize); + p.maxsize = getfloatfield_default(L, 1, "maxsize", p.maxsize); + p.collisiondetection = getboolfield_default(L, 1, + "collisiondetection", p.collisiondetection); + p.collision_removal = getboolfield_default(L, 1, + "collision_removal", p.collision_removal); + p.object_collision = getboolfield_default(L, 1, + "object_collision", p.object_collision); lua_getfield(L, 1, "animation"); - animation = read_animation_definition(L, -1); + p.animation = read_animation_definition(L, -1); lua_pop(L, 1); - // TODO: Implement this when a way to get an objectref on the client is added -// lua_getfield(L, 1, "attached"); -// if (!lua_isnil(L, -1)) { -// ObjectRef *ref = ObjectRef::checkobject(L, -1); -// lua_pop(L, 1); -// attached = ObjectRef::getobject(ref); -// } + p.vertical = getboolfield_default(L, 1, "vertical", p.vertical); + p.texture = getstringfield_default(L, 1, "texture", p.texture); + p.glow = getintfield_default(L, 1, "glow", p.glow); + + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); - texture = getstringfield_default(L, 1, "texture", ""); - glow = getintfield_default(L, 1, "glow", 0); + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); u64 id = getClient(L)->getParticleManager()->generateSpawnerId(); auto event = new ClientEvent(); - event->type = CE_ADD_PARTICLESPAWNER; - event->add_particlespawner.amount = amount; - event->add_particlespawner.spawntime = time; - event->add_particlespawner.minpos = new v3f (minpos); - event->add_particlespawner.maxpos = new v3f (maxpos); - event->add_particlespawner.minvel = new v3f (minvel); - event->add_particlespawner.maxvel = new v3f (maxvel); - event->add_particlespawner.minacc = new v3f (minacc); - event->add_particlespawner.maxacc = new v3f (maxacc); - event->add_particlespawner.minexptime = minexptime; - event->add_particlespawner.maxexptime = maxexptime; - event->add_particlespawner.minsize = minsize; - event->add_particlespawner.maxsize = maxsize; - event->add_particlespawner.collisiondetection = collisiondetection; - event->add_particlespawner.collision_removal = collision_removal; - event->add_particlespawner.attached_id = 0; - event->add_particlespawner.vertical = vertical; - event->add_particlespawner.texture = new std::string(texture); - event->add_particlespawner.id = id; - event->add_particlespawner.animation = animation; - event->add_particlespawner.glow = glow; + event->type = CE_ADD_PARTICLESPAWNER; + event->add_particlespawner.p = new ParticleSpawnerParameters(p); + event->add_particlespawner.attached_id = 0; + event->add_particlespawner.id = id; getClient(L)->pushToEventQueue(event); lua_pushnumber(L, id); diff --git a/src/script/lua_api/l_particles_local.h b/src/script/lua_api/l_particles_local.h index 5dff153b3..d8bb2b1c6 100644 --- a/src/script/lua_api/l_particles_local.h +++ b/src/script/lua_api/l_particles_local.h @@ -18,6 +18,8 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#pragma once + #include "lua_api/l_base.h" class ModApiParticlesLocal : public ModApiBase diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 00e849cdf..6f934bb9d 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_converter.h" #include "common/c_content.h" #include "cpp_api/s_base.h" +#include "cpp_api/s_security.h" #include "server.h" #include "environment.h" #include "remoteplayer.h" @@ -138,52 +139,54 @@ int ModApiServer::l_get_player_ip(lua_State *L) // get_player_information(name) int ModApiServer::l_get_player_information(lua_State *L) { - NO_MAP_LOCK_REQUIRED; - const char * name = luaL_checkstring(L, 1); - RemotePlayer *player = dynamic_cast<ServerEnvironment *>(getEnv(L))->getPlayer(name); - if (player == NULL) { + + Server *server = getServer(L); + + const char *name = luaL_checkstring(L, 1); + RemotePlayer *player = server->getEnv().getPlayer(name); + if (!player) { lua_pushnil(L); // no such player return 1; } Address addr; - try - { - addr = getServer(L)->getPeerAddress(player->getPeerId()); - } catch(const con::PeerNotFoundException &) { + try { + addr = server->getPeerAddress(player->getPeerId()); + } catch (const con::PeerNotFoundException &) { dstream << FUNCTION_NAME << ": peer was not found" << std::endl; lua_pushnil(L); // error return 1; } - float min_rtt,max_rtt,avg_rtt,min_jitter,max_jitter,avg_jitter; + float min_rtt, max_rtt, avg_rtt, min_jitter, max_jitter, avg_jitter; ClientState state; u32 uptime; u16 prot_vers; - u8 ser_vers,major,minor,patch; - std::string vers_string; - -#define ERET(code) \ - if (!(code)) { \ - dstream << FUNCTION_NAME << ": peer was not found" << std::endl; \ - lua_pushnil(L); /* error */ \ - return 1; \ + u8 ser_vers, major, minor, patch; + std::string vers_string, lang_code; + + auto getConInfo = [&] (con::rtt_stat_type type, float *value) -> bool { + return server->getClientConInfo(player->getPeerId(), type, value); + }; + + bool have_con_info = + getConInfo(con::MIN_RTT, &min_rtt) && + getConInfo(con::MAX_RTT, &max_rtt) && + getConInfo(con::AVG_RTT, &avg_rtt) && + getConInfo(con::MIN_JITTER, &min_jitter) && + getConInfo(con::MAX_JITTER, &max_jitter) && + getConInfo(con::AVG_JITTER, &avg_jitter); + + bool r = server->getClientInfo(player->getPeerId(), &state, &uptime, + &ser_vers, &prot_vers, &major, &minor, &patch, &vers_string, + &lang_code); + if (!r) { + dstream << FUNCTION_NAME << ": peer was not found" << std::endl; + lua_pushnil(L); // error + return 1; } - ERET(getServer(L)->getClientConInfo(player->getPeerId(), con::MIN_RTT, &min_rtt)) - ERET(getServer(L)->getClientConInfo(player->getPeerId(), con::MAX_RTT, &max_rtt)) - ERET(getServer(L)->getClientConInfo(player->getPeerId(), con::AVG_RTT, &avg_rtt)) - ERET(getServer(L)->getClientConInfo(player->getPeerId(), con::MIN_JITTER, - &min_jitter)) - ERET(getServer(L)->getClientConInfo(player->getPeerId(), con::MAX_JITTER, - &max_jitter)) - ERET(getServer(L)->getClientConInfo(player->getPeerId(), con::AVG_JITTER, - &avg_jitter)) - - ERET(getServer(L)->getClientInfo(player->getPeerId(), &state, &uptime, &ser_vers, - &prot_vers, &major, &minor, &patch, &vers_string)) - lua_newtable(L); int table = lua_gettop(L); @@ -201,29 +204,31 @@ int ModApiServer::l_get_player_information(lua_State *L) } lua_settable(L, table); - lua_pushstring(L,"min_rtt"); - lua_pushnumber(L, min_rtt); - lua_settable(L, table); + if (have_con_info) { // may be missing + lua_pushstring(L, "min_rtt"); + lua_pushnumber(L, min_rtt); + lua_settable(L, table); - lua_pushstring(L,"max_rtt"); - lua_pushnumber(L, max_rtt); - lua_settable(L, table); + lua_pushstring(L, "max_rtt"); + lua_pushnumber(L, max_rtt); + lua_settable(L, table); - lua_pushstring(L,"avg_rtt"); - lua_pushnumber(L, avg_rtt); - lua_settable(L, table); + lua_pushstring(L, "avg_rtt"); + lua_pushnumber(L, avg_rtt); + lua_settable(L, table); - lua_pushstring(L,"min_jitter"); - lua_pushnumber(L, min_jitter); - lua_settable(L, table); + lua_pushstring(L, "min_jitter"); + lua_pushnumber(L, min_jitter); + lua_settable(L, table); - lua_pushstring(L,"max_jitter"); - lua_pushnumber(L, max_jitter); - lua_settable(L, table); + lua_pushstring(L, "max_jitter"); + lua_pushnumber(L, max_jitter); + lua_settable(L, table); - lua_pushstring(L,"avg_jitter"); - lua_pushnumber(L, avg_jitter); - lua_settable(L, table); + lua_pushstring(L, "avg_jitter"); + lua_pushnumber(L, avg_jitter); + lua_settable(L, table); + } lua_pushstring(L,"connection_uptime"); lua_pushnumber(L, uptime); @@ -237,6 +242,10 @@ int ModApiServer::l_get_player_information(lua_State *L) lua_pushnumber(L, player->formspec_version); lua_settable(L, table); + lua_pushstring(L, "lang_code"); + lua_pushstring(L, lang_code.c_str()); + lua_settable(L, table); + #ifndef NDEBUG lua_pushstring(L,"serialization_version"); lua_pushnumber(L, ser_vers); @@ -263,7 +272,6 @@ int ModApiServer::l_get_player_information(lua_State *L) lua_settable(L, table); #endif -#undef ERET return 1; } @@ -405,9 +413,6 @@ int ModApiServer::l_get_modnames(lua_State *L) 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. std::sort(modlist.begin(), modlist.end()); // Package them up for Lua @@ -467,6 +472,23 @@ int ModApiServer::l_sound_fade(lua_State *L) return 0; } +// dynamic_add_media(filepath) +int ModApiServer::l_dynamic_add_media(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + // Reject adding media before the server has started up + if (!getEnv(L)) + throw LuaError("Dynamic media cannot be added before server has started up"); + + std::string filepath = readParam<std::string>(L, 1); + CHECK_SECURE_PATH(L, filepath.c_str(), false); + + bool ok = getServer(L)->dynamicAddMedia(filepath); + lua_pushboolean(L, ok); + return 1; +} + // is_singleplayer() int ModApiServer::l_is_singleplayer(lua_State *L) { @@ -531,6 +553,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(sound_play); API_FCT(sound_stop); API_FCT(sound_fade); + API_FCT(dynamic_add_media); API_FCT(get_player_information); API_FCT(get_player_privs); diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 3aa1785a2..938bfa8ef 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -70,6 +70,9 @@ private: // sound_fade(handle, step, gain) static int l_sound_fade(lua_State *L); + // dynamic_add_media(filepath) + static int l_dynamic_add_media(lua_State *L); + // get_player_privs(name, text) static int l_get_player_privs(lua_State *L); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index ae3e5df3d..cd63e20c2 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -44,7 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // log([level,] text) // Writes a line to the logger. -// The one-argument version logs to infostream. +// The one-argument version logs to LL_NONE. // The two-argument version accepts a log level. // Either the special case "deprecated" for deprecation notices, or any specified in // Logger::stringToLevel(name). @@ -318,9 +318,13 @@ int ModApiUtil::l_decode_base64(lua_State *L) NO_MAP_LOCK_REQUIRED; size_t size; - const char *data = luaL_checklstring(L, 1, &size); + const char *d = luaL_checklstring(L, 1, &size); + const std::string data = std::string(d, size); + + if (!base64_is_valid(data)) + return 0; - std::string out = base64_decode(std::string(data, size)); + std::string out = base64_decode(data); lua_pushlstring(L, out.data(), out.size()); return 1; diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h index 5697aab15..9ff91bb53 100644 --- a/src/script/lua_api/l_util.h +++ b/src/script/lua_api/l_util.h @@ -37,7 +37,7 @@ private: // log([level,] text) // Writes a line to the logger. - // The one-argument version logs to infostream. + // The one-argument version logs to LL_NONE. // The two-argument version accepts a log level. static int l_log(lua_State *L); diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp index fd73d21d1..b99b1d98c 100644 --- a/src/script/lua_api/l_vmanip.cpp +++ b/src/script/lua_api/l_vmanip.cpp @@ -72,7 +72,7 @@ int LuaVoxelManip::l_get_data(lua_State *L) if (use_buffer) lua_pushvalue(L, 2); else - lua_newtable(L); + lua_createtable(L, volume, 0); for (u32 i = 0; i != volume; i++) { lua_Integer cid = vm->m_data[i].getContent(); @@ -261,7 +261,7 @@ int LuaVoxelManip::l_get_light_data(lua_State *L) u32 volume = vm->m_area.getVolume(); - lua_newtable(L); + lua_createtable(L, volume, 0); for (u32 i = 0; i != volume; i++) { lua_Integer light = vm->m_data[i].param1; lua_pushinteger(L, light); @@ -309,7 +309,7 @@ int LuaVoxelManip::l_get_param2_data(lua_State *L) if (use_buffer) lua_pushvalue(L, 2); else - lua_newtable(L); + lua_createtable(L, volume, 0); for (u32 i = 0; i != volume; i++) { lua_Integer param2 = vm->m_data[i].param2; diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp index 1288b1df7..6643a9509 100644 --- a/src/script/scripting_client.cpp +++ b/src/script/scripting_client.cpp @@ -55,9 +55,6 @@ ClientScripting::ClientScripting(Client *client): InitializeModApi(L, top); lua_pop(L, 1); - if (client->getMinimap()) - LuaMinimap::create(L, client->getMinimap()); - // Push builtin initialization type lua_pushstring(L, "client"); lua_setglobal(L, "INIT"); @@ -94,3 +91,8 @@ void ClientScripting::on_camera_ready(Camera *camera) { LuaCamera::create(getStack(), camera); } + +void ClientScripting::on_minimap_ready(Minimap *minimap) +{ + LuaMinimap::create(getStack(), minimap); +} diff --git a/src/script/scripting_client.h b/src/script/scripting_client.h index cfecfa165..3088029f0 100644 --- a/src/script/scripting_client.h +++ b/src/script/scripting_client.h @@ -28,6 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc., class Client; class LocalPlayer; class Camera; +class Minimap; + class ClientScripting: virtual public ScriptApiBase, public ScriptApiSecurity, @@ -38,6 +40,7 @@ public: ClientScripting(Client *client); void on_client_ready(LocalPlayer *localplayer); void on_camera_ready(Camera *camera); + void on_minimap_ready(Minimap *minimap); private: virtual void InitializeModApi(lua_State *L, int top); diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp index b6068439a..0f672f917 100644 --- a/src/script/scripting_mainmenu.cpp +++ b/src/script/scripting_mainmenu.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content/mods.h" #include "cpp_api/s_internal.h" #include "lua_api/l_base.h" +#include "lua_api/l_http.h" #include "lua_api/l_mainmenu.h" #include "lua_api/l_sound.h" #include "lua_api/l_util.h" @@ -67,10 +68,12 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top) ModApiMainMenu::Initialize(L, top); ModApiUtil::Initialize(L, top); ModApiSound::Initialize(L, top); + ModApiHttp::Initialize(L, top); asyncEngine.registerStateInitializer(registerLuaClasses); asyncEngine.registerStateInitializer(ModApiMainMenu::InitializeAsync); asyncEngine.registerStateInitializer(ModApiUtil::InitializeAsync); + asyncEngine.registerStateInitializer(ModApiHttp::InitializeAsync); // Initialize async environment //TODO possibly make number of async threads configurable diff --git a/src/script/scripting_server.cpp b/src/script/scripting_server.cpp index cbf229640..85411ded4 100644 --- a/src/script/scripting_server.cpp +++ b/src/script/scripting_server.cpp @@ -62,6 +62,10 @@ ServerScripting::ServerScripting(Server* server): if (g_settings->getBool("secure.enable_security")) { initializeSecurity(); + } else { + warningstream << "\\!/ Mod security should never be disabled, as it allows any mod to " + << "access the host machine." + << "Mods should use minetest.request_insecure_environment() instead \\!/" << std::endl; } lua_getglobal(L, "core"); |