diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 431ba0a8e..739fcef83 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1869,6 +1869,9 @@ and `minetest.auth_reload` call the authetification handler. * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` * `minetest.find_nodes_in_area(minp, maxp, nodenames)`: returns a list of positions * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` +* `minetest.find_surface_nodes_in_area(minp, maxp, nodenames)`: returns a list of positions + * returned positions are nodes with a node air above + * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` * `minetest.get_perlin(noiseparams)` * `minetest.get_perlin(seeddiff, octaves, persistence, scale)` * Return world-specific perlin noise (`int(worldseed)+seeddiff`) diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 505faa09d..ca1586e39 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -541,17 +541,17 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) v3s16 minp = read_v3s16(L, 1); v3s16 maxp = read_v3s16(L, 2); std::set filter; - if(lua_istable(L, 3)){ + if(lua_istable(L, 3)) { int table = 3; lua_pushnil(L); - while(lua_next(L, table) != 0){ + while(lua_next(L, table) != 0) { // key at index -2 and value at index -1 luaL_checktype(L, -1, LUA_TSTRING); ndef->getIds(lua_tostring(L, -1), filter); // removes value, keeps key for next iteration lua_pop(L, 1); } - } else if(lua_isstring(L, 3)){ + } else if(lua_isstring(L, 3)) { ndef->getIds(lua_tostring(L, 3), filter); } @@ -570,6 +570,51 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) return 1; } +// find_surface_nodes_in_area(minp, maxp, nodenames) -> list of positions +// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" +int ModApiEnvMod::l_find_surface_nodes_in_area(lua_State *L) +{ + GET_ENV_PTR; + + INodeDefManager *ndef = getServer(L)->ndef(); + v3s16 minp = read_v3s16(L, 1); + v3s16 maxp = read_v3s16(L, 2); + std::set filter; + if(lua_istable(L, 3)) { + int table = 3; + lua_pushnil(L); + while(lua_next(L, table) != 0) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + ndef->getIds(lua_tostring(L, -1), filter); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } else if(lua_isstring(L, 3)) { + ndef->getIds(lua_tostring(L, 3), filter); + } + + lua_newtable(L); + u64 i = 0; + for(s16 x = minp.X; x <= maxp.X; x++) + for(s16 z = minp.Z; z <= maxp.Z; z++) { + s16 y = minp.Y; + v3s16 p(x, y, z); + content_t c = env->getMap().getNodeNoEx(p).getContent(); + for(; y <= maxp.Y; y++) { + v3s16 psurf(x, y + 1, z); + content_t csurf = env->getMap().getNodeNoEx(psurf).getContent(); + if(c != CONTENT_AIR && csurf == CONTENT_AIR && + filter.count(c) != 0) { + push_v3s16(L, v3s16(x, y, z)); + lua_rawseti(L, -2, ++i); + } + c = csurf; + } + } + return 1; +} + // get_perlin(seeddiff, octaves, persistence, scale) // returns world-specific PerlinNoise int ModApiEnvMod::l_get_perlin(lua_State *L) @@ -867,6 +912,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(get_gametime); API_FCT(find_node_near); API_FCT(find_nodes_in_area); + API_FCT(find_surface_nodes_in_area); API_FCT(delete_area); API_FCT(get_perlin); API_FCT(get_perlin_map); diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index bfaea1c4d..807afe459 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -119,6 +119,10 @@ private: // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" static int l_find_nodes_in_area(lua_State *L); + // find_surface_nodes_in_area(minp, maxp, nodenames) -> list of positions + // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" + static int l_find_surface_nodes_in_area(lua_State *L); + // delete_area(p1, p2) -> true/false static int l_delete_area(lua_State *L);