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"},
47 ModApiBasic::ModApiBasic() : ModApiBase() {
50 bool ModApiBasic::Initialize(lua_State* L,int top) {
54 retval &= API_FCT(debug);
55 retval &= API_FCT(log);
56 retval &= API_FCT(request_shutdown);
57 retval &= API_FCT(get_server_status);
59 retval &= API_FCT(register_biome);
61 retval &= API_FCT(setting_set);
62 retval &= API_FCT(setting_get);
63 retval &= API_FCT(setting_getbool);
64 retval &= API_FCT(setting_save);
66 retval &= API_FCT(chat_send_all);
67 retval &= API_FCT(chat_send_player);
68 retval &= API_FCT(show_formspec);
70 retval &= API_FCT(get_player_privs);
71 retval &= API_FCT(get_player_ip);
72 retval &= API_FCT(get_ban_list);
73 retval &= API_FCT(get_ban_description);
74 retval &= API_FCT(ban_player);
75 retval &= API_FCT(unban_player_of_ip);
76 retval &= API_FCT(get_password_hash);
77 retval &= API_FCT(notify_authentication_modified);
79 retval &= API_FCT(get_dig_params);
80 retval &= API_FCT(get_hit_params);
82 retval &= API_FCT(get_current_modname);
83 retval &= API_FCT(get_modpath);
84 retval &= API_FCT(get_modnames);
86 retval &= API_FCT(get_worldpath);
87 retval &= API_FCT(is_singleplayer);
88 retval &= API_FCT(sound_play);
89 retval &= API_FCT(sound_stop);
91 retval &= API_FCT(rollback_get_last_node_actor);
92 retval &= API_FCT(rollback_revert_actions_by);
94 retval &= API_FCT(register_ore);
100 // Writes a line to dstream
101 int ModApiBasic::l_debug(lua_State *L)
103 NO_MAP_LOCK_REQUIRED;
104 std::string text = lua_tostring(L, 1);
105 dstream << text << std::endl;
109 // log([level,] text)
110 // Writes a line to the logger.
111 // The one-argument version logs to infostream.
112 // The two-argument version accept a log level: error, action, info, or verbose.
113 int ModApiBasic::l_log(lua_State *L)
115 NO_MAP_LOCK_REQUIRED;
117 LogMessageLevel level = LMT_INFO;
120 text = lua_tostring(L, 1);
124 std::string levelname = luaL_checkstring(L, 1);
125 text = luaL_checkstring(L, 2);
126 if(levelname == "error")
128 else if(levelname == "action")
130 else if(levelname == "verbose")
133 log_printline(level, text);
137 // request_shutdown()
138 int ModApiBasic::l_request_shutdown(lua_State *L)
140 getServer(L)->requestShutdown();
144 // get_server_status()
145 int ModApiBasic::l_get_server_status(lua_State *L)
147 NO_MAP_LOCK_REQUIRED;
148 lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
152 // register_biome({lots of stuff})
153 int ModApiBasic::l_register_biome(lua_State *L)
156 luaL_checktype(L, index, LUA_TTABLE);
158 BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
160 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
164 enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
165 "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
166 Biome *b = bmgr->createBiome(terrain);
168 b->name = getstringfield_default(L, index, "name", "");
169 b->top_nodename = getstringfield_default(L, index, "top_node", "");
170 b->top_depth = getintfield_default(L, index, "top_depth", 0);
171 b->filler_nodename = getstringfield_default(L, index, "filler_node", "");
172 b->filler_height = getintfield_default(L, index, "filler_height", 0);
173 b->height_min = getintfield_default(L, index, "height_min", 0);
174 b->height_max = getintfield_default(L, index, "height_max", 0);
175 b->heat_point = getfloatfield_default(L, index, "heat_point", 0.);
176 b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.);
178 b->flags = 0; //reserved
179 b->c_top = CONTENT_IGNORE;
180 b->c_filler = CONTENT_IGNORE;
181 verbosestream << "register_biome: " << b->name << std::endl;
189 // setting_set(name, value)
190 int ModApiBasic::l_setting_set(lua_State *L)
192 NO_MAP_LOCK_REQUIRED;
193 const char *name = luaL_checkstring(L, 1);
194 const char *value = luaL_checkstring(L, 2);
195 g_settings->set(name, value);
200 int ModApiBasic::l_setting_get(lua_State *L)
202 NO_MAP_LOCK_REQUIRED;
203 const char *name = luaL_checkstring(L, 1);
205 std::string value = g_settings->get(name);
206 lua_pushstring(L, value.c_str());
207 } catch(SettingNotFoundException &e){
213 // setting_getbool(name)
214 int ModApiBasic::l_setting_getbool(lua_State *L)
216 NO_MAP_LOCK_REQUIRED;
217 const char *name = luaL_checkstring(L, 1);
219 bool value = g_settings->getBool(name);
220 lua_pushboolean(L, value);
221 } catch(SettingNotFoundException &e){
228 int ModApiBasic::l_setting_save(lua_State *L)
230 NO_MAP_LOCK_REQUIRED;
231 getServer(L)->saveConfig();
235 // chat_send_all(text)
236 int ModApiBasic::l_chat_send_all(lua_State *L)
238 NO_MAP_LOCK_REQUIRED;
239 const char *text = luaL_checkstring(L, 1);
240 // Get server from registry
241 Server *server = getServer(L);
243 server->notifyPlayers(narrow_to_wide(text));
247 // chat_send_player(name, text, prepend)
248 int ModApiBasic::l_chat_send_player(lua_State *L)
250 NO_MAP_LOCK_REQUIRED;
251 const char *name = luaL_checkstring(L, 1);
252 const char *text = luaL_checkstring(L, 2);
255 if (lua_isboolean(L, 3))
256 prepend = lua_toboolean(L, 3);
258 // Get server from registry
259 Server *server = getServer(L);
261 server->notifyPlayer(name, narrow_to_wide(text), prepend);
265 // get_player_privs(name, text)
266 int ModApiBasic::l_get_player_privs(lua_State *L)
268 NO_MAP_LOCK_REQUIRED;
269 const char *name = luaL_checkstring(L, 1);
270 // Get server from registry
271 Server *server = getServer(L);
274 int table = lua_gettop(L);
275 std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
276 for(std::set<std::string>::const_iterator
277 i = privs_s.begin(); i != privs_s.end(); i++){
278 lua_pushboolean(L, true);
279 lua_setfield(L, table, i->c_str());
281 lua_pushvalue(L, table);
286 int ModApiBasic::l_get_player_ip(lua_State *L)
288 NO_MAP_LOCK_REQUIRED;
289 const char * name = luaL_checkstring(L, 1);
290 Player *player = getEnv(L)->getPlayer(name);
293 lua_pushnil(L); // no such player
298 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
299 std::string ip_str = addr.serializeString();
300 lua_pushstring(L, ip_str.c_str());
303 catch(con::PeerNotFoundException) // unlikely
305 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
306 lua_pushnil(L); // error
312 int ModApiBasic::l_get_ban_list(lua_State *L)
314 NO_MAP_LOCK_REQUIRED;
315 lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
319 // get_ban_description()
320 int ModApiBasic::l_get_ban_description(lua_State *L)
322 NO_MAP_LOCK_REQUIRED;
323 const char * ip_or_name = luaL_checkstring(L, 1);
324 lua_pushstring(L, getServer(L)->getBanDescription(std::string(ip_or_name)).c_str());
329 int ModApiBasic::l_ban_player(lua_State *L)
331 NO_MAP_LOCK_REQUIRED;
332 const char * name = luaL_checkstring(L, 1);
333 Player *player = getEnv(L)->getPlayer(name);
336 lua_pushboolean(L, false); // no such player
341 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
342 std::string ip_str = addr.serializeString();
343 getServer(L)->setIpBanned(ip_str, name);
345 catch(con::PeerNotFoundException) // unlikely
347 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
348 lua_pushboolean(L, false); // error
351 lua_pushboolean(L, true);
355 // unban_player_or_ip()
356 int ModApiBasic::l_unban_player_of_ip(lua_State *L)
358 NO_MAP_LOCK_REQUIRED;
359 const char * ip_or_name = luaL_checkstring(L, 1);
360 getServer(L)->unsetIpBanned(ip_or_name);
361 lua_pushboolean(L, true);
365 // show_formspec(playername,formname,formspec)
366 int ModApiBasic::l_show_formspec(lua_State *L)
368 NO_MAP_LOCK_REQUIRED;
369 const char *playername = luaL_checkstring(L, 1);
370 const char *formname = luaL_checkstring(L, 2);
371 const char *formspec = luaL_checkstring(L, 3);
373 if(getServer(L)->showFormspec(playername,formspec,formname))
375 lua_pushboolean(L, true);
377 lua_pushboolean(L, false);
382 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
383 int ModApiBasic::l_get_dig_params(lua_State *L)
385 NO_MAP_LOCK_REQUIRED;
386 std::map<std::string, int> groups;
387 read_groups(L, 1, groups);
388 ToolCapabilities tp = read_tool_capabilities(L, 2);
389 if(lua_isnoneornil(L, 3))
390 push_dig_params(L, getDigParams(groups, &tp));
392 push_dig_params(L, getDigParams(groups, &tp,
393 luaL_checknumber(L, 3)));
397 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
398 int ModApiBasic::l_get_hit_params(lua_State *L)
400 NO_MAP_LOCK_REQUIRED;
401 std::map<std::string, int> groups;
402 read_groups(L, 1, groups);
403 ToolCapabilities tp = read_tool_capabilities(L, 2);
404 if(lua_isnoneornil(L, 3))
405 push_hit_params(L, getHitParams(groups, &tp));
407 push_hit_params(L, getHitParams(groups, &tp,
408 luaL_checknumber(L, 3)));
412 // get_current_modname()
413 int ModApiBasic::l_get_current_modname(lua_State *L)
415 NO_MAP_LOCK_REQUIRED;
416 lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
420 // get_modpath(modname)
421 int ModApiBasic::l_get_modpath(lua_State *L)
423 NO_MAP_LOCK_REQUIRED;
424 std::string modname = luaL_checkstring(L, 1);
426 if(modname == "__builtin"){
427 std::string path = getServer(L)->getBuiltinLuaPath();
428 lua_pushstring(L, path.c_str());
431 const ModSpec *mod = getServer(L)->getModSpec(modname);
436 lua_pushstring(L, mod->path.c_str());
441 // the returned list is sorted alphabetically for you
442 int ModApiBasic::l_get_modnames(lua_State *L)
444 NO_MAP_LOCK_REQUIRED;
445 // Get a list of mods
446 std::list<std::string> mods_unsorted, mods_sorted;
447 getServer(L)->getModNames(mods_unsorted);
449 // Take unsorted items from mods_unsorted and sort them into
450 // mods_sorted; not great performance but the number of mods on a
451 // server will likely be small.
452 for(std::list<std::string>::iterator i = mods_unsorted.begin();
453 i != mods_unsorted.end(); ++i)
456 for(std::list<std::string>::iterator x = mods_sorted.begin();
457 x != mods_sorted.end(); ++x)
459 // I doubt anybody using Minetest will be using
460 // anything not ASCII based :)
461 if((*i).compare(*x) <= 0)
463 mods_sorted.insert(x, *i);
469 mods_sorted.push_back(*i);
472 // Get the table insertion function from Lua.
473 lua_getglobal(L, "table");
474 lua_getfield(L, -1, "insert");
475 int insertion_func = lua_gettop(L);
477 // Package them up for Lua
479 int new_table = lua_gettop(L);
480 std::list<std::string>::iterator i = mods_sorted.begin();
481 while(i != mods_sorted.end())
483 lua_pushvalue(L, insertion_func);
484 lua_pushvalue(L, new_table);
485 lua_pushstring(L, (*i).c_str());
486 if(lua_pcall(L, 2, 0, 0) != 0)
488 script_error(L, "error: %s", lua_tostring(L, -1));
496 int ModApiBasic::l_get_worldpath(lua_State *L)
498 NO_MAP_LOCK_REQUIRED;
499 std::string worldpath = getServer(L)->getWorldPath();
500 lua_pushstring(L, worldpath.c_str());
504 // sound_play(spec, parameters)
505 int ModApiBasic::l_sound_play(lua_State *L)
507 NO_MAP_LOCK_REQUIRED;
508 SimpleSoundSpec spec;
509 read_soundspec(L, 1, spec);
510 ServerSoundParams params;
511 read_server_sound_params(L, 2, params);
512 s32 handle = getServer(L)->playSound(spec, params);
513 lua_pushinteger(L, handle);
517 // sound_stop(handle)
518 int ModApiBasic::l_sound_stop(lua_State *L)
520 NO_MAP_LOCK_REQUIRED;
521 int handle = luaL_checkinteger(L, 1);
522 getServer(L)->stopSound(handle);
527 int ModApiBasic::l_is_singleplayer(lua_State *L)
529 NO_MAP_LOCK_REQUIRED;
530 lua_pushboolean(L, getServer(L)->isSingleplayer());
534 // get_password_hash(name, raw_password)
535 int ModApiBasic::l_get_password_hash(lua_State *L)
537 NO_MAP_LOCK_REQUIRED;
538 std::string name = luaL_checkstring(L, 1);
539 std::string raw_password = luaL_checkstring(L, 2);
540 std::string hash = translatePassword(name,
541 narrow_to_wide(raw_password));
542 lua_pushstring(L, hash.c_str());
546 // notify_authentication_modified(name)
547 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
549 NO_MAP_LOCK_REQUIRED;
550 std::string name = "";
551 if(lua_isstring(L, 1))
552 name = lua_tostring(L, 1);
553 getServer(L)->reportPrivsModified(name);
557 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
558 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
560 v3s16 p = read_v3s16(L, 1);
561 int range = luaL_checknumber(L, 2);
562 int seconds = luaL_checknumber(L, 3);
563 Server *server = getServer(L);
564 IRollbackManager *rollback = server->getRollbackManager();
567 std::string actor = rollback->getLastNodeActor(p, range, seconds, &act_p, &act_seconds);
568 lua_pushstring(L, actor.c_str());
569 push_v3s16(L, act_p);
570 lua_pushnumber(L, act_seconds);
574 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
575 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
577 std::string actor = luaL_checkstring(L, 1);
578 int seconds = luaL_checknumber(L, 2);
579 Server *server = getServer(L);
580 IRollbackManager *rollback = server->getRollbackManager();
581 std::list<RollbackAction> actions = rollback->getRevertActions(actor, seconds);
582 std::list<std::string> log;
583 bool success = server->rollbackRevertActions(actions, &log);
584 // Push boolean result
585 lua_pushboolean(L, success);
586 // Get the table insert function and push the log table
587 lua_getglobal(L, "table");
588 lua_getfield(L, -1, "insert");
589 int table_insert = lua_gettop(L);
591 int table = lua_gettop(L);
592 for(std::list<std::string>::const_iterator i = log.begin();
595 lua_pushvalue(L, table_insert);
596 lua_pushvalue(L, table);
597 lua_pushstring(L, i->c_str());
598 if(lua_pcall(L, 2, 0, 0))
599 script_error(L, "error: %s", lua_tostring(L, -1));
601 lua_remove(L, -2); // Remove table
602 lua_remove(L, -2); // Remove insert
606 int ModApiBasic::l_register_ore(lua_State *L)
609 luaL_checktype(L, index, LUA_TTABLE);
611 EmergeManager *emerge = getServer(L)->getEmergeManager();
613 enum OreType oretype = (OreType)getenumfield(L, index,
614 "ore_type", es_OreType, ORE_SCATTER);
615 Ore *ore = createOre(oretype);
617 errorstream << "register_ore: ore_type "
618 << oretype << " not implemented";
622 ore->ore_name = getstringfield_default(L, index, "ore", "");
623 ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0);
624 ore->wherein_name = getstringfield_default(L, index, "wherein", "");
625 ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1);
626 ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1);
627 ore->clust_size = getintfield_default(L, index, "clust_size", 0);
628 ore->height_min = getintfield_default(L, index, "height_min", 0);
629 ore->height_max = getintfield_default(L, index, "height_max", 0);
630 ore->flags = getflagsfield(L, index, "flags", flagdesc_ore);
631 ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0.);
633 lua_getfield(L, index, "noise_params");
634 ore->np = read_noiseparams(L, -1);
639 if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) {
640 errorstream << "register_ore: clust_scarcity and clust_num_ores"
641 "must be greater than 0" << std::endl;
646 emerge->ores.push_back(ore);
648 verbosestream << "register_ore: ore '" << ore->ore_name
649 << "' registered" << std::endl;
653 ModApiBasic modapibasic_prototype;