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