]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_env.cpp
Add /emergeblocks command and core.emerge_area() Lua API
[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 #define GET_ENV_PTR ServerEnvironment* env =                                   \
40                                 dynamic_cast<ServerEnvironment*>(getEnv(L));                   \
41                                 if (env == NULL) return 0
42
43 ///////////////////////////////////////////////////////////////////////////////
44
45
46 void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
47                 u32 active_object_count, u32 active_object_count_wider)
48 {
49         GameScripting *scriptIface = env->getScriptIface();
50         scriptIface->realityCheck();
51
52         lua_State *L = scriptIface->getStack();
53         sanity_check(lua_checkstack(L, 20));
54         StackUnroller stack_unroller(L);
55
56         int error_handler = PUSH_ERROR_HANDLER(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, error_handler);
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         int error_handler = PUSH_ERROR_HANDLER(L);
416
417         // Use spawn_item to spawn a __builtin:item
418         lua_getglobal(L, "core");
419         lua_getfield(L, -1, "spawn_item");
420         lua_remove(L, -2); // Remove core
421         if(lua_isnil(L, -1))
422                 return 0;
423         lua_pushvalue(L, 1);
424         lua_pushstring(L, item.getItemString().c_str());
425
426         PCALL_RESL(L, lua_pcall(L, 2, 1, error_handler));
427
428         lua_remove(L, error_handler);
429         return 1;
430 }
431
432 // get_player_by_name(name)
433 int ModApiEnvMod::l_get_player_by_name(lua_State *L)
434 {
435         GET_ENV_PTR;
436
437         // Do it
438         const char *name = luaL_checkstring(L, 1);
439         Player *player = env->getPlayer(name);
440         if(player == NULL){
441                 lua_pushnil(L);
442                 return 1;
443         }
444         PlayerSAO *sao = player->getPlayerSAO();
445         if(sao == NULL){
446                 lua_pushnil(L);
447                 return 1;
448         }
449         // Put player on stack
450         getScriptApiBase(L)->objectrefGetOrCreate(L, sao);
451         return 1;
452 }
453
454 // get_objects_inside_radius(pos, radius)
455 int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
456 {
457         GET_ENV_PTR;
458
459         // Do it
460         v3f pos = checkFloatPos(L, 1);
461         float radius = luaL_checknumber(L, 2) * BS;
462         std::vector<u16> ids;
463         env->getObjectsInsideRadius(ids, pos, radius);
464         ScriptApiBase *script = getScriptApiBase(L);
465         lua_createtable(L, ids.size(), 0);
466         std::vector<u16>::const_iterator iter = ids.begin();
467         for(u32 i = 0; iter != ids.end(); iter++) {
468                 ServerActiveObject *obj = env->getActiveObject(*iter);
469                 // Insert object reference into table
470                 script->objectrefGetOrCreate(L, obj);
471                 lua_rawseti(L, -2, ++i);
472         }
473         return 1;
474 }
475
476 // set_timeofday(val)
477 // val = 0...1
478 int ModApiEnvMod::l_set_timeofday(lua_State *L)
479 {
480         GET_ENV_PTR;
481
482         // Do it
483         float timeofday_f = luaL_checknumber(L, 1);
484         sanity_check(timeofday_f >= 0.0 && timeofday_f <= 1.0);
485         int timeofday_mh = (int)(timeofday_f * 24000.0);
486         // This should be set directly in the environment but currently
487         // such changes aren't immediately sent to the clients, so call
488         // the server instead.
489         //env->setTimeOfDay(timeofday_mh);
490         getServer(L)->setTimeOfDay(timeofday_mh);
491         return 0;
492 }
493
494 // get_timeofday() -> 0...1
495 int ModApiEnvMod::l_get_timeofday(lua_State *L)
496 {
497         GET_ENV_PTR;
498
499         // Do it
500         int timeofday_mh = env->getTimeOfDay();
501         float timeofday_f = (float)timeofday_mh / 24000.0;
502         lua_pushnumber(L, timeofday_f);
503         return 1;
504 }
505
506 // get_gametime()
507 int ModApiEnvMod::l_get_gametime(lua_State *L)
508 {
509         GET_ENV_PTR;
510
511         int game_time = env->getGameTime();
512         lua_pushnumber(L, game_time);
513         return 1;
514 }
515
516
517 // find_node_near(pos, radius, nodenames) -> pos or nil
518 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
519 int ModApiEnvMod::l_find_node_near(lua_State *L)
520 {
521         GET_ENV_PTR;
522
523         INodeDefManager *ndef = getServer(L)->ndef();
524         v3s16 pos = read_v3s16(L, 1);
525         int radius = luaL_checkinteger(L, 2);
526         std::set<content_t> filter;
527         if(lua_istable(L, 3)){
528                 int table = 3;
529                 lua_pushnil(L);
530                 while(lua_next(L, table) != 0){
531                         // key at index -2 and value at index -1
532                         luaL_checktype(L, -1, LUA_TSTRING);
533                         ndef->getIds(lua_tostring(L, -1), filter);
534                         // removes value, keeps key for next iteration
535                         lua_pop(L, 1);
536                 }
537         } else if(lua_isstring(L, 3)){
538                 ndef->getIds(lua_tostring(L, 3), filter);
539         }
540
541         for(int d=1; d<=radius; d++){
542                 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
543                 for(std::vector<v3s16>::iterator i = list.begin();
544                                 i != list.end(); ++i){
545                         v3s16 p = pos + (*i);
546                         content_t c = env->getMap().getNodeNoEx(p).getContent();
547                         if(filter.count(c) != 0){
548                                 push_v3s16(L, p);
549                                 return 1;
550                         }
551                 }
552         }
553         return 0;
554 }
555
556 // find_nodes_in_area(minp, maxp, nodenames) -> list of positions
557 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
558 int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
559 {
560         GET_ENV_PTR;
561
562         INodeDefManager *ndef = getServer(L)->ndef();
563         v3s16 minp = read_v3s16(L, 1);
564         v3s16 maxp = read_v3s16(L, 2);
565         std::set<content_t> filter;
566         if(lua_istable(L, 3)) {
567                 int table = 3;
568                 lua_pushnil(L);
569                 while(lua_next(L, table) != 0) {
570                         // key at index -2 and value at index -1
571                         luaL_checktype(L, -1, LUA_TSTRING);
572                         ndef->getIds(lua_tostring(L, -1), filter);
573                         // removes value, keeps key for next iteration
574                         lua_pop(L, 1);
575                 }
576         } else if(lua_isstring(L, 3)) {
577                 ndef->getIds(lua_tostring(L, 3), filter);
578         }
579
580         std::map<content_t, u16> individual_count;
581
582         lua_newtable(L);
583         u64 i = 0;
584         for (s16 x = minp.X; x <= maxp.X; x++)
585                 for (s16 y = minp.Y; y <= maxp.Y; y++)
586                         for (s16 z = minp.Z; z <= maxp.Z; z++) {
587                                 v3s16 p(x, y, z);
588                                 content_t c = env->getMap().getNodeNoEx(p).getContent();
589                                 if (filter.count(c) != 0) {
590                                         push_v3s16(L, p);
591                                         lua_rawseti(L, -2, ++i);
592                                         individual_count[c]++;
593                                 }
594         }
595         lua_newtable(L);
596         for (std::set<content_t>::iterator it = filter.begin();
597                         it != filter.end(); ++it) {
598                 lua_pushnumber(L, individual_count[*it]);
599                 lua_setfield(L, -2, ndef->get(*it).name.c_str());
600         }
601         return 2;
602 }
603
604 // find_nodes_in_area_under_air(minp, maxp, nodenames) -> list of positions
605 // nodenames: e.g. {"ignore", "group:tree"} or "default:dirt"
606 int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
607 {
608         /* Note: A similar but generalized (and therefore slower) version of this
609          * function could be created -- e.g. find_nodes_in_area_under -- which
610          * would accept a node name (or ID?) or list of names that the "above node"
611          * should be.
612          * TODO
613          */
614
615         GET_ENV_PTR;
616
617         INodeDefManager *ndef = getServer(L)->ndef();
618         v3s16 minp = read_v3s16(L, 1);
619         v3s16 maxp = read_v3s16(L, 2);
620         std::set<content_t> filter;
621
622         if (lua_istable(L, 3)) {
623                 int table = 3;
624                 lua_pushnil(L);
625                 while(lua_next(L, table) != 0) {
626                         // key at index -2 and value at index -1
627                         luaL_checktype(L, -1, LUA_TSTRING);
628                         ndef->getIds(lua_tostring(L, -1), filter);
629                         // removes value, keeps key for next iteration
630                         lua_pop(L, 1);
631                 }
632         } else if (lua_isstring(L, 3)) {
633                 ndef->getIds(lua_tostring(L, 3), filter);
634         }
635
636         lua_newtable(L);
637         u64 i = 0;
638         for (s16 x = minp.X; x <= maxp.X; x++)
639         for (s16 z = minp.Z; z <= maxp.Z; z++) {
640                 s16 y = minp.Y;
641                 v3s16 p(x, y, z);
642                 content_t c = env->getMap().getNodeNoEx(p).getContent();
643                 for (; y <= maxp.Y; y++) {
644                         v3s16 psurf(x, y + 1, z);
645                         content_t csurf = env->getMap().getNodeNoEx(psurf).getContent();
646                         if(c != CONTENT_AIR && csurf == CONTENT_AIR &&
647                                         filter.count(c) != 0) {
648                                 push_v3s16(L, v3s16(x, y, z));
649                                 lua_rawseti(L, -2, ++i);
650                         }
651                         c = csurf;
652                 }
653         }
654         return 1;
655 }
656
657 // get_perlin(seeddiff, octaves, persistence, scale)
658 // returns world-specific PerlinNoise
659 int ModApiEnvMod::l_get_perlin(lua_State *L)
660 {
661         GET_ENV_PTR;
662
663         NoiseParams params;
664
665         if (lua_istable(L, 1)) {
666                 read_noiseparams(L, 1, &params);
667         } else {
668                 params.seed    = luaL_checkint(L, 1);
669                 params.octaves = luaL_checkint(L, 2);
670                 params.persist = luaL_checknumber(L, 3);
671                 params.spread  = v3f(1, 1, 1) * luaL_checknumber(L, 4);
672         }
673
674         params.seed += (int)env->getServerMap().getSeed();
675
676         LuaPerlinNoise *n = new LuaPerlinNoise(&params);
677         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
678         luaL_getmetatable(L, "PerlinNoise");
679         lua_setmetatable(L, -2);
680         return 1;
681 }
682
683 // get_perlin_map(noiseparams, size)
684 // returns world-specific PerlinNoiseMap
685 int ModApiEnvMod::l_get_perlin_map(lua_State *L)
686 {
687         GET_ENV_PTR;
688
689         NoiseParams np;
690         if (!read_noiseparams(L, 1, &np))
691                 return 0;
692         v3s16 size = read_v3s16(L, 2);
693
694         int seed = (int)(env->getServerMap().getSeed());
695         LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(&np, seed, size);
696         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
697         luaL_getmetatable(L, "PerlinNoiseMap");
698         lua_setmetatable(L, -2);
699         return 1;
700 }
701
702 // get_voxel_manip()
703 // returns voxel manipulator
704 int ModApiEnvMod::l_get_voxel_manip(lua_State *L)
705 {
706         GET_ENV_PTR;
707
708         Map *map = &(env->getMap());
709         LuaVoxelManip *o = (lua_istable(L, 1) && lua_istable(L, 2)) ?
710                 new LuaVoxelManip(map, read_v3s16(L, 1), read_v3s16(L, 2)) :
711                 new LuaVoxelManip(map);
712
713         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
714         luaL_getmetatable(L, "VoxelManip");
715         lua_setmetatable(L, -2);
716         return 1;
717 }
718
719 // clear_objects()
720 // clear all objects in the environment
721 int ModApiEnvMod::l_clear_objects(lua_State *L)
722 {
723         GET_ENV_PTR;
724
725         env->clearAllObjects();
726         return 0;
727 }
728
729 // line_of_sight(pos1, pos2, stepsize) -> true/false, pos
730 int ModApiEnvMod::l_line_of_sight(lua_State *L)
731 {
732         float stepsize = 1.0;
733
734         GET_ENV_PTR;
735
736         // read position 1 from lua
737         v3f pos1 = checkFloatPos(L, 1);
738         // read position 2 from lua
739         v3f pos2 = checkFloatPos(L, 2);
740         //read step size from lua
741         if (lua_isnumber(L, 3)) {
742                 stepsize = lua_tonumber(L, 3);
743         }
744
745         v3s16 p;
746         bool success = env->line_of_sight(pos1, pos2, stepsize, &p);
747         lua_pushboolean(L, success);
748         if (!success) {
749                 push_v3s16(L, p);
750                 return 2;
751         }
752         return 1;
753 }
754
755
756 // emerge_area(p1, p2)
757 // emerge mapblocks in area p1..p2
758 int ModApiEnvMod::l_emerge_area(lua_State *L)
759 {
760         GET_ENV_PTR;
761
762         EmergeManager *emerge = getServer(L)->getEmergeManager();
763
764         v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
765         v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
766         sortBoxVerticies(bpmin, bpmax);
767
768         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
769         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
770         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
771                 v3s16 chunkpos(x, y, z);
772                 emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, chunkpos, false, true);
773         }
774
775         return 0;
776 }
777
778 // delete_area(p1, p2)
779 // delete mapblocks in area p1..p2
780 int ModApiEnvMod::l_delete_area(lua_State *L)
781 {
782         GET_ENV_PTR;
783
784         v3s16 bpmin = getNodeBlockPos(read_v3s16(L, 1));
785         v3s16 bpmax = getNodeBlockPos(read_v3s16(L, 2));
786         sortBoxVerticies(bpmin, bpmax);
787
788         ServerMap &map = env->getServerMap();
789
790         MapEditEvent event;
791         event.type = MEET_OTHER;
792
793         bool success = true;
794         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
795         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
796         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
797                 v3s16 bp(x, y, z);
798                 if (map.deleteBlock(bp)) {
799                         env->setStaticForActiveObjectsInBlock(bp, false);
800                         event.modified_blocks.insert(bp);
801                 } else {
802                         success = false;
803                 }
804         }
805
806         map.dispatchEvent(&event);
807         lua_pushboolean(L, success);
808         return 1;
809 }
810
811 // find_path(pos1, pos2, searchdistance,
812 //     max_jump, max_drop, algorithm) -> table containing path
813 int ModApiEnvMod::l_find_path(lua_State *L)
814 {
815         GET_ENV_PTR;
816
817         v3s16 pos1                  = read_v3s16(L, 1);
818         v3s16 pos2                  = read_v3s16(L, 2);
819         unsigned int searchdistance = luaL_checkint(L, 3);
820         unsigned int max_jump       = luaL_checkint(L, 4);
821         unsigned int max_drop       = luaL_checkint(L, 5);
822         algorithm algo              = A_PLAIN_NP;
823         if (!lua_isnil(L, 6)) {
824                 std::string algorithm = luaL_checkstring(L,6);
825
826                 if (algorithm == "A*")
827                         algo = A_PLAIN;
828
829                 if (algorithm == "Dijkstra")
830                         algo = DIJKSTRA;
831         }
832
833         std::vector<v3s16> path =
834                         get_Path(env,pos1,pos2,searchdistance,max_jump,max_drop,algo);
835
836         if (path.size() > 0)
837         {
838                 lua_newtable(L);
839                 int top = lua_gettop(L);
840                 unsigned int index = 1;
841                 for (std::vector<v3s16>::iterator i = path.begin(); i != path.end();i++)
842                 {
843                         lua_pushnumber(L,index);
844                         push_v3s16(L, *i);
845                         lua_settable(L, top);
846                         index++;
847                 }
848                 return 1;
849         }
850
851         return 0;
852 }
853
854 // spawn_tree(pos, treedef)
855 int ModApiEnvMod::l_spawn_tree(lua_State *L)
856 {
857         GET_ENV_PTR;
858
859         v3s16 p0 = read_v3s16(L, 1);
860
861         treegen::TreeDef tree_def;
862         std::string trunk,leaves,fruit;
863         INodeDefManager *ndef = env->getGameDef()->ndef();
864
865         if(lua_istable(L, 2))
866         {
867                 getstringfield(L, 2, "axiom", tree_def.initial_axiom);
868                 getstringfield(L, 2, "rules_a", tree_def.rules_a);
869                 getstringfield(L, 2, "rules_b", tree_def.rules_b);
870                 getstringfield(L, 2, "rules_c", tree_def.rules_c);
871                 getstringfield(L, 2, "rules_d", tree_def.rules_d);
872                 getstringfield(L, 2, "trunk", trunk);
873                 tree_def.trunknode=ndef->getId(trunk);
874                 getstringfield(L, 2, "leaves", leaves);
875                 tree_def.leavesnode=ndef->getId(leaves);
876                 tree_def.leaves2_chance=0;
877                 getstringfield(L, 2, "leaves2", leaves);
878                 if (leaves !="")
879                 {
880                         tree_def.leaves2node=ndef->getId(leaves);
881                         getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance);
882                 }
883                 getintfield(L, 2, "angle", tree_def.angle);
884                 getintfield(L, 2, "iterations", tree_def.iterations);
885                 if (!getintfield(L, 2, "random_level", tree_def.iterations_random_level))
886                         tree_def.iterations_random_level = 0;
887                 getstringfield(L, 2, "trunk_type", tree_def.trunk_type);
888                 getboolfield(L, 2, "thin_branches", tree_def.thin_branches);
889                 tree_def.fruit_chance=0;
890                 getstringfield(L, 2, "fruit", fruit);
891                 if (fruit != "")
892                 {
893                         tree_def.fruitnode=ndef->getId(fruit);
894                         getintfield(L, 2, "fruit_chance",tree_def.fruit_chance);
895                 }
896                 tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed);
897         }
898         else
899                 return 0;
900
901         treegen::error e;
902         if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) {
903                 if (e == treegen::UNBALANCED_BRACKETS) {
904                         luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket");
905                 } else {
906                         luaL_error(L, "spawn_tree(): unknown error");
907                 }
908         }
909
910         return 1;
911 }
912
913 // transforming_liquid_add(pos)
914 int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
915 {
916         GET_ENV_PTR;
917
918         v3s16 p0 = read_v3s16(L, 1);
919         env->getMap().transforming_liquid_add(p0);
920         return 1;
921 }
922
923 // forceload_block(blockpos)
924 // blockpos = {x=num, y=num, z=num}
925 int ModApiEnvMod::l_forceload_block(lua_State *L)
926 {
927         GET_ENV_PTR;
928
929         v3s16 blockpos = read_v3s16(L, 1);
930         env->getForceloadedBlocks()->insert(blockpos);
931         return 0;
932 }
933
934 // forceload_free_block(blockpos)
935 // blockpos = {x=num, y=num, z=num}
936 int ModApiEnvMod::l_forceload_free_block(lua_State *L)
937 {
938         GET_ENV_PTR;
939
940         v3s16 blockpos = read_v3s16(L, 1);
941         env->getForceloadedBlocks()->erase(blockpos);
942         return 0;
943 }
944
945 // get_us_time()
946 int ModApiEnvMod::l_get_us_time(lua_State *L)
947 {
948         lua_pushnumber(L, porting::getTimeUs());
949         return 1;
950 }
951
952 void ModApiEnvMod::Initialize(lua_State *L, int top)
953 {
954         API_FCT(set_node);
955         API_FCT(add_node);
956         API_FCT(swap_node);
957         API_FCT(add_item);
958         API_FCT(remove_node);
959         API_FCT(get_node);
960         API_FCT(get_node_or_nil);
961         API_FCT(get_node_light);
962         API_FCT(place_node);
963         API_FCT(dig_node);
964         API_FCT(punch_node);
965         API_FCT(get_node_max_level);
966         API_FCT(get_node_level);
967         API_FCT(set_node_level);
968         API_FCT(add_node_level);
969         API_FCT(add_entity);
970         API_FCT(find_nodes_with_meta);
971         API_FCT(get_meta);
972         API_FCT(get_node_timer);
973         API_FCT(get_player_by_name);
974         API_FCT(get_objects_inside_radius);
975         API_FCT(set_timeofday);
976         API_FCT(get_timeofday);
977         API_FCT(get_gametime);
978         API_FCT(find_node_near);
979         API_FCT(find_nodes_in_area);
980         API_FCT(find_nodes_in_area_under_air);
981         API_FCT(emerge_area);
982         API_FCT(delete_area);
983         API_FCT(get_perlin);
984         API_FCT(get_perlin_map);
985         API_FCT(get_voxel_manip);
986         API_FCT(clear_objects);
987         API_FCT(spawn_tree);
988         API_FCT(find_path);
989         API_FCT(line_of_sight);
990         API_FCT(transforming_liquid_add);
991         API_FCT(forceload_block);
992         API_FCT(forceload_free_block);
993         API_FCT(get_us_time);
994 }