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