Switch to check_v3s16 in l_mapgen.cpp and l_vmanip.cpp for type safety
[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         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
61 int LuaVoxelManip::l_get_data(lua_State *L)
62 {
63         NO_MAP_LOCK_REQUIRED;
64
65         LuaVoxelManip *o = checkobject(L, 1);
66         MMVManip *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         MMVManip *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         MMVManip *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        = check_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        = check_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         MMVManip *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         MMVManip *vm = o->vm;
170
171         v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
172         v3s16 fpmin  = vm->m_area.MinEdge;
173         v3s16 fpmax  = vm->m_area.MaxEdge;
174         v3s16 pmin   = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
175         v3s16 pmax   = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
176
177         sortBoxVerticies(pmin, pmax);
178         if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
179                 throw LuaError("Specified voxel area out of VoxelManipulator bounds");
180
181         Mapgen mg;
182         mg.vm          = vm;
183         mg.ndef        = ndef;
184         mg.water_level = emerge->params.water_level;
185
186         mg.calcLighting(pmin, pmax, fpmin, fpmax);
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         MMVManip *vm = o->vm;
207
208         v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
209         v3s16 pmin = lua_istable(L, 3) ? check_v3s16(L, 3) : vm->m_area.MinEdge + yblock;
210         v3s16 pmax = lua_istable(L, 4) ? check_v3s16(L, 4) : vm->m_area.MaxEdge - yblock;
211
212         sortBoxVerticies(pmin, pmax);
213         if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
214                 throw LuaError("Specified voxel area out of VoxelManipulator bounds");
215
216         Mapgen mg;
217         mg.vm = vm;
218
219         mg.setLighting(light, pmin, pmax);
220
221         return 0;
222 }
223
224 int LuaVoxelManip::l_get_light_data(lua_State *L)
225 {
226         NO_MAP_LOCK_REQUIRED;
227
228         LuaVoxelManip *o = checkobject(L, 1);
229         MMVManip *vm = o->vm;
230
231         int volume = vm->m_area.getVolume();
232
233         lua_newtable(L);
234         for (int i = 0; i != volume; i++) {
235                 lua_Integer light = vm->m_data[i].param1;
236                 lua_pushinteger(L, light);
237                 lua_rawseti(L, -2, i + 1);
238         }
239
240         return 1;
241 }
242
243 int LuaVoxelManip::l_set_light_data(lua_State *L)
244 {
245         NO_MAP_LOCK_REQUIRED;
246
247         LuaVoxelManip *o = checkobject(L, 1);
248         MMVManip *vm = o->vm;
249
250         if (!lua_istable(L, 2))
251                 return 0;
252
253         int volume = vm->m_area.getVolume();
254         for (int i = 0; i != volume; i++) {
255                 lua_rawgeti(L, 2, i + 1);
256                 u8 light = lua_tointeger(L, -1);
257
258                 vm->m_data[i].param1 = light;
259
260                 lua_pop(L, 1);
261         }
262
263         return 0;
264 }
265
266 int LuaVoxelManip::l_get_param2_data(lua_State *L)
267 {
268         NO_MAP_LOCK_REQUIRED;
269
270         LuaVoxelManip *o = checkobject(L, 1);
271         MMVManip *vm = o->vm;
272
273         int volume = vm->m_area.getVolume();
274
275         lua_newtable(L);
276         for (int i = 0; i != volume; i++) {
277                 lua_Integer param2 = vm->m_data[i].param2;
278                 lua_pushinteger(L, param2);
279                 lua_rawseti(L, -2, i + 1);
280         }
281
282         return 1;
283 }
284
285 int LuaVoxelManip::l_set_param2_data(lua_State *L)
286 {
287         NO_MAP_LOCK_REQUIRED;
288
289         LuaVoxelManip *o = checkobject(L, 1);
290         MMVManip *vm = o->vm;
291
292         if (!lua_istable(L, 2))
293                 return 0;
294
295         int volume = vm->m_area.getVolume();
296         for (int i = 0; i != volume; i++) {
297                 lua_rawgeti(L, 2, i + 1);
298                 u8 param2 = lua_tointeger(L, -1);
299
300                 vm->m_data[i].param2 = param2;
301
302                 lua_pop(L, 1);
303         }
304
305         return 0;
306 }
307
308 int LuaVoxelManip::l_update_map(lua_State *L)
309 {
310         LuaVoxelManip *o = checkobject(L, 1);
311         if (o->is_mapgen_vm)
312                 return 0;
313
314         Environment *env = getEnv(L);
315         if (!env)
316                 return 0;
317
318         Map *map = &(env->getMap());
319
320         // TODO: Optimize this by using Mapgen::calcLighting() instead
321         std::map<v3s16, MapBlock *> lighting_mblocks;
322         std::map<v3s16, MapBlock *> *mblocks = &o->modified_blocks;
323
324         lighting_mblocks.insert(mblocks->begin(), mblocks->end());
325
326         map->updateLighting(lighting_mblocks, *mblocks);
327
328         MapEditEvent event;
329         event.type = MEET_OTHER;
330         for (std::map<v3s16, MapBlock *>::iterator
331                 it = mblocks->begin();
332                 it != mblocks->end(); ++it)
333                 event.modified_blocks.insert(it->first);
334
335         map->dispatchEvent(&event);
336
337         mblocks->clear();
338
339         return 0;
340 }
341
342 int LuaVoxelManip::l_was_modified(lua_State *L)
343 {
344         NO_MAP_LOCK_REQUIRED;
345
346         LuaVoxelManip *o = checkobject(L, 1);
347         MMVManip *vm = o->vm;
348
349         lua_pushboolean(L, vm->m_is_dirty);
350
351         return 1;
352 }
353
354 int LuaVoxelManip::l_get_emerged_area(lua_State *L)
355 {
356         LuaVoxelManip *o = checkobject(L, 1);
357
358         push_v3s16(L, o->vm->m_area.MinEdge);
359         push_v3s16(L, o->vm->m_area.MaxEdge);
360
361         return 2;
362 }
363
364 LuaVoxelManip::LuaVoxelManip(MMVManip *mmvm, bool is_mg_vm)
365 {
366         this->vm           = mmvm;
367         this->is_mapgen_vm = is_mg_vm;
368 }
369
370 LuaVoxelManip::LuaVoxelManip(Map *map)
371 {
372         this->vm = new MMVManip(map);
373         this->is_mapgen_vm = false;
374 }
375
376 LuaVoxelManip::LuaVoxelManip(Map *map, v3s16 p1, v3s16 p2)
377 {
378         this->vm = new MMVManip(map);
379         this->is_mapgen_vm = false;
380
381         v3s16 bp1 = getNodeBlockPos(p1);
382         v3s16 bp2 = getNodeBlockPos(p2);
383         sortBoxVerticies(bp1, bp2);
384         vm->initialEmerge(bp1, bp2);
385 }
386
387 LuaVoxelManip::~LuaVoxelManip()
388 {
389         if (!is_mapgen_vm)
390                 delete vm;
391 }
392
393 // LuaVoxelManip()
394 // Creates an LuaVoxelManip and leaves it on top of stack
395 int LuaVoxelManip::create_object(lua_State *L)
396 {
397         NO_MAP_LOCK_REQUIRED;
398
399         Environment *env = getEnv(L);
400         if (!env)
401                 return 0;
402
403         Map *map = &(env->getMap());
404         LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
405                 new LuaVoxelManip(map, check_v3s16(L, 1), check_v3s16(L, 2)) :
406                 new LuaVoxelManip(map);
407
408         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
409         luaL_getmetatable(L, className);
410         lua_setmetatable(L, -2);
411         return 1;
412 }
413
414 LuaVoxelManip *LuaVoxelManip::checkobject(lua_State *L, int narg)
415 {
416         NO_MAP_LOCK_REQUIRED;
417
418         luaL_checktype(L, narg, LUA_TUSERDATA);
419
420         void *ud = luaL_checkudata(L, narg, className);
421         if (!ud)
422                 luaL_typerror(L, narg, className);
423
424         return *(LuaVoxelManip **)ud;  // unbox pointer
425 }
426
427 void LuaVoxelManip::Register(lua_State *L)
428 {
429         lua_newtable(L);
430         int methodtable = lua_gettop(L);
431         luaL_newmetatable(L, className);
432         int metatable = lua_gettop(L);
433
434         lua_pushliteral(L, "__metatable");
435         lua_pushvalue(L, methodtable);
436         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
437
438         lua_pushliteral(L, "__index");
439         lua_pushvalue(L, methodtable);
440         lua_settable(L, metatable);
441
442         lua_pushliteral(L, "__gc");
443         lua_pushcfunction(L, gc_object);
444         lua_settable(L, metatable);
445
446         lua_pop(L, 1);  // drop metatable
447
448         luaL_openlib(L, 0, methods, 0);  // fill methodtable
449         lua_pop(L, 1);  // drop methodtable
450
451         // Can be created from Lua (VoxelManip())
452         lua_register(L, className, create_object);
453 }
454
455 const char LuaVoxelManip::className[] = "VoxelManip";
456 const luaL_reg LuaVoxelManip::methods[] = {
457         luamethod(LuaVoxelManip, read_from_map),
458         luamethod(LuaVoxelManip, get_data),
459         luamethod(LuaVoxelManip, set_data),
460         luamethod(LuaVoxelManip, get_node_at),
461         luamethod(LuaVoxelManip, set_node_at),
462         luamethod(LuaVoxelManip, write_to_map),
463         luamethod(LuaVoxelManip, update_map),
464         luamethod(LuaVoxelManip, update_liquids),
465         luamethod(LuaVoxelManip, calc_lighting),
466         luamethod(LuaVoxelManip, set_lighting),
467         luamethod(LuaVoxelManip, get_light_data),
468         luamethod(LuaVoxelManip, set_light_data),
469         luamethod(LuaVoxelManip, get_param2_data),
470         luamethod(LuaVoxelManip, set_param2_data),
471         luamethod(LuaVoxelManip, was_modified),
472         luamethod(LuaVoxelManip, get_emerged_area),
473         {0,0}
474 };