]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_env.cpp
idk
[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 <algorithm>
21 #include "lua_api/l_env.h"
22 #include "lua_api/l_internal.h"
23 #include "lua_api/l_nodemeta.h"
24 #include "lua_api/l_nodetimer.h"
25 #include "lua_api/l_noise.h"
26 #include "lua_api/l_vmanip.h"
27 #include "common/c_converter.h"
28 #include "common/c_content.h"
29 #include "scripting_server.h"
30 #include "environment.h"
31 #include "mapblock.h"
32 #include "server.h"
33 #include "nodedef.h"
34 #include "daynightratio.h"
35 #include "util/pointedthing.h"
36 #include "mapgen/treegen.h"
37 #include "emerge.h"
38 #include "pathfinder.h"
39 #include "face_position_cache.h"
40 #include "remoteplayer.h"
41 #include "server/luaentity_sao.h"
42 #include "server/player_sao.h"
43 #include "util/string.h"
44 #include "translation.h"
45 #ifndef SERVER
46 #include "client/client.h"
47 #endif
48
49 struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
50 {
51         {CLEAR_OBJECTS_MODE_FULL,  "full"},
52         {CLEAR_OBJECTS_MODE_QUICK, "quick"},
53         {0, NULL},
54 };
55
56 ///////////////////////////////////////////////////////////////////////////////
57
58
59 void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
60                 u32 active_object_count, u32 active_object_count_wider)
61 {
62         ServerScripting *scriptIface = env->getScriptIface();
63         scriptIface->realityCheck();
64
65         lua_State *L = scriptIface->getStack();
66         sanity_check(lua_checkstack(L, 20));
67         StackUnroller stack_unroller(L);
68
69         int error_handler = PUSH_ERROR_HANDLER(L);
70
71         // Get registered_abms
72         lua_getglobal(L, "core");
73         lua_getfield(L, -1, "registered_abms");
74         luaL_checktype(L, -1, LUA_TTABLE);
75         lua_remove(L, -2); // Remove core
76
77         // Get registered_abms[m_id]
78         lua_pushinteger(L, m_id);
79         lua_gettable(L, -2);
80         if(lua_isnil(L, -1))
81                 FATAL_ERROR("");
82         lua_remove(L, -2); // Remove registered_abms
83
84         scriptIface->setOriginFromTable(-1);
85
86         // Call action
87         luaL_checktype(L, -1, LUA_TTABLE);
88         lua_getfield(L, -1, "action");
89         luaL_checktype(L, -1, LUA_TFUNCTION);
90         lua_remove(L, -2); // Remove registered_abms[m_id]
91         push_v3s16(L, p);
92         pushnode(L, n, env->getGameDef()->ndef());
93         lua_pushnumber(L, active_object_count);
94         lua_pushnumber(L, active_object_count_wider);
95
96         int result = lua_pcall(L, 4, 0, error_handler);
97         if (result)
98                 scriptIface->scriptError(result, "LuaABM::trigger");
99
100         lua_pop(L, 1); // Pop error handler
101 }
102
103 void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
104 {
105         ServerScripting *scriptIface = env->getScriptIface();
106         scriptIface->realityCheck();
107
108         lua_State *L = scriptIface->getStack();
109         sanity_check(lua_checkstack(L, 20));
110         StackUnroller stack_unroller(L);
111
112         int error_handler = PUSH_ERROR_HANDLER(L);
113
114         // Get registered_lbms
115         lua_getglobal(L, "core");
116         lua_getfield(L, -1, "registered_lbms");
117         luaL_checktype(L, -1, LUA_TTABLE);
118         lua_remove(L, -2); // Remove core
119
120         // Get registered_lbms[m_id]
121         lua_pushinteger(L, m_id);
122         lua_gettable(L, -2);
123         FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table");
124         lua_remove(L, -2); // Remove registered_lbms
125
126         scriptIface->setOriginFromTable(-1);
127
128         // Call action
129         luaL_checktype(L, -1, LUA_TTABLE);
130         lua_getfield(L, -1, "action");
131         luaL_checktype(L, -1, LUA_TFUNCTION);
132         lua_remove(L, -2); // Remove registered_lbms[m_id]
133         push_v3s16(L, p);
134         pushnode(L, n, env->getGameDef()->ndef());
135
136         int result = lua_pcall(L, 2, 0, error_handler);
137         if (result)
138                 scriptIface->scriptError(result, "LuaLBM::trigger");
139
140         lua_pop(L, 1); // Pop error handler
141 }
142
143 int LuaRaycast::l_next(lua_State *L)
144 {
145         GET_PLAIN_ENV_PTR;
146
147         bool csm = false;
148 #ifndef SERVER
149         csm = getClient(L) != nullptr;
150 #endif
151
152         LuaRaycast *o = checkobject(L, 1);
153         PointedThing pointed;
154         env->continueRaycast(&o->state, &pointed);
155         if (pointed.type == POINTEDTHING_NOTHING)
156                 lua_pushnil(L);
157         else
158                 push_pointed_thing(L, pointed, csm, true);
159
160         return 1;
161 }
162
163 int LuaRaycast::create_object(lua_State *L)
164 {
165         NO_MAP_LOCK_REQUIRED;
166
167         bool objects = true;
168         bool liquids = false;
169
170         v3f pos1 = checkFloatPos(L, 1);
171         v3f pos2 = checkFloatPos(L, 2);
172         if (lua_isboolean(L, 3)) {
173                 objects = readParam<bool>(L, 3);
174         }
175         if (lua_isboolean(L, 4)) {
176                 liquids = readParam<bool>(L, 4);
177         }
178
179         LuaRaycast *o = new LuaRaycast(core::line3d<f32>(pos1, pos2),
180                 objects, liquids);
181
182         *(void **) (lua_newuserdata(L, sizeof(void *))) = o;
183         luaL_getmetatable(L, className);
184         lua_setmetatable(L, -2);
185         return 1;
186 }
187
188 LuaRaycast *LuaRaycast::checkobject(lua_State *L, int narg)
189 {
190         NO_MAP_LOCK_REQUIRED;
191
192         luaL_checktype(L, narg, LUA_TUSERDATA);
193         void *ud = luaL_checkudata(L, narg, className);
194         if (!ud)
195                 luaL_typerror(L, narg, className);
196         return *(LuaRaycast **) ud;
197 }
198
199 int LuaRaycast::gc_object(lua_State *L)
200 {
201         LuaRaycast *o = *(LuaRaycast **) (lua_touserdata(L, 1));
202         delete o;
203         return 0;
204 }
205
206 void LuaRaycast::Register(lua_State *L)
207 {
208         lua_newtable(L);
209         int methodtable = lua_gettop(L);
210         luaL_newmetatable(L, className);
211         int metatable = lua_gettop(L);
212
213         lua_pushliteral(L, "__metatable");
214         lua_pushvalue(L, methodtable);
215         lua_settable(L, metatable);
216
217         lua_pushliteral(L, "__index");
218         lua_pushvalue(L, methodtable);
219         lua_settable(L, metatable);
220
221         lua_pushliteral(L, "__gc");
222         lua_pushcfunction(L, gc_object);
223         lua_settable(L, metatable);
224
225         lua_pushliteral(L, "__call");
226         lua_pushcfunction(L, l_next);
227         lua_settable(L, metatable);
228
229         lua_pop(L, 1);
230
231         luaL_openlib(L, 0, methods, 0);
232         lua_pop(L, 1);
233
234         lua_register(L, className, create_object);
235 }
236
237 const char LuaRaycast::className[] = "Raycast";
238 const luaL_Reg LuaRaycast::methods[] =
239 {
240         luamethod(LuaRaycast, next),
241         { 0, 0 }
242 };
243
244 void LuaEmergeAreaCallback(v3s16 blockpos, EmergeAction action, void *param)
245 {
246         ScriptCallbackState *state = (ScriptCallbackState *)param;
247         assert(state != NULL);
248         assert(state->script != NULL);
249         assert(state->refcount > 0);
250
251         // state must be protected by envlock
252         Server *server = state->script->getServer();
253         MutexAutoLock envlock(server->m_env_mutex);
254
255         state->refcount--;
256
257         state->script->on_emerge_area_completion(blockpos, action, state);
258
259         if (state->refcount == 0)
260                 delete state;
261 }
262
263 // Exported functions
264
265 // set_node(pos, node)
266 // pos = {x=num, y=num, z=num}
267 int ModApiEnvMod::l_set_node(lua_State *L)
268 {
269         GET_ENV_PTR;
270
271         const NodeDefManager *ndef = env->getGameDef()->ndef();
272         // parameters
273         v3s16 pos = read_v3s16(L, 1);
274         MapNode n = readnode(L, 2, ndef);
275         // Do it
276         bool succeeded = env->setNode(pos, n);
277         lua_pushboolean(L, succeeded);
278         return 1;
279 }
280
281 // bulk_set_node([pos1, pos2, ...], node)
282 // pos = {x=num, y=num, z=num}
283 int ModApiEnvMod::l_bulk_set_node(lua_State *L)
284 {
285         GET_ENV_PTR;
286
287         const NodeDefManager *ndef = env->getGameDef()->ndef();
288         // parameters
289         if (!lua_istable(L, 1)) {
290                 return 0;
291         }
292
293         s32 len = lua_objlen(L, 1);
294         if (len == 0) {
295                 lua_pushboolean(L, true);
296                 return 1;
297         }
298
299         MapNode n = readnode(L, 2, ndef);
300
301         // Do it
302         bool succeeded = true;
303         for (s32 i = 1; i <= len; i++) {
304                 lua_rawgeti(L, 1, i);
305                 if (!env->setNode(read_v3s16(L, -1), n))
306                         succeeded = false;
307                 lua_pop(L, 1);
308         }
309
310         lua_pushboolean(L, succeeded);
311         return 1;
312 }
313
314 int ModApiEnvMod::l_add_node(lua_State *L)
315 {
316         return l_set_node(L);
317 }
318
319 // remove_node(pos)
320 // pos = {x=num, y=num, z=num}
321 int ModApiEnvMod::l_remove_node(lua_State *L)
322 {
323         GET_ENV_PTR;
324
325         // parameters
326         v3s16 pos = read_v3s16(L, 1);
327         // Do it
328         bool succeeded = env->removeNode(pos);
329         lua_pushboolean(L, succeeded);
330         return 1;
331 }
332
333 // swap_node(pos, node)
334 // pos = {x=num, y=num, z=num}
335 int ModApiEnvMod::l_swap_node(lua_State *L)
336 {
337         GET_ENV_PTR;
338
339         const NodeDefManager *ndef = env->getGameDef()->ndef();
340         // parameters
341         v3s16 pos = read_v3s16(L, 1);
342         MapNode n = readnode(L, 2, ndef);
343         // Do it
344         bool succeeded = env->swapNode(pos, n);
345         lua_pushboolean(L, succeeded);
346         return 1;
347 }
348
349 // get_node(pos)
350 // pos = {x=num, y=num, z=num}
351 int ModApiEnvMod::l_get_node(lua_State *L)
352 {
353         GET_ENV_PTR;
354
355         // pos
356         v3s16 pos = read_v3s16(L, 1);
357         // Do it
358         MapNode n = env->getMap().getNode(pos);
359         // Return node
360         pushnode(L, n, env->getGameDef()->ndef());
361         return 1;
362 }
363
364 // get_node_or_nil(pos)
365 // pos = {x=num, y=num, z=num}
366 int ModApiEnvMod::l_get_node_or_nil(lua_State *L)
367 {
368         GET_ENV_PTR;
369
370         // pos
371         v3s16 pos = read_v3s16(L, 1);
372         // Do it
373         bool pos_ok;
374         MapNode n = env->getMap().getNode(pos, &pos_ok);
375         if (pos_ok) {
376                 // Return node
377                 pushnode(L, n, env->getGameDef()->ndef());
378         } else {
379                 lua_pushnil(L);
380         }
381         return 1;
382 }
383
384 // get_node_light(pos, timeofday)
385 // pos = {x=num, y=num, z=num}
386 // timeofday: nil = current time, 0 = night, 0.5 = day
387 int ModApiEnvMod::l_get_node_light(lua_State *L)
388 {
389         GET_PLAIN_ENV_PTR;
390
391         // Do it
392         v3s16 pos = read_v3s16(L, 1);
393         u32 time_of_day = env->getTimeOfDay();
394         if(lua_isnumber(L, 2))
395                 time_of_day = 24000.0 * lua_tonumber(L, 2);
396         time_of_day %= 24000;
397         u32 dnr = time_to_daynight_ratio(time_of_day, true);
398
399         bool is_position_ok;
400         MapNode n = env->getMap().getNode(pos, &is_position_ok);
401         if (is_position_ok) {
402                 const NodeDefManager *ndef = env->getGameDef()->ndef();
403                 lua_pushinteger(L, n.getLightBlend(dnr, ndef));
404         } else {
405                 lua_pushnil(L);
406         }
407         return 1;
408 }
409
410 // place_node(pos, node)
411 // pos = {x=num, y=num, z=num}
412 int ModApiEnvMod::l_place_node(lua_State *L)
413 {
414         GET_ENV_PTR;
415
416         ScriptApiItem *scriptIfaceItem = getScriptApi<ScriptApiItem>(L);
417         Server *server = getServer(L);
418         const NodeDefManager *ndef = server->ndef();
419         IItemDefManager *idef = server->idef();
420
421         v3s16 pos = read_v3s16(L, 1);
422         MapNode n = readnode(L, 2, ndef);
423
424         // Don't attempt to load non-loaded area as of now
425         MapNode n_old = env->getMap().getNode(pos);
426         if(n_old.getContent() == CONTENT_IGNORE){
427                 lua_pushboolean(L, false);
428                 return 1;
429         }
430         // Create item to place
431         ItemStack item(ndef->get(n).name, 1, 0, idef);
432         // Make pointed position
433         PointedThing pointed;
434         pointed.type = POINTEDTHING_NODE;
435         pointed.node_abovesurface = pos;
436         pointed.node_undersurface = pos + v3s16(0,-1,0);
437         // Place it with a NULL placer (appears in Lua as nil)
438         bool success = scriptIfaceItem->item_OnPlace(item, nullptr, pointed);
439         lua_pushboolean(L, success);
440         return 1;
441 }
442
443 // dig_node(pos)
444 // pos = {x=num, y=num, z=num}
445 int ModApiEnvMod::l_dig_node(lua_State *L)
446 {
447         GET_ENV_PTR;
448
449         ScriptApiNode *scriptIfaceNode = getScriptApi<ScriptApiNode>(L);
450
451         v3s16 pos = read_v3s16(L, 1);
452
453         // Don't attempt to load non-loaded area as of now
454         MapNode n = env->getMap().getNode(pos);
455         if(n.getContent() == CONTENT_IGNORE){
456                 lua_pushboolean(L, false);
457                 return 1;
458         }
459         // Dig it out with a NULL digger (appears in Lua as a
460         // non-functional ObjectRef)
461         bool success = scriptIfaceNode->node_on_dig(pos, n, NULL);
462         lua_pushboolean(L, success);
463         return 1;
464 }
465
466 // punch_node(pos)
467 // pos = {x=num, y=num, z=num}
468 int ModApiEnvMod::l_punch_node(lua_State *L)
469 {
470         GET_ENV_PTR;
471
472         ScriptApiNode *scriptIfaceNode = getScriptApi<ScriptApiNode>(L);
473
474         v3s16 pos = read_v3s16(L, 1);
475
476         // Don't attempt to load non-loaded area as of now
477         MapNode n = env->getMap().getNode(pos);
478         if(n.getContent() == CONTENT_IGNORE){
479                 lua_pushboolean(L, false);
480                 return 1;
481         }
482         // Punch it with a NULL puncher (appears in Lua as a non-functional
483         // ObjectRef)
484         bool success = scriptIfaceNode->node_on_punch(pos, n, NULL, PointedThing());
485         lua_pushboolean(L, success);
486         return 1;
487 }
488
489 // get_node_max_level(pos)
490 // pos = {x=num, y=num, z=num}
491 int ModApiEnvMod::l_get_node_max_level(lua_State *L)
492 {
493         GET_PLAIN_ENV_PTR;
494
495         v3s16 pos = read_v3s16(L, 1);
496         MapNode n = env->getMap().getNode(pos);
497         lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
498         return 1;
499 }
500
501 // get_node_level(pos)
502 // pos = {x=num, y=num, z=num}
503 int ModApiEnvMod::l_get_node_level(lua_State *L)
504 {
505         GET_PLAIN_ENV_PTR;
506
507         v3s16 pos = read_v3s16(L, 1);
508         MapNode n = env->getMap().getNode(pos);
509         lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
510         return 1;
511 }
512
513 // set_node_level(pos, level)
514 // pos = {x=num, y=num, z=num}
515 // level: 0..63
516 int ModApiEnvMod::l_set_node_level(lua_State *L)
517 {
518         GET_ENV_PTR;
519
520         v3s16 pos = read_v3s16(L, 1);
521         u8 level = 1;
522         if(lua_isnumber(L, 2))
523                 level = lua_tonumber(L, 2);
524         MapNode n = env->getMap().getNode(pos);
525         lua_pushnumber(L, n.setLevel(env->getGameDef()->ndef(), level));
526         env->setNode(pos, n);
527         return 1;
528 }
529
530 // add_node_level(pos, level)
531 // pos = {x=num, y=num, z=num}
532 // level: -127..127
533 int ModApiEnvMod::l_add_node_level(lua_State *L)
534 {
535         GET_ENV_PTR;
536
537         v3s16 pos = read_v3s16(L, 1);
538         s16 level = 1;
539         if(lua_isnumber(L, 2))
540                 level = lua_tonumber(L, 2);
541         MapNode n = env->getMap().getNode(pos);
542         lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
543         env->setNode(pos, n);
544         return 1;
545 }
546
547 // find_nodes_with_meta(pos1, pos2)
548 int ModApiEnvMod::l_find_nodes_with_meta(lua_State *L)
549 {
550         GET_PLAIN_ENV_PTR;
551
552         std::vector<v3s16> positions = env->getMap().findNodesWithMetadata(
553                 check_v3s16(L, 1), check_v3s16(L, 2));
554
555         lua_createtable(L, positions.size(), 0);
556         for (size_t i = 0; i != positions.size(); i++) {
557                 push_v3s16(L, positions[i]);
558                 lua_rawseti(L, -2, i + 1);
559         }
560
561         return 1;
562 }
563
564 // get_meta(pos)
565 int ModApiEnvMod::l_get_meta(lua_State *L)
566 {
567         GET_ENV_PTR;
568
569         // Do it
570         v3s16 p = read_v3s16(L, 1);
571         NodeMetaRef::create(L, p, env);
572         return 1;
573 }
574
575 // get_node_timer(pos)
576 int ModApiEnvMod::l_get_node_timer(lua_State *L)
577 {
578         GET_ENV_PTR;
579
580         // Do it
581         v3s16 p = read_v3s16(L, 1);
582         NodeTimerRef::create(L, p, &env->getServerMap());
583         return 1;
584 }
585
586 // add_entity(pos, entityname, [staticdata]) -> ObjectRef or nil
587 // pos = {x=num, y=num, z=num}
588 int ModApiEnvMod::l_add_entity(lua_State *L)
589 {
590         GET_ENV_PTR;
591
592         v3f pos = checkFloatPos(L, 1);
593         const char *name = luaL_checkstring(L, 2);
594         const char *staticdata = luaL_optstring(L, 3, "");
595
596         ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, staticdata);
597         int objectid = env->addActiveObject(obj);
598         // If failed to add, return nothing (reads as nil)
599         if(objectid == 0)
600                 return 0;
601
602         // If already deleted (can happen in on_activate), return nil
603         if (obj->isGone())
604                 return 0;
605         getScriptApiBase(L)->objectrefGetOrCreate(L, obj);
606         return 1;
607 }
608
609 // add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
610 // pos = {x=num, y=num, z=num}
611 int ModApiEnvMod::l_add_item(lua_State *L)
612 {
613         GET_ENV_PTR;
614
615         // pos
616         //v3f pos = checkFloatPos(L, 1);
617         // item
618         ItemStack item = read_item(L, 2,getServer(L)->idef());
619         if(item.empty() || !item.isKnown(getServer(L)->idef()))
620                 return 0;
621
622         int error_handler = PUSH_ERROR_HANDLER(L);
623
624         // Use spawn_item to spawn a __builtin:item
625         lua_getglobal(L, "core");
626         lua_getfield(L, -1, "spawn_item");
627         lua_remove(L, -2); // Remove core
628         if(lua_isnil(L, -1))
629                 return 0;
630         lua_pushvalue(L, 1);
631         lua_pushstring(L, item.getItemString().c_str());
632
633         PCALL_RESL(L, lua_pcall(L, 2, 1, error_handler));
634
635         lua_remove(L, error_handler);
636         return 1;
637 }
638
639 // get_connected_players()
640 int ModApiEnvMod::l_get_connected_players(lua_State *L)
641 {
642         ServerEnvironment *env = (ServerEnvironment *) getEnv(L);
643         if (!env) {
644                 log_deprecated(L, "Calling get_connected_players() at mod load time"
645                                 " is deprecated");
646                 lua_createtable(L, 0, 0);
647                 return 1;
648         }
649
650         lua_createtable(L, env->getPlayerCount(), 0);
651         u32 i = 0;
652         for (RemotePlayer *player : env->getPlayers()) {
653                 if (player->getPeerId() == PEER_ID_INEXISTENT)
654                         continue;
655                 PlayerSAO *sao = player->getPlayerSAO();
656                 if (sao && !sao->isGone()) {
657                         getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
658                         lua_rawseti(L, -2, ++i);
659                 }
660         }
661         return 1;
662 }
663
664 // get_player_by_name(name)
665 int ModApiEnvMod::l_get_player_by_name(lua_State *L)
666 {
667         GET_ENV_PTR;
668
669         // Do it
670         const char *name = luaL_checkstring(L, 1);
671         RemotePlayer *player = env->getPlayer(name);
672         if (!player || player->getPeerId() == PEER_ID_INEXISTENT)
673                 return 0;
674         PlayerSAO *sao = player->getPlayerSAO();
675         if (!sao || sao->isGone())
676                 return 0;
677         // Put player on stack
678         getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
679         return 1;
680 }
681
682 // get_objects_inside_radius(pos, radius)
683 int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
684 {
685         GET_ENV_PTR;
686         ScriptApiBase *script = getScriptApiBase(L);
687
688         // Do it
689         v3f pos = checkFloatPos(L, 1);
690         float radius = readParam<float>(L, 2) * BS;
691         std::vector<ServerActiveObject *> objs;
692
693         auto include_obj_cb = [](ServerActiveObject *obj){ return !obj->isGone(); };
694         env->getObjectsInsideRadius(objs, pos, radius, include_obj_cb);
695
696         int i = 0;
697         lua_createtable(L, objs.size(), 0);
698         for (const auto obj : objs) {
699                 // Insert object reference into table
700                 script->objectrefGetOrCreate(L, obj);
701                 lua_rawseti(L, -2, ++i);
702         }
703         return 1;
704 }
705
706 // set_timeofday(val)
707 // val = 0...1
708 int ModApiEnvMod::l_set_timeofday(lua_State *L)
709 {
710         GET_ENV_PTR;
711
712         // Do it
713         float timeofday_f = readParam<float>(L, 1);
714         sanity_check(timeofday_f >= 0.0 && timeofday_f <= 1.0);
715         int timeofday_mh = (int)(timeofday_f * 24000.0);
716         // This should be set directly in the environment but currently
717         // such changes aren't immediately sent to the clients, so call
718         // the server instead.
719         //env->setTimeOfDay(timeofday_mh);
720         getServer(L)->setTimeOfDay(timeofday_mh);
721         return 0;
722 }
723
724 // get_timeofday() -> 0...1
725 int ModApiEnvMod::l_get_timeofday(lua_State *L)
726 {
727         GET_PLAIN_ENV_PTR;
728
729         // Do it
730         int timeofday_mh = env->getTimeOfDay();
731         float timeofday_f = (float)timeofday_mh / 24000.0f;
732         lua_pushnumber(L, timeofday_f);
733         return 1;
734 }
735
736 // get_day_count() -> int
737 int ModApiEnvMod::l_get_day_count(lua_State *L)
738 {
739         GET_PLAIN_ENV_PTR;
740
741         lua_pushnumber(L, env->getDayCount());
742         return 1;
743 }
744
745 // get_gametime()
746 int ModApiEnvMod::l_get_gametime(lua_State *L)
747 {
748         GET_ENV_PTR;
749
750         int game_time = env->getGameTime();
751         lua_pushnumber(L, game_time);
752         return 1;
753 }
754
755 void ModApiEnvMod::collectNodeIds(lua_State *L, int idx, const NodeDefManager *ndef,
756         std::vector<content_t> &filter)
757 {
758         if (lua_istable(L, idx)) {
759                 lua_pushnil(L);
760                 while (lua_next(L, idx) != 0) {
761                         // key at index -2 and value at index -1
762                         luaL_checktype(L, -1, LUA_TSTRING);
763                         ndef->getIds(readParam<std::string>(L, -1), filter);
764                         // removes value, keeps key for next iteration
765                         lua_pop(L, 1);
766                 }
767         } else if (lua_isstring(L, idx)) {
768                 ndef->getIds(readParam<std::string>(L, 3), filter);
769         }
770 }
771
772 // find_node_near(pos, radius, nodenames, [search_center]) -> pos or nil
773 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
774 int ModApiEnvMod::l_find_node_near(lua_State *L)
775 {
776         GET_PLAIN_ENV_PTR;
777
778         const NodeDefManager *ndef = env->getGameDef()->ndef();
779         Map &map = env->getMap();
780
781         v3s16 pos = read_v3s16(L, 1);
782         int radius = luaL_checkinteger(L, 2);
783         std::vector<content_t> filter;
784         collectNodeIds(L, 3, ndef, filter);
785         int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
786
787 #ifndef SERVER
788         // Client API limitations
789         if (Client *client = getClient(L))
790                 radius = client->CSMClampRadius(pos, radius);
791 #endif
792
793         for (int d = start_radius; d <= radius; d++) {
794                 const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
795                 for (const v3s16 &i : list) {
796                         v3s16 p = pos + i;
797                         content_t c = map.getNode(p).getContent();
798                         if (CONTAINS(filter, c)) {
799                                 std::cout << p.X << " " << p.Y << " " << p.Z << std::endl;
800                                 push_v3s16(L, p);
801                                 return 1;
802                         }
803                 }
804         }
805         return 0;
806 }
807
808 // find_nodes_near(pos, radius, nodenames, [search_center])
809 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
810 int ModApiEnvMod::l_find_nodes_near(lua_State *L)
811 {
812         GET_PLAIN_ENV_PTR;
813
814         const NodeDefManager *ndef = env->getGameDef()->ndef();
815         Map &map = env->getMap();
816
817         v3s16 pos = read_v3s16(L, 1);
818         int radius = luaL_checkinteger(L, 2);
819         std::vector<content_t> filter;
820         collectNodeIds(L, 3, ndef, filter);
821
822         int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
823
824 #ifndef SERVER
825         // Client API limitations
826         if (Client *client = getClient(L))
827                 radius = client->CSMClampRadius(pos, radius);
828 #endif
829         
830         std::vector<u32> individual_count;
831         individual_count.resize(filter.size());
832         
833         lua_newtable(L);
834         u32 i = 0;
835         
836         for (int d = start_radius; d <= radius; d++) {
837                 const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
838                 for (const v3s16 &posi : list) {
839                         v3s16 p = pos + posi;
840                         content_t c = map.getNode(p).getContent();
841                         auto it = std::find(filter.begin(), filter.end(), c);
842                         if (it != filter.end()) {
843                                 push_v3s16(L, p);
844                                 lua_rawseti(L, -2, ++i);
845
846                                 u32 filt_index = it - filter.begin();
847                                 individual_count[filt_index]++;
848                         }
849                 }
850         }
851         lua_createtable(L, 0, filter.size());
852         for (u32 i = 0; i < filter.size(); i++) {
853                 lua_pushinteger(L, individual_count[i]);
854                 lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
855         }
856         return 2;
857 }
858
859 // find_nodes_near_under_air(pos, radius, nodenames, [search_center])
860 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
861 int ModApiEnvMod::l_find_nodes_near_under_air(lua_State *L)
862 {
863         GET_PLAIN_ENV_PTR;
864
865         const NodeDefManager *ndef = env->getGameDef()->ndef();
866         Map &map = env->getMap();
867
868         v3s16 pos = read_v3s16(L, 1);
869         int radius = luaL_checkinteger(L, 2);
870         std::vector<content_t> filter;
871         collectNodeIds(L, 3, ndef, filter);
872         int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
873
874 #ifndef SERVER
875         // Client API limitations
876         if (Client *client = getClient(L))
877                 radius = client->CSMClampRadius(pos, radius);
878 #endif
879         
880         std::vector<u32> individual_count;
881         individual_count.resize(filter.size());
882         
883         lua_newtable(L);
884         u32 i = 0;
885         
886         for (int d = start_radius; d <= radius; d++) {
887                 const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
888                 for (const v3s16 &posi : list) {
889                         v3s16 p = pos + posi;
890                         content_t c = map.getNode(p).getContent();
891                         v3s16 psurf(p.X, p.Y + 1, p.Z);
892                         content_t csurf = map.getNode(psurf).getContent();
893                         if (c == CONTENT_AIR || csurf != CONTENT_AIR)
894                                 continue;
895                         auto it = std::find(filter.begin(), filter.end(), c);
896                         if (it != filter.end()) {
897                                 push_v3s16(L, p);
898                                 lua_rawseti(L, -2, ++i);
899
900                                 u32 filt_index = it - filter.begin();
901                                 individual_count[filt_index]++;
902                         }
903                 }
904         }
905         lua_createtable(L, 0, filter.size());
906         for (u32 i = 0; i < filter.size(); i++) {
907                 lua_pushinteger(L, individual_count[i]);
908                 lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
909         }
910         return 2;
911 }
912
913 // find_nodes_near_under_air_except(pos, radius, nodenames, [search_center])
914 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
915 int ModApiEnvMod::l_find_nodes_near_under_air_except(lua_State *L)
916 {
917         GET_PLAIN_ENV_PTR;
918
919         const NodeDefManager *ndef = env->getGameDef()->ndef();
920         Map &map = env->getMap();
921
922         v3s16 pos = read_v3s16(L, 1);
923         int radius = luaL_checkinteger(L, 2);
924         std::vector<content_t> filter;
925         collectNodeIds(L, 3, ndef, filter);
926         int start_radius = (lua_isboolean(L, 4) && readParam<bool>(L, 4)) ? 0 : 1;
927
928 #ifndef SERVER
929         // Client API limitations
930         if (Client *client = getClient(L))
931                 radius = client->CSMClampRadius(pos, radius);
932 #endif
933         
934         std::vector<u32> individual_count;
935         individual_count.resize(filter.size());
936         
937         lua_newtable(L);
938         u32 i = 0;
939         
940         for (int d = start_radius; d <= radius; d++) {
941                 const std::vector<v3s16> &list = FacePositionCache::getFacePositions(d);
942                 for (const v3s16 &posi : list) {
943                         v3s16 p = pos + posi;
944                         content_t c = map.getNode(p).getContent();
945                         v3s16 psurf(p.X, p.Y + 1, p.Z);
946                         content_t csurf = map.getNode(psurf).getContent();
947                         if (c == CONTENT_AIR || csurf != CONTENT_AIR)
948                                 continue;
949                         auto it = std::find(filter.begin(), filter.end(), c);
950                         if (it == filter.end()) {
951                                 push_v3s16(L, p);
952                                 lua_rawseti(L, -2, ++i);
953
954                                 u32 filt_index = it - filter.begin();
955                                 individual_count[filt_index]++;
956                         }
957                 }
958         }
959         lua_createtable(L, 0, filter.size());
960         for (u32 i = 0; i < filter.size(); i++) {
961                 lua_pushinteger(L, individual_count[i]);
962                 lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
963         }
964         return 2;
965 }
966
967 // find_nodes_in_area(minp, maxp, nodenames, [grouped])
968 int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
969 {
970         GET_PLAIN_ENV_PTR;
971
972         v3s16 minp = read_v3s16(L, 1);
973         v3s16 maxp = read_v3s16(L, 2);
974         sortBoxVerticies(minp, maxp);
975
976         const NodeDefManager *ndef = env->getGameDef()->ndef();
977         Map &map = env->getMap();
978
979 #ifndef SERVER
980         if (Client *client = getClient(L)) {
981                 minp = client->CSMClampPos(minp);
982                 maxp = client->CSMClampPos(maxp);
983         }
984 #endif
985
986         v3s16 cube = maxp - minp + 1;
987         // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
988         if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
989                 luaL_error(L, "find_nodes_in_area(): area volume"
990                                 " exceeds allowed value of 4096000");
991                 return 0;
992         }
993
994         std::vector<content_t> filter;
995         collectNodeIds(L, 3, ndef, filter);
996
997         bool grouped = lua_isboolean(L, 4) && readParam<bool>(L, 4);
998
999         if (grouped) {
1000                 // create the table we will be returning
1001                 lua_createtable(L, 0, filter.size());
1002                 int base = lua_gettop(L);
1003
1004                 // create one table for each filter
1005                 std::vector<u32> idx;
1006                 idx.resize(filter.size());
1007                 for (u32 i = 0; i < filter.size(); i++)
1008                         lua_newtable(L);
1009
1010                 v3s16 p;
1011                 for (p.X = minp.X; p.X <= maxp.X; p.X++)
1012                 for (p.Y = minp.Y; p.Y <= maxp.Y; p.Y++)
1013                 for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) {
1014                         content_t c = map.getNode(p).getContent();
1015
1016                         auto it = std::find(filter.begin(), filter.end(), c);
1017                         if (it != filter.end()) {
1018                                 // Calculate index of the table and append the position
1019                                 u32 filt_index = it - filter.begin();
1020                                 push_v3s16(L, p);
1021                                 lua_rawseti(L, base + 1 + filt_index, ++idx[filt_index]);
1022                         }
1023                 }
1024
1025                 // last filter table is at top of stack
1026                 u32 i = filter.size() - 1;
1027                 do {
1028                         if (idx[i] == 0) {
1029                                 // No such node found -> drop the empty table
1030                                 lua_pop(L, 1);
1031                         } else {
1032                                 // This node was found -> put table into the return table
1033                                 lua_setfield(L, base, ndef->get(filter[i]).name.c_str());
1034                         }
1035                 } while (i-- != 0);
1036
1037                 assert(lua_gettop(L) == base);
1038                 return 1;
1039         } else {
1040                 std::vector<u32> individual_count;
1041                 individual_count.resize(filter.size());
1042
1043                 lua_newtable(L);
1044                 u32 i = 0;
1045                 v3s16 p;
1046                 for (p.X = minp.X; p.X <= maxp.X; p.X++)
1047                 for (p.Y = minp.Y; p.Y <= maxp.Y; p.Y++)
1048                 for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) {
1049                         content_t c = env->getMap().getNode(p).getContent();
1050
1051                         auto it = std::find(filter.begin(), filter.end(), c);
1052                         if (it != filter.end()) {
1053                                 push_v3s16(L, p);
1054                                 lua_rawseti(L, -2, ++i);
1055
1056                                 u32 filt_index = it - filter.begin();
1057                                 individual_count[filt_index]++;
1058                         }
1059                 }
1060
1061                 lua_createtable(L, 0, filter.size());
1062                 for (u32 i = 0; i < filter.size(); i++) {
1063                         lua_pushinteger(L, individual_count[i]);
1064                         lua_setfield(L, -2, ndef->get(filter[i]).name.c_str());
1065                 }
1066                 return 2;
1067         }
1068 }
1069
1070 // find_nodes_in_area_under_air(minp, maxp, nodenames) -> list of positions
1071 // nodenames: e.g. {"ignore", "group:tree"} or "default:dirt"
1072 int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
1073 {
1074         /* Note: A similar but generalized (and therefore slower) version of this
1075          * function could be created -- e.g. find_nodes_in_area_under -- which
1076          * would accept a node name (or ID?) or list of names that the "above node"
1077          * should be.
1078          * TODO
1079          */
1080
1081         GET_PLAIN_ENV_PTR;
1082
1083         v3s16 minp = read_v3s16(L, 1);
1084         v3s16 maxp = read_v3s16(L, 2);
1085         sortBoxVerticies(minp, maxp);
1086
1087         const NodeDefManager *ndef = env->getGameDef()->ndef();
1088         Map &map = env->getMap();
1089
1090 #ifndef SERVER
1091         if (Client *client = getClient(L)) {
1092                 minp = client->CSMClampPos(minp);
1093                 maxp = client->CSMClampPos(maxp);
1094         }
1095 #endif
1096
1097         v3s16 cube = maxp - minp + 1;
1098         // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
1099         if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
1100                 luaL_error(L, "find_nodes_in_area_under_air(): area volume"
1101                                 " exceeds allowed value of 4096000");
1102                 return 0;
1103         }
1104
1105         std::vector<content_t> filter;
1106         collectNodeIds(L, 3, ndef, filter);
1107
1108         lua_newtable(L);
1109         u32 i = 0;
1110         v3s16 p;
1111         for (p.X = minp.X; p.X <= maxp.X; p.X++)
1112         for (p.Z = minp.Z; p.Z <= maxp.Z; p.Z++) {
1113                 p.Y = minp.Y;
1114                 content_t c = map.getNode(p).getContent();
1115                 for (; p.Y <= maxp.Y; p.Y++) {
1116                         v3s16 psurf(p.X, p.Y + 1, p.Z);
1117                         content_t csurf = map.getNode(psurf).getContent();
1118                         if (c != CONTENT_AIR && csurf == CONTENT_AIR &&
1119                                         CONTAINS(filter, c)) {
1120                                 push_v3s16(L, p);
1121                                 lua_rawseti(L, -2, ++i);
1122                         }
1123                         c = csurf;
1124                 }
1125         }
1126         return 1;
1127 }
1128
1129 // get_perlin(seeddiff, octaves, persistence, scale)
1130 // returns world-specific PerlinNoise
1131 int ModApiEnvMod::l_get_perlin(lua_State *L)
1132 {
1133         GET_ENV_PTR_NO_MAP_LOCK;
1134
1135         NoiseParams params;
1136
1137         if (lua_istable(L, 1)) {
1138                 read_noiseparams(L, 1, &params);
1139         } else {
1140                 params.seed    = luaL_checkint(L, 1);
1141                 params.octaves = luaL_checkint(L, 2);
1142                 params.persist = readParam<float>(L, 3);
1143                 params.spread  = v3f(1, 1, 1) * readParam<float>(L, 4);
1144         }
1145
1146         params.seed += (int)env->getServerMap().getSeed();
1147
1148         LuaPerlinNoise *n = new LuaPerlinNoise(&params);
1149         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
1150         luaL_getmetatable(L, "PerlinNoise");
1151         lua_setmetatable(L, -2);
1152         return 1;
1153 }
1154
1155 // get_perlin_map(noiseparams, size)
1156 // returns world-specific PerlinNoiseMap
1157 int ModApiEnvMod::l_get_perlin_map(lua_State *L)
1158 {
1159         GET_ENV_PTR_NO_MAP_LOCK;
1160
1161         NoiseParams np;
1162         if (!read_noiseparams(L, 1, &np))
1163                 return 0;
1164         v3s16 size = read_v3s16(L, 2);
1165
1166         s32 seed = (s32)(env->getServerMap().getSeed());
1167         LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(&np, seed, size);
1168         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
1169         luaL_getmetatable(L, "PerlinNoiseMap");
1170         lua_setmetatable(L, -2);
1171         return 1;
1172 }
1173
1174 // get_voxel_manip()
1175 // returns voxel manipulator
1176 int ModApiEnvMod::l_get_voxel_manip(lua_State *L)
1177 {
1178         GET_ENV_PTR;
1179
1180         Map *map = &(env->getMap());
1181         LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
1182                 new LuaVoxelManip(map, read_v3s16(L, 1), read_v3s16(L, 2)) :
1183                 new LuaVoxelManip(map);
1184
1185         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
1186         luaL_getmetatable(L, "VoxelManip");
1187         lua_setmetatable(L, -2);
1188         return 1;
1189 }
1190
1191 // clear_objects([options])
1192 // clear all objects in the environment
1193 // where options = {mode = "full" or "quick"}
1194 int ModApiEnvMod::l_clear_objects(lua_State *L)
1195 {
1196         GET_ENV_PTR;
1197
1198         ClearObjectsMode mode = CLEAR_OBJECTS_MODE_QUICK;
1199         if (lua_istable(L, 1)) {
1200                 mode = (ClearObjectsMode)getenumfield(L, 1, "mode",
1201                         ModApiEnvMod::es_ClearObjectsMode, mode);
1202         }
1203
1204         env->clearObjects(mode);
1205         return 0;
1206 }
1207
1208 // line_of_sight(pos1, pos2) -> true/false, pos
1209 int ModApiEnvMod::l_line_of_sight(lua_State *L)
1210 {
1211         GET_PLAIN_ENV_PTR;
1212
1213         // read position 1 from lua
1214         v3f pos1 = checkFloatPos(L, 1);
1215         // read position 2 from lua
1216         v3f pos2 = checkFloatPos(L, 2);
1217
1218         v3s16 p;
1219
1220         bool success = env->line_of_sight(pos1, pos2, &p);
1221         lua_pushboolean(L, success);
1222         if (!success) {
1223                 push_v3s16(L, p);
1224                 return 2;
1225         }
1226         return 1;
1227 }
1228
1229 // fix_light(p1, p2)
1230 int ModApiEnvMod::l_fix_light(lua_State *L)
1231 {
1232         GET_ENV_PTR;
1233
1234         v3s16 blockpos1 = getContainerPos(read_v3s16(L, 1), MAP_BLOCKSIZE);
1235         v3s16 blockpos2 = getContainerPos(read_v3s16(L, 2), MAP_BLOCKSIZE);
1236         ServerMap &map = env->getServerMap();
1237         std::map<v3s16, MapBlock *> modified_blocks;
1238         bool success = true;
1239         v3s16 blockpos;
1240         for (blockpos.X = blockpos1.X; blockpos.X <= blockpos2.X; blockpos.X++)
1241         for (blockpos.Y = blockpos1.Y; blockpos.Y <= blockpos2.Y; blockpos.Y++)
1242         for (blockpos.Z = blockpos1.Z; blockpos.Z <= blockpos2.Z; blockpos.Z++) {
1243                 success = success & map.repairBlockLight(blockpos, &modified_blocks);
1244         }
1245         if (!modified_blocks.empty()) {
1246                 MapEditEvent event;
1247                 event.type = MEET_OTHER;
1248                 for (auto &modified_block : modified_blocks)
1249                         event.modified_blocks.insert(modified_block.first);
1250
1251                 map.dispatchEvent(event);
1252         }
1253         lua_pushboolean(L, success);
1254
1255         return 1;
1256 }
1257
1258 int ModApiEnvMod::l_raycast(lua_State *L)
1259 {
1260         return LuaRaycast::create_object(L);
1261 }
1262
1263 // load_area(p1, [p2])
1264 // load mapblocks in area p1..p2, but do not generate map
1265 int ModApiEnvMod::l_load_area(lua_State *L)
1266 {
1267         GET_ENV_PTR;
1268         MAP_LOCK_REQUIRED;
1269
1270         Map *map = &(env->getMap());
1271         v3s16 bp1 = getNodeBlockPos(check_v3s16(L, 1));
1272         if (!lua_istable(L, 2)) {
1273                 map->emergeBlock(bp1);
1274         } else {
1275                 v3s16 bp2 = getNodeBlockPos(check_v3s16(L, 2));
1276                 sortBoxVerticies(bp1, bp2);
1277                 for (s16 z = bp1.Z; z <= bp2.Z; z++)
1278                 for (s16 y = bp1.Y; y <= bp2.Y; y++)
1279                 for (s16 x = bp1.X; x <= bp2.X; x++) {
1280                         map->emergeBlock(v3s16(x, y, z));
1281                 }
1282         }
1283
1284         return 0;
1285 }
1286
1287 // emerge_area(p1, p2, [callback, context])
1288 // emerge mapblocks in area p1..p2, calls callback with context upon completion
1289 int ModApiEnvMod::l_emerge_area(lua_State *L)
1290 {
1291         GET_ENV_PTR;
1292
1293         EmergeCompletionCallback callback = NULL;
1294         ScriptCallbackState *state = NULL;
1295
1296         EmergeManager *emerge = getServer(L)->getEmergeManager();
1297
1298         v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
1299         v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
1300         sortBoxVerticies(bpmin, bpmax);
1301
1302         size_t num_blocks = VoxelArea(bpmin, bpmax).getVolume();
1303         assert(num_blocks != 0);
1304
1305         if (lua_isfunction(L, 3)) {
1306                 callback = LuaEmergeAreaCallback;
1307
1308                 lua_pushvalue(L, 3);
1309                 int callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
1310
1311                 lua_pushvalue(L, 4);
1312                 int args_ref = luaL_ref(L, LUA_REGISTRYINDEX);
1313
1314                 state = new ScriptCallbackState;
1315                 state->script       = getServer(L)->getScriptIface();
1316                 state->callback_ref = callback_ref;
1317                 state->args_ref     = args_ref;
1318                 state->refcount     = num_blocks;
1319                 state->origin       = getScriptApiBase(L)->getOrigin();
1320         }
1321
1322         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1323         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
1324         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
1325                 emerge->enqueueBlockEmergeEx(v3s16(x, y, z), PEER_ID_INEXISTENT,
1326                         BLOCK_EMERGE_ALLOW_GEN | BLOCK_EMERGE_FORCE_QUEUE, callback, state);
1327         }
1328
1329         return 0;
1330 }
1331
1332 // delete_area(p1, p2)
1333 // delete mapblocks in area p1..p2
1334 int ModApiEnvMod::l_delete_area(lua_State *L)
1335 {
1336         GET_ENV_PTR;
1337
1338         v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
1339         v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
1340         sortBoxVerticies(bpmin, bpmax);
1341
1342         ServerMap &map = env->getServerMap();
1343
1344         MapEditEvent event;
1345         event.type = MEET_OTHER;
1346
1347         bool success = true;
1348         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1349         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
1350         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
1351                 v3s16 bp(x, y, z);
1352                 if (map.deleteBlock(bp)) {
1353                         env->setStaticForActiveObjectsInBlock(bp, false);
1354                         event.modified_blocks.insert(bp);
1355                 } else {
1356                         success = false;
1357                 }
1358         }
1359
1360         map.dispatchEvent(event);
1361         lua_pushboolean(L, success);
1362         return 1;
1363 }
1364
1365 // find_path(pos1, pos2, searchdistance,
1366 //     max_jump, max_drop, algorithm) -> table containing path
1367 int ModApiEnvMod::l_find_path(lua_State *L)
1368 {
1369         GET_ENV_PTR;
1370
1371         v3s16 pos1                  = read_v3s16(L, 1);
1372         v3s16 pos2                  = read_v3s16(L, 2);
1373         unsigned int searchdistance = luaL_checkint(L, 3);
1374         unsigned int max_jump       = luaL_checkint(L, 4);
1375         unsigned int max_drop       = luaL_checkint(L, 5);
1376         PathAlgorithm algo          = PA_PLAIN_NP;
1377         if (!lua_isnoneornil(L, 6)) {
1378                 std::string algorithm = luaL_checkstring(L,6);
1379
1380                 if (algorithm == "A*")
1381                         algo = PA_PLAIN;
1382
1383                 if (algorithm == "Dijkstra")
1384                         algo = PA_DIJKSTRA;
1385         }
1386
1387         std::vector<v3s16> path = get_path(&env->getServerMap(), env->getGameDef()->ndef(), pos1, pos2,
1388                 searchdistance, max_jump, max_drop, algo);
1389
1390         if (!path.empty()) {
1391                 lua_createtable(L, path.size(), 0);
1392                 int top = lua_gettop(L);
1393                 unsigned int index = 1;
1394                 for (const v3s16 &i : path) {
1395                         lua_pushnumber(L,index);
1396                         push_v3s16(L, i);
1397                         lua_settable(L, top);
1398                         index++;
1399                 }
1400                 return 1;
1401         }
1402
1403         return 0;
1404 }
1405
1406 // spawn_tree(pos, treedef)
1407 int ModApiEnvMod::l_spawn_tree(lua_State *L)
1408 {
1409         GET_ENV_PTR;
1410
1411         v3s16 p0 = read_v3s16(L, 1);
1412
1413         treegen::TreeDef tree_def;
1414         std::string trunk,leaves,fruit;
1415         const NodeDefManager *ndef = env->getGameDef()->ndef();
1416
1417         if(lua_istable(L, 2))
1418         {
1419                 getstringfield(L, 2, "axiom", tree_def.initial_axiom);
1420                 getstringfield(L, 2, "rules_a", tree_def.rules_a);
1421                 getstringfield(L, 2, "rules_b", tree_def.rules_b);
1422                 getstringfield(L, 2, "rules_c", tree_def.rules_c);
1423                 getstringfield(L, 2, "rules_d", tree_def.rules_d);
1424                 getstringfield(L, 2, "trunk", trunk);
1425                 tree_def.trunknode=ndef->getId(trunk);
1426                 getstringfield(L, 2, "leaves", leaves);
1427                 tree_def.leavesnode=ndef->getId(leaves);
1428                 tree_def.leaves2_chance=0;
1429                 getstringfield(L, 2, "leaves2", leaves);
1430                 if (!leaves.empty()) {
1431                         tree_def.leaves2node=ndef->getId(leaves);
1432                         getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
1433                 }
1434                 getintfield(L, 2, "angle", tree_def.angle);
1435                 getintfield(L, 2, "iterations", tree_def.iterations);
1436                 if (!getintfield(L, 2, "random_level", tree_def.iterations_random_level))
1437                         tree_def.iterations_random_level = 0;
1438                 getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
1439                 getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
1440                 tree_def.fruit_chance=0;
1441                 getstringfield(L, 2, "fruit", fruit);
1442                 if (!fruit.empty()) {
1443                         tree_def.fruitnode=ndef->getId(fruit);
1444                         getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
1445                 }
1446                 tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed);
1447         }
1448         else
1449                 return 0;
1450
1451         ServerMap *map = &env->getServerMap();
1452         treegen::error e;
1453         if ((e = treegen::spawn_ltree (map, p0, ndef, tree_def)) != treegen::SUCCESS) {
1454                 if (e == treegen::UNBALANCED_BRACKETS) {
1455                         luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket");
1456                 } else {
1457                         luaL_error(L, "spawn_tree(): unknown error");
1458                 }
1459         }
1460
1461         return 1;
1462 }
1463
1464 // transforming_liquid_add(pos)
1465 int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
1466 {
1467         GET_ENV_PTR;
1468
1469         v3s16 p0 = read_v3s16(L, 1);
1470         env->getMap().transforming_liquid_add(p0);
1471         return 1;
1472 }
1473
1474 // forceload_block(blockpos)
1475 // blockpos = {x=num, y=num, z=num}
1476 int ModApiEnvMod::l_forceload_block(lua_State *L)
1477 {
1478         GET_ENV_PTR;
1479
1480         v3s16 blockpos = read_v3s16(L, 1);
1481         env->getForceloadedBlocks()->insert(blockpos);
1482         return 0;
1483 }
1484
1485 // forceload_free_block(blockpos)
1486 // blockpos = {x=num, y=num, z=num}
1487 int ModApiEnvMod::l_forceload_free_block(lua_State *L)
1488 {
1489         GET_ENV_PTR;
1490
1491         v3s16 blockpos = read_v3s16(L, 1);
1492         env->getForceloadedBlocks()->erase(blockpos);
1493         return 0;
1494 }
1495
1496 // get_translated_string(lang_code, string)
1497 int ModApiEnvMod::l_get_translated_string(lua_State * L)
1498 {
1499         GET_ENV_PTR;
1500         std::string lang_code = luaL_checkstring(L, 1);
1501         std::string string = luaL_checkstring(L, 2);
1502         getServer(L)->loadTranslationLanguage(lang_code);
1503         string = wide_to_utf8(translate_string(utf8_to_wide(string),
1504                         &(*g_server_translations)[lang_code]));
1505         lua_pushstring(L, string.c_str());
1506         return 1;
1507 }
1508
1509 void ModApiEnvMod::Initialize(lua_State *L, int top)
1510 {
1511         API_FCT(set_node);
1512         API_FCT(bulk_set_node);
1513         API_FCT(add_node);
1514         API_FCT(swap_node);
1515         API_FCT(add_item);
1516         API_FCT(remove_node);
1517         API_FCT(get_node);
1518         API_FCT(get_node_or_nil);
1519         API_FCT(get_node_light);
1520         API_FCT(place_node);
1521         API_FCT(dig_node);
1522         API_FCT(punch_node);
1523         API_FCT(get_node_max_level);
1524         API_FCT(get_node_level);
1525         API_FCT(set_node_level);
1526         API_FCT(add_node_level);
1527         API_FCT(add_entity);
1528         API_FCT(find_nodes_with_meta);
1529         API_FCT(get_meta);
1530         API_FCT(get_node_timer);
1531         API_FCT(get_connected_players);
1532         API_FCT(get_player_by_name);
1533         API_FCT(get_objects_inside_radius);
1534         API_FCT(set_timeofday);
1535         API_FCT(get_timeofday);
1536         API_FCT(get_gametime);
1537         API_FCT(get_day_count);
1538         API_FCT(find_node_near);
1539         API_FCT(find_nodes_near);
1540         API_FCT(find_nodes_near_under_air);
1541         API_FCT(find_nodes_in_area);
1542         API_FCT(find_nodes_in_area_under_air);
1543         API_FCT(fix_light);
1544         API_FCT(load_area);
1545         API_FCT(emerge_area);
1546         API_FCT(delete_area);
1547         API_FCT(get_perlin);
1548         API_FCT(get_perlin_map);
1549         API_FCT(get_voxel_manip);
1550         API_FCT(clear_objects);
1551         API_FCT(spawn_tree);
1552         API_FCT(find_path);
1553         API_FCT(line_of_sight);
1554         API_FCT(raycast);
1555         API_FCT(transforming_liquid_add);
1556         API_FCT(forceload_block);
1557         API_FCT(forceload_free_block);
1558         API_FCT(get_translated_string);
1559 }
1560
1561 void ModApiEnvMod::InitializeClient(lua_State *L, int top)
1562 {
1563         API_FCT(get_node_light);
1564         API_FCT(get_timeofday);
1565         API_FCT(get_node_max_level);
1566         API_FCT(get_node_level);
1567         API_FCT(find_nodes_with_meta);
1568         API_FCT(find_node_near);
1569         API_FCT(find_nodes_near);
1570         API_FCT(find_nodes_near_under_air);
1571         API_FCT(find_nodes_near_under_air_except);
1572         API_FCT(find_nodes_in_area);
1573         API_FCT(find_nodes_in_area_under_air);
1574         API_FCT(line_of_sight);
1575         API_FCT(raycast);
1576 }