]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_env.cpp
SEnv: Remove static_exists from ActiveObjects in deleted blocks
[dragonfireclient.git] / src / script / lua_api / l_env.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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 "lua_api/l_env.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_nodemeta.h"
23 #include "lua_api/l_nodetimer.h"
24 #include "lua_api/l_noise.h"
25 #include "lua_api/l_vmanip.h"
26 #include "common/c_converter.h"
27 #include "common/c_content.h"
28 #include "scripting_game.h"
29 #include "environment.h"
30 #include "server.h"
31 #include "nodedef.h"
32 #include "daynightratio.h"
33 #include "util/pointedthing.h"
34 #include "content_sao.h"
35 #include "treegen.h"
36 #include "pathfinder.h"
37
38 #define GET_ENV_PTR ServerEnvironment* env =                                   \
39                                 dynamic_cast<ServerEnvironment*>(getEnv(L));                   \
40                                 if (env == NULL) return 0
41
42 ///////////////////////////////////////////////////////////////////////////////
43
44
45 void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
46                 u32 active_object_count, u32 active_object_count_wider)
47 {
48         GameScripting *scriptIface = env->getScriptIface();
49         scriptIface->realityCheck();
50
51         lua_State *L = scriptIface->getStack();
52         sanity_check(lua_checkstack(L, 20));
53         StackUnroller stack_unroller(L);
54
55         lua_pushcfunction(L, script_error_handler);
56         int errorhandler = lua_gettop(L);
57
58         // Get registered_abms
59         lua_getglobal(L, "core");
60         lua_getfield(L, -1, "registered_abms");
61         luaL_checktype(L, -1, LUA_TTABLE);
62         lua_remove(L, -2); // Remove core
63
64         // Get registered_abms[m_id]
65         lua_pushnumber(L, m_id);
66         lua_gettable(L, -2);
67         if(lua_isnil(L, -1))
68                 FATAL_ERROR("");
69         lua_remove(L, -2); // Remove registered_abms
70
71         scriptIface->setOriginFromTable(-1);
72
73         // Call action
74         luaL_checktype(L, -1, LUA_TTABLE);
75         lua_getfield(L, -1, "action");
76         luaL_checktype(L, -1, LUA_TFUNCTION);
77         lua_remove(L, -2); // Remove registered_abms[m_id]
78         push_v3s16(L, p);
79         pushnode(L, n, env->getGameDef()->ndef());
80         lua_pushnumber(L, active_object_count);
81         lua_pushnumber(L, active_object_count_wider);
82
83         int result = lua_pcall(L, 4, 0, errorhandler);
84         if (result)
85                 scriptIface->scriptError(result, "LuaABM::trigger");
86
87         lua_pop(L, 1); // Pop error handler
88 }
89
90 // Exported functions
91
92 // set_node(pos, node)
93 // pos = {x=num, y=num, z=num}
94 int ModApiEnvMod::l_set_node(lua_State *L)
95 {
96         GET_ENV_PTR;
97
98         INodeDefManager *ndef = env->getGameDef()->ndef();
99         // parameters
100         v3s16 pos = read_v3s16(L, 1);
101         MapNode n = readnode(L, 2, ndef);
102         // Do it
103         bool succeeded = env->setNode(pos, n);
104         lua_pushboolean(L, succeeded);
105         return 1;
106 }
107
108 int ModApiEnvMod::l_add_node(lua_State *L)
109 {
110         return l_set_node(L);
111 }
112
113 // remove_node(pos)
114 // pos = {x=num, y=num, z=num}
115 int ModApiEnvMod::l_remove_node(lua_State *L)
116 {
117         GET_ENV_PTR;
118
119         // parameters
120         v3s16 pos = read_v3s16(L, 1);
121         // Do it
122         bool succeeded = env->removeNode(pos);
123         lua_pushboolean(L, succeeded);
124         return 1;
125 }
126
127 // swap_node(pos, node)
128 // pos = {x=num, y=num, z=num}
129 int ModApiEnvMod::l_swap_node(lua_State *L)
130 {
131         GET_ENV_PTR;
132
133         INodeDefManager *ndef = env->getGameDef()->ndef();
134         // parameters
135         v3s16 pos = read_v3s16(L, 1);
136         MapNode n = readnode(L, 2, ndef);
137         // Do it
138         bool succeeded = env->swapNode(pos, n);
139         lua_pushboolean(L, succeeded);
140         return 1;
141 }
142
143 // get_node(pos)
144 // pos = {x=num, y=num, z=num}
145 int ModApiEnvMod::l_get_node(lua_State *L)
146 {
147         GET_ENV_PTR;
148
149         // pos
150         v3s16 pos = read_v3s16(L, 1);
151         // Do it
152         MapNode n = env->getMap().getNodeNoEx(pos);
153         // Return node
154         pushnode(L, n, env->getGameDef()->ndef());
155         return 1;
156 }
157
158 // get_node_or_nil(pos)
159 // pos = {x=num, y=num, z=num}
160 int ModApiEnvMod::l_get_node_or_nil(lua_State *L)
161 {
162         GET_ENV_PTR;
163
164         // pos
165         v3s16 pos = read_v3s16(L, 1);
166         // Do it
167         bool pos_ok;
168         MapNode n = env->getMap().getNodeNoEx(pos, &pos_ok);
169         if (pos_ok) {
170                 // Return node
171                 pushnode(L, n, env->getGameDef()->ndef());
172         } else {
173                 lua_pushnil(L);
174         }
175         return 1;
176 }
177
178 // get_node_light(pos, timeofday)
179 // pos = {x=num, y=num, z=num}
180 // timeofday: nil = current time, 0 = night, 0.5 = day
181 int ModApiEnvMod::l_get_node_light(lua_State *L)
182 {
183         GET_ENV_PTR;
184
185         // Do it
186         v3s16 pos = read_v3s16(L, 1);
187         u32 time_of_day = env->getTimeOfDay();
188         if(lua_isnumber(L, 2))
189                 time_of_day = 24000.0 * lua_tonumber(L, 2);
190         time_of_day %= 24000;
191         u32 dnr = time_to_daynight_ratio(time_of_day, true);
192
193         bool is_position_ok;
194         MapNode n = env->getMap().getNodeNoEx(pos, &is_position_ok);
195         if (is_position_ok) {
196                 INodeDefManager *ndef = env->getGameDef()->ndef();
197                 lua_pushinteger(L, n.getLightBlend(dnr, ndef));
198         } else {
199                 lua_pushnil(L);
200         }
201         return 1;
202 }
203
204 // place_node(pos, node)
205 // pos = {x=num, y=num, z=num}
206 int ModApiEnvMod::l_place_node(lua_State *L)
207 {
208         GET_ENV_PTR;
209
210         ScriptApiItem *scriptIfaceItem = getScriptApi<ScriptApiItem>(L);
211         Server *server = getServer(L);
212         INodeDefManager *ndef = server->ndef();
213         IItemDefManager *idef = server->idef();
214
215         v3s16 pos = read_v3s16(L, 1);
216         MapNode n = readnode(L, 2, ndef);
217
218         // Don't attempt to load non-loaded area as of now
219         MapNode n_old = env->getMap().getNodeNoEx(pos);
220         if(n_old.getContent() == CONTENT_IGNORE){
221                 lua_pushboolean(L, false);
222                 return 1;
223         }
224         // Create item to place
225         ItemStack item(ndef->get(n).name, 1, 0, "", idef);
226         // Make pointed position
227         PointedThing pointed;
228         pointed.type = POINTEDTHING_NODE;
229         pointed.node_abovesurface = pos;
230         pointed.node_undersurface = pos + v3s16(0,-1,0);
231         // Place it with a NULL placer (appears in Lua as a non-functional
232         // ObjectRef)
233         bool success = scriptIfaceItem->item_OnPlace(item, NULL, pointed);
234         lua_pushboolean(L, success);
235         return 1;
236 }
237
238 // dig_node(pos)
239 // pos = {x=num, y=num, z=num}
240 int ModApiEnvMod::l_dig_node(lua_State *L)
241 {
242         GET_ENV_PTR;
243
244         ScriptApiNode *scriptIfaceNode = getScriptApi<ScriptApiNode>(L);
245
246         v3s16 pos = read_v3s16(L, 1);
247
248         // Don't attempt to load non-loaded area as of now
249         MapNode n = env->getMap().getNodeNoEx(pos);
250         if(n.getContent() == CONTENT_IGNORE){
251                 lua_pushboolean(L, false);
252                 return 1;
253         }
254         // Dig it out with a NULL digger (appears in Lua as a
255         // non-functional ObjectRef)
256         bool success = scriptIfaceNode->node_on_dig(pos, n, NULL);
257         lua_pushboolean(L, success);
258         return 1;
259 }
260
261 // punch_node(pos)
262 // pos = {x=num, y=num, z=num}
263 int ModApiEnvMod::l_punch_node(lua_State *L)
264 {
265         GET_ENV_PTR;
266
267         ScriptApiNode *scriptIfaceNode = getScriptApi<ScriptApiNode>(L);
268
269         v3s16 pos = read_v3s16(L, 1);
270
271         // Don't attempt to load non-loaded area as of now
272         MapNode n = env->getMap().getNodeNoEx(pos);
273         if(n.getContent() == CONTENT_IGNORE){
274                 lua_pushboolean(L, false);
275                 return 1;
276         }
277         // Punch it with a NULL puncher (appears in Lua as a non-functional
278         // ObjectRef)
279         bool success = scriptIfaceNode->node_on_punch(pos, n, NULL, PointedThing());
280         lua_pushboolean(L, success);
281         return 1;
282 }
283
284 // get_node_max_level(pos)
285 // pos = {x=num, y=num, z=num}
286 int ModApiEnvMod::l_get_node_max_level(lua_State *L)
287 {
288         GET_ENV_PTR;
289
290         v3s16 pos = read_v3s16(L, 1);
291         MapNode n = env->getMap().getNodeNoEx(pos);
292         lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
293         return 1;
294 }
295
296 // get_node_level(pos)
297 // pos = {x=num, y=num, z=num}
298 int ModApiEnvMod::l_get_node_level(lua_State *L)
299 {
300         GET_ENV_PTR;
301
302         v3s16 pos = read_v3s16(L, 1);
303         MapNode n = env->getMap().getNodeNoEx(pos);
304         lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
305         return 1;
306 }
307
308 // set_node_level(pos, level)
309 // pos = {x=num, y=num, z=num}
310 // level: 0..63
311 int ModApiEnvMod::l_set_node_level(lua_State *L)
312 {
313         GET_ENV_PTR;
314
315         v3s16 pos = read_v3s16(L, 1);
316         u8 level = 1;
317         if(lua_isnumber(L, 2))
318                 level = lua_tonumber(L, 2);
319         MapNode n = env->getMap().getNodeNoEx(pos);
320         lua_pushnumber(L, n.setLevel(env->getGameDef()->ndef(), level));
321         env->setNode(pos, n);
322         return 1;
323 }
324
325 // add_node_level(pos, level)
326 // pos = {x=num, y=num, z=num}
327 // level: 0..63
328 int ModApiEnvMod::l_add_node_level(lua_State *L)
329 {
330         GET_ENV_PTR;
331
332         v3s16 pos = read_v3s16(L, 1);
333         u8 level = 1;
334         if(lua_isnumber(L, 2))
335                 level = lua_tonumber(L, 2);
336         MapNode n = env->getMap().getNodeNoEx(pos);
337         lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
338         env->setNode(pos, n);
339         return 1;
340 }
341
342 // find_nodes_with_meta(pos1, pos2)
343 int ModApiEnvMod::l_find_nodes_with_meta(lua_State *L)
344 {
345         GET_ENV_PTR;
346
347         std::vector<v3s16> positions = env->getMap().findNodesWithMetadata(
348                 check_v3s16(L, 1), check_v3s16(L, 2));
349
350         lua_newtable(L);
351         for (size_t i = 0; i != positions.size(); i++) {
352                 push_v3s16(L, positions[i]);
353                 lua_rawseti(L, -2, i + 1);
354         }
355
356         return 1;
357 }
358
359 // get_meta(pos)
360 int ModApiEnvMod::l_get_meta(lua_State *L)
361 {
362         GET_ENV_PTR;
363
364         // Do it
365         v3s16 p = read_v3s16(L, 1);
366         NodeMetaRef::create(L, p, env);
367         return 1;
368 }
369
370 // get_node_timer(pos)
371 int ModApiEnvMod::l_get_node_timer(lua_State *L)
372 {
373         GET_ENV_PTR;
374
375         // Do it
376         v3s16 p = read_v3s16(L, 1);
377         NodeTimerRef::create(L, p, env);
378         return 1;
379 }
380
381 // add_entity(pos, entityname) -> ObjectRef or nil
382 // pos = {x=num, y=num, z=num}
383 int ModApiEnvMod::l_add_entity(lua_State *L)
384 {
385         GET_ENV_PTR;
386
387         // pos
388         v3f pos = checkFloatPos(L, 1);
389         // content
390         const char *name = luaL_checkstring(L, 2);
391         // Do it
392         ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
393         int objectid = env->addActiveObject(obj);
394         // If failed to add, return nothing (reads as nil)
395         if(objectid == 0)
396                 return 0;
397         // Return ObjectRef
398         getScriptApiBase(L)->objectrefGetOrCreate(L, obj);
399         return 1;
400 }
401
402 // add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
403 // pos = {x=num, y=num, z=num}
404 int ModApiEnvMod::l_add_item(lua_State *L)
405 {
406         GET_ENV_PTR;
407
408         // pos
409         //v3f pos = checkFloatPos(L, 1);
410         // item
411         ItemStack item = read_item(L, 2,getServer(L));
412         if(item.empty() || !item.isKnown(getServer(L)->idef()))
413                 return 0;
414
415         lua_pushcfunction(L, script_error_handler);
416         int errorhandler = lua_gettop(L);
417
418         // Use spawn_item to spawn a __builtin:item
419         lua_getglobal(L, "core");
420         lua_getfield(L, -1, "spawn_item");
421         lua_remove(L, -2); // Remove core
422         if(lua_isnil(L, -1))
423                 return 0;
424         lua_pushvalue(L, 1);
425         lua_pushstring(L, item.getItemString().c_str());
426
427         PCALL_RESL(L, lua_pcall(L, 2, 1, errorhandler));
428
429         lua_remove(L, errorhandler); // Remove error handler
430         return 1;
431 }
432
433 // get_player_by_name(name)
434 int ModApiEnvMod::l_get_player_by_name(lua_State *L)
435 {
436         GET_ENV_PTR;
437
438         // Do it
439         const char *name = luaL_checkstring(L, 1);
440         Player *player = env->getPlayer(name);
441         if(player == NULL){
442                 lua_pushnil(L);
443                 return 1;
444         }
445         PlayerSAO *sao = player->getPlayerSAO();
446         if(sao == NULL){
447                 lua_pushnil(L);
448                 return 1;
449         }
450         // Put player on stack
451         getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
452         return 1;
453 }
454
455 // get_objects_inside_radius(pos, radius)
456 int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
457 {
458         GET_ENV_PTR;
459
460         // Do it
461         v3f pos = checkFloatPos(L, 1);
462         float radius = luaL_checknumber(L, 2) * BS;
463         std::vector<u16> ids;
464         env->getObjectsInsideRadius(ids, pos, radius);
465         ScriptApiBase *script = getScriptApiBase(L);
466         lua_createtable(L, ids.size(), 0);
467         std::vector<u16>::const_iterator iter = ids.begin();
468         for(u32 i = 0; iter != ids.end(); iter++) {
469                 ServerActiveObject *obj = env->getActiveObject(*iter);
470                 // Insert object reference into table
471                 script->objectrefGetOrCreate(L, obj);
472                 lua_rawseti(L, -2, ++i);
473         }
474         return 1;
475 }
476
477 // set_timeofday(val)
478 // val = 0...1
479 int ModApiEnvMod::l_set_timeofday(lua_State *L)
480 {
481         GET_ENV_PTR;
482
483         // Do it
484         float timeofday_f = luaL_checknumber(L, 1);
485         sanity_check(timeofday_f >= 0.0 && timeofday_f <= 1.0);
486         int timeofday_mh = (int)(timeofday_f * 24000.0);
487         // This should be set directly in the environment but currently
488         // such changes aren't immediately sent to the clients, so call
489         // the server instead.
490         //env->setTimeOfDay(timeofday_mh);
491         getServer(L)->setTimeOfDay(timeofday_mh);
492         return 0;
493 }
494
495 // get_timeofday() -> 0...1
496 int ModApiEnvMod::l_get_timeofday(lua_State *L)
497 {
498         GET_ENV_PTR;
499
500         // Do it
501         int timeofday_mh = env->getTimeOfDay();
502         float timeofday_f = (float)timeofday_mh / 24000.0;
503         lua_pushnumber(L, timeofday_f);
504         return 1;
505 }
506
507 // get_gametime()
508 int ModApiEnvMod::l_get_gametime(lua_State *L)
509 {
510         GET_ENV_PTR;
511
512         int game_time = env->getGameTime();
513         lua_pushnumber(L, game_time);
514         return 1;
515 }
516
517
518 // find_node_near(pos, radius, nodenames) -> pos or nil
519 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
520 int ModApiEnvMod::l_find_node_near(lua_State *L)
521 {
522         GET_ENV_PTR;
523
524         INodeDefManager *ndef = getServer(L)->ndef();
525         v3s16 pos = read_v3s16(L, 1);
526         int radius = luaL_checkinteger(L, 2);
527         std::set<content_t> filter;
528         if(lua_istable(L, 3)){
529                 int table = 3;
530                 lua_pushnil(L);
531                 while(lua_next(L, table) != 0){
532                         // key at index -2 and value at index -1
533                         luaL_checktype(L, -1, LUA_TSTRING);
534                         ndef->getIds(lua_tostring(L, -1), filter);
535                         // removes value, keeps key for next iteration
536                         lua_pop(L, 1);
537                 }
538         } else if(lua_isstring(L, 3)){
539                 ndef->getIds(lua_tostring(L, 3), filter);
540         }
541
542         for(int d=1; d<=radius; d++){
543                 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
544                 for(std::vector<v3s16>::iterator i = list.begin();
545                                 i != list.end(); ++i){
546                         v3s16 p = pos + (*i);
547                         content_t c = env->getMap().getNodeNoEx(p).getContent();
548                         if(filter.count(c) != 0){
549                                 push_v3s16(L, p);
550                                 return 1;
551                         }
552                 }
553         }
554         return 0;
555 }
556
557 // find_nodes_in_area(minp, maxp, nodenames) -> list of positions
558 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
559 int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
560 {
561         GET_ENV_PTR;
562
563         INodeDefManager *ndef = getServer(L)->ndef();
564         v3s16 minp = read_v3s16(L, 1);
565         v3s16 maxp = read_v3s16(L, 2);
566         std::set<content_t> filter;
567         if(lua_istable(L, 3)) {
568                 int table = 3;
569                 lua_pushnil(L);
570                 while(lua_next(L, table) != 0) {
571                         // key at index -2 and value at index -1
572                         luaL_checktype(L, -1, LUA_TSTRING);
573                         ndef->getIds(lua_tostring(L, -1), filter);
574                         // removes value, keeps key for next iteration
575                         lua_pop(L, 1);
576                 }
577         } else if(lua_isstring(L, 3)) {
578                 ndef->getIds(lua_tostring(L, 3), filter);
579         }
580
581         std::map<content_t, u16> individual_count;
582
583         lua_newtable(L);
584         u64 i = 0;
585         for (s16 x = minp.X; x <= maxp.X; x++)
586                 for (s16 y = minp.Y; y <= maxp.Y; y++)
587                         for (s16 z = minp.Z; z <= maxp.Z; z++) {
588                                 v3s16 p(x, y, z);
589                                 content_t c = env->getMap().getNodeNoEx(p).getContent();
590                                 if (filter.count(c) != 0) {
591                                         push_v3s16(L, p);
592                                         lua_rawseti(L, -2, ++i);
593                                         individual_count[c]++;
594                                 }
595         }
596         lua_newtable(L);
597         for (std::set<content_t>::iterator it = filter.begin();
598                         it != filter.end(); ++it) {
599                 lua_pushnumber(L, individual_count[*it]);
600                 lua_setfield(L, -2, ndef->get(*it).name.c_str());
601         }
602         return 2;
603 }
604
605 // find_nodes_in_area_under_air(minp, maxp, nodenames) -> list of positions
606 // nodenames: e.g. {"ignore", "group:tree"} or "default:dirt"
607 int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
608 {
609         /* Note: A similar but generalized (and therefore slower) version of this
610          * function could be created -- e.g. find_nodes_in_area_under -- which
611          * would accept a node name (or ID?) or list of names that the "above node"
612          * should be.
613          * TODO
614          */
615
616         GET_ENV_PTR;
617
618         INodeDefManager *ndef = getServer(L)->ndef();
619         v3s16 minp = read_v3s16(L, 1);
620         v3s16 maxp = read_v3s16(L, 2);
621         std::set<content_t> filter;
622
623         if (lua_istable(L, 3)) {
624                 int table = 3;
625                 lua_pushnil(L);
626                 while(lua_next(L, table) != 0) {
627                         // key at index -2 and value at index -1
628                         luaL_checktype(L, -1, LUA_TSTRING);
629                         ndef->getIds(lua_tostring(L, -1), filter);
630                         // removes value, keeps key for next iteration
631                         lua_pop(L, 1);
632                 }
633         } else if (lua_isstring(L, 3)) {
634                 ndef->getIds(lua_tostring(L, 3), filter);
635         }
636
637         lua_newtable(L);
638         u64 i = 0;
639         for (s16 x = minp.X; x <= maxp.X; x++)
640         for (s16 z = minp.Z; z <= maxp.Z; z++) {
641                 s16 y = minp.Y;
642                 v3s16 p(x, y, z);
643                 content_t c = env->getMap().getNodeNoEx(p).getContent();
644                 for (; y <= maxp.Y; y++) {
645                         v3s16 psurf(x, y + 1, z);
646                         content_t csurf = env->getMap().getNodeNoEx(psurf).getContent();
647                         if(c != CONTENT_AIR && csurf == CONTENT_AIR &&
648                                         filter.count(c) != 0) {
649                                 push_v3s16(L, v3s16(x, y, z));
650                                 lua_rawseti(L, -2, ++i);
651                         }
652                         c = csurf;
653                 }
654         }
655         return 1;
656 }
657
658 // get_perlin(seeddiff, octaves, persistence, scale)
659 // returns world-specific PerlinNoise
660 int ModApiEnvMod::l_get_perlin(lua_State *L)
661 {
662         GET_ENV_PTR;
663
664         NoiseParams params;
665
666         if (lua_istable(L, 1)) {
667                 read_noiseparams(L, 1, &params);
668         } else {
669                 params.seed    = luaL_checkint(L, 1);
670                 params.octaves = luaL_checkint(L, 2);
671                 params.persist = luaL_checknumber(L, 3);
672                 params.spread  = v3f(1, 1, 1) * luaL_checknumber(L, 4);
673         }
674
675         params.seed += (int)env->getServerMap().getSeed();
676
677         LuaPerlinNoise *n = new LuaPerlinNoise(&params);
678         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
679         luaL_getmetatable(L, "PerlinNoise");
680         lua_setmetatable(L, -2);
681         return 1;
682 }
683
684 // get_perlin_map(noiseparams, size)
685 // returns world-specific PerlinNoiseMap
686 int ModApiEnvMod::l_get_perlin_map(lua_State *L)
687 {
688         GET_ENV_PTR;
689
690         NoiseParams np;
691         if (!read_noiseparams(L, 1, &np))
692                 return 0;
693         v3s16 size = read_v3s16(L, 2);
694
695         int seed = (int)(env->getServerMap().getSeed());
696         LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(&np, seed, size);
697         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
698         luaL_getmetatable(L, "PerlinNoiseMap");
699         lua_setmetatable(L, -2);
700         return 1;
701 }
702
703 // get_voxel_manip()
704 // returns voxel manipulator
705 int ModApiEnvMod::l_get_voxel_manip(lua_State *L)
706 {
707         GET_ENV_PTR;
708
709         Map *map = &(env->getMap());
710         LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
711                 new LuaVoxelManip(map, read_v3s16(L, 1), read_v3s16(L, 2)) :
712                 new LuaVoxelManip(map);
713
714         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
715         luaL_getmetatable(L, "VoxelManip");
716         lua_setmetatable(L, -2);
717         return 1;
718 }
719
720 // clear_objects()
721 // clear all objects in the environment
722 int ModApiEnvMod::l_clear_objects(lua_State *L)
723 {
724         GET_ENV_PTR;
725
726         env->clearAllObjects();
727         return 0;
728 }
729
730 // line_of_sight(pos1, pos2, stepsize) -> true/false, pos
731 int ModApiEnvMod::l_line_of_sight(lua_State *L)
732 {
733         float stepsize = 1.0;
734
735         GET_ENV_PTR;
736
737         // read position 1 from lua
738         v3f pos1 = checkFloatPos(L, 1);
739         // read position 2 from lua
740         v3f pos2 = checkFloatPos(L, 2);
741         //read step size from lua
742         if (lua_isnumber(L, 3)) {
743                 stepsize = lua_tonumber(L, 3);
744         }
745
746         v3s16 p;
747         bool success = env->line_of_sight(pos1, pos2, stepsize, &p);
748         lua_pushboolean(L, success);
749         if (!success) {
750                 push_v3s16(L, p);
751                 return 2;
752         }
753         return 1;
754 }
755
756 // delete_area(p1, p2)
757 // delete mapblocks in area p1..p2
758 int ModApiEnvMod::l_delete_area(lua_State *L)
759 {
760         GET_ENV_PTR;
761
762         v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
763         v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
764         sortBoxVerticies(bpmin, bpmax);
765
766         ServerMap &map = env->getServerMap();
767
768         MapEditEvent event;
769         event.type = MEET_OTHER;
770
771         bool success = true;
772         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
773         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
774         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
775                 v3s16 bp(x, y, z);
776                 if (map.deleteBlock(bp)) {
777                         env->setStaticForActiveObjectsInBlock(bp, false);
778                         event.modified_blocks.insert(bp);
779                 } else {
780                         success = false;
781                 }
782         }
783
784         map.dispatchEvent(&event);
785         lua_pushboolean(L, success);
786         return 1;
787 }
788
789 // find_path(pos1, pos2, searchdistance,
790 //     max_jump, max_drop, algorithm) -> table containing path
791 int ModApiEnvMod::l_find_path(lua_State *L)
792 {
793         GET_ENV_PTR;
794
795         v3s16 pos1                  = read_v3s16(L, 1);
796         v3s16 pos2                  = read_v3s16(L, 2);
797         unsigned int searchdistance = luaL_checkint(L, 3);
798         unsigned int max_jump       = luaL_checkint(L, 4);
799         unsigned int max_drop       = luaL_checkint(L, 5);
800         algorithm algo              = A_PLAIN_NP;
801         if (!lua_isnil(L, 6)) {
802                 std::string algorithm = luaL_checkstring(L,6);
803
804                 if (algorithm == "A*")
805                         algo = A_PLAIN;
806
807                 if (algorithm == "Dijkstra")
808                         algo = DIJKSTRA;
809         }
810
811         std::vector<v3s16> path =
812                         get_Path(env,pos1,pos2,searchdistance,max_jump,max_drop,algo);
813
814         if (path.size() > 0)
815         {
816                 lua_newtable(L);
817                 int top = lua_gettop(L);
818                 unsigned int index = 1;
819                 for (std::vector<v3s16>::iterator i = path.begin(); i != path.end();i++)
820                 {
821                         lua_pushnumber(L,index);
822                         push_v3s16(L, *i);
823                         lua_settable(L, top);
824                         index++;
825                 }
826                 return 1;
827         }
828
829         return 0;
830 }
831
832 // spawn_tree(pos, treedef)
833 int ModApiEnvMod::l_spawn_tree(lua_State *L)
834 {
835         GET_ENV_PTR;
836
837         v3s16 p0 = read_v3s16(L, 1);
838
839         treegen::TreeDef tree_def;
840         std::string trunk,leaves,fruit;
841         INodeDefManager *ndef = env->getGameDef()->ndef();
842
843         if(lua_istable(L, 2))
844         {
845                 getstringfield(L, 2, "axiom", tree_def.initial_axiom);
846                 getstringfield(L, 2, "rules_a", tree_def.rules_a);
847                 getstringfield(L, 2, "rules_b", tree_def.rules_b);
848                 getstringfield(L, 2, "rules_c", tree_def.rules_c);
849                 getstringfield(L, 2, "rules_d", tree_def.rules_d);
850                 getstringfield(L, 2, "trunk", trunk);
851                 tree_def.trunknode=ndef->getId(trunk);
852                 getstringfield(L, 2, "leaves", leaves);
853                 tree_def.leavesnode=ndef->getId(leaves);
854                 tree_def.leaves2_chance=0;
855                 getstringfield(L, 2, "leaves2", leaves);
856                 if (leaves !="")
857                 {
858                         tree_def.leaves2node=ndef->getId(leaves);
859                         getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
860                 }
861                 getintfield(L, 2, "angle", tree_def.angle);
862                 getintfield(L, 2, "iterations", tree_def.iterations);
863                 if (!getintfield(L, 2, "random_level", tree_def.iterations_random_level))
864                         tree_def.iterations_random_level = 0;
865                 getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
866                 getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
867                 tree_def.fruit_chance=0;
868                 getstringfield(L, 2, "fruit", fruit);
869                 if (fruit != "")
870                 {
871                         tree_def.fruitnode=ndef->getId(fruit);
872                         getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
873                 }
874                 tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed);
875         }
876         else
877                 return 0;
878
879         treegen::error e;
880         if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) {
881                 if (e == treegen::UNBALANCED_BRACKETS) {
882                         luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket");
883                 } else {
884                         luaL_error(L, "spawn_tree(): unknown error");
885                 }
886         }
887
888         return 1;
889 }
890
891 // transforming_liquid_add(pos)
892 int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
893 {
894         GET_ENV_PTR;
895
896         v3s16 p0 = read_v3s16(L, 1);
897         env->getMap().transforming_liquid_add(p0);
898         return 1;
899 }
900
901 // forceload_block(blockpos)
902 // blockpos = {x=num, y=num, z=num}
903 int ModApiEnvMod::l_forceload_block(lua_State *L)
904 {
905         GET_ENV_PTR;
906
907         v3s16 blockpos = read_v3s16(L, 1);
908         env->getForceloadedBlocks()->insert(blockpos);
909         return 0;
910 }
911
912 // forceload_free_block(blockpos)
913 // blockpos = {x=num, y=num, z=num}
914 int ModApiEnvMod::l_forceload_free_block(lua_State *L)
915 {
916         GET_ENV_PTR;
917
918         v3s16 blockpos = read_v3s16(L, 1);
919         env->getForceloadedBlocks()->erase(blockpos);
920         return 0;
921 }
922
923 // get_us_time()
924 int ModApiEnvMod::l_get_us_time(lua_State *L)
925 {
926         lua_pushnumber(L, porting::getTimeUs());
927         return 1;
928 }
929
930 void ModApiEnvMod::Initialize(lua_State *L, int top)
931 {
932         API_FCT(set_node);
933         API_FCT(add_node);
934         API_FCT(swap_node);
935         API_FCT(add_item);
936         API_FCT(remove_node);
937         API_FCT(get_node);
938         API_FCT(get_node_or_nil);
939         API_FCT(get_node_light);
940         API_FCT(place_node);
941         API_FCT(dig_node);
942         API_FCT(punch_node);
943         API_FCT(get_node_max_level);
944         API_FCT(get_node_level);
945         API_FCT(set_node_level);
946         API_FCT(add_node_level);
947         API_FCT(add_entity);
948         API_FCT(find_nodes_with_meta);
949         API_FCT(get_meta);
950         API_FCT(get_node_timer);
951         API_FCT(get_player_by_name);
952         API_FCT(get_objects_inside_radius);
953         API_FCT(set_timeofday);
954         API_FCT(get_timeofday);
955         API_FCT(get_gametime);
956         API_FCT(find_node_near);
957         API_FCT(find_nodes_in_area);
958         API_FCT(find_nodes_in_area_under_air);
959         API_FCT(delete_area);
960         API_FCT(get_perlin);
961         API_FCT(get_perlin_map);
962         API_FCT(get_voxel_manip);
963         API_FCT(clear_objects);
964         API_FCT(spawn_tree);
965         API_FCT(find_path);
966         API_FCT(line_of_sight);
967         API_FCT(transforming_liquid_add);
968         API_FCT(forceload_block);
969         API_FCT(forceload_free_block);
970         API_FCT(get_us_time);
971 }