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 std::string text = lua_tostring(L, 1);
114 dstream << text << std::endl;
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)
124 NO_MAP_LOCK_REQUIRED;
126 LogMessageLevel level = LMT_INFO;
129 text = lua_tostring(L, 1);
133 std::string levelname = luaL_checkstring(L, 1);
134 text = luaL_checkstring(L, 2);
135 if(levelname == "error")
137 else if(levelname == "action")
139 else if(levelname == "verbose")
142 log_printline(level, text);
146 // request_shutdown()
147 int ModApiBasic::l_request_shutdown(lua_State *L)
149 getServer(L)->requestShutdown();
153 // get_server_status()
154 int ModApiBasic::l_get_server_status(lua_State *L)
156 NO_MAP_LOCK_REQUIRED;
157 lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
161 // register_biome({lots of stuff})
162 int ModApiBasic::l_register_biome(lua_State *L)
165 luaL_checktype(L, index, LUA_TTABLE);
167 BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
169 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
173 enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
174 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
175 Biome *b = bmgr->createBiome(terrain);
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.);
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;
196 // setting_set(name, value)
197 int ModApiBasic::l_setting_set(lua_State *L)
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);
207 int ModApiBasic::l_setting_get(lua_State *L)
209 NO_MAP_LOCK_REQUIRED;
210 const char *name = luaL_checkstring(L, 1);
212 std::string value = g_settings->get(name);
213 lua_pushstring(L, value.c_str());
214 } catch(SettingNotFoundException &e){
220 // setting_getbool(name)
221 int ModApiBasic::l_setting_getbool(lua_State *L)
223 NO_MAP_LOCK_REQUIRED;
224 const char *name = luaL_checkstring(L, 1);
226 bool value = g_settings->getBool(name);
227 lua_pushboolean(L, value);
228 } catch(SettingNotFoundException &e){
235 int ModApiBasic::l_setting_save(lua_State *L)
237 NO_MAP_LOCK_REQUIRED;
238 getServer(L)->saveConfig();
242 // chat_send_all(text)
243 int ModApiBasic::l_chat_send_all(lua_State *L)
245 NO_MAP_LOCK_REQUIRED;
246 const char *text = luaL_checkstring(L, 1);
247 // Get server from registry
248 Server *server = getServer(L);
250 server->notifyPlayers(narrow_to_wide(text));
254 // chat_send_player(name, text, prepend)
255 int ModApiBasic::l_chat_send_player(lua_State *L)
257 NO_MAP_LOCK_REQUIRED;
258 const char *name = luaL_checkstring(L, 1);
259 const char *text = luaL_checkstring(L, 2);
262 if (lua_isboolean(L, 3))
263 prepend = lua_toboolean(L, 3);
265 // Get server from registry
266 Server *server = getServer(L);
268 server->notifyPlayer(name, narrow_to_wide(text), prepend);
272 // get_player_privs(name, text)
273 int ModApiBasic::l_get_player_privs(lua_State *L)
275 NO_MAP_LOCK_REQUIRED;
276 const char *name = luaL_checkstring(L, 1);
277 // Get server from registry
278 Server *server = getServer(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());
288 lua_pushvalue(L, table);
293 int ModApiBasic::l_get_player_ip(lua_State *L)
295 NO_MAP_LOCK_REQUIRED;
296 const char * name = luaL_checkstring(L, 1);
297 Player *player = getEnv(L)->getPlayer(name);
300 lua_pushnil(L); // no such player
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());
310 catch(con::PeerNotFoundException) // unlikely
312 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
313 lua_pushnil(L); // error
319 int ModApiBasic::l_get_ban_list(lua_State *L)
321 NO_MAP_LOCK_REQUIRED;
322 lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
326 // get_ban_description()
327 int ModApiBasic::l_get_ban_description(lua_State *L)
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());
336 int ModApiBasic::l_ban_player(lua_State *L)
338 NO_MAP_LOCK_REQUIRED;
339 const char * name = luaL_checkstring(L, 1);
340 Player *player = getEnv(L)->getPlayer(name);
343 lua_pushboolean(L, false); // no such player
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);
352 catch(con::PeerNotFoundException) // unlikely
354 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
355 lua_pushboolean(L, false); // error
358 lua_pushboolean(L, true);
362 // unban_player_or_ip()
363 int ModApiBasic::l_unban_player_or_ip(lua_State *L)
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);
372 // show_formspec(playername,formname,formspec)
373 int ModApiBasic::l_show_formspec(lua_State *L)
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);
380 if(getServer(L)->showFormspec(playername,formspec,formname))
382 lua_pushboolean(L, true);
384 lua_pushboolean(L, false);
389 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
390 int ModApiBasic::l_get_dig_params(lua_State *L)
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));
399 push_dig_params(L, getDigParams(groups, &tp,
400 luaL_checknumber(L, 3)));
404 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
405 int ModApiBasic::l_get_hit_params(lua_State *L)
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));
414 push_hit_params(L, getHitParams(groups, &tp,
415 luaL_checknumber(L, 3)));
419 // get_current_modname()
420 int ModApiBasic::l_get_current_modname(lua_State *L)
422 NO_MAP_LOCK_REQUIRED;
423 lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
427 // get_modpath(modname)
428 int ModApiBasic::l_get_modpath(lua_State *L)
430 NO_MAP_LOCK_REQUIRED;
431 std::string modname = luaL_checkstring(L, 1);
433 if(modname == "__builtin"){
434 std::string path = getServer(L)->getBuiltinLuaPath();
435 lua_pushstring(L, path.c_str());
438 const ModSpec *mod = getServer(L)->getModSpec(modname);
443 lua_pushstring(L, mod->path.c_str());
448 // the returned list is sorted alphabetically for you
449 int ModApiBasic::l_get_modnames(lua_State *L)
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);
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)
463 for(std::list<std::string>::iterator x = mods_sorted.begin();
464 x != mods_sorted.end(); ++x)
466 // I doubt anybody using Minetest will be using
467 // anything not ASCII based :)
468 if((*i).compare(*x) <= 0)
470 mods_sorted.insert(x, *i);
476 mods_sorted.push_back(*i);
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);
484 // Package them up for Lua
486 int new_table = lua_gettop(L);
487 std::list<std::string>::iterator i = mods_sorted.begin();
488 while(i != mods_sorted.end())
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)
495 script_error(L, "error: %s", lua_tostring(L, -1));
503 int ModApiBasic::l_get_worldpath(lua_State *L)
505 NO_MAP_LOCK_REQUIRED;
506 std::string worldpath = getServer(L)->getWorldPath();
507 lua_pushstring(L, worldpath.c_str());
511 // sound_play(spec, parameters)
512 int ModApiBasic::l_sound_play(lua_State *L)
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);
524 // sound_stop(handle)
525 int ModApiBasic::l_sound_stop(lua_State *L)
527 NO_MAP_LOCK_REQUIRED;
528 int handle = luaL_checkinteger(L, 1);
529 getServer(L)->stopSound(handle);
534 int ModApiBasic::l_is_singleplayer(lua_State *L)
536 NO_MAP_LOCK_REQUIRED;
537 lua_pushboolean(L, getServer(L)->isSingleplayer());
541 // get_password_hash(name, raw_password)
542 int ModApiBasic::l_get_password_hash(lua_State *L)
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());
553 // notify_authentication_modified(name)
554 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
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);
564 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
565 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
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();
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);
581 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
582 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
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);
598 int table = lua_gettop(L);
599 for(std::list<std::string>::const_iterator i = log.begin();
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));
608 lua_remove(L, -2); // Remove table
609 lua_remove(L, -2); // Remove insert
613 int ModApiBasic::l_register_ore(lua_State *L)
616 luaL_checktype(L, index, LUA_TTABLE);
618 EmergeManager *emerge = getServer(L)->getEmergeManager();
620 enum OreType oretype = (OreType)getenumfield(L, index,
621 "ore_type", es_OreType, ORE_SCATTER);
622 Ore *ore = createOre(oretype);
624 errorstream << "register_ore: ore_type "
625 << oretype << " not implemented";
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.);
640 lua_getfield(L, index, "noise_params");
641 ore->np = read_noiseparams(L, -1);
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;
653 emerge->ores.push_back(ore);
655 verbosestream << "register_ore: ore '" << ore->ore_name
656 << "' registered" << std::endl;
660 // register_decoration({lots of stuff})
661 int ModApiBasic::l_register_decoration(lua_State *L)
664 luaL_checktype(L, index, LUA_TTABLE);
666 EmergeManager *emerge = getServer(L)->getEmergeManager();
667 BiomeDefManager *bdef = emerge->biomedef;
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";
677 Decoration *deco = createDecoration(decotype);
679 errorstream << "register_decoration: decoration placement type "
680 << decotype << " not implemented";
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);
689 lua_getfield(L, index, "noise_params");
690 deco->np = read_noiseparams(L, -1);
693 lua_getfield(L, index, "biomes");
694 if (lua_istable(L, -1)) {
696 while (lua_next(L, -2)) {
697 const char *s = lua_tostring(L, -1);
698 u8 biomeid = bdef->getBiomeIdByName(s);
700 deco->biomes.insert(biomeid);
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);
717 lua_getfield(L, index, "decoration");
718 if (lua_istable(L, -1)) {
720 while (lua_next(L, -2)) {
721 const char *s = lua_tostring(L, -1);
723 dsimple->decolist_names.push_back(str);
727 } else if (lua_isstring(L, -1)) {
728 dsimple->deco_name = std::string(lua_tostring(L, -1));
730 dsimple->deco_name = std::string("air");
734 if (dsimple->deco_height <= 0) {
735 errorstream << "register_decoration: simple decoration height"
736 " must be greater than 0" << std::endl;
742 case DECO_SCHEMATIC: {
743 //DecoSchematic *decoschematic = (DecoSchematic *)deco;
747 //DecoLSystem *decolsystem = (DecoLSystem *)deco;
752 if (deco->divlen <= 0) {
753 errorstream << "register_decoration: divlen must be "
754 "greater than 0" << std::endl;
759 emerge->decorations.push_back(deco);
761 verbosestream << "register_decoration: decoration '" << deco->getName()
762 << "' registered" << std::endl;
767 ModApiBasic modapibasic_prototype;