X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Flua_api%2Fl_env.cpp;h=94edf201e25ff572eb90f2d73d2c9268912604f4;hb=88b436e6a9c98af7215bd115e1b7a3f1a1db99d3;hp=f6ea23e95826857012b88f971f89a37576de0023;hpb=8bcd10b872bc88c6f474913d6efb8d53c50c5ae1;p=dragonfireclient.git diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index f6ea23e95..94edf201e 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -25,8 +25,10 @@ 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 "scripting_game.h" +#include +#include "scripting_server.h" #include "environment.h" +#include "mapblock.h" #include "server.h" #include "nodedef.h" #include "daynightratio.h" @@ -35,6 +37,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "treegen.h" #include "emerge.h" #include "pathfinder.h" +#include "face_position_cache.h" +#include "remoteplayer.h" +#ifndef SERVER +#include "client.h" +#endif struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = { @@ -49,7 +56,7 @@ struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider) { - GameScripting *scriptIface = env->getScriptIface(); + ServerScripting *scriptIface = env->getScriptIface(); scriptIface->realityCheck(); lua_State *L = scriptIface->getStack(); @@ -92,7 +99,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - GameScripting *scriptIface = env->getScriptIface(); + ServerScripting *scriptIface = env->getScriptIface(); scriptIface->realityCheck(); lua_State *L = scriptIface->getStack(); @@ -130,6 +137,105 @@ void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) lua_pop(L, 1); // Pop error handler } +int LuaRaycast::l_next(lua_State *L) +{ + MAP_LOCK_REQUIRED; + + ScriptApiItem *script = getScriptApi(L); + GET_ENV_PTR; + + LuaRaycast *o = checkobject(L, 1); + PointedThing pointed; + env->continueRaycast(&o->state, &pointed); + if (pointed.type == POINTEDTHING_NOTHING) + lua_pushnil(L); + else + script->pushPointedThing(pointed); + + 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 = lua_toboolean(L, 3); + } + if (lua_isboolean(L, 4)) { + liquids = lua_toboolean(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; @@ -137,6 +243,10 @@ void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param) assert(state->script != NULL); assert(state->refcount > 0); + // state must be protected by envlock + Server *server = state->script->getServer(); + MutexAutoLock envlock(server->m_env_mutex); + state->refcount--; state->script->on_emerge_area_completion(blockpos, action, state); @@ -280,7 +390,7 @@ int ModApiEnvMod::l_place_node(lua_State *L) return 1; } // Create item to place - ItemStack item(ndef->get(n).name, 1, 0, "", idef); + ItemStack item(ndef->get(n).name, 1, 0, idef); // Make pointed position PointedThing pointed; pointed.type = POINTEDTHING_NODE; @@ -343,7 +453,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) { - GET_ENV_PTR; + Environment *env = getEnv(L); + if (!env) { + return 0; + } v3s16 pos = read_v3s16(L, 1); MapNode n = env->getMap().getNodeNoEx(pos); @@ -355,7 +468,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) { - GET_ENV_PTR; + Environment *env = getEnv(L); + if (!env) { + return 0; + } v3s16 pos = read_v3s16(L, 1); MapNode n = env->getMap().getNodeNoEx(pos); @@ -436,7 +552,7 @@ int ModApiEnvMod::l_get_node_timer(lua_State *L) return 1; } -// add_entity(pos, entityname) -> ObjectRef or nil +// add_entity(pos, entityname, [staticdata]) -> ObjectRef or nil // pos = {x=num, y=num, z=num} int ModApiEnvMod::l_add_entity(lua_State *L) { @@ -446,8 +562,10 @@ int ModApiEnvMod::l_add_entity(lua_State *L) 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, ""); + 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) @@ -466,7 +584,7 @@ int ModApiEnvMod::l_add_item(lua_State *L) // pos //v3f pos = checkFloatPos(L, 1); // item - ItemStack item = read_item(L, 2,getServer(L)); + ItemStack item = read_item(L, 2,getServer(L)->idef()); if(item.empty() || !item.isKnown(getServer(L)->idef())) return 0; @@ -522,7 +640,7 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L) 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++) { + for(u32 i = 0; iter != ids.end(); ++iter) { ServerActiveObject *obj = env->getActiveObject(*iter); // Insert object reference into table script->objectrefGetOrCreate(L, obj); @@ -552,11 +670,14 @@ int ModApiEnvMod::l_set_timeofday(lua_State *L) // get_timeofday() -> 0...1 int ModApiEnvMod::l_get_timeofday(lua_State *L) { - GET_ENV_PTR; + Environment *env = getEnv(L); + if (!env) { + return 0; + } // Do it int timeofday_mh = env->getTimeOfDay(); - float timeofday_f = (float)timeofday_mh / 24000.0; + float timeofday_f = (float)timeofday_mh / 24000.0f; lua_pushnumber(L, timeofday_f); return 1; } @@ -564,7 +685,10 @@ int ModApiEnvMod::l_get_timeofday(lua_State *L) // get_day_count() -> int int ModApiEnvMod::l_get_day_count(lua_State *L) { - GET_ENV_PTR; + Environment *env = getEnv(L); + if (!env) { + return 0; + } lua_pushnumber(L, env->getDayCount()); return 1; @@ -581,37 +705,48 @@ int ModApiEnvMod::l_get_gametime(lua_State *L) } -// find_node_near(pos, radius, nodenames) -> pos or nil +// 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_ENV_PTR; + Environment *env = getEnv(L); + if (!env) { + return 0; + } - INodeDefManager *ndef = getServer(L)->ndef(); + 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, 3)) { lua_pushnil(L); - while(lua_next(L, table) != 0){ + 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); // 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); } - for(int d=1; d<=radius; d++){ + int start_radius = (lua_toboolean(L, 4)) ? 0 : 1; + +#ifndef SERVER + // Client API limitations + if (getClient(L) && + getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_LOOKUP_NODES)) { + radius = std::max(radius, getClient(L)->getCSMNodeRangeLimit()); + } +#endif + + for (int d = start_radius; d <= radius; d++) { std::vector list = FacePositionCache::getFacePositions(d); - for(std::vector::iterator i = list.begin(); - i != list.end(); ++i){ - v3s16 p = pos + (*i); + for (v3s16 i : list) { + v3s16 p = pos + i; content_t c = env->getMap().getNodeNoEx(p).getContent(); - if(filter.count(c) != 0){ + if (filter.count(c) != 0) { push_v3s16(L, p); return 1; } @@ -629,41 +764,53 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L) 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; + + /* 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) { + luaL_error(L, "find_nodes_in_area(): area volume" + " exceeds allowed value of 551368"); + return 0; + } + std::set filter; - if(lua_istable(L, 3)) { - int table = 3; + if (lua_istable(L, 3)) { lua_pushnil(L); - while(lua_next(L, table) != 0) { + 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); // removes value, keeps key for next iteration lua_pop(L, 1); } - } else if(lua_isstring(L, 3)) { + } else if (lua_isstring(L, 3)) { ndef->getIds(lua_tostring(L, 3), filter); } - std::map individual_count; + std::unordered_map individual_count; lua_newtable(L); u64 i = 0; for (s16 x = minp.X; x <= maxp.X; x++) - for (s16 y = minp.Y; y <= maxp.Y; y++) - for (s16 z = minp.Z; z <= maxp.Z; z++) { - v3s16 p(x, y, z); - content_t c = env->getMap().getNodeNoEx(p).getContent(); - if (filter.count(c) != 0) { - push_v3s16(L, p); - lua_rawseti(L, -2, ++i); - individual_count[c]++; - } + for (s16 y = minp.Y; y <= maxp.Y; y++) + for (s16 z = minp.Z; z <= maxp.Z; z++) { + v3s16 p(x, y, z); + content_t c = env->getMap().getNodeNoEx(p).getContent(); + if (filter.count(c) != 0) { + push_v3s16(L, p); + lua_rawseti(L, -2, ++i); + individual_count[c]++; + } } lua_newtable(L); - for (std::set::iterator it = filter.begin(); - it != filter.end(); ++it) { - lua_pushnumber(L, individual_count[*it]); - lua_setfield(L, -2, ndef->get(*it).name.c_str()); + for (content_t it : filter) { + lua_pushnumber(L, individual_count[it]); + lua_setfield(L, -2, ndef->get(it).name.c_str()); } return 2; } @@ -684,12 +831,25 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) 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; + + /* 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) { + luaL_error(L, "find_nodes_in_area_under_air(): area volume" + " exceeds allowed value of 551368"); + return 0; + } + std::set filter; if (lua_istable(L, 3)) { - int table = 3; lua_pushnil(L); - while(lua_next(L, table) != 0) { + 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); @@ -710,7 +870,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L) 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 && + if (c != CONTENT_AIR && csurf == CONTENT_AIR && filter.count(c) != 0) { push_v3s16(L, v3s16(x, y, z)); lua_rawseti(L, -2, ++i); @@ -826,6 +986,40 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L) return 1; } +// fix_light(p1, p2) +int ModApiEnvMod::l_fix_light(lua_State *L) +{ + GET_ENV_PTR; + + v3s16 blockpos1 = getContainerPos(read_v3s16(L, 1), MAP_BLOCKSIZE); + v3s16 blockpos2 = getContainerPos(read_v3s16(L, 2), MAP_BLOCKSIZE); + ServerMap &map = env->getServerMap(); + std::map modified_blocks; + 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.empty()) { + MapEditEvent event; + event.type = MEET_OTHER; + for (auto &modified_block : modified_blocks) + event.modified_blocks.insert(modified_block.first); + + map.dispatchEvent(&event); + } + lua_pushboolean(L, success); + + return 1; +} + +int ModApiEnvMod::l_raycast(lua_State *L) +{ + return LuaRaycast::create_object(L); +} + // 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) @@ -929,15 +1123,13 @@ int ModApiEnvMod::l_find_path(lua_State *L) std::vector path = get_path(env, pos1, pos2, searchdistance, max_jump, max_drop, algo); - if (path.size() > 0) - { + if (!path.empty()) { lua_newtable(L); int top = lua_gettop(L); unsigned int index = 1; - for (std::vector::iterator i = path.begin(); i != path.end();i++) - { + for (v3s16 i : path) { lua_pushnumber(L,index); - push_v3s16(L, *i); + push_v3s16(L, i); lua_settable(L, top); index++; } @@ -971,8 +1163,7 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) tree_def.leavesnode=ndef->getId(leaves); tree_def.leaves2_chance=0; getstringfield(L, 2, "leaves2", leaves); - if (leaves !="") - { + if (!leaves.empty()) { tree_def.leaves2node=ndef->getId(leaves); getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance); } @@ -984,8 +1175,7 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) getboolfield(L, 2, "thin_branches", tree_def.thin_branches); tree_def.fruit_chance=0; getstringfield(L, 2, "fruit", fruit); - if (fruit != "") - { + if (!fruit.empty()) { tree_def.fruitnode=ndef->getId(fruit); getintfield(L, 2, "fruit_chance",tree_def.fruit_chance); } @@ -1068,6 +1258,7 @@ void ModApiEnvMod::Initialize(lua_State *L, int top) API_FCT(find_node_near); API_FCT(find_nodes_in_area); API_FCT(find_nodes_in_area_under_air); + API_FCT(fix_light); API_FCT(emerge_area); API_FCT(delete_area); API_FCT(get_perlin); @@ -1077,7 +1268,17 @@ 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); } + +void ModApiEnvMod::InitializeClient(lua_State *L, int top) +{ + API_FCT(get_timeofday); + API_FCT(get_day_count); + API_FCT(get_node_max_level); + API_FCT(get_node_level); + API_FCT(find_node_near); +}