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