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