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