]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/luaapi.cpp
Add initial Decoration support, many misc. improvements & modifications
[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
55 ModApiBasic::ModApiBasic() : ModApiBase() {
56 }
57
58 bool ModApiBasic::Initialize(lua_State* L,int top) {
59
60         bool retval = true;
61
62         retval &= API_FCT(debug);
63         retval &= API_FCT(log);
64         retval &= API_FCT(request_shutdown);
65         retval &= API_FCT(get_server_status);
66
67         retval &= API_FCT(register_biome);
68
69         retval &= API_FCT(setting_set);
70         retval &= API_FCT(setting_get);
71         retval &= API_FCT(setting_getbool);
72         retval &= API_FCT(setting_save);
73
74         retval &= API_FCT(chat_send_all);
75         retval &= API_FCT(chat_send_player);
76         retval &= API_FCT(show_formspec);
77
78         retval &= API_FCT(get_player_privs);
79         retval &= API_FCT(get_player_ip);
80         retval &= API_FCT(get_ban_list);
81         retval &= API_FCT(get_ban_description);
82         retval &= API_FCT(ban_player);
83         retval &= API_FCT(unban_player_or_ip);
84         retval &= API_FCT(get_password_hash);
85         retval &= API_FCT(notify_authentication_modified);
86
87         retval &= API_FCT(get_dig_params);
88         retval &= API_FCT(get_hit_params);
89
90         retval &= API_FCT(get_current_modname);
91         retval &= API_FCT(get_modpath);
92         retval &= API_FCT(get_modnames);
93
94         retval &= API_FCT(get_worldpath);
95         retval &= API_FCT(is_singleplayer);
96         retval &= API_FCT(sound_play);
97         retval &= API_FCT(sound_stop);
98
99         retval &= API_FCT(rollback_get_last_node_actor);
100         retval &= API_FCT(rollback_revert_actions_by);
101
102         retval &= API_FCT(register_ore);
103         retval &= API_FCT(register_decoration);
104
105         return retval;
106 }
107
108 // debug(text)
109 // Writes a line to dstream
110 int ModApiBasic::l_debug(lua_State *L)
111 {
112         NO_MAP_LOCK_REQUIRED;
113         std::string text = lua_tostring(L, 1);
114         dstream << text << std::endl;
115         return 0;
116 }
117
118 // log([level,] text)
119 // Writes a line to the logger.
120 // The one-argument version logs to infostream.
121 // The two-argument version accept a log level: error, action, info, or verbose.
122 int ModApiBasic::l_log(lua_State *L)
123 {
124         NO_MAP_LOCK_REQUIRED;
125         std::string text;
126         LogMessageLevel level = LMT_INFO;
127         if(lua_isnone(L, 2))
128         {
129                 text = lua_tostring(L, 1);
130         }
131         else
132         {
133                 std::string levelname = luaL_checkstring(L, 1);
134                 text = luaL_checkstring(L, 2);
135                 if(levelname == "error")
136                         level = LMT_ERROR;
137                 else if(levelname == "action")
138                         level = LMT_ACTION;
139                 else if(levelname == "verbose")
140                         level = LMT_VERBOSE;
141         }
142         log_printline(level, text);
143         return 0;
144 }
145
146 // request_shutdown()
147 int ModApiBasic::l_request_shutdown(lua_State *L)
148 {
149         getServer(L)->requestShutdown();
150         return 0;
151 }
152
153 // get_server_status()
154 int ModApiBasic::l_get_server_status(lua_State *L)
155 {
156         NO_MAP_LOCK_REQUIRED;
157         lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
158         return 1;
159 }
160
161 // register_biome({lots of stuff})
162 int ModApiBasic::l_register_biome(lua_State *L)
163 {
164         int index = 1;
165         luaL_checktype(L, index, LUA_TTABLE);
166
167         BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
168         if (!bmgr) {
169                 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
170                 return 0;
171         }
172
173         enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
174                                 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
175         Biome *b = bmgr->createBiome(terrain);
176
177         b->name            = getstringfield_default(L, index, "name", "");
178         b->top_nodename    = getstringfield_default(L, index, "top_node", "");
179         b->top_depth       = getintfield_default(L, index, "top_depth", 0);
180         b->filler_nodename = getstringfield_default(L, index, "filler_node", "");
181         b->filler_height   = getintfield_default(L, index, "filler_height", 0);
182         b->height_min      = getintfield_default(L, index, "height_min", 0);
183         b->height_max      = getintfield_default(L, index, "height_max", 0);
184         b->heat_point      = getfloatfield_default(L, index, "heat_point", 0.);
185         b->humidity_point  = getfloatfield_default(L, index, "humidity_point", 0.);
186
187         b->flags    = 0; //reserved
188         b->c_top    = CONTENT_IGNORE;
189         b->c_filler = CONTENT_IGNORE;
190         verbosestream << "register_biome: " << b->name << std::endl;
191         bmgr->addBiome(b);
192
193         return 0;
194 }
195
196 // setting_set(name, value)
197 int ModApiBasic::l_setting_set(lua_State *L)
198 {
199         NO_MAP_LOCK_REQUIRED;
200         const char *name = luaL_checkstring(L, 1);
201         const char *value = luaL_checkstring(L, 2);
202         g_settings->set(name, value);
203         return 0;
204 }
205
206 // setting_get(name)
207 int ModApiBasic::l_setting_get(lua_State *L)
208 {
209         NO_MAP_LOCK_REQUIRED;
210         const char *name = luaL_checkstring(L, 1);
211         try{
212                 std::string value = g_settings->get(name);
213                 lua_pushstring(L, value.c_str());
214         } catch(SettingNotFoundException &e){
215                 lua_pushnil(L);
216         }
217         return 1;
218 }
219
220 // setting_getbool(name)
221 int ModApiBasic::l_setting_getbool(lua_State *L)
222 {
223         NO_MAP_LOCK_REQUIRED;
224         const char *name = luaL_checkstring(L, 1);
225         try{
226                 bool value = g_settings->getBool(name);
227                 lua_pushboolean(L, value);
228         } catch(SettingNotFoundException &e){
229                 lua_pushnil(L);
230         }
231         return 1;
232 }
233
234 // setting_save()
235 int ModApiBasic::l_setting_save(lua_State *L)
236 {
237         NO_MAP_LOCK_REQUIRED;
238         getServer(L)->saveConfig();
239         return 0;
240 }
241
242 // chat_send_all(text)
243 int ModApiBasic::l_chat_send_all(lua_State *L)
244 {
245         NO_MAP_LOCK_REQUIRED;
246         const char *text = luaL_checkstring(L, 1);
247         // Get server from registry
248         Server *server = getServer(L);
249         // Send
250         server->notifyPlayers(narrow_to_wide(text));
251         return 0;
252 }
253
254 // chat_send_player(name, text, prepend)
255 int ModApiBasic::l_chat_send_player(lua_State *L)
256 {
257         NO_MAP_LOCK_REQUIRED;
258         const char *name = luaL_checkstring(L, 1);
259         const char *text = luaL_checkstring(L, 2);
260         bool prepend = true;
261
262         if (lua_isboolean(L, 3))
263                 prepend = lua_toboolean(L, 3);
264
265         // Get server from registry
266         Server *server = getServer(L);
267         // Send
268         server->notifyPlayer(name, narrow_to_wide(text), prepend);
269         return 0;
270 }
271
272 // get_player_privs(name, text)
273 int ModApiBasic::l_get_player_privs(lua_State *L)
274 {
275         NO_MAP_LOCK_REQUIRED;
276         const char *name = luaL_checkstring(L, 1);
277         // Get server from registry
278         Server *server = getServer(L);
279         // Do it
280         lua_newtable(L);
281         int table = lua_gettop(L);
282         std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
283         for(std::set<std::string>::const_iterator
284                         i = privs_s.begin(); i != privs_s.end(); i++){
285                 lua_pushboolean(L, true);
286                 lua_setfield(L, table, i->c_str());
287         }
288         lua_pushvalue(L, table);
289         return 1;
290 }
291
292 // get_player_ip()
293 int ModApiBasic::l_get_player_ip(lua_State *L)
294 {
295         NO_MAP_LOCK_REQUIRED;
296         const char * name = luaL_checkstring(L, 1);
297         Player *player = getEnv(L)->getPlayer(name);
298         if(player == NULL)
299         {
300                 lua_pushnil(L); // no such player
301                 return 1;
302         }
303         try
304         {
305                 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
306                 std::string ip_str = addr.serializeString();
307                 lua_pushstring(L, ip_str.c_str());
308                 return 1;
309         }
310         catch(con::PeerNotFoundException) // unlikely
311         {
312                 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
313                 lua_pushnil(L); // error
314                 return 1;
315         }
316 }
317
318 // get_ban_list()
319 int ModApiBasic::l_get_ban_list(lua_State *L)
320 {
321         NO_MAP_LOCK_REQUIRED;
322         lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
323         return 1;
324 }
325
326 // get_ban_description()
327 int ModApiBasic::l_get_ban_description(lua_State *L)
328 {
329         NO_MAP_LOCK_REQUIRED;
330         const char * ip_or_name = luaL_checkstring(L, 1);
331         lua_pushstring(L, getServer(L)->getBanDescription(std::string(ip_or_name)).c_str());
332         return 1;
333 }
334
335 // ban_player()
336 int ModApiBasic::l_ban_player(lua_State *L)
337 {
338         NO_MAP_LOCK_REQUIRED;
339         const char * name = luaL_checkstring(L, 1);
340         Player *player = getEnv(L)->getPlayer(name);
341         if(player == NULL)
342         {
343                 lua_pushboolean(L, false); // no such player
344                 return 1;
345         }
346         try
347         {
348                 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
349                 std::string ip_str = addr.serializeString();
350                 getServer(L)->setIpBanned(ip_str, name);
351         }
352         catch(con::PeerNotFoundException) // unlikely
353         {
354                 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
355                 lua_pushboolean(L, false); // error
356                 return 1;
357         }
358         lua_pushboolean(L, true);
359         return 1;
360 }
361
362 // unban_player_or_ip()
363 int ModApiBasic::l_unban_player_or_ip(lua_State *L)
364 {
365         NO_MAP_LOCK_REQUIRED;
366         const char * ip_or_name = luaL_checkstring(L, 1);
367         getServer(L)->unsetIpBanned(ip_or_name);
368         lua_pushboolean(L, true);
369         return 1;
370 }
371
372 // show_formspec(playername,formname,formspec)
373 int ModApiBasic::l_show_formspec(lua_State *L)
374 {
375         NO_MAP_LOCK_REQUIRED;
376         const char *playername = luaL_checkstring(L, 1);
377         const char *formname = luaL_checkstring(L, 2);
378         const char *formspec = luaL_checkstring(L, 3);
379
380         if(getServer(L)->showFormspec(playername,formspec,formname))
381         {
382                 lua_pushboolean(L, true);
383         }else{
384                 lua_pushboolean(L, false);
385         }
386         return 1;
387 }
388
389 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
390 int ModApiBasic::l_get_dig_params(lua_State *L)
391 {
392         NO_MAP_LOCK_REQUIRED;
393         std::map<std::string, int> groups;
394         read_groups(L, 1, groups);
395         ToolCapabilities tp = read_tool_capabilities(L, 2);
396         if(lua_isnoneornil(L, 3))
397                 push_dig_params(L, getDigParams(groups, &tp));
398         else
399                 push_dig_params(L, getDigParams(groups, &tp,
400                                         luaL_checknumber(L, 3)));
401         return 1;
402 }
403
404 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
405 int ModApiBasic::l_get_hit_params(lua_State *L)
406 {
407         NO_MAP_LOCK_REQUIRED;
408         std::map<std::string, int> groups;
409         read_groups(L, 1, groups);
410         ToolCapabilities tp = read_tool_capabilities(L, 2);
411         if(lua_isnoneornil(L, 3))
412                 push_hit_params(L, getHitParams(groups, &tp));
413         else
414                 push_hit_params(L, getHitParams(groups, &tp,
415                                         luaL_checknumber(L, 3)));
416         return 1;
417 }
418
419 // get_current_modname()
420 int ModApiBasic::l_get_current_modname(lua_State *L)
421 {
422         NO_MAP_LOCK_REQUIRED;
423         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
424         return 1;
425 }
426
427 // get_modpath(modname)
428 int ModApiBasic::l_get_modpath(lua_State *L)
429 {
430         NO_MAP_LOCK_REQUIRED;
431         std::string modname = luaL_checkstring(L, 1);
432         // Do it
433         if(modname == "__builtin"){
434                 std::string path = getServer(L)->getBuiltinLuaPath();
435                 lua_pushstring(L, path.c_str());
436                 return 1;
437         }
438         const ModSpec *mod = getServer(L)->getModSpec(modname);
439         if(!mod){
440                 lua_pushnil(L);
441                 return 1;
442         }
443         lua_pushstring(L, mod->path.c_str());
444         return 1;
445 }
446
447 // get_modnames()
448 // the returned list is sorted alphabetically for you
449 int ModApiBasic::l_get_modnames(lua_State *L)
450 {
451         NO_MAP_LOCK_REQUIRED;
452         // Get a list of mods
453         std::list<std::string> mods_unsorted, mods_sorted;
454         getServer(L)->getModNames(mods_unsorted);
455
456         // Take unsorted items from mods_unsorted and sort them into
457         // mods_sorted; not great performance but the number of mods on a
458         // server will likely be small.
459         for(std::list<std::string>::iterator i = mods_unsorted.begin();
460                 i != mods_unsorted.end(); ++i)
461         {
462                 bool added = false;
463                 for(std::list<std::string>::iterator x = mods_sorted.begin();
464                         x != mods_sorted.end(); ++x)
465                 {
466                         // I doubt anybody using Minetest will be using
467                         // anything not ASCII based :)
468                         if((*i).compare(*x) <= 0)
469                         {
470                                 mods_sorted.insert(x, *i);
471                                 added = true;
472                                 break;
473                         }
474                 }
475                 if(!added)
476                         mods_sorted.push_back(*i);
477         }
478
479         // Get the table insertion function from Lua.
480         lua_getglobal(L, "table");
481         lua_getfield(L, -1, "insert");
482         int insertion_func = lua_gettop(L);
483
484         // Package them up for Lua
485         lua_newtable(L);
486         int new_table = lua_gettop(L);
487         std::list<std::string>::iterator i = mods_sorted.begin();
488         while(i != mods_sorted.end())
489         {
490                 lua_pushvalue(L, insertion_func);
491                 lua_pushvalue(L, new_table);
492                 lua_pushstring(L, (*i).c_str());
493                 if(lua_pcall(L, 2, 0, 0) != 0)
494                 {
495                         script_error(L, "error: %s", lua_tostring(L, -1));
496                 }
497                 ++i;
498         }
499         return 1;
500 }
501
502 // get_worldpath()
503 int ModApiBasic::l_get_worldpath(lua_State *L)
504 {
505         NO_MAP_LOCK_REQUIRED;
506         std::string worldpath = getServer(L)->getWorldPath();
507         lua_pushstring(L, worldpath.c_str());
508         return 1;
509 }
510
511 // sound_play(spec, parameters)
512 int ModApiBasic::l_sound_play(lua_State *L)
513 {
514         NO_MAP_LOCK_REQUIRED;
515         SimpleSoundSpec spec;
516         read_soundspec(L, 1, spec);
517         ServerSoundParams params;
518         read_server_sound_params(L, 2, params);
519         s32 handle = getServer(L)->playSound(spec, params);
520         lua_pushinteger(L, handle);
521         return 1;
522 }
523
524 // sound_stop(handle)
525 int ModApiBasic::l_sound_stop(lua_State *L)
526 {
527         NO_MAP_LOCK_REQUIRED;
528         int handle = luaL_checkinteger(L, 1);
529         getServer(L)->stopSound(handle);
530         return 0;
531 }
532
533 // is_singleplayer()
534 int ModApiBasic::l_is_singleplayer(lua_State *L)
535 {
536         NO_MAP_LOCK_REQUIRED;
537         lua_pushboolean(L, getServer(L)->isSingleplayer());
538         return 1;
539 }
540
541 // get_password_hash(name, raw_password)
542 int ModApiBasic::l_get_password_hash(lua_State *L)
543 {
544         NO_MAP_LOCK_REQUIRED;
545         std::string name = luaL_checkstring(L, 1);
546         std::string raw_password = luaL_checkstring(L, 2);
547         std::string hash = translatePassword(name,
548                         narrow_to_wide(raw_password));
549         lua_pushstring(L, hash.c_str());
550         return 1;
551 }
552
553 // notify_authentication_modified(name)
554 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
555 {
556         NO_MAP_LOCK_REQUIRED;
557         std::string name = "";
558         if(lua_isstring(L, 1))
559                 name = lua_tostring(L, 1);
560         getServer(L)->reportPrivsModified(name);
561         return 0;
562 }
563
564 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
565 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
566 {
567         v3s16 p = read_v3s16(L, 1);
568         int range = luaL_checknumber(L, 2);
569         int seconds = luaL_checknumber(L, 3);
570         Server *server = getServer(L);
571         IRollbackManager *rollback = server->getRollbackManager();
572         v3s16 act_p;
573         int act_seconds = 0;
574         std::string actor = rollback->getLastNodeActor(p, range, seconds, &act_p, &act_seconds);
575         lua_pushstring(L, actor.c_str());
576         push_v3s16(L, act_p);
577         lua_pushnumber(L, act_seconds);
578         return 3;
579 }
580
581 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
582 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
583 {
584         std::string actor = luaL_checkstring(L, 1);
585         int seconds = luaL_checknumber(L, 2);
586         Server *server = getServer(L);
587         IRollbackManager *rollback = server->getRollbackManager();
588         std::list<RollbackAction> actions = rollback->getRevertActions(actor, seconds);
589         std::list<std::string> log;
590         bool success = server->rollbackRevertActions(actions, &log);
591         // Push boolean result
592         lua_pushboolean(L, success);
593         // Get the table insert function and push the log table
594         lua_getglobal(L, "table");
595         lua_getfield(L, -1, "insert");
596         int table_insert = lua_gettop(L);
597         lua_newtable(L);
598         int table = lua_gettop(L);
599         for(std::list<std::string>::const_iterator i = log.begin();
600                         i != log.end(); i++)
601         {
602                 lua_pushvalue(L, table_insert);
603                 lua_pushvalue(L, table);
604                 lua_pushstring(L, i->c_str());
605                 if(lua_pcall(L, 2, 0, 0))
606                         script_error(L, "error: %s", lua_tostring(L, -1));
607         }
608         lua_remove(L, -2); // Remove table
609         lua_remove(L, -2); // Remove insert
610         return 2;
611 }
612
613 int ModApiBasic::l_register_ore(lua_State *L)
614 {
615         int index = 1;
616         luaL_checktype(L, index, LUA_TTABLE);
617
618         EmergeManager *emerge = getServer(L)->getEmergeManager();
619
620         enum OreType oretype = (OreType)getenumfield(L, index,
621                                 "ore_type", es_OreType, ORE_SCATTER);
622         Ore *ore = createOre(oretype);
623         if (!ore) {
624                 errorstream << "register_ore: ore_type "
625                         << oretype << " not implemented";
626                 return 0;
627         }
628
629         ore->ore_name       = getstringfield_default(L, index, "ore", "");
630         ore->ore_param2     = (u8)getintfield_default(L, index, "ore_param2", 0);
631         ore->wherein_name   = getstringfield_default(L, index, "wherein", "");
632         ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
633         ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
634         ore->clust_size     = getintfield_default(L, index, "clust_size", 0);
635         ore->height_min     = getintfield_default(L, index, "height_min", 0);
636         ore->height_max     = getintfield_default(L, index, "height_max", 0);
637         ore->flags          = getflagsfield(L, index, "flags", flagdesc_ore);
638         ore->nthresh        = getfloatfield_default(L, index, "noise_threshhold", 0.);
639
640         lua_getfield(L, index, "noise_params");
641         ore->np = read_noiseparams(L, -1);
642         lua_pop(L, 1);
643
644         ore->noise = NULL;
645
646         if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
647                 errorstream << "register_ore: clust_scarcity and clust_num_ores"
648                         "must be greater than 0" << std::endl;
649                 delete ore;
650                 return 0;
651         }
652
653         emerge->ores.push_back(ore);
654
655         verbosestream << "register_ore: ore '" << ore->ore_name
656                 << "' registered" << std::endl;
657         return 0;
658 }
659
660 // register_decoration({lots of stuff})
661 int ModApiBasic::l_register_decoration(lua_State *L)
662 {
663         int index = 1;
664         luaL_checktype(L, index, LUA_TTABLE);
665         
666         EmergeManager *emerge = getServer(L)->getEmergeManager();
667         BiomeDefManager *bdef = emerge->biomedef;
668
669         enum DecorationType decotype = (DecorationType)getenumfield(L, index,
670                                 "deco_type", es_DecorationType, -1);
671         if (decotype == -1) {
672                 errorstream << "register_decoration: unrecognized "
673                         "decoration placement type";
674                 return 0;
675         }
676         
677         Decoration *deco = createDecoration(decotype);
678         if (!deco) {
679                 errorstream << "register_decoration: decoration placement type "
680                         << decotype << " not implemented";
681                 return 0;
682         }
683
684         deco->c_place_on    = CONTENT_IGNORE;
685         deco->place_on_name = getstringfield_default(L, index, "place_on", "ignore");
686         deco->divlen        = getintfield_default(L, index, "divlen", 8);
687         deco->fill_ratio    = getfloatfield_default(L, index, "fill_ratio", 0.02);
688         
689         lua_getfield(L, index, "noise_params");
690         deco->np = read_noiseparams(L, -1);
691         lua_pop(L, 1);
692         
693         lua_getfield(L, index, "biomes");
694         if (lua_istable(L, -1)) {
695                 lua_pushnil(L);
696                 while (lua_next(L, -2)) {
697                         const char *s = lua_tostring(L, -1);
698                         u8 biomeid = bdef->getBiomeIdByName(s);
699                         if (biomeid)
700                                 deco->biomes.insert(biomeid);
701
702                         lua_pop(L, 1);
703                 }
704                 lua_pop(L, 1);
705         }
706         
707         switch (decotype) {
708                 case DECO_SIMPLE: {
709                         DecoSimple *dsimple = (DecoSimple *)deco;
710                         dsimple->c_deco     = CONTENT_IGNORE;
711                         dsimple->c_spawnby  = CONTENT_IGNORE;
712                         dsimple->spawnby_name    = getstringfield_default(L, index, "spawn_by", "air");
713                         dsimple->deco_height     = getintfield_default(L, index, "height", 1);
714                         dsimple->deco_height_max = getintfield_default(L, index, "height_max", 0);
715                         dsimple->nspawnby        = getintfield_default(L, index, "num_spawn_by", -1);
716                         
717                         lua_getfield(L, index, "decoration");
718                         if (lua_istable(L, -1)) {
719                                 lua_pushnil(L);
720                                 while (lua_next(L, -2)) {
721                                         const char *s = lua_tostring(L, -1);
722                                         std::string str(s);
723                                         dsimple->decolist_names.push_back(str);
724
725                                         lua_pop(L, 1);
726                                 }
727                         } else if (lua_isstring(L, -1)) {
728                                 dsimple->deco_name  = std::string(lua_tostring(L, -1));
729                         } else {
730                                 dsimple->deco_name = std::string("air");
731                         }
732                         lua_pop(L, 1);
733                         
734                         if (dsimple->deco_height <= 0) {
735                                 errorstream << "register_decoration: simple decoration height"
736                                         " must be greater than 0" << std::endl;
737                                 delete dsimple;
738                                 return 0;
739                         }
740
741                         break; }
742                 case DECO_SCHEMATIC: {
743                         //DecoSchematic *decoschematic = (DecoSchematic *)deco;
744                         
745                         break; }
746                 case DECO_LSYSTEM: {
747                         //DecoLSystem *decolsystem = (DecoLSystem *)deco;
748                 
749                         break; }
750         }
751         
752         if (deco->divlen <= 0) {
753                 errorstream << "register_decoration: divlen must be "
754                         "greater than 0" << std::endl;
755                 delete deco;
756                 return 0;
757         }
758         
759         emerge->decorations.push_back(deco);
760
761         verbosestream << "register_decoration: decoration '" << deco->getName()
762                 << "' registered" << std::endl;
763         return 0;
764 }
765
766
767 ModApiBasic modapibasic_prototype;