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