]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_server.cpp
88ab5e16b4b8dc41a51c8bcd24c1e28bce052a91
[minetest.git] / src / script / lua_api / l_server.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 #include "lua_api/l_server.h"
21 #include "lua_api/l_internal.h"
22 #include "common/c_converter.h"
23 #include "common/c_content.h"
24 #include "cpp_api/s_base.h"
25 #include "cpp_api/s_security.h"
26 #include "scripting_server.h"
27 #include "server.h"
28 #include "environment.h"
29 #include "remoteplayer.h"
30 #include "log.h"
31 #include <algorithm>
32
33 // request_shutdown()
34 int ModApiServer::l_request_shutdown(lua_State *L)
35 {
36         NO_MAP_LOCK_REQUIRED;
37         const char *msg = lua_tolstring(L, 1, NULL);
38         bool reconnect = readParam<bool>(L, 2);
39         float seconds_before_shutdown = lua_tonumber(L, 3);
40         getServer(L)->requestShutdown(msg ? msg : "", reconnect, seconds_before_shutdown);
41         return 0;
42 }
43
44 // get_server_status()
45 int ModApiServer::l_get_server_status(lua_State *L)
46 {
47         NO_MAP_LOCK_REQUIRED;
48         lua_pushstring(L, getServer(L)->getStatusString().c_str());
49         return 1;
50 }
51
52 // get_server_uptime()
53 int ModApiServer::l_get_server_uptime(lua_State *L)
54 {
55         NO_MAP_LOCK_REQUIRED;
56         lua_pushnumber(L, getServer(L)->getUptime());
57         return 1;
58 }
59
60 // get_server_max_lag()
61 int ModApiServer::l_get_server_max_lag(lua_State *L)
62 {
63         NO_MAP_LOCK_REQUIRED;
64         ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L));
65         if (!s_env)
66                 lua_pushnil(L);
67         else
68                 lua_pushnumber(L, s_env->getMaxLagEstimate());
69         return 1;
70 }
71
72 // print(text)
73 int ModApiServer::l_print(lua_State *L)
74 {
75         NO_MAP_LOCK_REQUIRED;
76         std::string text;
77         text = luaL_checkstring(L, 1);
78         getServer(L)->printToConsoleOnly(text);
79         return 0;
80 }
81
82 // chat_send_all(text)
83 int ModApiServer::l_chat_send_all(lua_State *L)
84 {
85         NO_MAP_LOCK_REQUIRED;
86         const char *text = luaL_checkstring(L, 1);
87         // Get server from registry
88         Server *server = getServer(L);
89         // Send
90         server->notifyPlayers(utf8_to_wide(text));
91         return 0;
92 }
93
94 // chat_send_player(name, text)
95 int ModApiServer::l_chat_send_player(lua_State *L)
96 {
97         NO_MAP_LOCK_REQUIRED;
98         const char *name = luaL_checkstring(L, 1);
99         const char *text = luaL_checkstring(L, 2);
100
101         // Get server from registry
102         Server *server = getServer(L);
103         // Send
104         server->notifyPlayer(name, utf8_to_wide(text));
105         return 0;
106 }
107
108 // get_player_privs(name, text)
109 int ModApiServer::l_get_player_privs(lua_State *L)
110 {
111         NO_MAP_LOCK_REQUIRED;
112         const char *name = luaL_checkstring(L, 1);
113         // Get server from registry
114         Server *server = getServer(L);
115         // Do it
116         lua_newtable(L);
117         int table = lua_gettop(L);
118         std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
119         for (const std::string &privs_ : privs_s) {
120                 lua_pushboolean(L, true);
121                 lua_setfield(L, table, privs_.c_str());
122         }
123         lua_pushvalue(L, table);
124         return 1;
125 }
126
127 // get_player_ip()
128 int ModApiServer::l_get_player_ip(lua_State *L)
129 {
130         NO_MAP_LOCK_REQUIRED;
131
132         Server *server = getServer(L);
133
134         const char *name = luaL_checkstring(L, 1);
135         RemotePlayer *player = server->getEnv().getPlayer(name);
136         if (!player) {
137                 lua_pushnil(L); // no such player
138                 return 1;
139         }
140
141         lua_pushstring(L, server->getPeerAddress(player->getPeerId()).serializeString().c_str());
142         return 1;
143 }
144
145 // get_player_information(name)
146 int ModApiServer::l_get_player_information(lua_State *L)
147 {
148         NO_MAP_LOCK_REQUIRED;
149
150         Server *server = getServer(L);
151
152         const char *name = luaL_checkstring(L, 1);
153         RemotePlayer *player = server->getEnv().getPlayer(name);
154         if (!player) {
155                 lua_pushnil(L); // no such player
156                 return 1;
157         }
158
159         /*
160                 Be careful not to introduce a depdendency on the connection to
161                 the peer here. This function is >>REQUIRED<< to still be able to return
162                 values even when the peer unexpectedly disappears.
163                 Hence all the ConInfo values here are optional.
164         */
165
166         auto getConInfo = [&] (con::rtt_stat_type type, float *value) -> bool {
167                 return server->getClientConInfo(player->getPeerId(), type, value);
168         };
169
170         float min_rtt, max_rtt, avg_rtt, min_jitter, max_jitter, avg_jitter;
171         bool have_con_info =
172                 getConInfo(con::MIN_RTT, &min_rtt) &&
173                 getConInfo(con::MAX_RTT, &max_rtt) &&
174                 getConInfo(con::AVG_RTT, &avg_rtt) &&
175                 getConInfo(con::MIN_JITTER, &min_jitter) &&
176                 getConInfo(con::MAX_JITTER, &max_jitter) &&
177                 getConInfo(con::AVG_JITTER, &avg_jitter);
178
179         ClientInfo info;
180         if (!server->getClientInfo(player->getPeerId(), info)) {
181                 warningstream << FUNCTION_NAME << ": no client info?!" << std::endl;
182                 lua_pushnil(L); // error
183                 return 1;
184         }
185
186         lua_newtable(L);
187         int table = lua_gettop(L);
188
189         lua_pushstring(L,"address");
190         lua_pushstring(L, info.addr.serializeString().c_str());
191         lua_settable(L, table);
192
193         lua_pushstring(L,"ip_version");
194         if (info.addr.getFamily() == AF_INET) {
195                 lua_pushnumber(L, 4);
196         } else if (info.addr.getFamily() == AF_INET6) {
197                 lua_pushnumber(L, 6);
198         } else {
199                 lua_pushnumber(L, 0);
200         }
201         lua_settable(L, table);
202
203         if (have_con_info) { // may be missing
204                 lua_pushstring(L, "min_rtt");
205                 lua_pushnumber(L, min_rtt);
206                 lua_settable(L, table);
207
208                 lua_pushstring(L, "max_rtt");
209                 lua_pushnumber(L, max_rtt);
210                 lua_settable(L, table);
211
212                 lua_pushstring(L, "avg_rtt");
213                 lua_pushnumber(L, avg_rtt);
214                 lua_settable(L, table);
215
216                 lua_pushstring(L, "min_jitter");
217                 lua_pushnumber(L, min_jitter);
218                 lua_settable(L, table);
219
220                 lua_pushstring(L, "max_jitter");
221                 lua_pushnumber(L, max_jitter);
222                 lua_settable(L, table);
223
224                 lua_pushstring(L, "avg_jitter");
225                 lua_pushnumber(L, avg_jitter);
226                 lua_settable(L, table);
227         }
228
229         lua_pushstring(L,"connection_uptime");
230         lua_pushnumber(L, info.uptime);
231         lua_settable(L, table);
232
233         lua_pushstring(L,"protocol_version");
234         lua_pushnumber(L, info.prot_vers);
235         lua_settable(L, table);
236
237         lua_pushstring(L, "formspec_version");
238         lua_pushnumber(L, player->formspec_version);
239         lua_settable(L, table);
240
241         lua_pushstring(L, "lang_code");
242         lua_pushstring(L, info.lang_code.c_str());
243         lua_settable(L, table);
244
245 #ifndef NDEBUG
246         lua_pushstring(L,"serialization_version");
247         lua_pushnumber(L, info.ser_vers);
248         lua_settable(L, table);
249
250         lua_pushstring(L,"major");
251         lua_pushnumber(L, info.major);
252         lua_settable(L, table);
253
254         lua_pushstring(L,"minor");
255         lua_pushnumber(L, info.minor);
256         lua_settable(L, table);
257
258         lua_pushstring(L,"patch");
259         lua_pushnumber(L, info.patch);
260         lua_settable(L, table);
261
262         lua_pushstring(L,"version_string");
263         lua_pushstring(L, info.vers_string.c_str());
264         lua_settable(L, table);
265
266         lua_pushstring(L,"state");
267         lua_pushstring(L, ClientInterface::state2Name(info.state).c_str());
268         lua_settable(L, table);
269 #endif
270
271         return 1;
272 }
273
274 // get_ban_list()
275 int ModApiServer::l_get_ban_list(lua_State *L)
276 {
277         NO_MAP_LOCK_REQUIRED;
278         lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
279         return 1;
280 }
281
282 // get_ban_description()
283 int ModApiServer::l_get_ban_description(lua_State *L)
284 {
285         NO_MAP_LOCK_REQUIRED;
286         const char * ip_or_name = luaL_checkstring(L, 1);
287         lua_pushstring(L, getServer(L)->getBanDescription(std::string(ip_or_name)).c_str());
288         return 1;
289 }
290
291 // ban_player()
292 int ModApiServer::l_ban_player(lua_State *L)
293 {
294         NO_MAP_LOCK_REQUIRED;
295
296         if (!getEnv(L))
297                 throw LuaError("Can't ban player before server has started up");
298
299         Server *server = getServer(L);
300         const char *name = luaL_checkstring(L, 1);
301         RemotePlayer *player = server->getEnv().getPlayer(name);
302         if (!player) {
303                 lua_pushboolean(L, false); // no such player
304                 return 1;
305         }
306
307         std::string ip_str = server->getPeerAddress(player->getPeerId()).serializeString();
308         server->setIpBanned(ip_str, name);
309         lua_pushboolean(L, true);
310         return 1;
311 }
312
313 // disconnect_player(name, [reason]) -> success
314 int ModApiServer::l_disconnect_player(lua_State *L)
315 {
316         NO_MAP_LOCK_REQUIRED;
317
318         if (!getEnv(L))
319                 throw LuaError("Can't kick player before server has started up");
320
321         const char *name = luaL_checkstring(L, 1);
322         std::string message;
323         if (lua_isstring(L, 2))
324                 message.append(readParam<std::string>(L, 2));
325         else
326                 message.append("Disconnected.");
327
328         RemotePlayer *player = dynamic_cast<ServerEnvironment *>(getEnv(L))->getPlayer(name);
329         if (player == NULL) {
330                 lua_pushboolean(L, false); // No such player
331                 return 1;
332         }
333         getServer(L)->DenyAccess_Legacy(player->getPeerId(), utf8_to_wide(message));
334         lua_pushboolean(L, true);
335         return 1;
336 }
337
338 int ModApiServer::l_remove_player(lua_State *L)
339 {
340         NO_MAP_LOCK_REQUIRED;
341         std::string name = luaL_checkstring(L, 1);
342         ServerEnvironment *s_env = dynamic_cast<ServerEnvironment *>(getEnv(L));
343         if (!s_env)
344                 throw LuaError("Can't remove player before server has started up");
345
346         RemotePlayer *player = s_env->getPlayer(name.c_str());
347         if (!player)
348                 lua_pushinteger(L, s_env->removePlayerFromDatabase(name) ? 0 : 1);
349         else
350                 lua_pushinteger(L, 2);
351
352         return 1;
353 }
354
355 // unban_player_or_ip()
356 int ModApiServer::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 ModApiServer::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_current_modname()
383 int ModApiServer::l_get_current_modname(lua_State *L)
384 {
385         NO_MAP_LOCK_REQUIRED;
386         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
387         return 1;
388 }
389
390 // get_modpath(modname)
391 int ModApiServer::l_get_modpath(lua_State *L)
392 {
393         NO_MAP_LOCK_REQUIRED;
394         std::string modname = luaL_checkstring(L, 1);
395         const ModSpec *mod = getServer(L)->getModSpec(modname);
396         if (!mod) {
397                 lua_pushnil(L);
398                 return 1;
399         }
400         lua_pushstring(L, mod->path.c_str());
401         return 1;
402 }
403
404 // get_modnames()
405 // the returned list is sorted alphabetically for you
406 int ModApiServer::l_get_modnames(lua_State *L)
407 {
408         NO_MAP_LOCK_REQUIRED;
409
410         // Get a list of mods
411         std::vector<std::string> modlist;
412         getServer(L)->getModNames(modlist);
413
414         std::sort(modlist.begin(), modlist.end());
415
416         // Package them up for Lua
417         lua_createtable(L, modlist.size(), 0);
418         std::vector<std::string>::iterator iter = modlist.begin();
419         for (u16 i = 0; iter != modlist.end(); ++iter) {
420                 lua_pushstring(L, iter->c_str());
421                 lua_rawseti(L, -2, ++i);
422         }
423         return 1;
424 }
425
426 // get_worldpath()
427 int ModApiServer::l_get_worldpath(lua_State *L)
428 {
429         NO_MAP_LOCK_REQUIRED;
430         std::string worldpath = getServer(L)->getWorldPath();
431         lua_pushstring(L, worldpath.c_str());
432         return 1;
433 }
434
435 // sound_play(spec, parameters, [ephemeral])
436 int ModApiServer::l_sound_play(lua_State *L)
437 {
438         NO_MAP_LOCK_REQUIRED;
439         SimpleSoundSpec spec;
440         read_soundspec(L, 1, spec);
441         ServerSoundParams params;
442         read_server_sound_params(L, 2, params);
443         bool ephemeral = lua_gettop(L) > 2 && readParam<bool>(L, 3);
444         if (ephemeral) {
445                 getServer(L)->playSound(spec, params, true);
446                 lua_pushnil(L);
447         } else {
448                 s32 handle = getServer(L)->playSound(spec, params);
449                 lua_pushinteger(L, handle);
450         }
451         return 1;
452 }
453
454 // sound_stop(handle)
455 int ModApiServer::l_sound_stop(lua_State *L)
456 {
457         NO_MAP_LOCK_REQUIRED;
458         s32 handle = luaL_checkinteger(L, 1);
459         getServer(L)->stopSound(handle);
460         return 0;
461 }
462
463 int ModApiServer::l_sound_fade(lua_State *L)
464 {
465         NO_MAP_LOCK_REQUIRED;
466         s32 handle = luaL_checkinteger(L, 1);
467         float step = readParam<float>(L, 2);
468         float gain = readParam<float>(L, 3);
469         getServer(L)->fadeSound(handle, step, gain);
470         return 0;
471 }
472
473 // dynamic_add_media(filepath)
474 int ModApiServer::l_dynamic_add_media(lua_State *L)
475 {
476         NO_MAP_LOCK_REQUIRED;
477
478         if (!getEnv(L))
479                 throw LuaError("Dynamic media cannot be added before server has started up");
480         Server *server = getServer(L);
481
482         std::string filepath;
483         std::string to_player;
484         bool ephemeral = false;
485
486         if (lua_istable(L, 1)) {
487                 getstringfield(L, 1, "filepath", filepath);
488                 getstringfield(L, 1, "to_player", to_player);
489                 getboolfield(L, 1, "ephemeral", ephemeral);
490         } else {
491                 filepath = readParam<std::string>(L, 1);
492         }
493         if (filepath.empty())
494                 luaL_typerror(L, 1, "non-empty string");
495         luaL_checktype(L, 2, LUA_TFUNCTION);
496
497         CHECK_SECURE_PATH(L, filepath.c_str(), false);
498
499         u32 token = server->getScriptIface()->allocateDynamicMediaCallback(L, 2);
500
501         bool ok = server->dynamicAddMedia(filepath, token, to_player, ephemeral);
502         if (!ok)
503                 server->getScriptIface()->freeDynamicMediaCallback(token);
504         lua_pushboolean(L, ok);
505
506         return 1;
507 }
508
509 // is_singleplayer()
510 int ModApiServer::l_is_singleplayer(lua_State *L)
511 {
512         NO_MAP_LOCK_REQUIRED;
513         lua_pushboolean(L, getServer(L)->isSingleplayer());
514         return 1;
515 }
516
517 // notify_authentication_modified(name)
518 int ModApiServer::l_notify_authentication_modified(lua_State *L)
519 {
520         NO_MAP_LOCK_REQUIRED;
521         std::string name;
522         if(lua_isstring(L, 1))
523                 name = readParam<std::string>(L, 1);
524         getServer(L)->reportPrivsModified(name);
525         return 0;
526 }
527
528 void ModApiServer::Initialize(lua_State *L, int top)
529 {
530         API_FCT(request_shutdown);
531         API_FCT(get_server_status);
532         API_FCT(get_server_uptime);
533         API_FCT(get_server_max_lag);
534         API_FCT(get_worldpath);
535         API_FCT(is_singleplayer);
536
537         API_FCT(get_current_modname);
538         API_FCT(get_modpath);
539         API_FCT(get_modnames);
540
541         API_FCT(print);
542
543         API_FCT(chat_send_all);
544         API_FCT(chat_send_player);
545         API_FCT(show_formspec);
546         API_FCT(sound_play);
547         API_FCT(sound_stop);
548         API_FCT(sound_fade);
549         API_FCT(dynamic_add_media);
550
551         API_FCT(get_player_information);
552         API_FCT(get_player_privs);
553         API_FCT(get_player_ip);
554         API_FCT(get_ban_list);
555         API_FCT(get_ban_description);
556         API_FCT(ban_player);
557         API_FCT(disconnect_player);
558         API_FCT(remove_player);
559         API_FCT(unban_player_or_ip);
560         API_FCT(notify_authentication_modified);
561 }