diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 8231364fb..62fe94b45 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1052,7 +1052,6 @@ minetest.setting_get(name) -> string or nil minetest.setting_getbool(name) -> boolean value or nil minetest.setting_get_pos(name) -> position or nil minetest.setting_save() -> nil, save all settings to config file -minetest.add_to_creative_inventory(itemstring) Authentication: minetest.notify_authentication_modified(name) @@ -1115,6 +1114,8 @@ minetest.find_nodes_in_area(minp, maxp, nodenames) -> list of positions ^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt" minetest.get_perlin(seeddiff, octaves, persistence, scale) ^ Return world-specific perlin noise (int(worldseed)+seeddiff) +minetest.get_voxel_manip() +^ Return voxel manipulator object minetest.clear_objects() ^ clear all objects in the environments minetest.line_of_sight(pos1,pos2,stepsize) ->true/false @@ -1306,6 +1307,10 @@ minetest.get_item_group(name, group) -> rating ^ Get rating of a group of an item. (0 = not in group) minetest.get_node_group(name, group) -> rating ^ Deprecated: An alias for the former. +minetest.get_content_id(name) -> integer +^ Gets the internal content ID of name +minetest.get_name_from_content_id(content_id) -> string +^ Gets the name of the content with that content ID minetest.serialize(table) -> string ^ Convert a table containing tables, strings, numbers, booleans and nils into string form readable by minetest.deserialize @@ -1522,6 +1527,23 @@ methods: - get2d(pos) -> 2d noise value at pos={x=,y=} - get3d(pos) -> 3d noise value at pos={x=,y=,z=} +VoxelManip: An interface to the MapVoxelManipulator for Lua +- Can be created via VoxelManip() +- Also minetest.get_voxel_manip() +methods: +- read_chunk(p1, p2): Read a chunk of map containing the region formed by p1 and p2. + ^ returns raw node data, actual emerged p1, actual emerged p2 + ^ raw node data is in the form of a table mapping indicies to node content ids +- write_chunk(data): Write back the data +- update_map(): Update map after writing chunk. + ^ To be used only by VoxelManip objects created by the mod itself; not VoxelManips passed to callbacks +- set_lighting(p1, p2, light): Set the lighting in the region formed by p1 and p2 to light + ^ light is a table containing two integer fields ranging from 0 to 15, day and night + ^ To be used only by VoxelManip objects passed to a callback; otherwise, set lighting will be ignored +- calc_lighting(p1, p2): Calculate lighting in the region formed by p1 and p2 + ^ To be used only by VoxelManip objects passed to a callback; otherwise, calculated lighting will be ignored +- update_liquids(): Update liquid flow + Registered entities -------------------- - Functions receive a "luaentity" as self: diff --git a/src/map.h b/src/map.h index 530d81e7a..8326d3e58 100644 --- a/src/map.h +++ b/src/map.h @@ -337,6 +337,7 @@ public: s32 transforming_liquid_size(); protected: + friend class LuaVoxelManip; std::ostream &m_dout; // A bit deprecated, could be removed diff --git a/src/mapgen.h b/src/mapgen.h index 0090b0eda..0ed64f85c 100644 --- a/src/mapgen.h +++ b/src/mapgen.h @@ -108,8 +108,8 @@ public: void calcLighting(v3s16 nmin, v3s16 nmax); void calcLightingOld(v3s16 nmin, v3s16 nmax); - virtual void makeChunk(BlockMakeData *data) {}; - virtual int getGroundLevelAtPoint(v2s16 p) = 0; + virtual void makeChunk(BlockMakeData *data) {} + virtual int getGroundLevelAtPoint(v2s16 p) { return 0; } //Legacy functions for Farmesh (pending removal) static bool get_have_beach(u64 seed, v2s16 p2d); diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index da4e17d89..8799d3c00 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -89,6 +89,7 @@ protected: friend class NodeMetaRef; friend class ModApiBase; friend class ModApiEnvMod; + friend class LuaVoxelManip; inline lua_State* getStack() diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt index 7610ce8f1..f67cf6886 100644 --- a/src/script/lua_api/CMakeLists.txt +++ b/src/script/lua_api/CMakeLists.txt @@ -10,4 +10,5 @@ set(SCRIPT_LUA_API_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_object.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_particles.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp PARENT_SCOPE) diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index a287281a9..6f663646c 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "cpp_api/scriptapi.h" #include "lua_api/l_base.h" #include "lua_api/l_env.h" +#include "lua_api/l_vmanip.h" #include "environment.h" #include "server.h" #include "daynightratio.h" @@ -533,6 +534,21 @@ int ModApiEnvMod::l_get_perlin_map(lua_State *L) return 1; } +// minetest.get_voxel_manip() +// returns voxel manipulator +int ModApiEnvMod::l_get_voxel_manip(lua_State *L) +{ + GET_ENV_PTR; + + Map *map = &(env->getMap()); + LuaVoxelManip *vm = new LuaVoxelManip(map); + + *(void **)(lua_newuserdata(L, sizeof(void *))) = vm; + luaL_getmetatable(L, "VoxelManip"); + lua_setmetatable(L, -2); + return 1; +} + // minetest.clear_objects() // clear all objects in the environment int ModApiEnvMod::l_clear_objects(lua_State *L) @@ -554,8 +570,8 @@ int ModApiEnvMod::l_line_of_sight(lua_State *L) { // 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); + if (lua_isnumber(L, 3)) + stepsize = lua_tonumber(L, 3); return (env->line_of_sight(pos1,pos2,stepsize)); } @@ -572,8 +588,8 @@ int ModApiEnvMod::l_find_path(lua_State *L) unsigned int max_jump = luaL_checkint(L, 4); unsigned int max_drop = luaL_checkint(L, 5); algorithm algo = A_PLAIN_NP; - if(! lua_isnil(L, 6)) { - std::string algorithm = luaL_checkstring(L,6); + if (!lua_isnil(L, 6)) { + std::string algorithm = luaL_checkstring(L,6); if (algorithm == "A*") algo = A_PLAIN; @@ -678,6 +694,7 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top) retval &= API_FCT(find_nodes_in_area); retval &= API_FCT(get_perlin); retval &= API_FCT(get_perlin_map); + retval &= API_FCT(get_voxel_manip); retval &= API_FCT(clear_objects); retval &= API_FCT(spawn_tree); retval &= API_FCT(find_path); diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 61ecaecc8..24700d27c 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -109,6 +109,10 @@ private: // minetest.get_perlin_map(noiseparams, size) // returns world-specific PerlinNoiseMap static int l_get_perlin_map(lua_State *L); + + // minetest.get_voxel_manip() + // returns world-specific voxel manipulator + static int l_get_voxel_manip(lua_State *L); // minetest.clear_objects() // clear all objects in the environment diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 730dfd49b..c69562dda 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -457,12 +457,40 @@ int ModApiItemMod::l_register_alias_raw(lua_State *L) return 0; /* number of results */ } +// get_content_id(name) +int ModApiItemMod::l_get_content_id(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + std::string name = luaL_checkstring(L, 1); + + INodeDefManager *ndef = STACK_TO_SERVER(L)->getNodeDefManager(); + content_t c = ndef->getId(name); + + lua_pushnumber(L, c); + return 1; /* number of results */ +} + +// get_name_from_content_id(name) +int ModApiItemMod::l_get_name_from_content_id(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + content_t c = luaL_checkint(L, 1); + + INodeDefManager *ndef = STACK_TO_SERVER(L)->getNodeDefManager(); + const char *name = ndef->get(c).name.c_str(); + + lua_pushstring(L, name); + return 1; /* number of results */ +} + bool ModApiItemMod::Initialize(lua_State *L,int top) { bool retval = true; retval &= API_FCT(register_item_raw); retval &= API_FCT(register_alias_raw); + retval &= API_FCT(get_content_id); + retval &= API_FCT(get_name_from_content_id); LuaItemStack::Register(L); diff --git a/src/script/lua_api/l_item.h b/src/script/lua_api/l_item.h index cbed4ae0b..bad517e08 100644 --- a/src/script/lua_api/l_item.h +++ b/src/script/lua_api/l_item.h @@ -140,10 +140,12 @@ class ModApiItemMod public: ModApiItemMod(); - bool Initialize(lua_State *L,int top); + bool Initialize(lua_State *L, int top); static int l_register_item_raw(lua_State *L); static int l_register_alias_raw(lua_State *L); + static int l_get_content_id(lua_State *L); + static int l_get_name_from_content_id(lua_State *L); }; diff --git a/src/script/lua_api/l_vmanip.cpp b/src/script/lua_api/l_vmanip.cpp new file mode 100644 index 000000000..e0397dfce --- /dev/null +++ b/src/script/lua_api/l_vmanip.cpp @@ -0,0 +1,264 @@ +/* +Minetest +Copyright (C) 2013 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "lua_api/l_base.h" +#include "lua_api/l_vmanip.h" + +/////// + +#include "cpp_api/scriptapi.h" +#include "common/c_converter.h" +#include "server.h" +#include "emerge.h" +#include "common/c_internal.h" + +// garbage collector +int LuaVoxelManip::gc_object(lua_State *L) +{ + LuaVoxelManip *o = *(LuaVoxelManip **)(lua_touserdata(L, 1)); + delete o; + + return 0; +} + +int LuaVoxelManip::l_read_chunk(lua_State *L) +{ + LuaVoxelManip *o = checkobject(L, 1); + + v3s16 bp1 = getNodeBlockPos(read_v3s16(L, 2)); + v3s16 bp2 = getNodeBlockPos(read_v3s16(L, 3)); + sortBoxVerticies(bp1, bp2); + ManualMapVoxelManipulator *vm = o->vm; + vm->initialEmerge(bp1, bp2); + + v3s16 emerged_p1 = vm->m_area.MinEdge; + v3s16 emerged_p2 = vm->m_area.MaxEdge; + + int volume = vm->m_area.getVolume(); + + lua_newtable(L); + for (int i = 0; i != volume; i++) { + lua_Number cid = vm->m_data[i].getContent(); + lua_pushnumber(L, cid); + lua_rawseti(L, -2, i + 1); + } + + push_v3s16(L, emerged_p1); + push_v3s16(L, emerged_p2); + + return 3; +} + +int LuaVoxelManip::l_write_chunk(lua_State *L) +{ + LuaVoxelManip *o = checkobject(L, 1); + if (!lua_istable(L, 2)) + return 0; + + ManualMapVoxelManipulator *vm = o->vm; + + int volume = vm->m_area.getVolume(); + for (int i = 0; i != volume; i++) { + lua_rawgeti(L, 2, i + 1); + content_t c = lua_tonumber(L, -1); + + vm->m_data[i].setContent(c); + + lua_pop(L, 1); + + } + + vm->blitBackAll(&o->modified_blocks); + + return 0; +} + +int LuaVoxelManip::l_update_liquids(lua_State *L) +{ + LuaVoxelManip *o = checkobject(L, 1); + + ManualMapVoxelManipulator *vm = o->vm; + INodeDefManager *ndef = STACK_TO_SERVER(L)->getNodeDefManager(); + Map *map = &(get_scriptapi(L)->getEnv()->getMap()); + + Mapgen mg; + mg.vm = vm; + mg.ndef = ndef; + + mg.updateLiquid(&map->m_transforming_liquid, + vm->m_area.MinEdge, vm->m_area.MaxEdge); + + return 0; +} + +int LuaVoxelManip::l_calc_lighting(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + LuaVoxelManip *o = checkobject(L, 1); + v3s16 p1 = read_v3s16(L, 2); + v3s16 p2 = read_v3s16(L, 3); + sortBoxVerticies(p1, p2); + + ManualMapVoxelManipulator *vm = o->vm; + INodeDefManager *ndef = STACK_TO_SERVER(L)->getNodeDefManager(); + EmergeManager *emerge = STACK_TO_SERVER(L)->getEmergeManager(); + + Mapgen mg; + mg.vm = vm; + mg.ndef = ndef; + mg.water_level = emerge->params->water_level; + + mg.calcLighting(p1, p2); + + return 0; +} + +int LuaVoxelManip::l_set_lighting(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + LuaVoxelManip *o = checkobject(L, 1); + v3s16 p1 = read_v3s16(L, 2); + v3s16 p2 = read_v3s16(L, 3); + sortBoxVerticies(p1, p2); + + u8 light; + if (!lua_istable(L, 4)) + return 0; + + light = getintfield_default(L, 4, "day", 0); + light |= getintfield_default(L, 4, "night", 0); + + ManualMapVoxelManipulator *vm = o->vm; + + Mapgen mg; + mg.vm = vm; + + mg.setLighting(p1, p2, light); + + return 0; +} + +int LuaVoxelManip::l_update_map(lua_State *L) +{ + LuaVoxelManip *o = checkobject(L, 1); + + // TODO: Optimize this by using Mapgen::calcLighting() instead + std::map lighting_mblocks; + std::map *mblocks = &o->modified_blocks; + + lighting_mblocks.insert(mblocks->begin(), mblocks->end()); + + Map *map = &(get_scriptapi(L)->getEnv()->getMap()); + map->updateLighting(lighting_mblocks, *mblocks); + + MapEditEvent event; + event.type = MEET_OTHER; + for (std::map::iterator + it = mblocks->begin(); + it != mblocks->end(); ++it) + event.modified_blocks.insert(it->first); + + map->dispatchEvent(&event); + + mblocks->clear(); + + return 0; +} + +LuaVoxelManip::LuaVoxelManip(Map *map) +{ + vm = new ManualMapVoxelManipulator(map); +} + +LuaVoxelManip::~LuaVoxelManip() +{ + delete vm; +} + +// LuaVoxelManip() +// Creates an LuaVoxelManip and leaves it on top of stack +int LuaVoxelManip::create_object(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + Map *map = &(get_scriptapi(L)->getEnv()->getMap()); + LuaVoxelManip *o = new LuaVoxelManip(map); + + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); + return 1; +} + +LuaVoxelManip *LuaVoxelManip::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 *(LuaVoxelManip **)ud; // unbox pointer +} + +void LuaVoxelManip::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); // hide metatable from Lua getmetatable() + + 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_pop(L, 1); // drop metatable + + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable + + // Can be created from Lua (VoxelManip() + lua_register(L, className, create_object); +} + +const char LuaVoxelManip::className[] = "VoxelManip"; +const luaL_reg LuaVoxelManip::methods[] = { + luamethod(LuaVoxelManip, read_chunk), + luamethod(LuaVoxelManip, write_chunk), + luamethod(LuaVoxelManip, update_map), + luamethod(LuaVoxelManip, update_liquids), + luamethod(LuaVoxelManip, calc_lighting), + luamethod(LuaVoxelManip, set_lighting), + {0,0} +}; + +REGISTER_LUA_REF(LuaVoxelManip); diff --git a/src/script/lua_api/l_vmanip.h b/src/script/lua_api/l_vmanip.h new file mode 100644 index 000000000..568f7104e --- /dev/null +++ b/src/script/lua_api/l_vmanip.h @@ -0,0 +1,65 @@ +/* +Minetest +Copyright (C) 2013 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef L_VMANIP_H_ +#define L_VMANIP_H_ + +extern "C" { +#include +#include +} + +#include "irr_v3d.h" +#include "map.h" + +/* + VoxelManip + */ +class LuaVoxelManip +{ +private: + ManualMapVoxelManipulator *vm; + std::map modified_blocks; + + static const char className[]; + static const luaL_reg methods[]; + + static int gc_object(lua_State *L); + + static int l_read_chunk(lua_State *L); + static int l_write_chunk(lua_State *L); + static int l_update_map(lua_State *L); + static int l_update_liquids(lua_State *L); + static int l_calc_lighting(lua_State *L); + static int l_set_lighting(lua_State *L); + +public: + LuaVoxelManip(Map *map); + ~LuaVoxelManip(); + + // LuaVoxelManip() + // Creates a LuaVoxelManip and leaves it on top of stack + static int create_object(lua_State *L); + + static LuaVoxelManip *checkobject(lua_State *L, int narg); + + static void Register(lua_State *L); +}; + +#endif // L_VMANIP_H_