Lazy sunday typo fixing. s/unban_player_of_ip/unban_player_or_ip/g
[oweals/minetest.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
47 ModApiBasic::ModApiBasic() : ModApiBase() {
48 }
49
50 bool ModApiBasic::Initialize(lua_State* L,int top) {
51
52         bool retval = true;
53
54         retval &= API_FCT(debug);
55         retval &= API_FCT(log);
56         retval &= API_FCT(request_shutdown);
57         retval &= API_FCT(get_server_status);
58
59         retval &= API_FCT(register_biome);
60
61         retval &= API_FCT(setting_set);
62         retval &= API_FCT(setting_get);
63         retval &= API_FCT(setting_getbool);
64         retval &= API_FCT(setting_save);
65
66         retval &= API_FCT(chat_send_all);
67         retval &= API_FCT(chat_send_player);
68         retval &= API_FCT(show_formspec);
69
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_or_ip);
76         retval &= API_FCT(get_password_hash);
77         retval &= API_FCT(notify_authentication_modified);
78
79         retval &= API_FCT(get_dig_params);
80         retval &= API_FCT(get_hit_params);
81
82         retval &= API_FCT(get_current_modname);
83         retval &= API_FCT(get_modpath);
84         retval &= API_FCT(get_modnames);
85
86         retval &= API_FCT(get_worldpath);
87         retval &= API_FCT(is_singleplayer);
88         retval &= API_FCT(sound_play);
89         retval &= API_FCT(sound_stop);
90
91         retval &= API_FCT(rollback_get_last_node_actor);
92         retval &= API_FCT(rollback_revert_actions_by);
93
94         retval &= API_FCT(register_ore);
95
96         return retval;
97 }
98
99 // debug(text)
100 // Writes a line to dstream
101 int ModApiBasic::l_debug(lua_State *L)
102 {
103         NO_MAP_LOCK_REQUIRED;
104         std::string text = lua_tostring(L, 1);
105         dstream << text << std::endl;
106         return 0;
107 }
108
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)
114 {
115         NO_MAP_LOCK_REQUIRED;
116         std::string text;
117         LogMessageLevel level = LMT_INFO;
118         if(lua_isnone(L, 2))
119         {
120                 text = lua_tostring(L, 1);
121         }
122         else
123         {
124                 std::string levelname = luaL_checkstring(L, 1);
125                 text = luaL_checkstring(L, 2);
126                 if(levelname == "error")
127                         level = LMT_ERROR;
128                 else if(levelname == "action")
129                         level = LMT_ACTION;
130                 else if(levelname == "verbose")
131                         level = LMT_VERBOSE;
132         }
133         log_printline(level, text);
134         return 0;
135 }
136
137 // request_shutdown()
138 int ModApiBasic::l_request_shutdown(lua_State *L)
139 {
140         getServer(L)->requestShutdown();
141         return 0;
142 }
143
144 // get_server_status()
145 int ModApiBasic::l_get_server_status(lua_State *L)
146 {
147         NO_MAP_LOCK_REQUIRED;
148         lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
149         return 1;
150 }
151
152 // register_biome({lots of stuff})
153 int ModApiBasic::l_register_biome(lua_State *L)
154 {
155         int index = 1;
156         luaL_checktype(L, index, LUA_TTABLE);
157
158         BiomeDefManager *bmgr = getServer(L)->getEmergeManager()->biomedef;
159         if (!bmgr) {
160                 verbosestream << "register_biome: BiomeDefManager not active" << std::endl;
161                 return 0;
162         }
163
164         enum BiomeTerrainType terrain = (BiomeTerrainType)getenumfield(L, index,
165         "terrain_type", es_BiomeTerrainType, BIOME_TERRAIN_NORMAL);
166         Biome *b = bmgr->createBiome(terrain);
167
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.);
177
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;
182         bmgr->addBiome(b);
183
184         return 0;
185 }
186
187
188
189 // setting_set(name, value)
190 int ModApiBasic::l_setting_set(lua_State *L)
191 {
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);
196         return 0;
197 }
198
199 // setting_get(name)
200 int ModApiBasic::l_setting_get(lua_State *L)
201 {
202         NO_MAP_LOCK_REQUIRED;
203         const char *name = luaL_checkstring(L, 1);
204         try{
205                 std::string value = g_settings->get(name);
206                 lua_pushstring(L, value.c_str());
207         } catch(SettingNotFoundException &e){
208                 lua_pushnil(L);
209         }
210         return 1;
211 }
212
213 // setting_getbool(name)
214 int ModApiBasic::l_setting_getbool(lua_State *L)
215 {
216         NO_MAP_LOCK_REQUIRED;
217         const char *name = luaL_checkstring(L, 1);
218         try{
219                 bool value = g_settings->getBool(name);
220                 lua_pushboolean(L, value);
221         } catch(SettingNotFoundException &e){
222                 lua_pushnil(L);
223         }
224         return 1;
225 }
226
227 // setting_save()
228 int ModApiBasic::l_setting_save(lua_State *L)
229 {
230         NO_MAP_LOCK_REQUIRED;
231         getServer(L)->saveConfig();
232         return 0;
233 }
234
235 // chat_send_all(text)
236 int ModApiBasic::l_chat_send_all(lua_State *L)
237 {
238         NO_MAP_LOCK_REQUIRED;
239         const char *text = luaL_checkstring(L, 1);
240         // Get server from registry
241         Server *server = getServer(L);
242         // Send
243         server->notifyPlayers(narrow_to_wide(text));
244         return 0;
245 }
246
247 // chat_send_player(name, text, prepend)
248 int ModApiBasic::l_chat_send_player(lua_State *L)
249 {
250         NO_MAP_LOCK_REQUIRED;
251         const char *name = luaL_checkstring(L, 1);
252         const char *text = luaL_checkstring(L, 2);
253         bool prepend = true;
254
255         if (lua_isboolean(L, 3))
256                 prepend = lua_toboolean(L, 3);
257
258         // Get server from registry
259         Server *server = getServer(L);
260         // Send
261         server->notifyPlayer(name, narrow_to_wide(text), prepend);
262         return 0;
263 }
264
265 // get_player_privs(name, text)
266 int ModApiBasic::l_get_player_privs(lua_State *L)
267 {
268         NO_MAP_LOCK_REQUIRED;
269         const char *name = luaL_checkstring(L, 1);
270         // Get server from registry
271         Server *server = getServer(L);
272         // Do it
273         lua_newtable(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());
280         }
281         lua_pushvalue(L, table);
282         return 1;
283 }
284
285 // get_player_ip()
286 int ModApiBasic::l_get_player_ip(lua_State *L)
287 {
288         NO_MAP_LOCK_REQUIRED;
289         const char * name = luaL_checkstring(L, 1);
290         Player *player = getEnv(L)->getPlayer(name);
291         if(player == NULL)
292         {
293                 lua_pushnil(L); // no such player
294                 return 1;
295         }
296         try
297         {
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());
301                 return 1;
302         }
303         catch(con::PeerNotFoundException) // unlikely
304         {
305                 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
306                 lua_pushnil(L); // error
307                 return 1;
308         }
309 }
310
311 // get_ban_list()
312 int ModApiBasic::l_get_ban_list(lua_State *L)
313 {
314         NO_MAP_LOCK_REQUIRED;
315         lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
316         return 1;
317 }
318
319 // get_ban_description()
320 int ModApiBasic::l_get_ban_description(lua_State *L)
321 {
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());
325         return 1;
326 }
327
328 // ban_player()
329 int ModApiBasic::l_ban_player(lua_State *L)
330 {
331         NO_MAP_LOCK_REQUIRED;
332         const char * name = luaL_checkstring(L, 1);
333         Player *player = getEnv(L)->getPlayer(name);
334         if(player == NULL)
335         {
336                 lua_pushboolean(L, false); // no such player
337                 return 1;
338         }
339         try
340         {
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);
344         }
345         catch(con::PeerNotFoundException) // unlikely
346         {
347                 dstream << __FUNCTION_NAME << ": peer was not found" << std::endl;
348                 lua_pushboolean(L, false); // error
349                 return 1;
350         }
351         lua_pushboolean(L, true);
352         return 1;
353 }
354
355 // unban_player_or_ip()
356 int ModApiBasic::l_unban_player_or_ip(lua_State *L)
357 {
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);
362         return 1;
363 }
364
365 // show_formspec(playername,formname,formspec)
366 int ModApiBasic::l_show_formspec(lua_State *L)
367 {
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);
372
373         if(getServer(L)->showFormspec(playername,formspec,formname))
374         {
375                 lua_pushboolean(L, true);
376         }else{
377                 lua_pushboolean(L, false);
378         }
379         return 1;
380 }
381
382 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
383 int ModApiBasic::l_get_dig_params(lua_State *L)
384 {
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));
391         else
392                 push_dig_params(L, getDigParams(groups, &tp,
393                                         luaL_checknumber(L, 3)));
394         return 1;
395 }
396
397 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
398 int ModApiBasic::l_get_hit_params(lua_State *L)
399 {
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));
406         else
407                 push_hit_params(L, getHitParams(groups, &tp,
408                                         luaL_checknumber(L, 3)));
409         return 1;
410 }
411
412 // get_current_modname()
413 int ModApiBasic::l_get_current_modname(lua_State *L)
414 {
415         NO_MAP_LOCK_REQUIRED;
416         lua_getfield(L, LUA_REGISTRYINDEX, "minetest_current_modname");
417         return 1;
418 }
419
420 // get_modpath(modname)
421 int ModApiBasic::l_get_modpath(lua_State *L)
422 {
423         NO_MAP_LOCK_REQUIRED;
424         std::string modname = luaL_checkstring(L, 1);
425         // Do it
426         if(modname == "__builtin"){
427                 std::string path = getServer(L)->getBuiltinLuaPath();
428                 lua_pushstring(L, path.c_str());
429                 return 1;
430         }
431         const ModSpec *mod = getServer(L)->getModSpec(modname);
432         if(!mod){
433                 lua_pushnil(L);
434                 return 1;
435         }
436         lua_pushstring(L, mod->path.c_str());
437         return 1;
438 }
439
440 // get_modnames()
441 // the returned list is sorted alphabetically for you
442 int ModApiBasic::l_get_modnames(lua_State *L)
443 {
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);
448
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)
454         {
455                 bool added = false;
456                 for(std::list<std::string>::iterator x = mods_sorted.begin();
457                         x != mods_sorted.end(); ++x)
458                 {
459                         // I doubt anybody using Minetest will be using
460                         // anything not ASCII based :)
461                         if((*i).compare(*x) <= 0)
462                         {
463                                 mods_sorted.insert(x, *i);
464                                 added = true;
465                                 break;
466                         }
467                 }
468                 if(!added)
469                         mods_sorted.push_back(*i);
470         }
471
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);
476
477         // Package them up for Lua
478         lua_newtable(L);
479         int new_table = lua_gettop(L);
480         std::list<std::string>::iterator i = mods_sorted.begin();
481         while(i != mods_sorted.end())
482         {
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)
487                 {
488                         script_error(L, "error: %s", lua_tostring(L, -1));
489                 }
490                 ++i;
491         }
492         return 1;
493 }
494
495 // get_worldpath()
496 int ModApiBasic::l_get_worldpath(lua_State *L)
497 {
498         NO_MAP_LOCK_REQUIRED;
499         std::string worldpath = getServer(L)->getWorldPath();
500         lua_pushstring(L, worldpath.c_str());
501         return 1;
502 }
503
504 // sound_play(spec, parameters)
505 int ModApiBasic::l_sound_play(lua_State *L)
506 {
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);
514         return 1;
515 }
516
517 // sound_stop(handle)
518 int ModApiBasic::l_sound_stop(lua_State *L)
519 {
520         NO_MAP_LOCK_REQUIRED;
521         int handle = luaL_checkinteger(L, 1);
522         getServer(L)->stopSound(handle);
523         return 0;
524 }
525
526 // is_singleplayer()
527 int ModApiBasic::l_is_singleplayer(lua_State *L)
528 {
529         NO_MAP_LOCK_REQUIRED;
530         lua_pushboolean(L, getServer(L)->isSingleplayer());
531         return 1;
532 }
533
534 // get_password_hash(name, raw_password)
535 int ModApiBasic::l_get_password_hash(lua_State *L)
536 {
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());
543         return 1;
544 }
545
546 // notify_authentication_modified(name)
547 int ModApiBasic::l_notify_authentication_modified(lua_State *L)
548 {
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);
554         return 0;
555 }
556
557 // rollback_get_last_node_actor(p, range, seconds) -> actor, p, seconds
558 int ModApiBasic::l_rollback_get_last_node_actor(lua_State *L)
559 {
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();
565         v3s16 act_p;
566         int act_seconds = 0;
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);
571         return 3;
572 }
573
574 // rollback_revert_actions_by(actor, seconds) -> bool, log messages
575 int ModApiBasic::l_rollback_revert_actions_by(lua_State *L)
576 {
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);
590         lua_newtable(L);
591         int table = lua_gettop(L);
592         for(std::list<std::string>::const_iterator i = log.begin();
593                         i != log.end(); i++)
594         {
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));
600         }
601         lua_remove(L, -2); // Remove table
602         lua_remove(L, -2); // Remove insert
603         return 2;
604 }
605
606 int ModApiBasic::l_register_ore(lua_State *L)
607 {
608         int index = 1;
609         luaL_checktype(L, index, LUA_TTABLE);
610
611         EmergeManager *emerge = getServer(L)->getEmergeManager();
612
613         enum OreType oretype = (OreType)getenumfield(L, index,
614                                 "ore_type", es_OreType, ORE_SCATTER);
615         Ore *ore = createOre(oretype);
616         if (!ore) {
617                 errorstream << "register_ore: ore_type "
618                         << oretype << " not implemented";
619                 return 0;
620         }
621
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.);
632
633         lua_getfield(L, index, "noise_params");
634         ore->np = read_noiseparams(L, -1);
635         lua_pop(L, 1);
636
637         ore->noise = NULL;
638
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;
642                 delete ore;
643                 return 0;
644         }
645
646         emerge->ores.push_back(ore);
647
648         verbosestream << "register_ore: ore '" << ore->ore_name
649                 << "' registered" << std::endl;
650         return 0;
651 }
652
653 ModApiBasic modapibasic_prototype;