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"},
55 ModApiBasic::ModApiBasic() : ModApiBase() {
58 bool ModApiBasic::Initialize(lua_State* L,int top) {
62 retval &= API_FCT(debug);
63 retval &= API_FCT(log);
64 retval &= API_FCT(request_shutdown);
65 retval &= API_FCT(get_server_status);
67 retval &= API_FCT(register_biome);
69 retval &= API_FCT(setting_set);
70 retval &= API_FCT(setting_get);
71 retval &= API_FCT(setting_getbool);
72 retval &= API_FCT(setting_save);
74 retval &= API_FCT(chat_send_all);
75 retval &= API_FCT(chat_send_player);
76 retval &= API_FCT(show_formspec);
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);
87 retval &= API_FCT(get_dig_params);
88 retval &= API_FCT(get_hit_params);
90 retval &= API_FCT(get_current_modname);
91 retval &= API_FCT(get_modpath);
92 retval &= API_FCT(get_modnames);
94 retval &= API_FCT(get_worldpath);
95 retval &= API_FCT(is_singleplayer);
96 retval &= API_FCT(sound_play);
97 retval &= API_FCT(sound_stop);
99 retval &= API_FCT(rollback_get_last_node_actor);
100 retval &= API_FCT(rollback_revert_actions_by);
102 retval &= API_FCT(register_ore);
103 retval &= API_FCT(register_decoration);
109 // Writes a line to dstream
110 int ModApiBasic::l_debug(lua_State *L)
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++){
118 Call tostring(i-th argument).
119 This is what print() does, and it behaves a bit
120 differently from directly calling lua_tostring.
122 lua_pushvalue(L, -1); /* function to be called */
123 lua_pushvalue(L, i); /* value to print */
125 const char *s = lua_tostring(L, -1);
132 dstream << std::endl;
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)
142 NO_MAP_LOCK_REQUIRED;
144 LogMessageLevel level = LMT_INFO;
147 text = lua_tostring(L, 1);
151 std::string levelname = luaL_checkstring(L, 1);
152 text = luaL_checkstring(L, 2);
153 if(levelname == "error")
155 else if(levelname == "action")
157 else if(levelname == "verbose")
160 log_printline(level, text);
164 // request_shutdown()
165 int ModApiBasic::l_request_shutdown(lua_State *L)
167 getServer(L)->requestShutdown();
171 // get_server_status()
172 int ModApiBasic::l_get_server_status(lua_State *L)
174 NO_MAP_LOCK_REQUIRED;
175 lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
179 // register_biome({lots of stuff})
180 int ModApiBasic::l_register_biome(lua_State *L)
183 luaL_checktype(L, index, LUA_TTABLE);
185 BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
187 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
191 enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
192 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
193 Biome *b = bmgr->createBiome(terrain);
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.);
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;
214 // setting_set(name, value)
215 int ModApiBasic::l_setting_set(lua_State *L)
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);
225 int ModApiBasic::l_setting_get(lua_State *L)
227 NO_MAP_LOCK_REQUIRED;
228 const char *name = luaL_checkstring(L, 1);
230 std::string value = g_settings->get(name);
231 lua_pushstring(L, value.c_str());
232 } catch(SettingNotFoundException &e){
238 // setting_getbool(name)
239 int ModApiBasic::l_setting_getbool(lua_State *L)
241 NO_MAP_LOCK_REQUIRED;
242 const char *name = luaL_checkstring(L, 1);
244 bool value = g_settings->getBool(name);
245 lua_pushboolean(L, value);
246 } catch(SettingNotFoundException &e){
253 int ModApiBasic::l_setting_save(lua_State *L)
255 NO_MAP_LOCK_REQUIRED;
256 getServer(L)->saveConfig();
260 // chat_send_all(text)
261 int ModApiBasic::l_chat_send_all(lua_State *L)
263 NO_MAP_LOCK_REQUIRED;
264 const char *text = luaL_checkstring(L, 1);
265 // Get server from registry
266 Server *server = getServer(L);
268 server->notifyPlayers(narrow_to_wide(text));
272 // chat_send_player(name, text, prepend)
273 int ModApiBasic::l_chat_send_player(lua_State *L)
275 NO_MAP_LOCK_REQUIRED;
276 const char *name = luaL_checkstring(L, 1);
277 const char *text = luaL_checkstring(L, 2);
280 if (lua_isboolean(L, 3))
281 prepend = lua_toboolean(L, 3);
283 // Get server from registry
284 Server *server = getServer(L);
286 server->notifyPlayer(name, narrow_to_wide(text), prepend);
290 // get_player_privs(name, text)
291 int ModApiBasic::l_get_player_privs(lua_State *L)
293 NO_MAP_LOCK_REQUIRED;
294 const char *name = luaL_checkstring(L, 1);
295 // Get server from registry
296 Server *server = getServer(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());
306 lua_pushvalue(L, table);
311 int ModApiBasic::l_get_player_ip(lua_State *L)
313 NO_MAP_LOCK_REQUIRED;
314 const char * name = luaL_checkstring(L, 1);
315 Player *player = getEnv(L)->getPlayer(name);
318 lua_pushnil(L); // no such player
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());
328 catch(con::PeerNotFoundException) // unlikely
330 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
331 lua_pushnil(L); // error
337 int ModApiBasic::l_get_ban_list(lua_State *L)
339 NO_MAP_LOCK_REQUIRED;
340 lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
344 // get_ban_description()
345 int ModApiBasic::l_get_ban_description(lua_State *L)
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());
354 int ModApiBasic::l_ban_player(lua_State *L)
356 NO_MAP_LOCK_REQUIRED;
357 const char * name = luaL_checkstring(L, 1);
358 Player *player = getEnv(L)->getPlayer(name);
361 lua_pushboolean(L, false); // no such player
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);
370 catch(con::PeerNotFoundException) // unlikely
372 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
373 lua_pushboolean(L, false); // error
376 lua_pushboolean(L, true);
380 // unban_player_or_ip()
381 int ModApiBasic::l_unban_player_or_ip(lua_State *L)
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);
390 // show_formspec(playername,formname,formspec)
391 int ModApiBasic::l_show_formspec(lua_State *L)
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);
398 if(getServer(L)->showFormspec(playername,formspec,formname))
400 lua_pushboolean(L, true);
402 lua_pushboolean(L, false);
407 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
408 int ModApiBasic::l_get_dig_params(lua_State *L)
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));
417 push_dig_params(L, getDigParams(groups, &tp,
418 luaL_checknumber(L, 3)));
422 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
423 int ModApiBasic::l_get_hit_params(lua_State *L)
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));
432 push_hit_params(L, getHitParams(groups, &tp,
433 luaL_checknumber(L, 3)));
437 // get_current_modname()
438 int ModApiBasic::l_get_current_modname(lua_State *L)
440 NO_MAP_LOCK_REQUIRED;
441 lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
445 // get_modpath(modname)
446 int ModApiBasic::l_get_modpath(lua_State *L)
448 NO_MAP_LOCK_REQUIRED;
449 std::string modname = luaL_checkstring(L, 1);
451 if(modname == "__builtin"){
452 std::string path = getServer(L)->getBuiltinLuaPath();
453 lua_pushstring(L, path.c_str());
456 const ModSpec *mod = getServer(L)->getModSpec(modname);
461 lua_pushstring(L, mod->path.c_str());
466 // the returned list is sorted alphabetically for you
467 int ModApiBasic::l_get_modnames(lua_State *L)
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);
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)
481 for(std::list<std::string>::iterator x = mods_sorted.begin();
482 x != mods_sorted.end(); ++x)
484 // I doubt anybody using Minetest will be using
485 // anything not ASCII based :)
486 if((*i).compare(*x) <= 0)
488 mods_sorted.insert(x, *i);
494 mods_sorted.push_back(*i);
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);
502 // Package them up for Lua
504 int new_table = lua_gettop(L);
505 std::list<std::string>::iterator i = mods_sorted.begin();
506 while(i != mods_sorted.end())
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)
513 script_error(L, "error: %s", lua_tostring(L, -1));
521 int ModApiBasic::l_get_worldpath(lua_State *L)
523 NO_MAP_LOCK_REQUIRED;
524 std::string worldpath = getServer(L)->getWorldPath();
525 lua_pushstring(L, worldpath.c_str());
529 // sound_play(spec, parameters)
530 int ModApiBasic::l_sound_play(lua_State *L)
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);
542 // sound_stop(handle)
543 int ModApiBasic::l_sound_stop(lua_State *L)
545 NO_MAP_LOCK_REQUIRED;
546 int handle = luaL_checkinteger(L, 1);
547 getServer(L)->stopSound(handle);
552 int ModApiBasic::l_is_singleplayer(lua_State *L)
554 NO_MAP_LOCK_REQUIRED;
555 lua_pushboolean(L, getServer(L)->isSingleplayer());
559 // get_password_hash(name, raw_password)
560 int ModApiBasic::l_get_password_hash(lua_State *L)
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());
571 // notify_authentication_modified(name)
572 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
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);
582 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
583 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
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();
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);
599 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
600 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
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);
616 int table = lua_gettop(L);
617 for(std::list<std::string>::const_iterator i = log.begin();
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));
626 lua_remove(L, -2); // Remove table
627 lua_remove(L, -2); // Remove insert
631 int ModApiBasic::l_register_ore(lua_State *L)
634 luaL_checktype(L, index, LUA_TTABLE);
636 EmergeManager *emerge = getServer(L)->getEmergeManager();
638 enum OreType oretype = (OreType)getenumfield(L, index,
639 "ore_type", es_OreType, ORE_SCATTER);
640 Ore *ore = createOre(oretype);
642 errorstream << "register_ore: ore_type "
643 << oretype << " not implemented";
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.);
658 lua_getfield(L, index, "noise_params");
659 ore->np = read_noiseparams(L, -1);
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;
671 emerge->ores.push_back(ore);
673 verbosestream << "register_ore: ore '" << ore->ore_name
674 << "' registered" << std::endl;
678 // register_decoration({lots of stuff})
679 int ModApiBasic::l_register_decoration(lua_State *L)
682 luaL_checktype(L, index, LUA_TTABLE);
684 EmergeManager *emerge = getServer(L)->getEmergeManager();
685 BiomeDefManager *bdef = emerge->biomedef;
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";
695 Decoration *deco = createDecoration(decotype);
697 errorstream << "register_decoration: decoration placement type "
698 << decotype << " not implemented";
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);
707 lua_getfield(L, index, "noise_params");
708 deco->np = read_noiseparams(L, -1);
711 lua_getfield(L, index, "biomes");
712 if (lua_istable(L, -1)) {
714 while (lua_next(L, -2)) {
715 const char *s = lua_tostring(L, -1);
716 u8 biomeid = bdef->getBiomeIdByName(s);
718 deco->biomes.insert(biomeid);
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);
735 lua_getfield(L, index, "decoration");
736 if (lua_istable(L, -1)) {
738 while (lua_next(L, -2)) {
739 const char *s = lua_tostring(L, -1);
741 dsimple->decolist_names.push_back(str);
745 } else if (lua_isstring(L, -1)) {
746 dsimple->deco_name = std::string(lua_tostring(L, -1));
748 dsimple->deco_name = std::string("air");
752 if (dsimple->deco_height <= 0) {
753 errorstream << "register_decoration: simple decoration height"
754 " must be greater than 0" << std::endl;
760 case DECO_SCHEMATIC: {
761 //DecoSchematic *decoschematic = (DecoSchematic *)deco;
765 //DecoLSystem *decolsystem = (DecoLSystem *)deco;
770 if (deco->sidelen <= 0) {
771 errorstream << "register_decoration: sidelen must be "
772 "greater than 0" << std::endl;
777 emerge->decorations.push_back(deco);
779 verbosestream << "register_decoration: decoration '" << deco->getName()
780 << "' registered" << std::endl;
785 ModApiBasic modapibasic_prototype;