3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
25 #include "lua_api/l_base.h"
26 #include "common/c_internal.h"
28 #include "common/c_converter.h"
29 #include "common/c_content.h"
30 #include "lua_api/luaapi.h"
36 #include "main.h" //required for g_settings
38 struct EnumString ModApiBasic::es_OreType[] =
40 {ORE_SCATTER, "scatter"},
42 {ORE_CLAYLIKE, "claylike"},
46 struct EnumString ModApiBasic::es_DecorationType[] =
48 {DECO_SIMPLE, "simple"},
49 {DECO_SCHEMATIC, "schematic"},
50 {DECO_LSYSTEM, "lsystem"},
54 struct EnumString ModApiBasic::es_Rotation[] =
60 {ROTATE_RAND, "random"},
65 ModApiBasic::ModApiBasic() : ModApiBase() {
68 bool ModApiBasic::Initialize(lua_State* L,int top) {
72 retval &= API_FCT(debug);
73 retval &= API_FCT(log);
74 retval &= API_FCT(request_shutdown);
75 retval &= API_FCT(get_server_status);
77 retval &= API_FCT(register_biome);
79 retval &= API_FCT(setting_set);
80 retval &= API_FCT(setting_get);
81 retval &= API_FCT(setting_getbool);
82 retval &= API_FCT(setting_save);
84 retval &= API_FCT(chat_send_all);
85 retval &= API_FCT(chat_send_player);
86 retval &= API_FCT(show_formspec);
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);
97 retval &= API_FCT(get_dig_params);
98 retval &= API_FCT(get_hit_params);
100 retval &= API_FCT(get_current_modname);
101 retval &= API_FCT(get_modpath);
102 retval &= API_FCT(get_modnames);
104 retval &= API_FCT(get_worldpath);
105 retval &= API_FCT(is_singleplayer);
106 retval &= API_FCT(sound_play);
107 retval &= API_FCT(sound_stop);
109 retval &= API_FCT(rollback_get_last_node_actor);
110 retval &= API_FCT(rollback_revert_actions_by);
112 retval &= API_FCT(register_ore);
113 retval &= API_FCT(register_decoration);
114 retval &= API_FCT(create_schematic);
115 retval &= API_FCT(place_schematic);
121 // Writes a line to dstream
122 int ModApiBasic::l_debug(lua_State *L)
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++){
130 Call tostring(i-th argument).
131 This is what print() does, and it behaves a bit
132 differently from directly calling lua_tostring.
134 lua_pushvalue(L, -1); /* function to be called */
135 lua_pushvalue(L, i); /* value to print */
137 const char *s = lua_tostring(L, -1);
144 dstream << std::endl;
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)
154 NO_MAP_LOCK_REQUIRED;
156 LogMessageLevel level = LMT_INFO;
159 text = lua_tostring(L, 1);
163 std::string levelname = luaL_checkstring(L, 1);
164 text = luaL_checkstring(L, 2);
165 if(levelname == "error")
167 else if(levelname == "action")
169 else if(levelname == "verbose")
172 log_printline(level, text);
176 // request_shutdown()
177 int ModApiBasic::l_request_shutdown(lua_State *L)
179 getServer(L)->requestShutdown();
183 // get_server_status()
184 int ModApiBasic::l_get_server_status(lua_State *L)
186 NO_MAP_LOCK_REQUIRED;
187 lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
191 // register_biome({lots of stuff})
192 int ModApiBasic::l_register_biome(lua_State *L)
195 luaL_checktype(L, index, LUA_TTABLE);
197 BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
199 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
203 enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
204 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
205 Biome *b = bmgr->createBiome(terrain);
207 b->name = getstringfield_default(L, index, "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",
213 b->nname_water = getstringfield_default(L, index, "node_water",
214 "mapgen_water_source");
215 b->nname_dust = getstringfield_default(L, index, "node_dust",
217 b->nname_dust_water = getstringfield_default(L, index, "node_dust_water",
218 "mapgen_water_source");
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.);
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;
234 verbosestream << "register_biome: " << b->name << std::endl;
240 // setting_set(name, value)
241 int ModApiBasic::l_setting_set(lua_State *L)
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);
251 int ModApiBasic::l_setting_get(lua_State *L)
253 NO_MAP_LOCK_REQUIRED;
254 const char *name = luaL_checkstring(L, 1);
256 std::string value = g_settings->get(name);
257 lua_pushstring(L, value.c_str());
258 } catch(SettingNotFoundException &e){
264 // setting_getbool(name)
265 int ModApiBasic::l_setting_getbool(lua_State *L)
267 NO_MAP_LOCK_REQUIRED;
268 const char *name = luaL_checkstring(L, 1);
270 bool value = g_settings->getBool(name);
271 lua_pushboolean(L, value);
272 } catch(SettingNotFoundException &e){
279 int ModApiBasic::l_setting_save(lua_State *L)
281 NO_MAP_LOCK_REQUIRED;
282 getServer(L)->saveConfig();
286 // chat_send_all(text)
287 int ModApiBasic::l_chat_send_all(lua_State *L)
289 NO_MAP_LOCK_REQUIRED;
290 const char *text = luaL_checkstring(L, 1);
291 // Get server from registry
292 Server *server = getServer(L);
294 server->notifyPlayers(narrow_to_wide(text));
298 // chat_send_player(name, text, prepend)
299 int ModApiBasic::l_chat_send_player(lua_State *L)
301 NO_MAP_LOCK_REQUIRED;
302 const char *name = luaL_checkstring(L, 1);
303 const char *text = luaL_checkstring(L, 2);
306 if (lua_isboolean(L, 3))
307 prepend = lua_toboolean(L, 3);
309 // Get server from registry
310 Server *server = getServer(L);
312 server->notifyPlayer(name, narrow_to_wide(text), prepend);
316 // get_player_privs(name, text)
317 int ModApiBasic::l_get_player_privs(lua_State *L)
319 NO_MAP_LOCK_REQUIRED;
320 const char *name = luaL_checkstring(L, 1);
321 // Get server from registry
322 Server *server = getServer(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());
332 lua_pushvalue(L, table);
337 int ModApiBasic::l_get_player_ip(lua_State *L)
339 NO_MAP_LOCK_REQUIRED;
340 const char * name = luaL_checkstring(L, 1);
341 Player *player = getEnv(L)->getPlayer(name);
344 lua_pushnil(L); // no such player
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());
354 catch(con::PeerNotFoundException) // unlikely
356 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
357 lua_pushnil(L); // error
363 int ModApiBasic::l_get_ban_list(lua_State *L)
365 NO_MAP_LOCK_REQUIRED;
366 lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
370 // get_ban_description()
371 int ModApiBasic::l_get_ban_description(lua_State *L)
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());
380 int ModApiBasic::l_ban_player(lua_State *L)
382 NO_MAP_LOCK_REQUIRED;
383 const char * name = luaL_checkstring(L, 1);
384 Player *player = getEnv(L)->getPlayer(name);
387 lua_pushboolean(L, false); // no such player
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);
396 catch(con::PeerNotFoundException) // unlikely
398 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
399 lua_pushboolean(L, false); // error
402 lua_pushboolean(L, true);
406 // unban_player_or_ip()
407 int ModApiBasic::l_unban_player_or_ip(lua_State *L)
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);
416 // show_formspec(playername,formname,formspec)
417 int ModApiBasic::l_show_formspec(lua_State *L)
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);
424 if(getServer(L)->showFormspec(playername,formspec,formname))
426 lua_pushboolean(L, true);
428 lua_pushboolean(L, false);
433 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
434 int ModApiBasic::l_get_dig_params(lua_State *L)
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));
443 push_dig_params(L, getDigParams(groups, &tp,
444 luaL_checknumber(L, 3)));
448 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
449 int ModApiBasic::l_get_hit_params(lua_State *L)
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));
458 push_hit_params(L, getHitParams(groups, &tp,
459 luaL_checknumber(L, 3)));
463 // get_current_modname()
464 int ModApiBasic::l_get_current_modname(lua_State *L)
466 NO_MAP_LOCK_REQUIRED;
467 lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
471 // get_modpath(modname)
472 int ModApiBasic::l_get_modpath(lua_State *L)
474 NO_MAP_LOCK_REQUIRED;
475 std::string modname = luaL_checkstring(L, 1);
477 if(modname == "__builtin"){
478 std::string path = getServer(L)->getBuiltinLuaPath();
479 lua_pushstring(L, path.c_str());
482 const ModSpec *mod = getServer(L)->getModSpec(modname);
487 lua_pushstring(L, mod->path.c_str());
492 // the returned list is sorted alphabetically for you
493 int ModApiBasic::l_get_modnames(lua_State *L)
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);
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)
507 for(std::list<std::string>::iterator x = mods_sorted.begin();
508 x != mods_sorted.end(); ++x)
510 // I doubt anybody using Minetest will be using
511 // anything not ASCII based :)
512 if((*i).compare(*x) <= 0)
514 mods_sorted.insert(x, *i);
520 mods_sorted.push_back(*i);
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);
528 // Package them up for Lua
530 int new_table = lua_gettop(L);
531 std::list<std::string>::iterator i = mods_sorted.begin();
532 while(i != mods_sorted.end())
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)
539 script_error(L, "error: %s", lua_tostring(L, -1));
547 int ModApiBasic::l_get_worldpath(lua_State *L)
549 NO_MAP_LOCK_REQUIRED;
550 std::string worldpath = getServer(L)->getWorldPath();
551 lua_pushstring(L, worldpath.c_str());
555 // sound_play(spec, parameters)
556 int ModApiBasic::l_sound_play(lua_State *L)
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);
568 // sound_stop(handle)
569 int ModApiBasic::l_sound_stop(lua_State *L)
571 NO_MAP_LOCK_REQUIRED;
572 int handle = luaL_checkinteger(L, 1);
573 getServer(L)->stopSound(handle);
578 int ModApiBasic::l_is_singleplayer(lua_State *L)
580 NO_MAP_LOCK_REQUIRED;
581 lua_pushboolean(L, getServer(L)->isSingleplayer());
585 // get_password_hash(name, raw_password)
586 int ModApiBasic::l_get_password_hash(lua_State *L)
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());
597 // notify_authentication_modified(name)
598 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
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);
608 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
609 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
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();
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);
625 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
626 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
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);
642 int table = lua_gettop(L);
643 for(std::list<std::string>::const_iterator i = log.begin();
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));
652 lua_remove(L, -2); // Remove table
653 lua_remove(L, -2); // Remove insert
657 int ModApiBasic::l_register_ore(lua_State *L)
660 luaL_checktype(L, index, LUA_TTABLE);
662 EmergeManager *emerge = getServer(L)->getEmergeManager();
664 enum OreType oretype = (OreType)getenumfield(L, index,
665 "ore_type", es_OreType, ORE_SCATTER);
666 Ore *ore = createOre(oretype);
668 errorstream << "register_ore: ore_type "
669 << oretype << " not implemented";
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.);
683 lua_getfield(L, index, "wherein");
684 if (lua_istable(L, -1)) {
685 int i = lua_gettop(L);
687 while(lua_next(L, i) != 0) {
688 ore->wherein_names.push_back(lua_tostring(L, -1));
691 } else if (lua_isstring(L, -1)) {
692 ore->wherein_names.push_back(lua_tostring(L, -1));
694 ore->wherein_names.push_back("");
698 lua_getfield(L, index, "noise_params");
699 ore->np = read_noiseparams(L, -1);
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;
711 emerge->ores.push_back(ore);
713 verbosestream << "register_ore: ore '" << ore->ore_name
714 << "' registered" << std::endl;
718 // register_decoration({lots of stuff})
719 int ModApiBasic::l_register_decoration(lua_State *L)
722 luaL_checktype(L, index, LUA_TTABLE);
724 EmergeManager *emerge = getServer(L)->getEmergeManager();
725 BiomeDefManager *bdef = emerge->biomedef;
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";
735 Decoration *deco = createDecoration(decotype);
737 errorstream << "register_decoration: decoration placement type "
738 << decotype << " not implemented";
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;
753 lua_getfield(L, index, "noise_params");
754 deco->np = read_noiseparams(L, -1);
757 lua_getfield(L, index, "biomes");
758 if (lua_istable(L, -1)) {
760 while (lua_next(L, -2)) {
761 const char *s = lua_tostring(L, -1);
762 u8 biomeid = bdef->getBiomeIdByName(s);
764 deco->biomes.insert(biomeid);
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);
781 lua_getfield(L, index, "decoration");
782 if (lua_istable(L, -1)) {
784 while (lua_next(L, -2)) {
785 const char *s = lua_tostring(L, -1);
787 dsimple->decolist_names.push_back(str);
791 } else if (lua_isstring(L, -1)) {
792 dsimple->deco_name = std::string(lua_tostring(L, -1));
794 dsimple->deco_name = std::string("air");
798 if (dsimple->deco_height <= 0) {
799 errorstream << "register_decoration: simple decoration height"
800 " must be greater than 0" << std::endl;
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);
812 lua_getfield(L, index, "replacements");
813 if (lua_istable(L, -1)) {
814 int i = lua_gettop(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);
821 lua_rawgeti(L, -1, 2);
822 std::string replace_to = lua_tostring(L, -1);
824 dschem->replacements[replace_from] = replace_to;
825 // removes value, keeps key for next iteration
831 lua_getfield(L, index, "schematic");
832 if (!read_schematic(L, -1, dschem, getServer(L))) {
838 if (!dschem->filename.empty() && !dschem->loadSchematicFile()) {
839 errorstream << "register_decoration: failed to load schematic file '"
840 << dschem->filename << "'" << std::endl;
846 //DecoLSystem *decolsystem = (DecoLSystem *)deco;
851 emerge->decorations.push_back(deco);
853 verbosestream << "register_decoration: decoration '" << deco->getName()
854 << "' registered" << std::endl;
858 // create_schematic(p1, p2, probability_list, filename)
859 int ModApiBasic::l_create_schematic(lua_State *L)
861 DecoSchematic dschem;
863 Map *map = &(getEnv(L)->getMap());
864 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
866 v3s16 p1 = read_v3s16(L, 1);
867 v3s16 p2 = read_v3s16(L, 2);
868 sortBoxVerticies(p1, p2);
870 std::vector<std::pair<v3s16, u8> > probability_list;
871 if (lua_istable(L, 3)) {
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);
879 u8 prob = getintfield_default(L, -1, "prob", 0xFF);
880 probability_list.push_back(std::make_pair(pos, prob));
887 dschem.filename = std::string(lua_tostring(L, 4));
889 if (!dschem.getSchematicFromMap(map, p1, p2)) {
890 errorstream << "create_schematic: failed to get schematic "
891 "from map" << std::endl;
895 dschem.applyProbabilities(&probability_list, p1);
897 dschem.saveSchematicFile(ndef);
898 actionstream << "create_schematic: saved schematic file '"
899 << dschem.filename << "'." << std::endl;
905 // place_schematic(p, schematic, rotation, replacement)
906 int ModApiBasic::l_place_schematic(lua_State *L)
908 DecoSchematic dschem;
910 Map *map = &(getEnv(L)->getMap());
911 INodeDefManager *ndef = getServer(L)->getNodeDefManager();
913 v3s16 p = read_v3s16(L, 1);
914 if (!read_schematic(L, 2, &dschem, getServer(L)))
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)));
921 dschem.rotation = rot;
923 if (lua_istable(L, 4)) {
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);
931 lua_rawgeti(L, -1, 2);
932 std::string replace_to = lua_tostring(L, -1);
934 dschem.replacements[replace_from] = replace_to;
935 // removes value, keeps key for next iteration
940 if (!dschem.filename.empty()) {
941 if (!dschem.loadSchematicFile()) {
942 errorstream << "place_schematic: failed to load schematic file '"
943 << dschem.filename << "'" << std::endl;
946 dschem.resolveNodeNames(ndef);
949 dschem.placeStructure(map, p);
955 ModApiBasic modapibasic_prototype;