X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Flua_api%2Fl_env.cpp;h=2c612eb9af9092e020f4b99678349933278f09f1;hb=ad148587dcf5244c2d2011dba339786c765c54c4;hp=85791f90b0740366e4fc8bf81df0c686f05e5605;hpb=2818d3f2244d2146a5cdb61cd41f6561c514f97c;p=dragonfireclient.git diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 85791f90b..2c612eb9a 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 #include "lua_api/l_env.h" #include "lua_api/l_internal.h" #include "lua_api/l_nodemeta.h" @@ -27,27 +28,34 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "scripting_server.h" #include "environment.h" +#include "mapblock.h" #include "server.h" #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" - -struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = -{ - {CLEAR_OBJECTS_MODE_FULL, "full"}, - {CLEAR_OBJECTS_MODE_QUICK, "quick"}, - {0, NULL}, +#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 + +struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = { + {CLEAR_OBJECTS_MODE_FULL, "full"}, + {CLEAR_OBJECTS_MODE_QUICK, "quick"}, + {0, NULL}, }; /////////////////////////////////////////////////////////////////////////////// - -void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, - u32 active_object_count, u32 active_object_count_wider) +void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, + u32 active_object_count_wider) { ServerScripting *scriptIface = env->getScriptIface(); scriptIface->realityCheck(); @@ -65,9 +73,9 @@ 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)) + if (lua_isnil(L, -1)) FATAL_ERROR(""); lua_remove(L, -2); // Remove registered_abms @@ -108,9 +116,10 @@ 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"); + FATAL_ERROR_IF(lua_isnil(L, -1), + "Entry with given id not found in registered_lbms table"); lua_remove(L, -2); // Remove registered_lbms scriptIface->setOriginFromTable(-1); @@ -130,6 +139,102 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) lua_pop(L, 1); // Pop error handler } +int LuaRaycast::l_next(lua_State *L) +{ + GET_PLAIN_ENV_PTR; + + bool csm = false; +#ifndef SERVER + csm = getClient(L) != nullptr; +#endif + + LuaRaycast *o = checkobject(L, 1); + PointedThing pointed; + env->continueRaycast(&o->state, &pointed); + if (pointed.type == POINTEDTHING_NOTHING) + lua_pushnil(L); + else + push_pointed_thing(L, pointed, csm, true); + + return 1; +} + +int LuaRaycast::create_object(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + bool objects = true; + bool liquids = false; + + v3f pos1 = checkFloatPos(L, 1); + v3f pos2 = checkFloatPos(L, 2); + if (lua_isboolean(L, 3)) { + objects = readParam(L, 3); + } + if (lua_isboolean(L, 4)) { + liquids = readParam(L, 4); + } + + LuaRaycast *o = new LuaRaycast(core::line3d(pos1, pos2), objects, liquids); + + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + return 1; +} + +LuaRaycast *LuaRaycast::checkobject(lua_State *L, int narg) +{ + NO_MAP_LOCK_REQUIRED; + + luaL_checktype(L, narg, LUA_TUSERDATA); + void *ud = luaL_checkudata(L, narg, className); + if (!ud) + luaL_typerror(L, narg, className); + return *(LuaRaycast **)ud; +} + +int LuaRaycast::gc_object(lua_State *L) +{ + LuaRaycast *o = *(LuaRaycast **)(lua_touserdata(L, 1)); + delete o; + return 0; +} + +void LuaRaycast::Register(lua_State *L) +{ + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pushliteral(L, "__call"); + lua_pushcfunction(L, l_next); + lua_settable(L, metatable); + + lua_pop(L, 1); + + luaL_openlib(L, 0, methods, 0); + lua_pop(L, 1); + + lua_register(L, className, create_object); +} + +const char LuaRaycast::className[] = "Raycast"; +const luaL_Reg LuaRaycast::methods[] = {luamethod(LuaRaycast, next), {0, 0}}; + void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param) { ScriptCallbackState *state = (ScriptCallbackState *)param; @@ -157,7 +262,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); @@ -167,6 +272,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); @@ -192,7 +330,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); @@ -211,7 +349,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; @@ -227,7 +365,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()); @@ -242,20 +380,20 @@ 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); u32 time_of_day = env->getTimeOfDay(); - if(lua_isnumber(L, 2)) + if (lua_isnumber(L, 2)) time_of_day = 24000.0 * lua_tonumber(L, 2); time_of_day %= 24000; 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); @@ -271,15 +409,15 @@ int ModApiEnvMod::l_place_node(lua_State *L) ScriptApiItem *scriptIfaceItem = getScriptApi(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); - if(n_old.getContent() == CONTENT_IGNORE){ + MapNode n_old = env->getMap().getNode(pos); + if (n_old.getContent() == CONTENT_IGNORE) { lua_pushboolean(L, false); return 1; } @@ -289,10 +427,9 @@ int ModApiEnvMod::l_place_node(lua_State *L) PointedThing pointed; 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); + pointed.node_undersurface = pos + v3s16(0, -1, 0); + // 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; } @@ -308,8 +445,8 @@ 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); - if(n.getContent() == CONTENT_IGNORE){ + MapNode n = env->getMap().getNode(pos); + if (n.getContent() == CONTENT_IGNORE) { lua_pushboolean(L, false); return 1; } @@ -331,8 +468,8 @@ 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); - if(n.getContent() == CONTENT_IGNORE){ + MapNode n = env->getMap().getNode(pos); + if (n.getContent() == CONTENT_IGNORE) { lua_pushboolean(L, false); return 1; } @@ -347,13 +484,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; } @@ -362,13 +496,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; } @@ -382,9 +513,9 @@ int ModApiEnvMod::l_set_node_level(lua_State *L) v3s16 pos = read_v3s16(L, 1); u8 level = 1; - if(lua_isnumber(L, 2)) + 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; @@ -392,16 +523,16 @@ 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; - if(lua_isnumber(L, 2)) + s16 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; @@ -410,12 +541,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 positions = env->getMap().findNodesWithMetadata( - check_v3s16(L, 1), check_v3s16(L, 2)); + 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); @@ -442,7 +573,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; } @@ -452,19 +583,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) + if (objectid == 0) + return 0; + + // If already deleted (can happen in on_activate), return nil + if (obj->isGone()) return 0; - // Return ObjectRef getScriptApiBase(L)->objectrefGetOrCreate(L, obj); return 1; } @@ -476,10 +607,10 @@ int ModApiEnvMod::l_add_item(lua_State *L) GET_ENV_PTR; // pos - //v3f pos = checkFloatPos(L, 1); + // v3f pos = checkFloatPos(L, 1); // item - ItemStack item = read_item(L, 2,getServer(L)->idef()); - if(item.empty() || !item.isKnown(getServer(L)->idef())) + ItemStack item = read_item(L, 2, getServer(L)->idef()); + if (item.empty() || !item.isKnown(getServer(L)->idef())) return 0; int error_handler = PUSH_ERROR_HANDLER(L); @@ -488,7 +619,7 @@ int ModApiEnvMod::l_add_item(lua_State *L) lua_getglobal(L, "core"); lua_getfield(L, -1, "spawn_item"); lua_remove(L, -2); // Remove core - if(lua_isnil(L, -1)) + if (lua_isnil(L, -1)) return 0; lua_pushvalue(L, 1); lua_pushstring(L, item.getItemString().c_str()); @@ -499,6 +630,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) { @@ -506,16 +662,12 @@ int ModApiEnvMod::l_get_player_by_name(lua_State *L) // Do it const char *name = luaL_checkstring(L, 1); - RemotePlayer *player = dynamic_cast(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; @@ -525,17 +677,19 @@ 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 = luaL_checknumber(L, 2) * BS; - std::vector ids; - env->getObjectsInsideRadius(ids, pos, radius); - ScriptApiBase *script = getScriptApiBase(L); - lua_createtable(L, ids.size(), 0); - std::vector::const_iterator iter = ids.begin(); - for(u32 i = 0; iter != ids.end(); ++iter) { - ServerActiveObject *obj = env->getActiveObject(*iter); + float radius = readParam(L, 2) * BS; + std::vector 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); @@ -550,13 +704,13 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L) GET_ENV_PTR; // Do it - float timeofday_f = luaL_checknumber(L, 1); + float timeofday_f = readParam(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 // such changes aren't immediately sent to the clients, so call // the server instead. - //env->setTimeOfDay(timeofday_mh); + // env->setTimeOfDay(timeofday_mh); getServer(L)->setTimeOfDay(timeofday_mh); return 0; } @@ -564,10 +718,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(); @@ -579,10 +730,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; @@ -598,41 +746,50 @@ int ModApiEnvMod::l_get_gametime(lua_State *L) return 1; } - -// find_node_near(pos, radius, nodenames) -> pos or nil -// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" -int ModApiEnvMod::l_find_node_near(lua_State *L) +void ModApiEnvMod::collectNodeIds(lua_State *L, int idx, const NodeDefManager *ndef, + std::vector &filter) { - Environment *env = getEnv(L); - if (!env) { - return 0; - } - - INodeDefManager *ndef = getGameDef(L)->ndef(); - v3s16 pos = read_v3s16(L, 1); - int radius = luaL_checkinteger(L, 2); - std::set filter; - if(lua_istable(L, 3)){ - int table = 3; + if (lua_istable(L, idx)) { lua_pushnil(L); - while(lua_next(L, table) != 0){ + while (lua_next(L, idx) != 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(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); + } else if (lua_isstring(L, idx)) { + ndef->getIds(readParam(L, 3), filter); } +} - for (int d=1; d<=radius; d++){ - std::vector list = FacePositionCache::getFacePositions(d); - for (std::vector::iterator i = list.begin(); - i != list.end(); ++i){ - v3s16 p = pos + (*i); - content_t c = env->getMap().getNodeNoEx(p).getContent(); - if (filter.count(c) != 0){ +// find_node_near(pos, radius, nodenames, [search_center]) -> pos or nil +// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" +int ModApiEnvMod::l_find_node_near(lua_State *L) +{ + GET_PLAIN_ENV_PTR; + + const NodeDefManager *ndef = env->getGameDef()->ndef(); + Map &map = env->getMap(); + + v3s16 pos = read_v3s16(L, 1); + int radius = luaL_checkinteger(L, 2); + std::vector filter; + collectNodeIds(L, 3, ndef, filter); + int start_radius = (lua_isboolean(L, 4) && readParam(L, 4)) ? 0 : 1; + +#ifndef SERVER + // Client API limitations + if (Client *client = getClient(L)) + radius = client->CSMClampRadius(pos, radius); +#endif + + for (int d = start_radius; d <= radius; d++) { + const std::vector &list = FacePositionCache::getFacePositions(d); + for (const v3s16 &i : list) { + v3s16 p = pos + i; + content_t c = map.getNode(p).getContent(); + if (CONTAINS(filter, c)) { push_v3s16(L, p); return 1; } @@ -641,54 +798,273 @@ int ModApiEnvMod::l_find_node_near(lua_State *L) return 0; } -// find_nodes_in_area(minp, maxp, nodenames) -> list of positions +// find_nodes_near(pos, radius, nodenames, [search_center]) // nodenames: eg. {"ignore", "group:tree"} or "default:dirt" -int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) +int ModApiEnvMod::l_find_nodes_near(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); - 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); + const NodeDefManager *ndef = env->getGameDef()->ndef(); + Map &map = env->getMap(); + + v3s16 pos = read_v3s16(L, 1); + int radius = luaL_checkinteger(L, 2); + std::vector filter; + collectNodeIds(L, 3, ndef, filter); + + int start_radius = (lua_isboolean(L, 4) && readParam(L, 4)) ? 0 : 1; + +#ifndef SERVER + // Client API limitations + if (Client *client = getClient(L)) + radius = client->CSMClampRadius(pos, radius); +#endif + + std::vector individual_count; + individual_count.resize(filter.size()); + + lua_newtable(L); + u32 i = 0; + + for (int d = start_radius; d <= radius; d++) { + const std::vector &list = FacePositionCache::getFacePositions(d); + for (const v3s16 &posi : list) { + v3s16 p = pos + posi; + content_t c = map.getNode(p).getContent(); + auto it = std::find(filter.begin(), filter.end(), c); + if (it != filter.end()) { + push_v3s16(L, p); + lua_rawseti(L, -2, ++i); + + u32 filt_index = it - filter.begin(); + individual_count[filt_index]++; + } } - } else if(lua_isstring(L, 3)) { - ndef->getIds(lua_tostring(L, 3), filter); } + lua_createtable(L, 0, filter.size()); + for (u32 i = 0; i < filter.size(); i++) { + lua_pushinteger(L, individual_count[i]); + lua_setfield(L, -2, ndef->get(filter[i]).name.c_str()); + } + return 2; +} + +// find_nodes_near_under_air(pos, radius, nodenames, [search_center]) +// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" +int ModApiEnvMod::l_find_nodes_near_under_air(lua_State *L) +{ + GET_PLAIN_ENV_PTR; + + const NodeDefManager *ndef = env->getGameDef()->ndef(); + Map &map = env->getMap(); - std::map individual_count; + v3s16 pos = read_v3s16(L, 1); + int radius = luaL_checkinteger(L, 2); + std::vector filter; + collectNodeIds(L, 3, ndef, filter); + int start_radius = (lua_isboolean(L, 4) && readParam(L, 4)) ? 0 : 1; + +#ifndef SERVER + // Client API limitations + if (Client *client = getClient(L)) + radius = client->CSMClampRadius(pos, radius); +#endif + + std::vector individual_count; + individual_count.resize(filter.size()); lua_newtable(L); - u64 i = 0; - for (s16 x = minp.X; x <= maxp.X; x++) - for (s16 y = minp.Y; y <= maxp.Y; y++) - for (s16 z = minp.Z; z <= maxp.Z; z++) { - v3s16 p(x, y, z); - content_t c = env->getMap().getNodeNoEx(p).getContent(); - if (filter.count(c) != 0) { - push_v3s16(L, p); - lua_rawseti(L, -2, ++i); - individual_count[c]++; - } + u32 i = 0; + + for (int d = start_radius; d <= radius; d++) { + const std::vector &list = FacePositionCache::getFacePositions(d); + for (const v3s16 &posi : list) { + v3s16 p = pos + posi; + content_t c = map.getNode(p).getContent(); + v3s16 psurf(p.X, p.Y + 1, p.Z); + content_t csurf = map.getNode(psurf).getContent(); + if (c == CONTENT_AIR || csurf != CONTENT_AIR) + continue; + auto it = std::find(filter.begin(), filter.end(), c); + if (it != filter.end()) { + push_v3s16(L, p); + lua_rawseti(L, -2, ++i); + + u32 filt_index = it - filter.begin(); + individual_count[filt_index]++; + } + } + } + lua_createtable(L, 0, filter.size()); + for (u32 i = 0; i < filter.size(); i++) { + lua_pushinteger(L, individual_count[i]); + lua_setfield(L, -2, ndef->get(filter[i]).name.c_str()); } + return 2; +} + +// find_nodes_near_under_air_except(pos, radius, nodenames, [search_center]) +// nodenames: eg. {"ignore", "group:tree"} or "default:dirt" +int ModApiEnvMod::l_find_nodes_near_under_air_except(lua_State *L) +{ + GET_PLAIN_ENV_PTR; + + const NodeDefManager *ndef = env->getGameDef()->ndef(); + Map &map = env->getMap(); + + v3s16 pos = read_v3s16(L, 1); + int radius = luaL_checkinteger(L, 2); + std::vector filter; + collectNodeIds(L, 3, ndef, filter); + int start_radius = (lua_isboolean(L, 4) && readParam(L, 4)) ? 0 : 1; + +#ifndef SERVER + // Client API limitations + if (Client *client = getClient(L)) + radius = client->CSMClampRadius(pos, radius); +#endif + + std::vector individual_count; + individual_count.resize(filter.size()); + lua_newtable(L); - for (std::set::iterator it = filter.begin(); - it != filter.end(); ++it) { - lua_pushnumber(L, individual_count[*it]); - lua_setfield(L, -2, ndef->get(*it).name.c_str()); + u32 i = 0; + + for (int d = start_radius; d <= radius; d++) { + const std::vector &list = FacePositionCache::getFacePositions(d); + for (const v3s16 &posi : list) { + v3s16 p = pos + posi; + content_t c = map.getNode(p).getContent(); + v3s16 psurf(p.X, p.Y + 1, p.Z); + content_t csurf = map.getNode(psurf).getContent(); + if (c == CONTENT_AIR || csurf != CONTENT_AIR) + continue; + auto it = std::find(filter.begin(), filter.end(), c); + if (it == filter.end()) { + push_v3s16(L, p); + lua_rawseti(L, -2, ++i); + + u32 filt_index = it - filter.begin(); + individual_count[filt_index]++; + } + } + } + lua_createtable(L, 0, filter.size()); + for (u32 i = 0; i < filter.size(); i++) { + lua_pushinteger(L, individual_count[i]); + lua_setfield(L, -2, ndef->get(filter[i]).name.c_str()); } return 2; } +// find_nodes_in_area(minp, maxp, nodenames, [grouped]) +int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) +{ + 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(); + Map &map = env->getMap(); + +#ifndef SERVER + if (Client *client = getClient(L)) { + minp = client->CSMClampPos(minp); + maxp = client->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 4096000"); + return 0; + } + + std::vector filter; + collectNodeIds(L, 3, ndef, filter); + + bool grouped = lua_isboolean(L, 4) && readParam(L, 4); + + if (grouped) { + // create the table we will be returning + lua_createtable(L, 0, filter.size()); + int base = lua_gettop(L); + + // create one table for each filter + std::vector idx; + idx.resize(filter.size()); + for (u32 i = 0; i < filter.size(); i++) + lua_newtable(L); + + v3s16 p; + for (p.X = minp.X; p.X <= maxp.X; p.X++) + for (p.Y = minp.Y; p.Y <= maxp.Y; p.Y++) + for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) { + content_t c = map.getNode(p).getContent(); + + auto it = std::find( + filter.begin(), filter.end(), c); + if (it != filter.end()) { + // Calculate index of the table and append + // the position + u32 filt_index = it - filter.begin(); + push_v3s16(L, p); + lua_rawseti(L, base + 1 + filt_index, + ++idx[filt_index]); + } + } + + // last filter table is at top of stack + u32 i = filter.size() - 1; + do { + if (idx[i] == 0) { + // No such node found -> drop the empty table + lua_pop(L, 1); + } else { + // This node was found -> put table into the return table + lua_setfield(L, base, ndef->get(filter[i]).name.c_str()); + } + } while (i-- != 0); + + assert(lua_gettop(L) == base); + return 1; + } else { + std::vector individual_count; + individual_count.resize(filter.size()); + + lua_newtable(L); + u32 i = 0; + v3s16 p; + for (p.X = minp.X; p.X <= maxp.X; p.X++) + for (p.Y = minp.Y; p.Y <= maxp.Y; p.Y++) + for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) { + content_t c = env->getMap().getNode(p) + .getContent(); + + auto it = std::find( + filter.begin(), filter.end(), c); + if (it != filter.end()) { + push_v3s16(L, p); + lua_rawseti(L, -2, ++i); + + u32 filt_index = it - filter.begin(); + individual_count[filt_index]++; + } + } + + lua_createtable(L, 0, filter.size()); + for (u32 i = 0; i < filter.size(); i++) { + lua_pushinteger(L, individual_count[i]); + lua_setfield(L, -2, ndef->get(filter[i]).name.c_str()); + } + return 2; + } +} + // find_nodes_in_area_under_air(minp, maxp, nodenames) -> list of positions // nodenames: e.g. {"ignore", "group:tree"} or "default:dirt" int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) @@ -700,45 +1076,51 @@ 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); - std::set filter; + sortBoxVerticies(minp, maxp); - 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); + const NodeDefManager *ndef = env->getGameDef()->ndef(); + Map &map = env->getMap(); + +#ifndef SERVER + if (Client *client = getClient(L)) { + minp = client->CSMClampPos(minp); + maxp = client->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_under_air(): area volume" + " exceeds allowed value of 4096000"); + return 0; + } + + std::vector filter; + collectNodeIds(L, 3, ndef, 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); + u32 i = 0; + v3s16 p; + for (p.X = minp.X; p.X <= maxp.X; p.X++) + for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) { + p.Y = minp.Y; + content_t c = map.getNode(p).getContent(); + for (; p.Y <= maxp.Y; p.Y++) { + v3s16 psurf(p.X, p.Y + 1, p.Z); + content_t csurf = map.getNode(psurf).getContent(); + if (c != CONTENT_AIR && csurf == CONTENT_AIR && + CONTAINS(filter, c)) { + push_v3s16(L, p); + lua_rawseti(L, -2, ++i); + } + c = csurf; } - c = csurf; } - } return 1; } @@ -753,10 +1135,10 @@ int ModApiEnvMod::l_get_perlin(lua_State *L) if (lua_istable(L, 1)) { read_noiseparams(L, 1, ¶ms); } else { - params.seed = luaL_checkint(L, 1); + 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(L, 3); + params.spread = v3f(1, 1, 1) * readParam(L, 4); } params.seed += (int)env->getServerMap().getSeed(); @@ -794,9 +1176,10 @@ int ModApiEnvMod::l_get_voxel_manip(lua_State *L) GET_ENV_PTR; Map *map = &(env->getMap()); - LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ? - new LuaVoxelManip(map, read_v3s16(L, 1), read_v3s16(L, 2)) : - new LuaVoxelManip(map); + LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) + ? new LuaVoxelManip(map, read_v3s16(L, 1), + read_v3s16(L, 2)) + : new LuaVoxelManip(map); *(void **)(lua_newuserdata(L, sizeof(void *))) = o; luaL_getmetatable(L, "VoxelManip"); @@ -811,34 +1194,29 @@ 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); + mode = (ClearObjectsMode)getenumfield( + L, 1, "mode", ModApiEnvMod::es_ClearObjectsMode, mode); } env->clearObjects(mode); 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); @@ -859,24 +1237,54 @@ int ModApiEnvMod::l_fix_light(lua_State *L) bool success = true; v3s16 blockpos; for (blockpos.X = blockpos1.X; blockpos.X <= blockpos2.X; blockpos.X++) - for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++) - for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z; blockpos.Z++) { - success = success & map.repairBlockLight(blockpos, &modified_blocks); - } - if (modified_blocks.size() > 0) { + for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++) + for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z; + blockpos.Z++) { + success = success & map.repairBlockLight(blockpos, + &modified_blocks); + } + if (!modified_blocks.empty()) { MapEditEvent event; event.type = MEET_OTHER; - for (std::map::iterator it = modified_blocks.begin(); - it != modified_blocks.end(); ++it) - event.modified_blocks.insert(it->first); + for (auto &modified_block : modified_blocks) + event.modified_blocks.insert(modified_block.first); - map.dispatchEvent(&event); + map.dispatchEvent(event); } lua_pushboolean(L, success); return 1; } +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) @@ -905,19 +1313,22 @@ int ModApiEnvMod::l_emerge_area(lua_State *L) int args_ref = luaL_ref(L, LUA_REGISTRYINDEX); state = new ScriptCallbackState; - state->script = getServer(L)->getScriptIface(); + state->script = getServer(L)->getScriptIface(); state->callback_ref = callback_ref; - state->args_ref = args_ref; - state->refcount = num_blocks; - state->origin = getScriptApiBase(L)->getOrigin(); + state->args_ref = args_ref; + state->refcount = num_blocks; + state->origin = getScriptApiBase(L)->getOrigin(); } for (s16 z = bpmin.Z; z <= bpmax.Z; z++) - for (s16 y = bpmin.Y; y <= bpmax.Y; y++) - for (s16 x = bpmin.X; x <= bpmax.X; x++) { - emerge->enqueueBlockEmergeEx(v3s16(x, y, z), PEER_ID_INEXISTENT, - BLOCK_EMERGE_ALLOW_GEN | BLOCK_EMERGE_FORCE_QUEUE, callback, state); - } + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) + for (s16 x = bpmin.X; x <= bpmax.X; x++) { + emerge->enqueueBlockEmergeEx(v3s16(x, y, z), + PEER_ID_INEXISTENT, + BLOCK_EMERGE_ALLOW_GEN | + BLOCK_EMERGE_FORCE_QUEUE, + callback, state); + } return 0; } @@ -939,18 +1350,18 @@ int ModApiEnvMod::l_delete_area(lua_State *L) bool success = true; for (s16 z = bpmin.Z; z <= bpmax.Z; z++) - for (s16 y = bpmin.Y; y <= bpmax.Y; y++) - for (s16 x = bpmin.X; x <= bpmax.X; x++) { - v3s16 bp(x, y, z); - if (map.deleteBlock(bp)) { - env->setStaticForActiveObjectsInBlock(bp, false); - event.modified_blocks.insert(bp); - } else { - success = false; - } - } + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) + for (s16 x = bpmin.X; x <= bpmax.X; x++) { + v3s16 bp(x, y, z); + if (map.deleteBlock(bp)) { + env->setStaticForActiveObjectsInBlock(bp, false); + event.modified_blocks.insert(bp); + } else { + success = false; + } + } - map.dispatchEvent(&event); + map.dispatchEvent(event); lua_pushboolean(L, success); return 1; } @@ -959,16 +1370,16 @@ int ModApiEnvMod::l_delete_area(lua_State *L) // max_jump, max_drop, algorithm) -> table containing path int ModApiEnvMod::l_find_path(lua_State *L) { - GET_ENV_PTR; + Environment *env = getEnv(L); - v3s16 pos1 = read_v3s16(L, 1); - v3s16 pos2 = read_v3s16(L, 2); + v3s16 pos1 = read_v3s16(L, 1); + v3s16 pos2 = read_v3s16(L, 2); unsigned int searchdistance = luaL_checkint(L, 3); - 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)) { - std::string algorithm = luaL_checkstring(L,6); + unsigned int max_jump = luaL_checkint(L, 4); + unsigned int max_drop = luaL_checkint(L, 5); + PathAlgorithm algo = PA_PLAIN_NP; + if (!lua_isnoneornil(L, 6)) { + std::string algorithm = luaL_checkstring(L, 6); if (algorithm == "A*") algo = PA_PLAIN; @@ -977,17 +1388,16 @@ int ModApiEnvMod::l_find_path(lua_State *L) algo = PA_DIJKSTRA; } - std::vector path = get_path(env, pos1, pos2, - searchdistance, max_jump, max_drop, algo); + std::vector path = get_path(&env->getMap(), env->getGameDef()->ndef(), + pos1, pos2, searchdistance, max_jump, max_drop, algo); - if (path.size() > 0) - { - lua_newtable(L); + if (!path.empty()) { + lua_createtable(L, path.size(), 0); int top = lua_gettop(L); unsigned int index = 1; - for (std::vector::iterator i = path.begin(); i != path.end(); ++i) { - lua_pushnumber(L,index); - push_v3s16(L, *i); + for (const v3s16 &i : path) { + lua_pushnumber(L, index); + push_v3s16(L, i); lua_settable(L, top); index++; } @@ -1005,25 +1415,23 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) v3s16 p0 = read_v3s16(L, 1); treegen::TreeDef tree_def; - std::string trunk,leaves,fruit; - INodeDefManager *ndef = env->getGameDef()->ndef(); + std::string trunk, leaves, fruit; + const NodeDefManager *ndef = env->getGameDef()->ndef(); - if(lua_istable(L, 2)) - { + if (lua_istable(L, 2)) { getstringfield(L, 2, "axiom", tree_def.initial_axiom); getstringfield(L, 2, "rules_a", tree_def.rules_a); getstringfield(L, 2, "rules_b", tree_def.rules_b); getstringfield(L, 2, "rules_c", tree_def.rules_c); getstringfield(L, 2, "rules_d", tree_def.rules_d); getstringfield(L, 2, "trunk", trunk); - tree_def.trunknode=ndef->getId(trunk); + tree_def.trunknode = ndef->getId(trunk); getstringfield(L, 2, "leaves", leaves); - tree_def.leavesnode=ndef->getId(leaves); - tree_def.leaves2_chance=0; + tree_def.leavesnode = ndef->getId(leaves); + tree_def.leaves2_chance = 0; getstringfield(L, 2, "leaves2", leaves); - if (leaves !="") - { - tree_def.leaves2node=ndef->getId(leaves); + if (!leaves.empty()) { + tree_def.leaves2node = ndef->getId(leaves); getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance); } getintfield(L, 2, "angle", tree_def.angle); @@ -1032,22 +1440,22 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) tree_def.iterations_random_level = 0; getstringfield(L, 2, "trunk_type", tree_def.trunk_type); getboolfield(L, 2, "thin_branches", tree_def.thin_branches); - tree_def.fruit_chance=0; + tree_def.fruit_chance = 0; getstringfield(L, 2, "fruit", fruit); - if (fruit != "") - { - tree_def.fruitnode=ndef->getId(fruit); - getintfield(L, 2, "fruit_chance",tree_def.fruit_chance); + if (!fruit.empty()) { + tree_def.fruitnode = ndef->getId(fruit); + getintfield(L, 2, "fruit_chance", tree_def.fruit_chance); } tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed); - } - else + } 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"); + luaL_error(L, "spawn_tree(): closing ']' has no matching opening " + "bracket"); } else { luaL_error(L, "spawn_tree(): unknown error"); } @@ -1088,9 +1496,23 @@ 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); + API_FCT(bulk_set_node); API_FCT(add_node); API_FCT(swap_node); API_FCT(add_item); @@ -1109,6 +1531,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); @@ -1119,6 +1542,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); @@ -1128,16 +1552,27 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(spawn_tree); API_FCT(find_path); API_FCT(line_of_sight); + API_FCT(raycast); 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) { + 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_near); + API_FCT(find_nodes_near_under_air); + API_FCT(find_nodes_near_under_air_except); + API_FCT(find_nodes_in_area); + API_FCT(find_nodes_in_area_under_air); + API_FCT(find_path); + API_FCT(line_of_sight); + API_FCT(raycast); }