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