]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/script/lua_api/l_env.cpp
Drop content_sao.{cpp,h}
[dragonfireclient.git] / src / script / lua_api / l_env.cpp
index 94edf201e25ff572eb90f2d73d2c9268912604f4..40e50e64a81ee8803928bd12fb6662a963d14fc8 100644 (file)
@@ -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,14 +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 "treegen.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"
 #ifndef SERVER
-#include "client.h"
+#include "client/client.h"
 #endif
 
 struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
@@ -139,10 +140,12 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
 
 int LuaRaycast::l_next(lua_State *L)
 {
-       MAP_LOCK_REQUIRED;
+       GET_PLAIN_ENV_PTR;
 
-       ScriptApiItem *script = getScriptApi<ScriptApiItem>(L);
-       GET_ENV_PTR;
+       bool csm = false;
+#ifndef SERVER
+       csm = getClient(L) != nullptr;
+#endif
 
        LuaRaycast *o = checkobject(L, 1);
        PointedThing pointed;
@@ -150,7 +153,7 @@ int LuaRaycast::l_next(lua_State *L)
        if (pointed.type == POINTEDTHING_NOTHING)
                lua_pushnil(L);
        else
-               script->pushPointedThing(pointed);
+               push_pointed_thing(L, pointed, csm, true);
 
        return 1;
 }
@@ -165,10 +168,10 @@ int LuaRaycast::create_object(lua_State *L)
        v3f pos1 = checkFloatPos(L, 1);
        v3f pos2 = checkFloatPos(L, 2);
        if (lua_isboolean(L, 3)) {
-               objects = lua_toboolean(L, 3);
+               objects = readParam<bool>(L, 3);
        }
        if (lua_isboolean(L, 4)) {
-               liquids = lua_toboolean(L, 4);
+               liquids = readParam<bool>(L, 4);
        }
 
        LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
@@ -263,7 +266,7 @@ int ModApiEnvMod::l_set_node(lua_State *L)
 {
        GET_ENV_PTR;
 
-       INodeDefManager *ndef = env->getGameDef()->ndef();
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
        // parameters
        v3s16 pos = read_v3s16(L, 1);
        MapNode n = readnode(L, 2, ndef);
@@ -273,6 +276,39 @@ int ModApiEnvMod::l_set_node(lua_State *L)
        return 1;
 }
 
+// bulk_set_node([pos1, pos2, ...], node)
+// pos = {x=num, y=num, z=num}
+int ModApiEnvMod::l_bulk_set_node(lua_State *L)
+{
+       GET_ENV_PTR;
+
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
+       // parameters
+       if (!lua_istable(L, 1)) {
+               return 0;
+       }
+
+       s32 len = lua_objlen(L, 1);
+       if (len == 0) {
+               lua_pushboolean(L, true);
+               return 1;
+       }
+
+       MapNode n = readnode(L, 2, ndef);
+
+       // Do it
+       bool succeeded = true;
+       for (s32 i = 1; i <= len; i++) {
+               lua_rawgeti(L, 1, i);
+               if (!env->setNode(read_v3s16(L, -1), n))
+                       succeeded = false;
+               lua_pop(L, 1);
+       }
+
+       lua_pushboolean(L, succeeded);
+       return 1;
+}
+
 int ModApiEnvMod::l_add_node(lua_State *L)
 {
        return l_set_node(L);
@@ -298,7 +334,7 @@ int ModApiEnvMod::l_swap_node(lua_State *L)
 {
        GET_ENV_PTR;
 
-       INodeDefManager *ndef = env->getGameDef()->ndef();
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
        // parameters
        v3s16 pos = read_v3s16(L, 1);
        MapNode n = readnode(L, 2, ndef);
@@ -317,7 +353,7 @@ int ModApiEnvMod::l_get_node(lua_State *L)
        // pos
        v3s16 pos = read_v3s16(L, 1);
        // Do it
-       MapNode n = env->getMap().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        // Return node
        pushnode(L, n, env->getGameDef()->ndef());
        return 1;
@@ -333,7 +369,7 @@ int ModApiEnvMod::l_get_node_or_nil(lua_State *L)
        v3s16 pos = read_v3s16(L, 1);
        // Do it
        bool pos_ok;
-       MapNode n = env->getMap().getNodeNoEx(pos, &pos_ok);
+       MapNode n = env->getMap().getNode(pos, &pos_ok);
        if (pos_ok) {
                // Return node
                pushnode(L, n, env->getGameDef()->ndef());
@@ -348,7 +384,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);
@@ -359,9 +395,9 @@ int ModApiEnvMod::l_get_node_light(lua_State *L)
        u32 dnr = time_to_daynight_ratio(time_of_day, true);
 
        bool is_position_ok;
-       MapNode n = env->getMap().getNodeNoEx(pos, &is_position_ok);
+       MapNode n = env->getMap().getNode(pos, &is_position_ok);
        if (is_position_ok) {
-               INodeDefManager *ndef = env->getGameDef()->ndef();
+               const NodeDefManager *ndef = env->getGameDef()->ndef();
                lua_pushinteger(L, n.getLightBlend(dnr, ndef));
        } else {
                lua_pushnil(L);
@@ -377,14 +413,14 @@ int ModApiEnvMod::l_place_node(lua_State *L)
 
        ScriptApiItem *scriptIfaceItem = getScriptApi<ScriptApiItem>(L);
        Server *server = getServer(L);
-       INodeDefManager *ndef = server->ndef();
+       const NodeDefManager *ndef = server->ndef();
        IItemDefManager *idef = server->idef();
 
        v3s16 pos = read_v3s16(L, 1);
        MapNode n = readnode(L, 2, ndef);
 
        // Don't attempt to load non-loaded area as of now
-       MapNode n_old = env->getMap().getNodeNoEx(pos);
+       MapNode n_old = env->getMap().getNode(pos);
        if(n_old.getContent() == CONTENT_IGNORE){
                lua_pushboolean(L, false);
                return 1;
@@ -396,9 +432,8 @@ int ModApiEnvMod::l_place_node(lua_State *L)
        pointed.type = POINTEDTHING_NODE;
        pointed.node_abovesurface = pos;
        pointed.node_undersurface = pos + v3s16(0,-1,0);
-       // Place it with a NULL placer (appears in Lua as a non-functional
-       // ObjectRef)
-       bool success = scriptIfaceItem->item_OnPlace(item, NULL, pointed);
+       // Place it with a NULL placer (appears in Lua as nil)
+       bool success = scriptIfaceItem->item_OnPlace(item, nullptr, pointed);
        lua_pushboolean(L, success);
        return 1;
 }
@@ -414,7 +449,7 @@ int ModApiEnvMod::l_dig_node(lua_State *L)
        v3s16 pos = read_v3s16(L, 1);
 
        // Don't attempt to load non-loaded area as of now
-       MapNode n = env->getMap().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        if(n.getContent() == CONTENT_IGNORE){
                lua_pushboolean(L, false);
                return 1;
@@ -437,7 +472,7 @@ int ModApiEnvMod::l_punch_node(lua_State *L)
        v3s16 pos = read_v3s16(L, 1);
 
        // Don't attempt to load non-loaded area as of now
-       MapNode n = env->getMap().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        if(n.getContent() == CONTENT_IGNORE){
                lua_pushboolean(L, false);
                return 1;
@@ -453,13 +488,10 @@ 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().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
        return 1;
 }
@@ -468,13 +500,10 @@ 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().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
        return 1;
 }
@@ -490,7 +519,7 @@ int ModApiEnvMod::l_set_node_level(lua_State *L)
        u8 level = 1;
        if(lua_isnumber(L, 2))
                level = lua_tonumber(L, 2);
-       MapNode n = env->getMap().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        lua_pushnumber(L, n.setLevel(env->getGameDef()->ndef(), level));
        env->setNode(pos, n);
        return 1;
@@ -507,7 +536,7 @@ int ModApiEnvMod::l_add_node_level(lua_State *L)
        u8 level = 1;
        if(lua_isnumber(L, 2))
                level = lua_tonumber(L, 2);
-       MapNode n = env->getMap().getNodeNoEx(pos);
+       MapNode n = env->getMap().getNode(pos);
        lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
        env->setNode(pos, n);
        return 1;
@@ -516,7 +545,7 @@ 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));
@@ -605,6 +634,31 @@ int ModApiEnvMod::l_add_item(lua_State *L)
        return 1;
 }
 
+// get_connected_players()
+int ModApiEnvMod::l_get_connected_players(lua_State *L)
+{
+       ServerEnvironment *env = (ServerEnvironment *) getEnv(L);
+       if (!env) {
+               log_deprecated(L, "Calling get_connected_players() at mod load time"
+                               " is deprecated");
+               lua_createtable(L, 0, 0);
+               return 1;
+       }
+
+       lua_createtable(L, env->getPlayerCount(), 0);
+       u32 i = 0;
+       for (RemotePlayer *player : env->getPlayers()) {
+               if (player->getPeerId() == PEER_ID_INEXISTENT)
+                       continue;
+               PlayerSAO *sao = player->getPlayerSAO();
+               if (sao && !sao->isGone()) {
+                       getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
+                       lua_rawseti(L, -2, ++i);
+               }
+       }
+       return 1;
+}
+
 // get_player_by_name(name)
 int ModApiEnvMod::l_get_player_by_name(lua_State *L)
 {
@@ -612,16 +666,12 @@ int ModApiEnvMod::l_get_player_by_name(lua_State *L)
 
        // Do it
        const char *name = luaL_checkstring(L, 1);
-       RemotePlayer *player = dynamic_cast<RemotePlayer *>(env->getPlayer(name));
-       if (player == NULL){
-               lua_pushnil(L);
-               return 1;
-       }
+       RemotePlayer *player = env->getPlayer(name);
+       if (!player || player->getPeerId() == PEER_ID_INEXISTENT)
+               return 0;
        PlayerSAO *sao = player->getPlayerSAO();
-       if(sao == NULL){
-               lua_pushnil(L);
-               return 1;
-       }
+       if (!sao || sao->isGone())
+               return 0;
        // Put player on stack
        getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
        return 1;
@@ -634,7 +684,7 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
 
        // Do it
        v3f pos = checkFloatPos(L, 1);
-       float radius = luaL_checknumber(L, 2) * BS;
+       float radius = readParam<float>(L, 2) * BS;
        std::vector<u16> ids;
        env->getObjectsInsideRadius(ids, pos, radius);
        ScriptApiBase *script = getScriptApiBase(L);
@@ -642,9 +692,11 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
        std::vector<u16>::const_iterator iter = ids.begin();
        for(u32 i = 0; iter != ids.end(); ++iter) {
                ServerActiveObject *obj = env->getActiveObject(*iter);
-               // Insert object reference into table
-               script->objectrefGetOrCreate(L, obj);
-               lua_rawseti(L, -2, ++i);
+               if (!obj->isGone()) {
+                       // Insert object reference into table
+                       script->objectrefGetOrCreate(L, obj);
+                       lua_rawseti(L, -2, ++i);
+               }
        }
        return 1;
 }
@@ -656,7 +708,7 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L)
        GET_ENV_PTR;
 
        // Do it
-       float timeofday_f = luaL_checknumber(L, 1);
+       float timeofday_f = readParam<float>(L, 1);
        sanity_check(timeofday_f >= 0.0 && timeofday_f <= 1.0);
        int timeofday_mh = (int)(timeofday_f * 24000.0);
        // This should be set directly in the environment but currently
@@ -670,10 +722,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();
@@ -685,10 +734,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;
@@ -709,44 +755,39 @@ 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;
 
-       INodeDefManager *ndef = getGameDef(L)->ndef();
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
        v3s16 pos = read_v3s16(L, 1);
        int radius = luaL_checkinteger(L, 2);
-       std::set<content_t> filter;
+       std::vector<content_t> filter;
        if (lua_istable(L, 3)) {
                lua_pushnil(L);
                while (lua_next(L, 3) != 0) {
                        // key at index -2 and value at index -1
                        luaL_checktype(L, -1, LUA_TSTRING);
-                       ndef->getIds(lua_tostring(L, -1), filter);
+                       ndef->getIds(readParam<std::string>(L, -1), filter);
                        // removes value, keeps key for next iteration
                        lua_pop(L, 1);
                }
        } else if (lua_isstring(L, 3)) {
-               ndef->getIds(lua_tostring(L, 3), filter);
+               ndef->getIds(readParam<std::string>(L, 3), filter);
        }
 
-       int start_radius = (lua_toboolean(L, 4)) ? 0 : 1;
+       int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
 
 #ifndef SERVER
        // Client API limitations
-       if (getClient(L) &&
-                       getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_LOOKUP_NODES)) {
-               radius = std::max<int>(radius, getClient(L)->getCSMNodeRangeLimit());
-       }
+       if (getClient(L))
+               radius = getClient(L)->CSMClampRadius(pos, radius);
 #endif
 
        for (int d = start_radius; d <= radius; d++) {
                std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
-               for (v3s16 i : list) {
+               for (const v3s16 &i : list) {
                        v3s16 p = pos + i;
-                       content_t c = env->getMap().getNodeNoEx(p).getContent();
-                       if (filter.count(c) != 0) {
+                       content_t c = env->getMap().getNode(p).getContent();
+                       if (CONTAINS(filter, c)) {
                                push_v3s16(L, p);
                                return 1;
                        }
@@ -759,40 +800,45 @@ 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;
 
-       INodeDefManager *ndef = getServer(L)->ndef();
        v3s16 minp = read_v3s16(L, 1);
        v3s16 maxp = read_v3s16(L, 2);
        sortBoxVerticies(minp, maxp);
 
-       v3s16 cube = maxp - minp + 1;
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
 
-       /* Limit for too large areas, assume default values
-        * and give tolerances of 1 node on each side
-        * (chunksize * MAP_BLOCKSIZE + 2)^3 = 551368
-       */
-       if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 551368) {
+#ifndef SERVER
+       if (getClient(L)) {
+               minp = getClient(L)->CSMClampPos(minp);
+               maxp = getClient(L)->CSMClampPos(maxp);
+       }
+#endif
+
+       v3s16 cube = maxp - minp + 1;
+       // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+       if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
                luaL_error(L, "find_nodes_in_area(): area volume"
-                               " exceeds allowed value of 551368");
+                               " exceeds allowed value of 4096000");
                return 0;
        }
 
-       std::set<content_t> filter;
+       std::vector<content_t> filter;
        if (lua_istable(L, 3)) {
                lua_pushnil(L);
                while (lua_next(L, 3) != 0) {
                        // key at index -2 and value at index -1
                        luaL_checktype(L, -1, LUA_TSTRING);
-                       ndef->getIds(lua_tostring(L, -1), filter);
+                       ndef->getIds(readParam<std::string>(L, -1), filter);
                        // removes value, keeps key for next iteration
                        lua_pop(L, 1);
                }
        } else if (lua_isstring(L, 3)) {
-               ndef->getIds(lua_tostring(L, 3), filter);
+               ndef->getIds(readParam<std::string>(L, 3), filter);
        }
 
-       std::unordered_map<content_t, u32> individual_count;
+       std::vector<u32> individual_count;
+       individual_count.resize(filter.size());
 
        lua_newtable(L);
        u64 i = 0;
@@ -800,17 +846,21 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
        for (s16 y = minp.Y; y <= maxp.Y; y++)
        for (s16 z = minp.Z; z <= maxp.Z; z++) {
                v3s16 p(x, y, z);
-               content_t c = env->getMap().getNodeNoEx(p).getContent();
-               if (filter.count(c) != 0) {
+               content_t c = env->getMap().getNode(p).getContent();
+
+               std::vector<content_t>::iterator it = std::find(filter.begin(), filter.end(), c);
+               if (it != filter.end()) {
                        push_v3s16(L, p);
                        lua_rawseti(L, -2, ++i);
-                       individual_count[c]++;
+
+                       u32 filt_index = it - filter.begin();
+                       individual_count[filt_index]++;
                }
        }
        lua_newtable(L);
-       for (content_t it : filter) {
-               lua_pushnumber(L, individual_count[it]);
-               lua_setfield(L, -2, ndef->get(it).name.c_str());
+       for (u32 i = 0; i < filter.size(); i++) {
+               lua_pushnumber(L, individual_count[i]);
+               lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
        }
        return 2;
 }
@@ -826,38 +876,42 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
         * TODO
         */
 
-       GET_ENV_PTR;
+       GET_PLAIN_ENV_PTR;
 
-       INodeDefManager *ndef = getServer(L)->ndef();
        v3s16 minp = read_v3s16(L, 1);
        v3s16 maxp = read_v3s16(L, 2);
        sortBoxVerticies(minp, maxp);
 
-       v3s16 cube = maxp - minp + 1;
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
+
+#ifndef SERVER
+       if (getClient(L)) {
+               minp = getClient(L)->CSMClampPos(minp);
+               maxp = getClient(L)->CSMClampPos(maxp);
+       }
+#endif
 
-       /* Limit for too large areas, assume default values
-        * and give tolerances of 1 node on each side
-        * (chunksize * MAP_BLOCKSIZE + 2)^3 = 551368
-       */
-       if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 551368) {
+       v3s16 cube = maxp - minp + 1;
+       // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+       if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
                luaL_error(L, "find_nodes_in_area_under_air(): area volume"
-                               " exceeds allowed value of 551368");
+                               " exceeds allowed value of 4096000");
                return 0;
        }
 
-       std::set<content_t> filter;
+       std::vector<content_t> filter;
 
        if (lua_istable(L, 3)) {
                lua_pushnil(L);
                while (lua_next(L, 3) != 0) {
                        // key at index -2 and value at index -1
                        luaL_checktype(L, -1, LUA_TSTRING);
-                       ndef->getIds(lua_tostring(L, -1), filter);
+                       ndef->getIds(readParam<std::string>(L, -1), filter);
                        // removes value, keeps key for next iteration
                        lua_pop(L, 1);
                }
        } else if (lua_isstring(L, 3)) {
-               ndef->getIds(lua_tostring(L, 3), filter);
+               ndef->getIds(readParam<std::string>(L, 3), filter);
        }
 
        lua_newtable(L);
@@ -866,12 +920,12 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
        for (s16 z = minp.Z; z <= maxp.Z; z++) {
                s16 y = minp.Y;
                v3s16 p(x, y, z);
-               content_t c = env->getMap().getNodeNoEx(p).getContent();
+               content_t c = env->getMap().getNode(p).getContent();
                for (; y <= maxp.Y; y++) {
                        v3s16 psurf(x, y + 1, z);
-                       content_t csurf = env->getMap().getNodeNoEx(psurf).getContent();
+                       content_t csurf = env->getMap().getNode(psurf).getContent();
                        if (c != CONTENT_AIR && csurf == CONTENT_AIR &&
-                                       filter.count(c) != 0) {
+                                       CONTAINS(filter, c)) {
                                push_v3s16(L, v3s16(x, y, z));
                                lua_rawseti(L, -2, ++i);
                        }
@@ -894,8 +948,8 @@ int ModApiEnvMod::l_get_perlin(lua_State *L)
        } else {
                params.seed    = luaL_checkint(L, 1);
                params.octaves = luaL_checkint(L, 2);
-               params.persist = luaL_checknumber(L, 3);
-               params.spread  = v3f(1, 1, 1) * luaL_checknumber(L, 4);
+               params.persist = readParam<float>(L, 3);
+               params.spread  = v3f(1, 1, 1) * readParam<float>(L, 4);
        }
 
        params.seed += (int)env->getServerMap().getSeed();
@@ -950,7 +1004,7 @@ int ModApiEnvMod::l_clear_objects(lua_State *L)
 {
        GET_ENV_PTR;
 
-       ClearObjectsMode mode = CLEAR_OBJECTS_MODE_FULL;
+       ClearObjectsMode mode = CLEAR_OBJECTS_MODE_QUICK;
        if (lua_istable(L, 1)) {
                mode = (ClearObjectsMode)getenumfield(L, 1, "mode",
                        ModApiEnvMod::es_ClearObjectsMode, mode);
@@ -960,24 +1014,19 @@ int ModApiEnvMod::l_clear_objects(lua_State *L)
        return 0;
 }
 
-// line_of_sight(pos1, pos2, stepsize) -> true/false, pos
+// line_of_sight(pos1, pos2) -> true/false, pos
 int ModApiEnvMod::l_line_of_sight(lua_State *L)
 {
-       float stepsize = 1.0;
-
-       GET_ENV_PTR;
+       GET_PLAIN_ENV_PTR;
 
        // read position 1 from lua
        v3f pos1 = checkFloatPos(L, 1);
        // read position 2 from lua
        v3f pos2 = checkFloatPos(L, 2);
-       //read step size from lua
-       if (lua_isnumber(L, 3)) {
-               stepsize = lua_tonumber(L, 3);
-       }
 
        v3s16 p;
-       bool success = env->line_of_sight(pos1, pos2, stepsize, &p);
+
+       bool success = env->line_of_sight(pos1, pos2, &p);
        lua_pushboolean(L, success);
        if (!success) {
                push_v3s16(L, p);
@@ -1008,7 +1057,7 @@ int ModApiEnvMod::l_fix_light(lua_State *L)
                for (auto &modified_block : modified_blocks)
                        event.modified_blocks.insert(modified_block.first);
 
-               map.dispatchEvent(&event);
+               map.dispatchEvent(event);
        }
        lua_pushboolean(L, success);
 
@@ -1020,6 +1069,30 @@ int ModApiEnvMod::l_raycast(lua_State *L)
        return LuaRaycast::create_object(L);
 }
 
+// load_area(p1, [p2])
+// load mapblocks in area p1..p2, but do not generate map
+int ModApiEnvMod::l_load_area(lua_State *L)
+{
+       GET_ENV_PTR;
+       MAP_LOCK_REQUIRED;
+
+       Map *map = &(env->getMap());
+       v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 1));
+       if (!lua_istable(L, 2)) {
+               map->emergeBlock(bp1);
+       } else {
+               v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 2));
+               sortBoxVerticies(bp1, bp2);
+               for (s16 z = bp1.Z; z <= bp2.Z; z++)
+               for (s16 y = bp1.Y; y <= bp2.Y; y++)
+               for (s16 x = bp1.X; x <= bp2.X; x++) {
+                       map->emergeBlock(v3s16(x, y, z));
+               }
+       }
+
+       return 0;
+}
+
 // emerge_area(p1, p2, [callback, context])
 // emerge mapblocks in area p1..p2, calls callback with context upon completion
 int ModApiEnvMod::l_emerge_area(lua_State *L)
@@ -1093,7 +1166,7 @@ int ModApiEnvMod::l_delete_area(lua_State *L)
                }
        }
 
-       map.dispatchEvent(&event);
+       map.dispatchEvent(event);
        lua_pushboolean(L, success);
        return 1;
 }
@@ -1110,7 +1183,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
        unsigned int max_jump       = luaL_checkint(L, 4);
        unsigned int max_drop       = luaL_checkint(L, 5);
        PathAlgorithm algo          = PA_PLAIN_NP;
-       if (!lua_isnil(L, 6)) {
+       if (!lua_isnoneornil(L, 6)) {
                std::string algorithm = luaL_checkstring(L,6);
 
                if (algorithm == "A*")
@@ -1127,7 +1200,7 @@ int ModApiEnvMod::l_find_path(lua_State *L)
                lua_newtable(L);
                int top = lua_gettop(L);
                unsigned int index = 1;
-               for (v3s16 i : path) {
+               for (const v3s16 &i : path) {
                        lua_pushnumber(L,index);
                        push_v3s16(L, i);
                        lua_settable(L, top);
@@ -1148,7 +1221,7 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L)
 
        treegen::TreeDef tree_def;
        std::string trunk,leaves,fruit;
-       INodeDefManager *ndef = env->getGameDef()->ndef();
+       const NodeDefManager *ndef = env->getGameDef()->ndef();
 
        if(lua_istable(L, 2))
        {
@@ -1231,6 +1304,7 @@ int ModApiEnvMod::l_forceload_free_block(lua_State *L)
 void ModApiEnvMod::Initialize(lua_State *L, int top)
 {
        API_FCT(set_node);
+       API_FCT(bulk_set_node);
        API_FCT(add_node);
        API_FCT(swap_node);
        API_FCT(add_item);
@@ -1249,6 +1323,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
        API_FCT(find_nodes_with_meta);
        API_FCT(get_meta);
        API_FCT(get_node_timer);
+       API_FCT(get_connected_players);
        API_FCT(get_player_by_name);
        API_FCT(get_objects_inside_radius);
        API_FCT(set_timeofday);
@@ -1259,6 +1334,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
        API_FCT(find_nodes_in_area);
        API_FCT(find_nodes_in_area_under_air);
        API_FCT(fix_light);
+       API_FCT(load_area);
        API_FCT(emerge_area);
        API_FCT(delete_area);
        API_FCT(get_perlin);
@@ -1276,9 +1352,14 @@ void ModApiEnvMod::Initialize(lua_State *L, int top)
 
 void ModApiEnvMod::InitializeClient(lua_State *L, int top)
 {
+       API_FCT(get_node_light);
        API_FCT(get_timeofday);
-       API_FCT(get_day_count);
        API_FCT(get_node_max_level);
        API_FCT(get_node_level);
+       API_FCT(find_nodes_with_meta);
        API_FCT(find_node_near);
+       API_FCT(find_nodes_in_area);
+       API_FCT(find_nodes_in_area_under_air);
+       API_FCT(line_of_sight);
+       API_FCT(raycast);
 }