Re-add jungles, apple trees
[oweals/minetest.git] / src / scriptapi_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 "scriptapi.h"
21 #include "scriptapi_env.h"
22 #include "nodedef.h"
23 #include "gamedef.h"
24 #include "map.h"
25 #include "daynightratio.h"
26 #include "content_sao.h"
27 #include "script.h"
28 #include "treegen.h"
29 #include "util/pointedthing.h"
30 #include "scriptapi_types.h"
31 #include "scriptapi_noise.h"
32 #include "scriptapi_nodemeta.h"
33 #include "scriptapi_nodetimer.h"
34 #include "scriptapi_object.h"
35 #include "scriptapi_common.h"
36 #include "scriptapi_item.h"
37 #include "scriptapi_node.h"
38
39
40 //TODO
41 extern void scriptapi_run_callbacks(lua_State *L, int nargs,
42                 RunCallbacksMode mode);
43
44
45 class LuaABM : public ActiveBlockModifier
46 {
47 private:
48         lua_State *m_lua;
49         int m_id;
50
51         std::set<std::string> m_trigger_contents;
52         std::set<std::string> m_required_neighbors;
53         float m_trigger_interval;
54         u32 m_trigger_chance;
55 public:
56         LuaABM(lua_State *L, int id,
57                         const std::set<std::string> &trigger_contents,
58                         const std::set<std::string> &required_neighbors,
59                         float trigger_interval, u32 trigger_chance):
60                 m_lua(L),
61                 m_id(id),
62                 m_trigger_contents(trigger_contents),
63                 m_required_neighbors(required_neighbors),
64                 m_trigger_interval(trigger_interval),
65                 m_trigger_chance(trigger_chance)
66         {
67         }
68         virtual std::set<std::string> getTriggerContents()
69         {
70                 return m_trigger_contents;
71         }
72         virtual std::set<std::string> getRequiredNeighbors()
73         {
74                 return m_required_neighbors;
75         }
76         virtual float getTriggerInterval()
77         {
78                 return m_trigger_interval;
79         }
80         virtual u32 getTriggerChance()
81         {
82                 return m_trigger_chance;
83         }
84         virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
85                         u32 active_object_count, u32 active_object_count_wider)
86         {
87                 lua_State *L = m_lua;
88
89                 realitycheck(L);
90                 assert(lua_checkstack(L, 20));
91                 StackUnroller stack_unroller(L);
92
93                 // Get minetest.registered_abms
94                 lua_getglobal(L, "minetest");
95                 lua_getfield(L, -1, "registered_abms");
96                 luaL_checktype(L, -1, LUA_TTABLE);
97                 int registered_abms = lua_gettop(L);
98
99                 // Get minetest.registered_abms[m_id]
100                 lua_pushnumber(L, m_id);
101                 lua_gettable(L, registered_abms);
102                 if(lua_isnil(L, -1))
103                         assert(0);
104
105                 // Call action
106                 luaL_checktype(L, -1, LUA_TTABLE);
107                 lua_getfield(L, -1, "action");
108                 luaL_checktype(L, -1, LUA_TFUNCTION);
109                 push_v3s16(L, p);
110                 pushnode(L, n, env->getGameDef()->ndef());
111                 lua_pushnumber(L, active_object_count);
112                 lua_pushnumber(L, active_object_count_wider);
113                 if(lua_pcall(L, 4, 0, 0))
114                         script_error(L, "error: %s", lua_tostring(L, -1));
115         }
116 };
117
118 /*
119         EnvRef
120 */
121
122 int EnvRef::gc_object(lua_State *L) {
123         EnvRef *o = *(EnvRef **)(lua_touserdata(L, 1));
124         delete o;
125         return 0;
126 }
127
128 EnvRef* EnvRef::checkobject(lua_State *L, int narg)
129 {
130         luaL_checktype(L, narg, LUA_TUSERDATA);
131         void *ud = luaL_checkudata(L, narg, className);
132         if(!ud) luaL_typerror(L, narg, className);
133         return *(EnvRef**)ud;  // unbox pointer
134 }
135
136 // Exported functions
137
138 // EnvRef:set_node(pos, node)
139 // pos = {x=num, y=num, z=num}
140 int EnvRef::l_set_node(lua_State *L)
141 {
142         EnvRef *o = checkobject(L, 1);
143         ServerEnvironment *env = o->m_env;
144         if(env == NULL) return 0;
145         INodeDefManager *ndef = env->getGameDef()->ndef();
146         // parameters
147         v3s16 pos = read_v3s16(L, 2);
148         MapNode n = readnode(L, 3, ndef);
149         // Do it
150         bool succeeded = env->setNode(pos, n);
151         lua_pushboolean(L, succeeded);
152         return 1;
153 }
154
155 int EnvRef::l_add_node(lua_State *L)
156 {
157         return l_set_node(L);
158 }
159
160 // EnvRef:remove_node(pos)
161 // pos = {x=num, y=num, z=num}
162 int EnvRef::l_remove_node(lua_State *L)
163 {
164         EnvRef *o = checkobject(L, 1);
165         ServerEnvironment *env = o->m_env;
166         if(env == NULL) return 0;
167
168         // parameters
169         v3s16 pos = read_v3s16(L, 2);
170         // Do it
171         bool succeeded = env->removeNode(pos);
172         lua_pushboolean(L, succeeded);
173         return 1;
174 }
175
176 // EnvRef:get_node(pos)
177 // pos = {x=num, y=num, z=num}
178 int EnvRef::l_get_node(lua_State *L)
179 {
180         EnvRef *o = checkobject(L, 1);
181         ServerEnvironment *env = o->m_env;
182         if(env == NULL) return 0;
183         // pos
184         v3s16 pos = read_v3s16(L, 2);
185         // Do it
186         MapNode n = env->getMap().getNodeNoEx(pos);
187         // Return node
188         pushnode(L, n, env->getGameDef()->ndef());
189         return 1;
190 }
191
192 // EnvRef:get_node_or_nil(pos)
193 // pos = {x=num, y=num, z=num}
194 int EnvRef::l_get_node_or_nil(lua_State *L)
195 {
196         EnvRef *o = checkobject(L, 1);
197         ServerEnvironment *env = o->m_env;
198         if(env == NULL) return 0;
199         // pos
200         v3s16 pos = read_v3s16(L, 2);
201         // Do it
202         try{
203                 MapNode n = env->getMap().getNode(pos);
204                 // Return node
205                 pushnode(L, n, env->getGameDef()->ndef());
206                 return 1;
207         } catch(InvalidPositionException &e)
208         {
209                 lua_pushnil(L);
210                 return 1;
211         }
212 }
213
214 // EnvRef:get_node_light(pos, timeofday)
215 // pos = {x=num, y=num, z=num}
216 // timeofday: nil = current time, 0 = night, 0.5 = day
217 int EnvRef::l_get_node_light(lua_State *L)
218 {
219         EnvRef *o = checkobject(L, 1);
220         ServerEnvironment *env = o->m_env;
221         if(env == NULL) return 0;
222         // Do it
223         v3s16 pos = read_v3s16(L, 2);
224         u32 time_of_day = env->getTimeOfDay();
225         if(lua_isnumber(L, 3))
226                 time_of_day = 24000.0 * lua_tonumber(L, 3);
227         time_of_day %= 24000;
228         u32 dnr = time_to_daynight_ratio(time_of_day, true);
229         MapNode n = env->getMap().getNodeNoEx(pos);
230         try{
231                 MapNode n = env->getMap().getNode(pos);
232                 INodeDefManager *ndef = env->getGameDef()->ndef();
233                 lua_pushinteger(L, n.getLightBlend(dnr, ndef));
234                 return 1;
235         } catch(InvalidPositionException &e)
236         {
237                 lua_pushnil(L);
238                 return 1;
239         }
240 }
241
242 // EnvRef:place_node(pos, node)
243 // pos = {x=num, y=num, z=num}
244 int EnvRef::l_place_node(lua_State *L)
245 {
246         EnvRef *o = checkobject(L, 1);
247         ServerEnvironment *env = o->m_env;
248         if(env == NULL) return 0;
249         v3s16 pos = read_v3s16(L, 2);
250         MapNode n = readnode(L, 3, env->getGameDef()->ndef());
251
252         // Don't attempt to load non-loaded area as of now
253         MapNode n_old = env->getMap().getNodeNoEx(pos);
254         if(n_old.getContent() == CONTENT_IGNORE){
255                 lua_pushboolean(L, false);
256                 return 1;
257         }
258         // Create item to place
259         INodeDefManager *ndef = get_server(L)->ndef();
260         IItemDefManager *idef = get_server(L)->idef();
261         ItemStack item(ndef->get(n).name, 1, 0, "", idef);
262         // Make pointed position
263         PointedThing pointed;
264         pointed.type = POINTEDTHING_NODE;
265         pointed.node_abovesurface = pos;
266         pointed.node_undersurface = pos + v3s16(0,-1,0);
267         // Place it with a NULL placer (appears in Lua as a non-functional
268         // ObjectRef)
269         bool success = scriptapi_item_on_place(L, item, NULL, pointed);
270         lua_pushboolean(L, success);
271         return 1;
272 }
273
274 // EnvRef:dig_node(pos)
275 // pos = {x=num, y=num, z=num}
276 int EnvRef::l_dig_node(lua_State *L)
277 {
278         EnvRef *o = checkobject(L, 1);
279         ServerEnvironment *env = o->m_env;
280         if(env == NULL) return 0;
281         v3s16 pos = read_v3s16(L, 2);
282
283         // Don't attempt to load non-loaded area as of now
284         MapNode n = env->getMap().getNodeNoEx(pos);
285         if(n.getContent() == CONTENT_IGNORE){
286                 lua_pushboolean(L, false);
287                 return 1;
288         }
289         // Dig it out with a NULL digger (appears in Lua as a
290         // non-functional ObjectRef)
291         bool success = scriptapi_node_on_dig(L, pos, n, NULL);
292         lua_pushboolean(L, success);
293         return 1;
294 }
295
296 // EnvRef:punch_node(pos)
297 // pos = {x=num, y=num, z=num}
298 int EnvRef::l_punch_node(lua_State *L)
299 {
300         EnvRef *o = checkobject(L, 1);
301         ServerEnvironment *env = o->m_env;
302         if(env == NULL) return 0;
303         v3s16 pos = read_v3s16(L, 2);
304
305         // Don't attempt to load non-loaded area as of now
306         MapNode n = env->getMap().getNodeNoEx(pos);
307         if(n.getContent() == CONTENT_IGNORE){
308                 lua_pushboolean(L, false);
309                 return 1;
310         }
311         // Punch it with a NULL puncher (appears in Lua as a non-functional
312         // ObjectRef)
313         bool success = scriptapi_node_on_punch(L, pos, n, NULL);
314         lua_pushboolean(L, success);
315         return 1;
316 }
317
318 // EnvRef:get_meta(pos)
319 int EnvRef::l_get_meta(lua_State *L)
320 {
321         //infostream<<"EnvRef::l_get_meta()"<<std::endl;
322         EnvRef *o = checkobject(L, 1);
323         ServerEnvironment *env = o->m_env;
324         if(env == NULL) return 0;
325         // Do it
326         v3s16 p = read_v3s16(L, 2);
327         NodeMetaRef::create(L, p, env);
328         return 1;
329 }
330
331 // EnvRef:get_node_timer(pos)
332 int EnvRef::l_get_node_timer(lua_State *L)
333 {
334         EnvRef *o = checkobject(L, 1);
335         ServerEnvironment *env = o->m_env;
336         if(env == NULL) return 0;
337         // Do it
338         v3s16 p = read_v3s16(L, 2);
339         NodeTimerRef::create(L, p, env);
340         return 1;
341 }
342
343 // EnvRef:add_entity(pos, entityname) -> ObjectRef or nil
344 // pos = {x=num, y=num, z=num}
345 int EnvRef::l_add_entity(lua_State *L)
346 {
347         //infostream<<"EnvRef::l_add_entity()"<<std::endl;
348         EnvRef *o = checkobject(L, 1);
349         ServerEnvironment *env = o->m_env;
350         if(env == NULL) return 0;
351         // pos
352         v3f pos = checkFloatPos(L, 2);
353         // content
354         const char *name = luaL_checkstring(L, 3);
355         // Do it
356         ServerActiveObject *obj = new LuaEntitySAO(env, pos, name, "");
357         int objectid = env->addActiveObject(obj);
358         // If failed to add, return nothing (reads as nil)
359         if(objectid == 0)
360                 return 0;
361         // Return ObjectRef
362         objectref_get_or_create(L, obj);
363         return 1;
364 }
365
366 // EnvRef:add_item(pos, itemstack or itemstring or table) -> ObjectRef or nil
367 // pos = {x=num, y=num, z=num}
368 int EnvRef::l_add_item(lua_State *L)
369 {
370         //infostream<<"EnvRef::l_add_item()"<<std::endl;
371         EnvRef *o = checkobject(L, 1);
372         ServerEnvironment *env = o->m_env;
373         if(env == NULL) return 0;
374         // pos
375         v3f pos = checkFloatPos(L, 2);
376         // item
377         ItemStack item = read_item(L, 3);
378         if(item.empty() || !item.isKnown(get_server(L)->idef()))
379                 return 0;
380         // Use minetest.spawn_item to spawn a __builtin:item
381         lua_getglobal(L, "minetest");
382         lua_getfield(L, -1, "spawn_item");
383         if(lua_isnil(L, -1))
384                 return 0;
385         lua_pushvalue(L, 2);
386         lua_pushstring(L, item.getItemString().c_str());
387         if(lua_pcall(L, 2, 1, 0))
388                 script_error(L, "error: %s", lua_tostring(L, -1));
389         return 1;
390         /*lua_pushvalue(L, 1);
391         lua_pushstring(L, "__builtin:item");
392         lua_pushstring(L, item.getItemString().c_str());
393         return l_add_entity(L);*/
394         /*// Do it
395         ServerActiveObject *obj = createItemSAO(env, pos, item.getItemString());
396         int objectid = env->addActiveObject(obj);
397         // If failed to add, return nothing (reads as nil)
398         if(objectid == 0)
399                 return 0;
400         // Return ObjectRef
401         objectref_get_or_create(L, obj);
402         return 1;*/
403 }
404
405 // EnvRef:add_rat(pos)
406 // pos = {x=num, y=num, z=num}
407 int EnvRef::l_add_rat(lua_State *L)
408 {
409         infostream<<"EnvRef::l_add_rat(): C++ mobs have been removed."
410                         <<" Doing nothing."<<std::endl;
411         return 0;
412 }
413
414 // EnvRef:add_firefly(pos)
415 // pos = {x=num, y=num, z=num}
416 int EnvRef::l_add_firefly(lua_State *L)
417 {
418         infostream<<"EnvRef::l_add_firefly(): C++ mobs have been removed."
419                         <<" Doing nothing."<<std::endl;
420         return 0;
421 }
422
423 // EnvRef:get_player_by_name(name)
424 int EnvRef::l_get_player_by_name(lua_State *L)
425 {
426         EnvRef *o = checkobject(L, 1);
427         ServerEnvironment *env = o->m_env;
428         if(env == NULL) return 0;
429         // Do it
430         const char *name = luaL_checkstring(L, 2);
431         Player *player = env->getPlayer(name);
432         if(player == NULL){
433                 lua_pushnil(L);
434                 return 1;
435         }
436         PlayerSAO *sao = player->getPlayerSAO();
437         if(sao == NULL){
438                 lua_pushnil(L);
439                 return 1;
440         }
441         // Put player on stack
442         objectref_get_or_create(L, sao);
443         return 1;
444 }
445
446 // EnvRef:get_objects_inside_radius(pos, radius)
447 int EnvRef::l_get_objects_inside_radius(lua_State *L)
448 {
449         // Get the table insert function
450         lua_getglobal(L, "table");
451         lua_getfield(L, -1, "insert");
452         int table_insert = lua_gettop(L);
453         // Get environemnt
454         EnvRef *o = checkobject(L, 1);
455         ServerEnvironment *env = o->m_env;
456         if(env == NULL) return 0;
457         // Do it
458         v3f pos = checkFloatPos(L, 2);
459         float radius = luaL_checknumber(L, 3) * BS;
460         std::set<u16> ids = env->getObjectsInsideRadius(pos, radius);
461         lua_newtable(L);
462         int table = lua_gettop(L);
463         for(std::set<u16>::const_iterator
464                         i = ids.begin(); i != ids.end(); i++){
465                 ServerActiveObject *obj = env->getActiveObject(*i);
466                 // Insert object reference into table
467                 lua_pushvalue(L, table_insert);
468                 lua_pushvalue(L, table);
469                 objectref_get_or_create(L, obj);
470                 if(lua_pcall(L, 2, 0, 0))
471                         script_error(L, "error: %s", lua_tostring(L, -1));
472         }
473         return 1;
474 }
475
476 // EnvRef:set_timeofday(val)
477 // val = 0...1
478 int EnvRef::l_set_timeofday(lua_State *L)
479 {
480         EnvRef *o = checkobject(L, 1);
481         ServerEnvironment *env = o->m_env;
482         if(env == NULL) return 0;
483         // Do it
484         float timeofday_f = luaL_checknumber(L, 2);
485         assert(timeofday_f >= 0.0 && timeofday_f <= 1.0);
486         int timeofday_mh = (int)(timeofday_f * 24000.0);
487         // This should be set directly in the environment but currently
488         // such changes aren't immediately sent to the clients, so call
489         // the server instead.
490         //env->setTimeOfDay(timeofday_mh);
491         get_server(L)->setTimeOfDay(timeofday_mh);
492         return 0;
493 }
494
495 // EnvRef:get_timeofday() -> 0...1
496 int EnvRef::l_get_timeofday(lua_State *L)
497 {
498         EnvRef *o = checkobject(L, 1);
499         ServerEnvironment *env = o->m_env;
500         if(env == NULL) return 0;
501         // Do it
502         int timeofday_mh = env->getTimeOfDay();
503         float timeofday_f = (float)timeofday_mh / 24000.0;
504         lua_pushnumber(L, timeofday_f);
505         return 1;
506 }
507
508
509 // EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil
510 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
511 int EnvRef::l_find_node_near(lua_State *L)
512 {
513         EnvRef *o = checkobject(L, 1);
514         ServerEnvironment *env = o->m_env;
515         if(env == NULL) return 0;
516         INodeDefManager *ndef = get_server(L)->ndef();
517         v3s16 pos = read_v3s16(L, 2);
518         int radius = luaL_checkinteger(L, 3);
519         std::set<content_t> filter;
520         if(lua_istable(L, 4)){
521                 int table = 4;
522                 lua_pushnil(L);
523                 while(lua_next(L, table) != 0){
524                         // key at index -2 and value at index -1
525                         luaL_checktype(L, -1, LUA_TSTRING);
526                         ndef->getIds(lua_tostring(L, -1), filter);
527                         // removes value, keeps key for next iteration
528                         lua_pop(L, 1);
529                 }
530         } else if(lua_isstring(L, 4)){
531                 ndef->getIds(lua_tostring(L, 4), filter);
532         }
533
534         for(int d=1; d<=radius; d++){
535                 std::list<v3s16> list;
536                 getFacePositions(list, d);
537                 for(std::list<v3s16>::iterator i = list.begin();
538                                 i != list.end(); ++i){
539                         v3s16 p = pos + (*i);
540                         content_t c = env->getMap().getNodeNoEx(p).getContent();
541                         if(filter.count(c) != 0){
542                                 push_v3s16(L, p);
543                                 return 1;
544                         }
545                 }
546         }
547         return 0;
548 }
549
550 // EnvRef:find_nodes_in_area(minp, maxp, nodenames) -> list of positions
551 // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
552 int EnvRef::l_find_nodes_in_area(lua_State *L)
553 {
554         EnvRef *o = checkobject(L, 1);
555         ServerEnvironment *env = o->m_env;
556         if(env == NULL) return 0;
557         INodeDefManager *ndef = get_server(L)->ndef();
558         v3s16 minp = read_v3s16(L, 2);
559         v3s16 maxp = read_v3s16(L, 3);
560         std::set<content_t> filter;
561         if(lua_istable(L, 4)){
562                 int table = 4;
563                 lua_pushnil(L);
564                 while(lua_next(L, table) != 0){
565                         // key at index -2 and value at index -1
566                         luaL_checktype(L, -1, LUA_TSTRING);
567                         ndef->getIds(lua_tostring(L, -1), filter);
568                         // removes value, keeps key for next iteration
569                         lua_pop(L, 1);
570                 }
571         } else if(lua_isstring(L, 4)){
572                 ndef->getIds(lua_tostring(L, 4), filter);
573         }
574
575         // Get the table insert function
576         lua_getglobal(L, "table");
577         lua_getfield(L, -1, "insert");
578         int table_insert = lua_gettop(L);
579
580         lua_newtable(L);
581         int table = lua_gettop(L);
582         for(s16 x=minp.X; x<=maxp.X; x++)
583         for(s16 y=minp.Y; y<=maxp.Y; y++)
584         for(s16 z=minp.Z; z<=maxp.Z; z++)
585         {
586                 v3s16 p(x,y,z);
587                 content_t c = env->getMap().getNodeNoEx(p).getContent();
588                 if(filter.count(c) != 0){
589                         lua_pushvalue(L, table_insert);
590                         lua_pushvalue(L, table);
591                         push_v3s16(L, p);
592                         if(lua_pcall(L, 2, 0, 0))
593                                 script_error(L, "error: %s", lua_tostring(L, -1));
594                 }
595         }
596         return 1;
597 }
598
599 //      EnvRef:get_perlin(seeddiff, octaves, persistence, scale)
600 //  returns world-specific PerlinNoise
601 int EnvRef::l_get_perlin(lua_State *L)
602 {
603         EnvRef *o = checkobject(L, 1);
604         ServerEnvironment *env = o->m_env;
605         if(env == NULL) return 0;
606
607         int seeddiff = luaL_checkint(L, 2);
608         int octaves = luaL_checkint(L, 3);
609         float persistence = luaL_checknumber(L, 4);
610         float scale = luaL_checknumber(L, 5);
611
612         LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
613         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
614         luaL_getmetatable(L, "PerlinNoise");
615         lua_setmetatable(L, -2);
616         return 1;
617 }
618
619 //  EnvRef:get_perlin_map(noiseparams, size)
620 //  returns world-specific PerlinNoiseMap
621 int EnvRef::l_get_perlin_map(lua_State *L)
622 {
623         EnvRef *o = checkobject(L, 1);
624         ServerEnvironment *env = o->m_env;
625         if (env == NULL)
626                 return 0;
627
628         NoiseParams *np = read_noiseparams(L, 2);
629         if (!np)
630                 return 0;
631         v3s16 size = read_v3s16(L, 3);
632
633         int seed = (int)(env->getServerMap().getSeed());
634         LuaPerlinNoiseMap *n = new LuaPerlinNoiseMap(np, seed, size);
635         *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
636         luaL_getmetatable(L, "PerlinNoiseMap");
637         lua_setmetatable(L, -2);
638         return 1;
639 }
640
641 // EnvRef:clear_objects()
642 // clear all objects in the environment
643 int EnvRef::l_clear_objects(lua_State *L)
644 {
645         EnvRef *o = checkobject(L, 1);
646         o->m_env->clearAllObjects();
647         return 0;
648 }
649
650 int EnvRef::l_spawn_tree(lua_State *L)
651 {
652         EnvRef *o = checkobject(L, 1);
653         ServerEnvironment *env = o->m_env;
654         if(env == NULL) return 0;
655         v3s16 p0 = read_v3s16(L, 2);
656
657         treegen::TreeDef tree_def;
658         std::string trunk,leaves,fruit;
659         INodeDefManager *ndef = env->getGameDef()->ndef();
660
661         if(lua_istable(L, 3))
662         {
663                 getstringfield(L, 3, "axiom", tree_def.initial_axiom);
664                 getstringfield(L, 3, "rules_a", tree_def.rules_a);
665                 getstringfield(L, 3, "rules_b", tree_def.rules_b);
666                 getstringfield(L, 3, "rules_c", tree_def.rules_c);
667                 getstringfield(L, 3, "rules_d", tree_def.rules_d);
668                 getstringfield(L, 3, "trunk", trunk);
669                 tree_def.trunknode=ndef->getId(trunk);
670                 getstringfield(L, 3, "leaves", leaves);
671                 tree_def.leavesnode=ndef->getId(leaves);
672                 tree_def.leaves2_chance=0;
673                 getstringfield(L, 3, "leaves2", leaves);
674                 if (leaves !="")
675                 {
676                         tree_def.leaves2node=ndef->getId(leaves);
677                         getintfield(L, 3, "leaves2_chance", tree_def.leaves2_chance);
678                 }
679                 getintfield(L, 3, "angle", tree_def.angle);
680                 getintfield(L, 3, "iterations", tree_def.iterations);
681                 getintfield(L, 3, "random_level", tree_def.iterations_random_level);
682                 getstringfield(L, 3, "trunk_type", tree_def.trunk_type);
683                 getboolfield(L, 3, "thin_branches", tree_def.thin_branches);
684                 tree_def.fruit_chance=0;
685                 getstringfield(L, 3, "fruit", fruit);
686                 if (fruit != "")
687                 {
688                         tree_def.fruitnode=ndef->getId(fruit);
689                         getintfield(L, 3, "fruit_chance",tree_def.fruit_chance);
690                 }
691                 getintfield(L, 3, "seed", tree_def.seed);
692         }
693         else
694                 return 0;
695         treegen::spawn_ltree (env, p0, ndef, tree_def);
696         return 1;
697 }
698
699
700 EnvRef::EnvRef(ServerEnvironment *env):
701         m_env(env)
702 {
703         //infostream<<"EnvRef created"<<std::endl;
704 }
705
706 EnvRef::~EnvRef()
707 {
708         //infostream<<"EnvRef destructing"<<std::endl;
709 }
710
711 // Creates an EnvRef and leaves it on top of stack
712 // Not callable from Lua; all references are created on the C side.
713 void EnvRef::create(lua_State *L, ServerEnvironment *env)
714 {
715         EnvRef *o = new EnvRef(env);
716         //infostream<<"EnvRef::create: o="<<o<<std::endl;
717         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
718         luaL_getmetatable(L, className);
719         lua_setmetatable(L, -2);
720 }
721
722 void EnvRef::set_null(lua_State *L)
723 {
724         EnvRef *o = checkobject(L, -1);
725         o->m_env = NULL;
726 }
727
728 void EnvRef::Register(lua_State *L)
729 {
730         lua_newtable(L);
731         int methodtable = lua_gettop(L);
732         luaL_newmetatable(L, className);
733         int metatable = lua_gettop(L);
734
735         lua_pushliteral(L, "__metatable");
736         lua_pushvalue(L, methodtable);
737         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
738
739         lua_pushliteral(L, "__index");
740         lua_pushvalue(L, methodtable);
741         lua_settable(L, metatable);
742
743         lua_pushliteral(L, "__gc");
744         lua_pushcfunction(L, gc_object);
745         lua_settable(L, metatable);
746
747         lua_pop(L, 1);  // drop metatable
748
749         luaL_openlib(L, 0, methods, 0);  // fill methodtable
750         lua_pop(L, 1);  // drop methodtable
751
752         // Cannot be created from Lua
753         //lua_register(L, className, create_object);
754 }
755
756 const char EnvRef::className[] = "EnvRef";
757 const luaL_reg EnvRef::methods[] = {
758         luamethod(EnvRef, set_node),
759         luamethod(EnvRef, add_node),
760         luamethod(EnvRef, remove_node),
761         luamethod(EnvRef, get_node),
762         luamethod(EnvRef, get_node_or_nil),
763         luamethod(EnvRef, get_node_light),
764         luamethod(EnvRef, place_node),
765         luamethod(EnvRef, dig_node),
766         luamethod(EnvRef, punch_node),
767         luamethod(EnvRef, add_entity),
768         luamethod(EnvRef, add_item),
769         luamethod(EnvRef, add_rat),
770         luamethod(EnvRef, add_firefly),
771         luamethod(EnvRef, get_meta),
772         luamethod(EnvRef, get_node_timer),
773         luamethod(EnvRef, get_player_by_name),
774         luamethod(EnvRef, get_objects_inside_radius),
775         luamethod(EnvRef, set_timeofday),
776         luamethod(EnvRef, get_timeofday),
777         luamethod(EnvRef, find_node_near),
778         luamethod(EnvRef, find_nodes_in_area),
779         luamethod(EnvRef, get_perlin),
780         luamethod(EnvRef, get_perlin_map),
781         luamethod(EnvRef, clear_objects),
782         luamethod(EnvRef, spawn_tree),
783         {0,0}
784 };
785
786 void scriptapi_environment_on_generated(lua_State *L, v3s16 minp, v3s16 maxp,
787                 u32 blockseed)
788 {
789         realitycheck(L);
790         assert(lua_checkstack(L, 20));
791         //infostream<<"scriptapi_environment_on_generated"<<std::endl;
792         StackUnroller stack_unroller(L);
793
794         // Get minetest.registered_on_generateds
795         lua_getglobal(L, "minetest");
796         lua_getfield(L, -1, "registered_on_generateds");
797         // Call callbacks
798         push_v3s16(L, minp);
799         push_v3s16(L, maxp);
800         lua_pushnumber(L, blockseed);
801         scriptapi_run_callbacks(L, 3, RUN_CALLBACKS_MODE_FIRST);
802 }
803
804 void scriptapi_environment_step(lua_State *L, float dtime)
805 {
806         realitycheck(L);
807         assert(lua_checkstack(L, 20));
808         //infostream<<"scriptapi_environment_step"<<std::endl;
809         StackUnroller stack_unroller(L);
810
811         // Get minetest.registered_globalsteps
812         lua_getglobal(L, "minetest");
813         lua_getfield(L, -1, "registered_globalsteps");
814         // Call callbacks
815         lua_pushnumber(L, dtime);
816         scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
817 }
818
819 void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
820 {
821         realitycheck(L);
822         assert(lua_checkstack(L, 20));
823         verbosestream<<"scriptapi_add_environment"<<std::endl;
824         StackUnroller stack_unroller(L);
825
826         // Create EnvRef on stack
827         EnvRef::create(L, env);
828         int envref = lua_gettop(L);
829
830         // minetest.env = envref
831         lua_getglobal(L, "minetest");
832         luaL_checktype(L, -1, LUA_TTABLE);
833         lua_pushvalue(L, envref);
834         lua_setfield(L, -2, "env");
835
836         // Store environment as light userdata in registry
837         lua_pushlightuserdata(L, env);
838         lua_setfield(L, LUA_REGISTRYINDEX, "minetest_env");
839
840         /*
841                 Add ActiveBlockModifiers to environment
842         */
843
844         // Get minetest.registered_abms
845         lua_getglobal(L, "minetest");
846         lua_getfield(L, -1, "registered_abms");
847         luaL_checktype(L, -1, LUA_TTABLE);
848         int registered_abms = lua_gettop(L);
849
850         if(lua_istable(L, registered_abms)){
851                 int table = lua_gettop(L);
852                 lua_pushnil(L);
853                 while(lua_next(L, table) != 0){
854                         // key at index -2 and value at index -1
855                         int id = lua_tonumber(L, -2);
856                         int current_abm = lua_gettop(L);
857
858                         std::set<std::string> trigger_contents;
859                         lua_getfield(L, current_abm, "nodenames");
860                         if(lua_istable(L, -1)){
861                                 int table = lua_gettop(L);
862                                 lua_pushnil(L);
863                                 while(lua_next(L, table) != 0){
864                                         // key at index -2 and value at index -1
865                                         luaL_checktype(L, -1, LUA_TSTRING);
866                                         trigger_contents.insert(lua_tostring(L, -1));
867                                         // removes value, keeps key for next iteration
868                                         lua_pop(L, 1);
869                                 }
870                         } else if(lua_isstring(L, -1)){
871                                 trigger_contents.insert(lua_tostring(L, -1));
872                         }
873                         lua_pop(L, 1);
874
875                         std::set<std::string> required_neighbors;
876                         lua_getfield(L, current_abm, "neighbors");
877                         if(lua_istable(L, -1)){
878                                 int table = lua_gettop(L);
879                                 lua_pushnil(L);
880                                 while(lua_next(L, table) != 0){
881                                         // key at index -2 and value at index -1
882                                         luaL_checktype(L, -1, LUA_TSTRING);
883                                         required_neighbors.insert(lua_tostring(L, -1));
884                                         // removes value, keeps key for next iteration
885                                         lua_pop(L, 1);
886                                 }
887                         } else if(lua_isstring(L, -1)){
888                                 required_neighbors.insert(lua_tostring(L, -1));
889                         }
890                         lua_pop(L, 1);
891
892                         float trigger_interval = 10.0;
893                         getfloatfield(L, current_abm, "interval", trigger_interval);
894
895                         int trigger_chance = 50;
896                         getintfield(L, current_abm, "chance", trigger_chance);
897
898                         LuaABM *abm = new LuaABM(L, id, trigger_contents,
899                                         required_neighbors, trigger_interval, trigger_chance);
900
901                         env->addActiveBlockModifier(abm);
902
903                         // removes value, keeps key for next iteration
904                         lua_pop(L, 1);
905                 }
906         }
907         lua_pop(L, 1);
908 }