Optimize headers (part 2) (#6272)
[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 "mapblock.h"
29 #include "server.h"
30 #include "mapgen.h"
31 #include "voxelalgorithms.h"
32
33 // garbage collector
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
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
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_newtable(L);
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
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                 return 0;
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
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) ? lua_toboolean(L, 2) : true;
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 (std::map<v3s16, MapBlock *>::iterator it = o->modified_blocks.begin();
127                         it != o->modified_blocks.end(); ++it)
128                 event.modified_blocks.insert(it->first);
129
130         map->dispatchEvent(&event);
131
132         o->modified_blocks.clear();
133         return 0;
134 }
135
136 int LuaVoxelManip::l_get_node_at(lua_State *L)
137 {
138         NO_MAP_LOCK_REQUIRED;
139
140         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
141
142         LuaVoxelManip *o = checkobject(L, 1);
143         v3s16 pos        = check_v3s16(L, 2);
144
145         pushnode(L, o->vm->getNodeNoExNoEmerge(pos), ndef);
146         return 1;
147 }
148
149 int LuaVoxelManip::l_set_node_at(lua_State *L)
150 {
151         NO_MAP_LOCK_REQUIRED;
152
153         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
154
155         LuaVoxelManip *o = checkobject(L, 1);
156         v3s16 pos        = check_v3s16(L, 2);
157         MapNode n        = readnode(L, 3, ndef);
158
159         o->vm->setNodeNoEmerge(pos, n);
160
161         return 0;
162 }
163
164 int LuaVoxelManip::l_update_liquids(lua_State *L)
165 {
166         GET_ENV_PTR;
167
168         LuaVoxelManip *o = checkobject(L, 1);
169
170         Map *map = &(env->getMap());
171         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
172         MMVManip *vm = o->vm;
173
174         Mapgen mg;
175         mg.vm   = vm;
176         mg.ndef = ndef;
177
178         mg.updateLiquid(&map->m_transforming_liquid,
179                         vm->m_area.MinEdge, vm->m_area.MaxEdge);
180
181         return 0;
182 }
183
184 int LuaVoxelManip::l_calc_lighting(lua_State *L)
185 {
186         NO_MAP_LOCK_REQUIRED;
187
188         LuaVoxelManip *o = checkobject(L, 1);
189         if (!o->is_mapgen_vm)
190                 return 0;
191
192         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
193         EmergeManager *emerge = getServer(L)->getEmergeManager();
194         MMVManip *vm = o->vm;
195
196         v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
197         v3s16 fpmin  = vm->m_area.MinEdge;
198         v3s16 fpmax  = vm->m_area.MaxEdge;
199         v3s16 pmin   = lua_istable(L, 2) ? check_v3s16(L, 2) : fpmin + yblock;
200         v3s16 pmax   = lua_istable(L, 3) ? check_v3s16(L, 3) : fpmax - yblock;
201         bool propagate_shadow = lua_isboolean(L, 4) ? lua_toboolean(L, 4) : true;
202
203         sortBoxVerticies(pmin, pmax);
204         if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
205                 throw LuaError("Specified voxel area out of VoxelManipulator bounds");
206
207         Mapgen mg;
208         mg.vm          = vm;
209         mg.ndef        = ndef;
210         mg.water_level = emerge->mgparams->water_level;
211
212         mg.calcLighting(pmin, pmax, fpmin, fpmax, propagate_shadow);
213
214         return 0;
215 }
216
217 int LuaVoxelManip::l_set_lighting(lua_State *L)
218 {
219         NO_MAP_LOCK_REQUIRED;
220
221         LuaVoxelManip *o = checkobject(L, 1);
222         if (!o->is_mapgen_vm)
223                 return 0;
224
225         if (!lua_istable(L, 2))
226                 return 0;
227
228         u8 light;
229         light  = (getintfield_default(L, 2, "day",   0) & 0x0F);
230         light |= (getintfield_default(L, 2, "night", 0) & 0x0F) << 4;
231
232         MMVManip *vm = o->vm;
233
234         v3s16 yblock = v3s16(0, 1, 0) * MAP_BLOCKSIZE;
235         v3s16 pmin = lua_istable(L, 3) ? check_v3s16(L, 3) : vm->m_area.MinEdge + yblock;
236         v3s16 pmax = lua_istable(L, 4) ? check_v3s16(L, 4) : vm->m_area.MaxEdge - yblock;
237
238         sortBoxVerticies(pmin, pmax);
239         if (!vm->m_area.contains(VoxelArea(pmin, pmax)))
240                 throw LuaError("Specified voxel area out of VoxelManipulator bounds");
241
242         Mapgen mg;
243         mg.vm = vm;
244
245         mg.setLighting(light, pmin, pmax);
246
247         return 0;
248 }
249
250 int LuaVoxelManip::l_get_light_data(lua_State *L)
251 {
252         NO_MAP_LOCK_REQUIRED;
253
254         LuaVoxelManip *o = checkobject(L, 1);
255         MMVManip *vm = o->vm;
256
257         u32 volume = vm->m_area.getVolume();
258
259         lua_newtable(L);
260         for (u32 i = 0; i != volume; i++) {
261                 lua_Integer light = vm->m_data[i].param1;
262                 lua_pushinteger(L, light);
263                 lua_rawseti(L, -2, i + 1);
264         }
265
266         return 1;
267 }
268
269 int LuaVoxelManip::l_set_light_data(lua_State *L)
270 {
271         NO_MAP_LOCK_REQUIRED;
272
273         LuaVoxelManip *o = checkobject(L, 1);
274         MMVManip *vm = o->vm;
275
276         if (!lua_istable(L, 2))
277                 return 0;
278
279         u32 volume = vm->m_area.getVolume();
280         for (u32 i = 0; i != volume; i++) {
281                 lua_rawgeti(L, 2, i + 1);
282                 u8 light = lua_tointeger(L, -1);
283
284                 vm->m_data[i].param1 = light;
285
286                 lua_pop(L, 1);
287         }
288
289         return 0;
290 }
291
292 int LuaVoxelManip::l_get_param2_data(lua_State *L)
293 {
294         NO_MAP_LOCK_REQUIRED;
295
296         LuaVoxelManip *o = checkobject(L, 1);
297         bool use_buffer  = lua_istable(L, 2);
298
299         MMVManip *vm = o->vm;
300
301         u32 volume = vm->m_area.getVolume();
302
303         if (use_buffer)
304                 lua_pushvalue(L, 2);
305         else
306                 lua_newtable(L);
307
308         for (u32 i = 0; i != volume; i++) {
309                 lua_Integer param2 = vm->m_data[i].param2;
310                 lua_pushinteger(L, param2);
311                 lua_rawseti(L, -2, i + 1);
312         }
313
314         return 1;
315 }
316
317 int LuaVoxelManip::l_set_param2_data(lua_State *L)
318 {
319         NO_MAP_LOCK_REQUIRED;
320
321         LuaVoxelManip *o = checkobject(L, 1);
322         MMVManip *vm = o->vm;
323
324         if (!lua_istable(L, 2))
325                 return 0;
326
327         u32 volume = vm->m_area.getVolume();
328         for (u32 i = 0; i != volume; i++) {
329                 lua_rawgeti(L, 2, i + 1);
330                 u8 param2 = lua_tointeger(L, -1);
331
332                 vm->m_data[i].param2 = param2;
333
334                 lua_pop(L, 1);
335         }
336
337         return 0;
338 }
339
340 int LuaVoxelManip::l_update_map(lua_State *L)
341 {
342         return 0;
343 }
344
345 int LuaVoxelManip::l_was_modified(lua_State *L)
346 {
347         NO_MAP_LOCK_REQUIRED;
348
349         LuaVoxelManip *o = checkobject(L, 1);
350         MMVManip *vm = o->vm;
351
352         lua_pushboolean(L, vm->m_is_dirty);
353
354         return 1;
355 }
356
357 int LuaVoxelManip::l_get_emerged_area(lua_State *L)
358 {
359         NO_MAP_LOCK_REQUIRED;
360
361         LuaVoxelManip *o = checkobject(L, 1);
362
363         push_v3s16(L, o->vm->m_area.MinEdge);
364         push_v3s16(L, o->vm->m_area.MaxEdge);
365
366         return 2;
367 }
368
369 LuaVoxelManip::LuaVoxelManip(MMVManip *mmvm, bool is_mg_vm) :
370         is_mapgen_vm(is_mg_vm),
371         vm(mmvm)
372 {
373 }
374
375 LuaVoxelManip::LuaVoxelManip(Map *map) : vm(new MMVManip(map))
376 {
377 }
378
379 LuaVoxelManip::LuaVoxelManip(Map *map, v3s16 p1, v3s16 p2)
380 {
381         vm = new MMVManip(map);
382
383         v3s16 bp1 = getNodeBlockPos(p1);
384         v3s16 bp2 = getNodeBlockPos(p2);
385         sortBoxVerticies(bp1, bp2);
386         vm->initialEmerge(bp1, bp2);
387 }
388
389 LuaVoxelManip::~LuaVoxelManip()
390 {
391         if (!is_mapgen_vm)
392                 delete vm;
393 }
394
395 // LuaVoxelManip()
396 // Creates an LuaVoxelManip and leaves it on top of stack
397 int LuaVoxelManip::create_object(lua_State *L)
398 {
399         GET_ENV_PTR;
400
401         Map *map = &(env->getMap());
402         LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
403                 new LuaVoxelManip(map, check_v3s16(L, 1), check_v3s16(L, 2)) :
404                 new LuaVoxelManip(map);
405
406         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
407         luaL_getmetatable(L, className);
408         lua_setmetatable(L, -2);
409         return 1;
410 }
411
412 LuaVoxelManip *LuaVoxelManip::checkobject(lua_State *L, int narg)
413 {
414         NO_MAP_LOCK_REQUIRED;
415
416         luaL_checktype(L, narg, LUA_TUSERDATA);
417
418         void *ud = luaL_checkudata(L, narg, className);
419         if (!ud)
420                 luaL_typerror(L, narg, className);
421
422         return *(LuaVoxelManip **)ud;  // unbox pointer
423 }
424
425 void LuaVoxelManip::Register(lua_State *L)
426 {
427         lua_newtable(L);
428         int methodtable = lua_gettop(L);
429         luaL_newmetatable(L, className);
430         int metatable = lua_gettop(L);
431
432         lua_pushliteral(L, "__metatable");
433         lua_pushvalue(L, methodtable);
434         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
435
436         lua_pushliteral(L, "__index");
437         lua_pushvalue(L, methodtable);
438         lua_settable(L, metatable);
439
440         lua_pushliteral(L, "__gc");
441         lua_pushcfunction(L, gc_object);
442         lua_settable(L, metatable);
443
444         lua_pop(L, 1);  // drop metatable
445
446         luaL_openlib(L, 0, methods, 0);  // fill methodtable
447         lua_pop(L, 1);  // drop methodtable
448
449         // Can be created from Lua (VoxelManip())
450         lua_register(L, className, create_object);
451 }
452
453 const char LuaVoxelManip::className[] = "VoxelManip";
454 const luaL_Reg LuaVoxelManip::methods[] = {
455         luamethod(LuaVoxelManip, read_from_map),
456         luamethod(LuaVoxelManip, get_data),
457         luamethod(LuaVoxelManip, set_data),
458         luamethod(LuaVoxelManip, get_node_at),
459         luamethod(LuaVoxelManip, set_node_at),
460         luamethod(LuaVoxelManip, write_to_map),
461         luamethod(LuaVoxelManip, update_map),
462         luamethod(LuaVoxelManip, update_liquids),
463         luamethod(LuaVoxelManip, calc_lighting),
464         luamethod(LuaVoxelManip, set_lighting),
465         luamethod(LuaVoxelManip, get_light_data),
466         luamethod(LuaVoxelManip, set_light_data),
467         luamethod(LuaVoxelManip, get_param2_data),
468         luamethod(LuaVoxelManip, set_param2_data),
469         luamethod(LuaVoxelManip, was_modified),
470         luamethod(LuaVoxelManip, get_emerged_area),
471         {0,0}
472 };