From d6ac3d8d9a6484f2d348d1caea203de0069b6bd6 Mon Sep 17 00:00:00 2001
From: kwolekr <kwolekr@minetest.net>
Date: Tue, 25 Jun 2013 11:02:02 -0400
Subject: [PATCH] Add LuaVoxelManip

---
 doc/lua_api.txt                   |  24 ++-
 src/map.h                         |   1 +
 src/mapgen.h                      |   4 +-
 src/script/cpp_api/s_base.h       |   1 +
 src/script/lua_api/CMakeLists.txt |   1 +
 src/script/lua_api/l_env.cpp      |  25 ++-
 src/script/lua_api/l_env.h        |   4 +
 src/script/lua_api/l_item.cpp     |  28 ++++
 src/script/lua_api/l_item.h       |   4 +-
 src/script/lua_api/l_vmanip.cpp   | 264 ++++++++++++++++++++++++++++++
 src/script/lua_api/l_vmanip.h     |  65 ++++++++
 11 files changed, 413 insertions(+), 8 deletions(-)
 create mode 100644 src/script/lua_api/l_vmanip.cpp
 create mode 100644 src/script/lua_api/l_vmanip.h

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 @@ class Map /*: public NodeContainer*/
 	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 @@ class Mapgen {
 	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 @@ class ScriptApiBase {
 	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 @@ class ModApiEnvMod
 	// 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 <kwolekr@minetest.net>
+
+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<v3s16, MapBlock *> lighting_mblocks;
+	std::map<v3s16, MapBlock *> *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<v3s16, MapBlock *>::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 <kwolekr@minetest.net>
+
+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 <lua.h>
+#include <lauxlib.h>
+}
+
+#include "irr_v3d.h"
+#include "map.h"
+
+/*
+  VoxelManip
+ */
+class LuaVoxelManip
+{
+private:
+	ManualMapVoxelManipulator *vm;
+	std::map<v3s16, MapBlock *> 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_
-- 
GitLab