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