]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/luaapi.cpp
Fix my name.
[dragonfireclient.git] / src / script / lua_api / luaapi.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 extern "C" {
21 #include "lua.h"
22 #include "lauxlib.h"
23 }
24
25 #include "lua_api/l_base.h"
26 #include "common/c_internal.h"
27 #include "server.h"
28 #include "common/c_converter.h"
29 #include "common/c_content.h"
30 #include "lua_api/luaapi.h"
31 #include "settings.h"
32 #include "tool.h"
33 #include "rollback.h"
34 #include "log.h"
35 #include "emerge.h"
36 #include "main.h"  //required for g_settings
37
38 struct EnumString ModApiBasic::es_OreType[] =
39 {
40         {ORE_SCATTER,  "scatter"},
41         {ORE_SHEET,    "sheet"},
42         {ORE_CLAYLIKE, "claylike"},
43         {0, NULL},
44 };
45
46 struct EnumString ModApiBasic::es_DecorationType[] =
47 {
48         {DECO_SIMPLE,    "simple"},
49         {DECO_SCHEMATIC, "schematic"},
50         {DECO_LSYSTEM,   "lsystem"},
51         {0, NULL},
52 };
53
54 struct EnumString ModApiBasic::es_Rotation[] =
55 {
56         {ROTATE_0,    "0"},
57         {ROTATE_90,   "90"},
58         {ROTATE_180,  "180"},
59         {ROTATE_270,  "270"},
60         {ROTATE_RAND, "random"},
61         {0, NULL},
62 };
63
64
65 ModApiBasic::ModApiBasic() : ModApiBase() {
66 }
67
68 bool ModApiBasic::Initialize(lua_State* L,int top) {
69
70         bool retval = true;
71
72         retval &= API_FCT(debug);
73         retval &= API_FCT(log);
74         retval &= API_FCT(request_shutdown);
75         retval &= API_FCT(get_server_status);
76
77         retval &= API_FCT(register_biome);
78
79         retval &= API_FCT(setting_set);
80         retval &= API_FCT(setting_get);
81         retval &= API_FCT(setting_getbool);
82         retval &= API_FCT(setting_save);
83
84         retval &= API_FCT(chat_send_all);
85         retval &= API_FCT(chat_send_player);
86         retval &= API_FCT(show_formspec);
87
88         retval &= API_FCT(get_player_privs);
89         retval &= API_FCT(get_player_ip);
90         retval &= API_FCT(get_ban_list);
91         retval &= API_FCT(get_ban_description);
92         retval &= API_FCT(ban_player);
93         retval &= API_FCT(unban_player_or_ip);
94         retval &= API_FCT(get_password_hash);
95         retval &= API_FCT(notify_authentication_modified);
96
97         retval &= API_FCT(get_dig_params);
98         retval &= API_FCT(get_hit_params);
99
100         retval &= API_FCT(get_current_modname);
101         retval &= API_FCT(get_modpath);
102         retval &= API_FCT(get_modnames);
103
104         retval &= API_FCT(get_worldpath);
105         retval &= API_FCT(is_singleplayer);
106         retval &= API_FCT(sound_play);
107         retval &= API_FCT(sound_stop);
108
109         retval &= API_FCT(rollback_get_last_node_actor);
110         retval &= API_FCT(rollback_revert_actions_by);
111
112         retval &= API_FCT(register_ore);
113         retval &= API_FCT(register_decoration);
114         retval &= API_FCT(create_schematic);
115         retval &= API_FCT(place_schematic);
116
117         return retval;
118 }
119
120 // debug(...)
121 // Writes a line to dstream
122 int ModApiBasic::l_debug(lua_State *L)
123 {
124         NO_MAP_LOCK_REQUIRED;
125         // Handle multiple parameters to behave like standard lua print()
126         int n = lua_gettop(L);
127         lua_getglobal(L, "tostring");
128         for(int i = 1; i <= n; i++){
129                 /*
130                         Call tostring(i-th argument).
131                         This is what print() does, and it behaves a bit
132                         differently from directly calling lua_tostring.
133                 */
134                 lua_pushvalue(L, -1);  /* function to be called */
135                 lua_pushvalue(L, i);   /* value to print */
136                 lua_call(L, 1, 1);
137                 const char *s = lua_tostring(L, -1);
138                 if(i>1)
139                         dstream << "\t";
140                 if(s)
141                         dstream << s;
142                 lua_pop(L, 1);
143         }
144         dstream << std::endl;
145         return 0;
146 }
147
148 // log([level,] text)
149 // Writes a line to the logger.
150 // The one-argument version logs to infostream.
151 // The two-argument version accept a log level: error, action, info, or verbose.
152 int ModApiBasic::l_log(lua_State *L)
153 {
154         NO_MAP_LOCK_REQUIRED;
155         std::string text;
156         LogMessageLevel level = LMT_INFO;
157         if(lua_isnone(L, 2))
158         {
159                 text = lua_tostring(L, 1);
160         }
161         else
162         {
163                 std::string levelname = luaL_checkstring(L, 1);
164                 text = luaL_checkstring(L, 2);
165                 if(levelname == "error")
166                         level = LMT_ERROR;
167                 else if(levelname == "action")
168                         level = LMT_ACTION;
169                 else if(levelname == "verbose")
170                         level = LMT_VERBOSE;
171         }
172         log_printline(level, text);
173         return 0;
174 }
175
176 // request_shutdown()
177 int ModApiBasic::l_request_shutdown(lua_State *L)
178 {
179         getServer(L)->requestShutdown();
180         return 0;
181 }
182
183 // get_server_status()
184 int ModApiBasic::l_get_server_status(lua_State *L)
185 {
186         NO_MAP_LOCK_REQUIRED;
187         lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
188         return 1;
189 }
190
191 // register_biome({lots of stuff})
192 int ModApiBasic::l_register_biome(lua_State *L)
193 {
194         int index = 1;
195         luaL_checktype(L, index, LUA_TTABLE);
196
197         BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
198         if (!bmgr) {
199                 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
200                 return 0;
201         }
202
203         enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
204                                 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
205         Biome *b = bmgr->createBiome(terrain);
206
207         b->name         = getstringfield_default(L, index, "name",
208                                                                                                 "<no name>");
209         b->nname_top    = getstringfield_default(L, index, "node_top",
210                                                                                                 "mapgen_dirt_with_grass");
211         b->nname_filler = getstringfield_default(L, index, "node_filler",
212                                                                                                 "mapgen_dirt");
213         b->nname_water  = getstringfield_default(L, index, "node_water",
214                                                                                                 "mapgen_water_source");
215         b->nname_dust   = getstringfield_default(L, index, "node_dust",
216                                                                                                 "air");
217         b->nname_dust_water = getstringfield_default(L, index, "node_dust_water",
218                                                                                                 "mapgen_water_source");
219         
220         b->depth_top      = getintfield_default(L, index, "depth_top",    1);
221         b->depth_filler   = getintfield_default(L, index, "depth_filler", 3);
222         b->height_min     = getintfield_default(L, index, "height_min",   0);
223         b->height_max     = getintfield_default(L, index, "height_max",   0);
224         b->heat_point     = getfloatfield_default(L, index, "heat_point",     0.);
225         b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
226
227         b->flags        = 0; //reserved
228         b->c_top        = CONTENT_IGNORE;
229         b->c_filler     = CONTENT_IGNORE;
230         b->c_water      = CONTENT_IGNORE;
231         b->c_dust       = CONTENT_IGNORE;
232         b->c_dust_water = CONTENT_IGNORE;
233         
234         verbosestream << "register_biome: " << b->name << std::endl;
235         bmgr->addBiome(b);
236
237         return 0;
238 }
239
240 // setting_set(name, value)
241 int ModApiBasic::l_setting_set(lua_State *L)
242 {
243         NO_MAP_LOCK_REQUIRED;
244         const char *name = luaL_checkstring(L, 1);
245         const char *value = luaL_checkstring(L, 2);
246         g_settings->set(name, value);
247         return 0;
248 }
249
250 // setting_get(name)
251 int ModApiBasic::l_setting_get(lua_State *L)
252 {
253         NO_MAP_LOCK_REQUIRED;
254         const char *name = luaL_checkstring(L, 1);
255         try{
256                 std::string value = g_settings->get(name);
257                 lua_pushstring(L, value.c_str());
258         } catch(SettingNotFoundException &e){
259                 lua_pushnil(L);
260         }
261         return 1;
262 }
263
264 // setting_getbool(name)
265 int ModApiBasic::l_setting_getbool(lua_State *L)
266 {
267         NO_MAP_LOCK_REQUIRED;
268         const char *name = luaL_checkstring(L, 1);
269         try{
270                 bool value = g_settings->getBool(name);
271                 lua_pushboolean(L, value);
272         } catch(SettingNotFoundException &e){
273                 lua_pushnil(L);
274         }
275         return 1;
276 }
277
278 // setting_save()
279 int ModApiBasic::l_setting_save(lua_State *L)
280 {
281         NO_MAP_LOCK_REQUIRED;
282         getServer(L)->saveConfig();
283         return 0;
284 }
285
286 // chat_send_all(text)
287 int ModApiBasic::l_chat_send_all(lua_State *L)
288 {
289         NO_MAP_LOCK_REQUIRED;
290         const char *text = luaL_checkstring(L, 1);
291         // Get server from registry
292         Server *server = getServer(L);
293         // Send
294         server->notifyPlayers(narrow_to_wide(text));
295         return 0;
296 }
297
298 // chat_send_player(name, text, prepend)
299 int ModApiBasic::l_chat_send_player(lua_State *L)
300 {
301         NO_MAP_LOCK_REQUIRED;
302         const char *name = luaL_checkstring(L, 1);
303         const char *text = luaL_checkstring(L, 2);
304         bool prepend = true;
305
306         if (lua_isboolean(L, 3))
307                 prepend = lua_toboolean(L, 3);
308
309         // Get server from registry
310         Server *server = getServer(L);
311         // Send
312         server->notifyPlayer(name, narrow_to_wide(text), prepend);
313         return 0;
314 }
315
316 // get_player_privs(name, text)
317 int ModApiBasic::l_get_player_privs(lua_State *L)
318 {
319         NO_MAP_LOCK_REQUIRED;
320         const char *name = luaL_checkstring(L, 1);
321         // Get server from registry
322         Server *server = getServer(L);
323         // Do it
324         lua_newtable(L);
325         int table = lua_gettop(L);
326         std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
327         for(std::set<std::string>::const_iterator
328                         i = privs_s.begin(); i != privs_s.end(); i++){
329                 lua_pushboolean(L, true);
330                 lua_setfield(L, table, i->c_str());
331         }
332         lua_pushvalue(L, table);
333         return 1;
334 }
335
336 // get_player_ip()
337 int ModApiBasic::l_get_player_ip(lua_State *L)
338 {
339         NO_MAP_LOCK_REQUIRED;
340         const char * name = luaL_checkstring(L, 1);
341         Player *player = getEnv(L)->getPlayer(name);
342         if(player == NULL)
343         {
344                 lua_pushnil(L); // no such player
345                 return 1;
346         }
347         try
348         {
349                 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
350                 std::string ip_str = addr.serializeString();
351                 lua_pushstring(L, ip_str.c_str());
352                 return 1;
353         }
354         catch(con::PeerNotFoundException) // unlikely
355         {
356                 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
357                 lua_pushnil(L); // error
358                 return 1;
359         }
360 }
361
362 // get_ban_list()
363 int ModApiBasic::l_get_ban_list(lua_State *L)
364 {
365         NO_MAP_LOCK_REQUIRED;
366         lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
367         return 1;
368 }
369
370 // get_ban_description()
371 int ModApiBasic::l_get_ban_description(lua_State *L)
372 {
373         NO_MAP_LOCK_REQUIRED;
374         const char * ip_or_name = luaL_checkstring(L, 1);
375         lua_pushstring(L, getServer(L)->getBanDescription(std::string(ip_or_name)).c_str());
376         return 1;
377 }
378
379 // ban_player()
380 int ModApiBasic::l_ban_player(lua_State *L)
381 {
382         NO_MAP_LOCK_REQUIRED;
383         const char * name = luaL_checkstring(L, 1);
384         Player *player = getEnv(L)->getPlayer(name);
385         if(player == NULL)
386         {
387                 lua_pushboolean(L, false); // no such player
388                 return 1;
389         }
390         try
391         {
392                 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
393                 std::string ip_str = addr.serializeString();
394                 getServer(L)->setIpBanned(ip_str, name);
395         }
396         catch(con::PeerNotFoundException) // unlikely
397         {
398                 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
399                 lua_pushboolean(L, false); // error
400                 return 1;
401         }
402         lua_pushboolean(L, true);
403         return 1;
404 }
405
406 // unban_player_or_ip()
407 int ModApiBasic::l_unban_player_or_ip(lua_State *L)
408 {
409         NO_MAP_LOCK_REQUIRED;
410         const char * ip_or_name = luaL_checkstring(L, 1);
411         getServer(L)->unsetIpBanned(ip_or_name);
412         lua_pushboolean(L, true);
413         return 1;
414 }
415
416 // show_formspec(playername,formname,formspec)
417 int ModApiBasic::l_show_formspec(lua_State *L)
418 {
419         NO_MAP_LOCK_REQUIRED;
420         const char *playername = luaL_checkstring(L, 1);
421         const char *formname = luaL_checkstring(L, 2);
422         const char *formspec = luaL_checkstring(L, 3);
423
424         if(getServer(L)->showFormspec(playername,formspec,formname))
425         {
426                 lua_pushboolean(L, true);
427         }else{
428                 lua_pushboolean(L, false);
429         }
430         return 1;
431 }
432
433 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
434 int ModApiBasic::l_get_dig_params(lua_State *L)
435 {
436         NO_MAP_LOCK_REQUIRED;
437         std::map<std::string, int> groups;
438         read_groups(L, 1, groups);
439         ToolCapabilities tp = read_tool_capabilities(L, 2);
440         if(lua_isnoneornil(L, 3))
441                 push_dig_params(L, getDigParams(groups, &tp));
442         else
443                 push_dig_params(L, getDigParams(groups, &tp,
444                                         luaL_checknumber(L, 3)));
445         return 1;
446 }
447
448 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
449 int ModApiBasic::l_get_hit_params(lua_State *L)
450 {
451         NO_MAP_LOCK_REQUIRED;
452         std::map<std::string, int> groups;
453         read_groups(L, 1, groups);
454         ToolCapabilities tp = read_tool_capabilities(L, 2);
455         if(lua_isnoneornil(L, 3))
456                 push_hit_params(L, getHitParams(groups, &tp));
457         else
458                 push_hit_params(L, getHitParams(groups, &tp,
459                                         luaL_checknumber(L, 3)));
460         return 1;
461 }
462
463 // get_current_modname()
464 int ModApiBasic::l_get_current_modname(lua_State *L)
465 {
466         NO_MAP_LOCK_REQUIRED;
467         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
468         return 1;
469 }
470
471 // get_modpath(modname)
472 int ModApiBasic::l_get_modpath(lua_State *L)
473 {
474         NO_MAP_LOCK_REQUIRED;
475         std::string modname = luaL_checkstring(L, 1);
476         // Do it
477         if(modname == "__builtin"){
478                 std::string path = getServer(L)->getBuiltinLuaPath();
479                 lua_pushstring(L, path.c_str());
480                 return 1;
481         }
482         const ModSpec *mod = getServer(L)->getModSpec(modname);
483         if(!mod){
484                 lua_pushnil(L);
485                 return 1;
486         }
487         lua_pushstring(L, mod->path.c_str());
488         return 1;
489 }
490
491 // get_modnames()
492 // the returned list is sorted alphabetically for you
493 int ModApiBasic::l_get_modnames(lua_State *L)
494 {
495         NO_MAP_LOCK_REQUIRED;
496         // Get a list of mods
497         std::list<std::string> mods_unsorted, mods_sorted;
498         getServer(L)->getModNames(mods_unsorted);
499
500         // Take unsorted items from mods_unsorted and sort them into
501         // mods_sorted; not great performance but the number of mods on a
502         // server will likely be small.
503         for(std::list<std::string>::iterator i = mods_unsorted.begin();
504                 i != mods_unsorted.end(); ++i)
505         {
506                 bool added = false;
507                 for(std::list<std::string>::iterator x = mods_sorted.begin();
508                         x != mods_sorted.end(); ++x)
509                 {
510                         // I doubt anybody using Minetest will be using
511                         // anything not ASCII based :)
512                         if((*i).compare(*x) <= 0)
513                         {
514                                 mods_sorted.insert(x, *i);
515                                 added = true;
516                                 break;
517                         }
518                 }
519                 if(!added)
520                         mods_sorted.push_back(*i);
521         }
522
523         // Get the table insertion function from Lua.
524         lua_getglobal(L, "table");
525         lua_getfield(L, -1, "insert");
526         int insertion_func = lua_gettop(L);
527
528         // Package them up for Lua
529         lua_newtable(L);
530         int new_table = lua_gettop(L);
531         std::list<std::string>::iterator i = mods_sorted.begin();
532         while(i != mods_sorted.end())
533         {
534                 lua_pushvalue(L, insertion_func);
535                 lua_pushvalue(L, new_table);
536                 lua_pushstring(L, (*i).c_str());
537                 if(lua_pcall(L, 2, 0, 0) != 0)
538                 {
539                         script_error(L, "error: %s", lua_tostring(L, -1));
540                 }
541                 ++i;
542         }
543         return 1;
544 }
545
546 // get_worldpath()
547 int ModApiBasic::l_get_worldpath(lua_State *L)
548 {
549         NO_MAP_LOCK_REQUIRED;
550         std::string worldpath = getServer(L)->getWorldPath();
551         lua_pushstring(L, worldpath.c_str());
552         return 1;
553 }
554
555 // sound_play(spec, parameters)
556 int ModApiBasic::l_sound_play(lua_State *L)
557 {
558         NO_MAP_LOCK_REQUIRED;
559         SimpleSoundSpec spec;
560         read_soundspec(L, 1, spec);
561         ServerSoundParams params;
562         read_server_sound_params(L, 2, params);
563         s32 handle = getServer(L)->playSound(spec, params);
564         lua_pushinteger(L, handle);
565         return 1;
566 }
567
568 // sound_stop(handle)
569 int ModApiBasic::l_sound_stop(lua_State *L)
570 {
571         NO_MAP_LOCK_REQUIRED;
572         int handle = luaL_checkinteger(L, 1);
573         getServer(L)->stopSound(handle);
574         return 0;
575 }
576
577 // is_singleplayer()
578 int ModApiBasic::l_is_singleplayer(lua_State *L)
579 {
580         NO_MAP_LOCK_REQUIRED;
581         lua_pushboolean(L, getServer(L)->isSingleplayer());
582         return 1;
583 }
584
585 // get_password_hash(name, raw_password)
586 int ModApiBasic::l_get_password_hash(lua_State *L)
587 {
588         NO_MAP_LOCK_REQUIRED;
589         std::string name = luaL_checkstring(L, 1);
590         std::string raw_password = luaL_checkstring(L, 2);
591         std::string hash = translatePassword(name,
592                         narrow_to_wide(raw_password));
593         lua_pushstring(L, hash.c_str());
594         return 1;
595 }
596
597 // notify_authentication_modified(name)
598 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
599 {
600         NO_MAP_LOCK_REQUIRED;
601         std::string name = "";
602         if(lua_isstring(L, 1))
603                 name = lua_tostring(L, 1);
604         getServer(L)->reportPrivsModified(name);
605         return 0;
606 }
607
608 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
609 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
610 {
611         v3s16 p = read_v3s16(L, 1);
612         int range = luaL_checknumber(L, 2);
613         int seconds = luaL_checknumber(L, 3);
614         Server *server = getServer(L);
615         IRollbackManager *rollback = server->getRollbackManager();
616         v3s16 act_p;
617         int act_seconds = 0;
618         std::string actor = rollback->getLastNodeActor(p, range, seconds, &act_p, &act_seconds);
619         lua_pushstring(L, actor.c_str());
620         push_v3s16(L, act_p);
621         lua_pushnumber(L, act_seconds);
622         return 3;
623 }
624
625 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
626 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
627 {
628         std::string actor = luaL_checkstring(L, 1);
629         int seconds = luaL_checknumber(L, 2);
630         Server *server = getServer(L);
631         IRollbackManager *rollback = server->getRollbackManager();
632         std::list<RollbackAction> actions = rollback->getRevertActions(actor, seconds);
633         std::list<std::string> log;
634         bool success = server->rollbackRevertActions(actions, &log);
635         // Push boolean result
636         lua_pushboolean(L, success);
637         // Get the table insert function and push the log table
638         lua_getglobal(L, "table");
639         lua_getfield(L, -1, "insert");
640         int table_insert = lua_gettop(L);
641         lua_newtable(L);
642         int table = lua_gettop(L);
643         for(std::list<std::string>::const_iterator i = log.begin();
644                         i != log.end(); i++)
645         {
646                 lua_pushvalue(L, table_insert);
647                 lua_pushvalue(L, table);
648                 lua_pushstring(L, i->c_str());
649                 if(lua_pcall(L, 2, 0, 0))
650                         script_error(L, "error: %s", lua_tostring(L, -1));
651         }
652         lua_remove(L, -2); // Remove table
653         lua_remove(L, -2); // Remove insert
654         return 2;
655 }
656
657 int ModApiBasic::l_register_ore(lua_State *L)
658 {
659         int index = 1;
660         luaL_checktype(L, index, LUA_TTABLE);
661
662         EmergeManager *emerge = getServer(L)->getEmergeManager();
663
664         enum OreType oretype = (OreType)getenumfield(L, index,
665                                 "ore_type", es_OreType, ORE_SCATTER);
666         Ore *ore = createOre(oretype);
667         if (!ore) {
668                 errorstream << "register_ore: ore_type "
669                         << oretype << " not implemented";
670                 return 0;
671         }
672
673         ore->ore_name       = getstringfield_default(L, index, "ore", "");
674         ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
675         ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
676         ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
677         ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
678         ore->height_min     = getintfield_default(L, index, "height_min", 0);
679         ore->height_max     = getintfield_default(L, index, "height_max", 0);
680         ore->flags          = getflagsfield(L, index, "flags", flagdesc_ore);
681         ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0.);
682
683         lua_getfield(L, index, "wherein");
684         if (lua_istable(L, -1)) {
685                 int  i = lua_gettop(L);
686                 lua_pushnil(L);
687                 while(lua_next(L, i) != 0) {
688                         ore->wherein_names.push_back(lua_tostring(L, -1));
689                         lua_pop(L, 1);
690                 }
691         } else if (lua_isstring(L, -1)) {
692                 ore->wherein_names.push_back(lua_tostring(L, -1));
693         } else {
694                 ore->wherein_names.push_back("");
695         }
696         lua_pop(L, 1);
697
698         lua_getfield(L, index, "noise_params");
699         ore->np = read_noiseparams(L, -1);
700         lua_pop(L, 1);
701
702         ore->noise = NULL;
703
704         if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
705                 errorstream << "register_ore: clust_scarcity and clust_num_ores"
706                         "must be greater than 0" << std::endl;
707                 delete ore;
708                 return 0;
709         }
710
711         emerge->ores.push_back(ore);
712
713         verbosestream << "register_ore: ore '" << ore->ore_name
714                 << "' registered" << std::endl;
715         return 0;
716 }
717
718 // register_decoration({lots of stuff})
719 int ModApiBasic::l_register_decoration(lua_State *L)
720 {
721         int index = 1;
722         luaL_checktype(L, index, LUA_TTABLE);
723
724         EmergeManager *emerge = getServer(L)->getEmergeManager();
725         BiomeDefManager *bdef = emerge->biomedef;
726
727         enum DecorationType decotype = (DecorationType)getenumfield(L, index,
728                                 "deco_type", es_DecorationType, -1);
729         if (decotype == -1) {
730                 errorstream << "register_decoration: unrecognized "
731                         "decoration placement type";
732                 return 0;
733         }
734         
735         Decoration *deco = createDecoration(decotype);
736         if (!deco) {
737                 errorstream << "register_decoration: decoration placement type "
738                         << decotype << " not implemented";
739                 return 0;
740         }
741
742         deco->c_place_on    = CONTENT_IGNORE;
743         deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore");
744         deco->fill_ratio    = getfloatfield_default(L, index, "fill_ratio", 0.02);
745         deco->sidelen       = getintfield_default(L, index, "sidelen", 8);
746         if (deco->sidelen <= 0) {
747                 errorstream << "register_decoration: sidelen must be "
748                         "greater than 0" << std::endl;
749                 delete deco;
750                 return 0;
751         }
752         
753         lua_getfield(L, index, "noise_params");
754         deco->np = read_noiseparams(L, -1);
755         lua_pop(L, 1);
756         
757         lua_getfield(L, index, "biomes");
758         if (lua_istable(L, -1)) {
759                 lua_pushnil(L);
760                 while (lua_next(L, -2)) {
761                         const char *s = lua_tostring(L, -1);
762                         u8 biomeid = bdef->getBiomeIdByName(s);
763                         if (biomeid)
764                                 deco->biomes.insert(biomeid);
765
766                         lua_pop(L, 1);
767                 }
768                 lua_pop(L, 1);
769         }
770         
771         switch (decotype) {
772                 case DECO_SIMPLE: {
773                         DecoSimple *dsimple = (DecoSimple *)deco;
774                         dsimple->c_deco     = CONTENT_IGNORE;
775                         dsimple->c_spawnby  = CONTENT_IGNORE;
776                         dsimple->spawnby_name    = getstringfield_default(L, index, "spawn_by", "air");
777                         dsimple->deco_height     = getintfield_default(L, index, "height", 1);
778                         dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0);
779                         dsimple->nspawnby        = getintfield_default(L, index, "num_spawn_by", -1);
780                         
781                         lua_getfield(L, index, "decoration");
782                         if (lua_istable(L, -1)) {
783                                 lua_pushnil(L);
784                                 while (lua_next(L, -2)) {
785                                         const char *s = lua_tostring(L, -1);
786                                         std::string str(s);
787                                         dsimple->decolist_names.push_back(str);
788
789                                         lua_pop(L, 1);
790                                 }
791                         } else if (lua_isstring(L, -1)) {
792                                 dsimple->deco_name = std::string(lua_tostring(L, -1));
793                         } else {
794                                 dsimple->deco_name = std::string("air");
795                         }
796                         lua_pop(L, 1);
797                         
798                         if (dsimple->deco_height <= 0) {
799                                 errorstream << "register_decoration: simple decoration height"
800                                         " must be greater than 0" << std::endl;
801                                 delete dsimple;
802                                 return 0;
803                         }
804
805                         break; }
806                 case DECO_SCHEMATIC: {
807                         DecoSchematic *dschem = (DecoSchematic *)deco;
808                         dschem->flags    = getflagsfield(L, index, "flags", flagdesc_deco_schematic);
809                         dschem->rotation = (Rotation)getenumfield(L, index,
810                                                                 "rotation", es_Rotation, ROTATE_0);
811
812                         lua_getfield(L, index, "replacements");
813                         if (lua_istable(L, -1)) {
814                                 int i = lua_gettop(L);
815                                 lua_pushnil(L);
816                                 while (lua_next(L, i) != 0) {
817                                         // key at index -2 and value at index -1
818                                         lua_rawgeti(L, -1, 1);
819                                         std::string replace_from = lua_tostring(L, -1);
820                                         lua_pop(L, 1);
821                                         lua_rawgeti(L, -1, 2);
822                                         std::string replace_to = lua_tostring(L, -1);
823                                         lua_pop(L, 1);
824                                         dschem->replacements[replace_from] = replace_to;
825                                         // removes value, keeps key for next iteration
826                                         lua_pop(L, 1);
827                                 }
828                         }
829                         lua_pop(L, 1);
830
831                         lua_getfield(L, index, "schematic");
832                         if (!read_schematic(L, -1, dschem, getServer(L))) {
833                                 delete dschem;
834                                 return 0;
835                         }
836                         lua_pop(L, -1);
837                         
838                         if (!dschem->filename.empty() && !dschem->loadSchematicFile()) {
839                                 errorstream << "register_decoration: failed to load schematic file '"
840                                         << dschem->filename << "'" << std::endl;
841                                 delete dschem;
842                                 return 0;
843                         }
844                         break; }
845                 case DECO_LSYSTEM: {
846                         //DecoLSystem *decolsystem = (DecoLSystem *)deco;
847                 
848                         break; }
849         }
850
851         emerge->decorations.push_back(deco);
852
853         verbosestream << "register_decoration: decoration '" << deco->getName()
854                 << "' registered" << std::endl;
855         return 0;
856 }
857
858 // create_schematic(p1, p2, probability_list, filename)
859 int ModApiBasic::l_create_schematic(lua_State *L)
860 {
861         DecoSchematic dschem;
862
863         Map *map = &(getEnv(L)->getMap());
864         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
865
866         v3s16 p1 = read_v3s16(L, 1);
867         v3s16 p2 = read_v3s16(L, 2);
868         sortBoxVerticies(p1, p2);
869         
870         std::vector<std::pair<v3s16, u8> > probability_list;
871         if (lua_istable(L, 3)) {
872                 lua_pushnil(L);
873                 while (lua_next(L, 3)) {
874                         if (lua_istable(L, -1)) {
875                                 lua_getfield(L, -1, "pos");
876                                 v3s16 pos = read_v3s16(L, -1);
877                                 lua_pop(L, 1);
878                                 
879                                 u8 prob = getintfield_default(L, -1, "prob", 0xFF);
880                                 probability_list.push_back(std::make_pair(pos, prob));
881                         }
882
883                         lua_pop(L, 1);
884                 }
885         }
886         
887         dschem.filename = std::string(lua_tostring(L, 4));
888
889         if (!dschem.getSchematicFromMap(map, p1, p2)) {
890                 errorstream << "create_schematic: failed to get schematic "
891                         "from map" << std::endl;
892                 return 0;
893         }
894         
895         dschem.applyProbabilities(&probability_list, p1);
896         
897         dschem.saveSchematicFile(ndef);
898         actionstream << "create_schematic: saved schematic file '"
899                 << dschem.filename << "'." << std::endl;
900
901         return 1;
902 }
903
904
905 // place_schematic(p, schematic, rotation, replacement)
906 int ModApiBasic::l_place_schematic(lua_State *L)
907 {
908         DecoSchematic dschem;
909
910         Map *map = &(getEnv(L)->getMap());
911         INodeDefManager *ndef = getServer(L)->getNodeDefManager();
912
913         v3s16 p = read_v3s16(L, 1);
914         if (!read_schematic(L, 2, &dschem, getServer(L)))
915                 return 0;
916                 
917         Rotation rot = ROTATE_0;
918         if (lua_isstring(L, 3))
919                 string_to_enum(es_Rotation, (int &)rot, std::string(lua_tostring(L, 3)));
920                 
921         dschem.rotation = rot;
922
923         if (lua_istable(L, 4)) {
924                 int index = 4;
925                 lua_pushnil(L);
926                 while (lua_next(L, index) != 0) {
927                         // key at index -2 and value at index -1
928                         lua_rawgeti(L, -1, 1);
929                         std::string replace_from = lua_tostring(L, -1);
930                         lua_pop(L, 1);
931                         lua_rawgeti(L, -1, 2);
932                         std::string replace_to = lua_tostring(L, -1);
933                         lua_pop(L, 1);
934                         dschem.replacements[replace_from] = replace_to;
935                         // removes value, keeps key for next iteration
936                         lua_pop(L, 1);
937                 }
938         }
939
940         if (!dschem.filename.empty()) {
941                 if (!dschem.loadSchematicFile()) {
942                         errorstream << "place_schematic: failed to load schematic file '"
943                                 << dschem.filename << "'" << std::endl;
944                         return 0;
945                 }
946                 dschem.resolveNodeNames(ndef);
947         }
948         
949         dschem.placeStructure(map, p);
950
951         return 1;
952 }
953
954
955 ModApiBasic modapibasic_prototype;