1 /*
2 Minetest
3 Copyright (C) 2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 
21 #include "lua_api/l_vmanip.h"
22 #include "lua_api/l_internal.h"
23 #include "common/c_content.h"
24 #include "common/c_converter.h"
25 #include "emerge.h"
26 #include "environment.h"
27 #include "map.h"
28 #include "mapblock.h"
29 #include "server.h"
30 #include "mapgen/mapgen.h"
31 #include "voxelalgorithms.h"
32 
33 // garbage collector
gc_object(lua_State * L)34 int LuaVoxelManip::gc_object(lua_State *L)
35 {
36 	LuaVoxelManip *o = *(LuaVoxelManip **)(lua_touserdata(L, 1));
37 	delete o;
38 
39 	return 0;
40 }
41 
l_read_from_map(lua_State * L)42 int LuaVoxelManip::l_read_from_map(lua_State *L)
43 {
44 	MAP_LOCK_REQUIRED;
45 
46 	LuaVoxelManip *o = checkobject(L, 1);
47 	MMVManip *vm = o->vm;
48 
49 	v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 2));
50 	v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 3));
51 	sortBoxVerticies(bp1, bp2);
52 
53 	vm->initialEmerge(bp1, bp2);
54 
55 	push_v3s16(L, vm->m_area.MinEdge);
56 	push_v3s16(L, vm->m_area.MaxEdge);
57 
58 	return 2;
59 }
60 
l_get_data(lua_State * L)61 int LuaVoxelManip::l_get_data(lua_State *L)
62 {
63 	NO_MAP_LOCK_REQUIRED;
64 
65 	LuaVoxelManip *o = checkobject(L, 1);
66 	bool use_buffer  = lua_istable(L, 2);
67 
68 	MMVManip *vm = o->vm;
69 
70 	u32 volume = vm->m_area.getVolume();
71 
72 	if (use_buffer)
73 		lua_pushvalue(L, 2);
74 	else
75 		lua_createtable(L, volume, 0);
76 
77 	for (u32 i = 0; i != volume; i++) {
78 		lua_Integer cid = vm->m_data[i].getContent();
79 		lua_pushinteger(L, cid);
80 		lua_rawseti(L, -2, i + 1);
81 	}
82 
83 	return 1;
84 }
85 
l_set_data(lua_State * L)86 int LuaVoxelManip::l_set_data(lua_State *L)
87 {
88 	NO_MAP_LOCK_REQUIRED;
89 
90 	LuaVoxelManip *o = checkobject(L, 1);
91 	MMVManip *vm = o->vm;
92 
93 	if (!lua_istable(L, 2))
94 		throw LuaError("VoxelManip:set_data called with missing parameter");
95 
96 	u32 volume = vm->m_area.getVolume();
97 	for (u32 i = 0; i != volume; i++) {
98 		lua_rawgeti(L, 2, i + 1);
99 		content_t c = lua_tointeger(L, -1);
100 
101 		vm->m_data[i].setContent(c);
102 
103 		lua_pop(L, 1);
104 	}
105 
106 	return 0;
107 }
108 
l_write_to_map(lua_State * L)109 int LuaVoxelManip::l_write_to_map(lua_State *L)
110 {
111 	MAP_LOCK_REQUIRED;
112 
113 	LuaVoxelManip *o = checkobject(L, 1);
114 	bool update_light = !lua_isboolean(L, 2) || readParam<bool>(L, 2);
115 	GET_ENV_PTR;
116 	ServerMap *map = &(env->getServerMap());
117 	if (o->is_mapgen_vm || !update_light) {
118 		o->vm->blitBackAll(&(o->modified_blocks));
119 	} else {
120 		voxalgo::blit_back_with_light(map, o->vm,
121 			&(o->modified_blocks));
122 	}
123 
124 	MapEditEvent event;
125 	event.type = MEET_OTHER;
126 	for (const auto &modified_block : o->modified_blocks)
127 		event.modified_blocks.insert(modified_block.first);
128 
129 	map->dispatchEvent(event);
130 
131 	o->modified_blocks.clear();
132 	return 0;
133 }
134 
l_get_node_at(lua_State * L)135 int LuaVoxelManip::l_get_node_at(lua_State *L)
136 {
137 	NO_MAP_LOCK_REQUIRED;
138 
139 	const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
140 
141 	LuaVoxelManip *o = checkobject(L, 1);
142 	v3s16 pos        = check_v3s16(L, 2);
143 
144 	pushnode(L, o->vm->getNodeNoExNoEmerge(pos), ndef);
145 	return 1;
146 }
147 
l_set_node_at(lua_State * L)148 int LuaVoxelManip::l_set_node_at(lua_State *L)
149 {
150 	NO_MAP_LOCK_REQUIRED;
151 
152 	const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
153 
154 	LuaVoxelManip *o = checkobject(L, 1);
155 	v3s16 pos        = check_v3s16(L, 2);
156 	MapNode n        = readnode(L, 3, ndef);
157 
158 	o->vm->setNodeNoEmerge(pos, n);
159 
160 	return 0;
161 }
162 
l_update_liquids(lua_State * L)163 int LuaVoxelManip::l_update_liquids(lua_State *L)
164 {
165 	GET_ENV_PTR;
166 
167 	LuaVoxelManip *o = checkobject(L, 1);
168 
169 	Map *map = &(env->getMap());
170 	const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
171 	MMVManip *vm = o->vm;
172 
173 	Mapgen mg;
174 	mg.vm   = vm;
175 	mg.ndef = ndef;
176 
177 	mg.updateLiquid(&map->m_transforming_liquid,
178 			vm->m_area.MinEdge, vm->m_area.MaxEdge);
179 
180 	return 0;
181 }
182 
l_calc_lighting(lua_State * L)183 int LuaVoxelManip::l_calc_lighting(lua_State *L)
184 {
185 	NO_MAP_LOCK_REQUIRED;
186 
187 	LuaVoxelManip *o = checkobject(L, 1);
188 	if (!o->is_mapgen_vm) {
189 		warningstream << "VoxelManip:calc_lighting called for a non-mapgen "
190 			"VoxelManip object" << std::endl;
191 		return 0;
192 	}
193 
194 	const NodeDefManager *ndef = getServer(L)->getNodeDefManager();
195 	EmergeManager *emerge = getServer(L)->getEmergeManager();
196 	MMVManip *vm = o->vm;
197 
198 	v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
199 	v3s16 fpmin  = vm->m_area.MinEdge;
200 	v3s16 fpmax  = vm->m_area.MaxEdge;
201 	v3s16 pmin   = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
202 	v3s16 pmax   = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
203 	bool propagate_shadow = !lua_isboolean(L, 4) || readParam<bool>(L, 4);
204 
205 	sortBoxVerticies(pmin, pmax);
206 	if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
207 		throw LuaError("Specified voxel area out of VoxelManipulator bounds");
208 
209 	Mapgen mg;
210 	mg.vm          = vm;
211 	mg.ndef        = ndef;
212 	mg.water_level = emerge->mgparams->water_level;
213 
214 	mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);
215 
216 	return 0;
217 }
218 
l_set_lighting(lua_State * L)219 int LuaVoxelManip::l_set_lighting(lua_State *L)
220 {
221 	NO_MAP_LOCK_REQUIRED;
222 
223 	LuaVoxelManip *o = checkobject(L, 1);
224 	if (!o->is_mapgen_vm) {
225 		warningstream << "VoxelManip:set_lighting called for a non-mapgen "
226 			"VoxelManip object" << std::endl;
227 		return 0;
228 	}
229 
230 	if (!lua_istable(L, 2))
231 		throw LuaError("VoxelManip:set_lighting called with missing parameter");
232 
233 	u8 light;
234 	light  = (getintfield_default(L, 2, "day",   0) & 0x0F);
235 	light |= (getintfield_default(L, 2, "night", 0) & 0x0F) << 4;
236 
237 	MMVManip *vm = o->vm;
238 
239 	v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
240 	v3s16 pmin = lua_istable(L, 3) ? check_v3s16(L, 3) : vm->m_area.MinEdge + yblock;
241 	v3s16 pmax = lua_istable(L, 4) ? check_v3s16(L, 4) : vm->m_area.MaxEdge - yblock;
242 
243 	sortBoxVerticies(pmin, pmax);
244 	if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
245 		throw LuaError("Specified voxel area out of VoxelManipulator bounds");
246 
247 	Mapgen mg;
248 	mg.vm = vm;
249 
250 	mg.setLighting(light, pmin, pmax);
251 
252 	return 0;
253 }
254 
l_get_light_data(lua_State * L)255 int LuaVoxelManip::l_get_light_data(lua_State *L)
256 {
257 	NO_MAP_LOCK_REQUIRED;
258 
259 	LuaVoxelManip *o = checkobject(L, 1);
260 	MMVManip *vm = o->vm;
261 
262 	u32 volume = vm->m_area.getVolume();
263 
264 	lua_createtable(L, volume, 0);
265 	for (u32 i = 0; i != volume; i++) {
266 		lua_Integer light = vm->m_data[i].param1;
267 		lua_pushinteger(L, light);
268 		lua_rawseti(L, -2, i + 1);
269 	}
270 
271 	return 1;
272 }
273 
l_set_light_data(lua_State * L)274 int LuaVoxelManip::l_set_light_data(lua_State *L)
275 {
276 	NO_MAP_LOCK_REQUIRED;
277 
278 	LuaVoxelManip *o = checkobject(L, 1);
279 	MMVManip *vm = o->vm;
280 
281 	if (!lua_istable(L, 2))
282 		throw LuaError("VoxelManip:set_light_data called with missing "
283 				"parameter");
284 
285 	u32 volume = vm->m_area.getVolume();
286 	for (u32 i = 0; i != volume; i++) {
287 		lua_rawgeti(L, 2, i + 1);
288 		u8 light = lua_tointeger(L, -1);
289 
290 		vm->m_data[i].param1 = light;
291 
292 		lua_pop(L, 1);
293 	}
294 
295 	return 0;
296 }
297 
l_get_param2_data(lua_State * L)298 int LuaVoxelManip::l_get_param2_data(lua_State *L)
299 {
300 	NO_MAP_LOCK_REQUIRED;
301 
302 	LuaVoxelManip *o = checkobject(L, 1);
303 	bool use_buffer  = lua_istable(L, 2);
304 
305 	MMVManip *vm = o->vm;
306 
307 	u32 volume = vm->m_area.getVolume();
308 
309 	if (use_buffer)
310 		lua_pushvalue(L, 2);
311 	else
312 		lua_createtable(L, volume, 0);
313 
314 	for (u32 i = 0; i != volume; i++) {
315 		lua_Integer param2 = vm->m_data[i].param2;
316 		lua_pushinteger(L, param2);
317 		lua_rawseti(L, -2, i + 1);
318 	}
319 
320 	return 1;
321 }
322 
l_set_param2_data(lua_State * L)323 int LuaVoxelManip::l_set_param2_data(lua_State *L)
324 {
325 	NO_MAP_LOCK_REQUIRED;
326 
327 	LuaVoxelManip *o = checkobject(L, 1);
328 	MMVManip *vm = o->vm;
329 
330 	if (!lua_istable(L, 2))
331 		throw LuaError("VoxelManip:set_param2_data called with missing "
332 				"parameter");
333 
334 	u32 volume = vm->m_area.getVolume();
335 	for (u32 i = 0; i != volume; i++) {
336 		lua_rawgeti(L, 2, i + 1);
337 		u8 param2 = lua_tointeger(L, -1);
338 
339 		vm->m_data[i].param2 = param2;
340 
341 		lua_pop(L, 1);
342 	}
343 
344 	return 0;
345 }
346 
l_update_map(lua_State * L)347 int LuaVoxelManip::l_update_map(lua_State *L)
348 {
349 	return 0;
350 }
351 
l_was_modified(lua_State * L)352 int LuaVoxelManip::l_was_modified(lua_State *L)
353 {
354 	NO_MAP_LOCK_REQUIRED;
355 
356 	LuaVoxelManip *o = checkobject(L, 1);
357 	MMVManip *vm = o->vm;
358 
359 	lua_pushboolean(L, vm->m_is_dirty);
360 
361 	return 1;
362 }
363 
l_get_emerged_area(lua_State * L)364 int LuaVoxelManip::l_get_emerged_area(lua_State *L)
365 {
366 	NO_MAP_LOCK_REQUIRED;
367 
368 	LuaVoxelManip *o = checkobject(L, 1);
369 
370 	push_v3s16(L, o->vm->m_area.MinEdge);
371 	push_v3s16(L, o->vm->m_area.MaxEdge);
372 
373 	return 2;
374 }
375 
LuaVoxelManip(MMVManip * mmvm,bool is_mg_vm)376 LuaVoxelManip::LuaVoxelManip(MMVManip *mmvm, bool is_mg_vm) :
377 	is_mapgen_vm(is_mg_vm),
378 	vm(mmvm)
379 {
380 }
381 
LuaVoxelManip(Map * map)382 LuaVoxelManip::LuaVoxelManip(Map *map) : vm(new MMVManip(map))
383 {
384 }
385 
LuaVoxelManip(Map * map,v3s16 p1,v3s16 p2)386 LuaVoxelManip::LuaVoxelManip(Map *map, v3s16 p1, v3s16 p2)
387 {
388 	vm = new MMVManip(map);
389 
390 	v3s16 bp1 = getNodeBlockPos(p1);
391 	v3s16 bp2 = getNodeBlockPos(p2);
392 	sortBoxVerticies(bp1, bp2);
393 	vm->initialEmerge(bp1, bp2);
394 }
395 
~LuaVoxelManip()396 LuaVoxelManip::~LuaVoxelManip()
397 {
398 	if (!is_mapgen_vm)
399 		delete vm;
400 }
401 
402 // LuaVoxelManip()
403 // Creates an LuaVoxelManip and leaves it on top of stack
create_object(lua_State * L)404 int LuaVoxelManip::create_object(lua_State *L)
405 {
406 	GET_ENV_PTR;
407 
408 	Map *map = &(env->getMap());
409 	LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
410 		new LuaVoxelManip(map, check_v3s16(L, 1), check_v3s16(L, 2)) :
411 		new LuaVoxelManip(map);
412 
413 	*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
414 	luaL_getmetatable(L, className);
415 	lua_setmetatable(L, -2);
416 	return 1;
417 }
418 
checkobject(lua_State * L,int narg)419 LuaVoxelManip *LuaVoxelManip::checkobject(lua_State *L, int narg)
420 {
421 	NO_MAP_LOCK_REQUIRED;
422 
423 	luaL_checktype(L, narg, LUA_TUSERDATA);
424 
425 	void *ud = luaL_checkudata(L, narg, className);
426 	if (!ud)
427 		luaL_typerror(L, narg, className);
428 
429 	return *(LuaVoxelManip **)ud;  // unbox pointer
430 }
431 
Register(lua_State * L)432 void LuaVoxelManip::Register(lua_State *L)
433 {
434 	lua_newtable(L);
435 	int methodtable = lua_gettop(L);
436 	luaL_newmetatable(L, className);
437 	int metatable = lua_gettop(L);
438 
439 	lua_pushliteral(L, "__metatable");
440 	lua_pushvalue(L, methodtable);
441 	lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
442 
443 	lua_pushliteral(L, "__index");
444 	lua_pushvalue(L, methodtable);
445 	lua_settable(L, metatable);
446 
447 	lua_pushliteral(L, "__gc");
448 	lua_pushcfunction(L, gc_object);
449 	lua_settable(L, metatable);
450 
451 	lua_pop(L, 1);  // drop metatable
452 
453 	luaL_openlib(L, 0, methods, 0);  // fill methodtable
454 	lua_pop(L, 1);  // drop methodtable
455 
456 	// Can be created from Lua (VoxelManip())
457 	lua_register(L, className, create_object);
458 }
459 
460 const char LuaVoxelManip::className[] = "VoxelManip";
461 const luaL_Reg LuaVoxelManip::methods[] = {
462 	luamethod(LuaVoxelManip, read_from_map),
463 	luamethod(LuaVoxelManip, get_data),
464 	luamethod(LuaVoxelManip, set_data),
465 	luamethod(LuaVoxelManip, get_node_at),
466 	luamethod(LuaVoxelManip, set_node_at),
467 	luamethod(LuaVoxelManip, write_to_map),
468 	luamethod(LuaVoxelManip, update_map),
469 	luamethod(LuaVoxelManip, update_liquids),
470 	luamethod(LuaVoxelManip, calc_lighting),
471 	luamethod(LuaVoxelManip, set_lighting),
472 	luamethod(LuaVoxelManip, get_light_data),
473 	luamethod(LuaVoxelManip, set_light_data),
474 	luamethod(LuaVoxelManip, get_param2_data),
475 	luamethod(LuaVoxelManip, set_param2_data),
476 	luamethod(LuaVoxelManip, was_modified),
477 	luamethod(LuaVoxelManip, get_emerged_area),
478 	{0,0}
479 };
480