]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_server.cpp
Rename macros with two leading underscores
[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 "server.h"
26 #include "environment.h"
27 #include "player.h"
28 #include "log.h"
29
30 // request_shutdown()
31 int ModApiServer::l_request_shutdown(lua_State *L)
32 {
33         const char *msg = lua_tolstring(L, 1, NULL);
34         bool reconnect = lua_toboolean(L, 2);
35         getServer(L)->requestShutdown(msg ? msg : "", reconnect);
36         return 0;
37 }
38
39 // get_server_status()
40 int ModApiServer::l_get_server_status(lua_State *L)
41 {
42         NO_MAP_LOCK_REQUIRED;
43         lua_pushstring(L, wide_to_narrow(getServer(L)->getStatusString()).c_str());
44         return 1;
45 }
46
47 // chat_send_all(text)
48 int ModApiServer::l_chat_send_all(lua_State *L)
49 {
50         NO_MAP_LOCK_REQUIRED;
51         const char *text = luaL_checkstring(L, 1);
52         // Get server from registry
53         Server *server = getServer(L);
54         // Send
55         server->notifyPlayers(narrow_to_wide(text));
56         return 0;
57 }
58
59 // chat_send_player(name, text)
60 int ModApiServer::l_chat_send_player(lua_State *L)
61 {
62         NO_MAP_LOCK_REQUIRED;
63         const char *name = luaL_checkstring(L, 1);
64         const char *text = luaL_checkstring(L, 2);
65
66         // Get server from registry
67         Server *server = getServer(L);
68         // Send
69         server->notifyPlayer(name, narrow_to_wide(text));
70         return 0;
71 }
72
73 // get_player_privs(name, text)
74 int ModApiServer::l_get_player_privs(lua_State *L)
75 {
76         NO_MAP_LOCK_REQUIRED;
77         const char *name = luaL_checkstring(L, 1);
78         // Get server from registry
79         Server *server = getServer(L);
80         // Do it
81         lua_newtable(L);
82         int table = lua_gettop(L);
83         std::set<std::string> privs_s = server->getPlayerEffectivePrivs(name);
84         for(std::set<std::string>::const_iterator
85                         i = privs_s.begin(); i != privs_s.end(); i++){
86                 lua_pushboolean(L, true);
87                 lua_setfield(L, table, i->c_str());
88         }
89         lua_pushvalue(L, table);
90         return 1;
91 }
92
93 // get_player_ip()
94 int ModApiServer::l_get_player_ip(lua_State *L)
95 {
96         NO_MAP_LOCK_REQUIRED;
97         const char * name = luaL_checkstring(L, 1);
98         Player *player = getEnv(L)->getPlayer(name);
99         if(player == NULL)
100         {
101                 lua_pushnil(L); // no such player
102                 return 1;
103         }
104         try
105         {
106                 Address addr = getServer(L)->getPeerAddress(player->peer_id);
107                 std::string ip_str = addr.serializeString();
108                 lua_pushstring(L, ip_str.c_str());
109                 return 1;
110         }
111         catch(con::PeerNotFoundException) // unlikely
112         {
113                 dstream << FUNCTION_NAME << ": peer was not found" << std::endl;
114                 lua_pushnil(L); // error
115                 return 1;
116         }
117 }
118
119 // get_player_information()
120 int ModApiServer::l_get_player_information(lua_State *L)
121 {
122
123         NO_MAP_LOCK_REQUIRED;
124         const char * name = luaL_checkstring(L, 1);
125         Player *player = getEnv(L)->getPlayer(name);
126         if(player == NULL)
127         {
128                 lua_pushnil(L); // no such player
129                 return 1;
130         }
131
132         Address addr;
133         try
134         {
135                 addr = getServer(L)->getPeerAddress(player->peer_id);
136         }
137         catch(con::PeerNotFoundException) // unlikely
138         {
139                 dstream << FUNCTION_NAME << ": peer was not found" << std::endl;
140                 lua_pushnil(L); // error
141                 return 1;
142         }
143
144         float min_rtt,max_rtt,avg_rtt,min_jitter,max_jitter,avg_jitter;
145         ClientState state;
146         u32 uptime;
147         u16 prot_vers;
148         u8 ser_vers,major,minor,patch;
149         std::string vers_string;
150
151 #define ERET(code)                                                             \
152         if (!(code)) {                                                             \
153                 dstream << FUNCTION_NAME << ": peer was not found" << std::endl;     \
154                 lua_pushnil(L); /* error */                                            \
155                 return 1;                                                              \
156         }
157
158         ERET(getServer(L)->getClientConInfo(player->peer_id,con::MIN_RTT,&min_rtt))
159         ERET(getServer(L)->getClientConInfo(player->peer_id,con::MAX_RTT,&max_rtt))
160         ERET(getServer(L)->getClientConInfo(player->peer_id,con::AVG_RTT,&avg_rtt))
161         ERET(getServer(L)->getClientConInfo(player->peer_id,con::MIN_JITTER,&min_jitter))
162         ERET(getServer(L)->getClientConInfo(player->peer_id,con::MAX_JITTER,&max_jitter))
163         ERET(getServer(L)->getClientConInfo(player->peer_id,con::AVG_JITTER,&avg_jitter))
164
165         ERET(getServer(L)->getClientInfo(player->peer_id,
166                                                                                 &state, &uptime, &ser_vers, &prot_vers,
167                                                                                 &major, &minor, &patch, &vers_string))
168
169         lua_newtable(L);
170         int table = lua_gettop(L);
171
172         lua_pushstring(L,"address");
173         lua_pushstring(L, addr.serializeString().c_str());
174         lua_settable(L, table);
175
176         lua_pushstring(L,"ip_version");
177         if (addr.getFamily() == AF_INET) {
178                 lua_pushnumber(L, 4);
179         } else if (addr.getFamily() == AF_INET6) {
180                 lua_pushnumber(L, 6);
181         } else {
182                 lua_pushnumber(L, 0);
183         }
184         lua_settable(L, table);
185
186         lua_pushstring(L,"min_rtt");
187         lua_pushnumber(L, min_rtt);
188         lua_settable(L, table);
189
190         lua_pushstring(L,"max_rtt");
191         lua_pushnumber(L, max_rtt);
192         lua_settable(L, table);
193
194         lua_pushstring(L,"avg_rtt");
195         lua_pushnumber(L, avg_rtt);
196         lua_settable(L, table);
197
198         lua_pushstring(L,"min_jitter");
199         lua_pushnumber(L, min_jitter);
200         lua_settable(L, table);
201
202         lua_pushstring(L,"max_jitter");
203         lua_pushnumber(L, max_jitter);
204         lua_settable(L, table);
205
206         lua_pushstring(L,"avg_jitter");
207         lua_pushnumber(L, avg_jitter);
208         lua_settable(L, table);
209
210         lua_pushstring(L,"connection_uptime");
211         lua_pushnumber(L, uptime);
212         lua_settable(L, table);
213
214 #ifndef NDEBUG
215         lua_pushstring(L,"serialization_version");
216         lua_pushnumber(L, ser_vers);
217         lua_settable(L, table);
218
219         lua_pushstring(L,"protocol_version");
220         lua_pushnumber(L, prot_vers);
221         lua_settable(L, table);
222
223         lua_pushstring(L,"major");
224         lua_pushnumber(L, major);
225         lua_settable(L, table);
226
227         lua_pushstring(L,"minor");
228         lua_pushnumber(L, minor);
229         lua_settable(L, table);
230
231         lua_pushstring(L,"patch");
232         lua_pushnumber(L, patch);
233         lua_settable(L, table);
234
235         lua_pushstring(L,"version_string");
236         lua_pushstring(L, vers_string.c_str());
237         lua_settable(L, table);
238
239         lua_pushstring(L,"state");
240         lua_pushstring(L,ClientInterface::state2Name(state).c_str());
241         lua_settable(L, table);
242 #endif
243
244 #undef ERET
245         return 1;
246 }
247
248 // get_ban_list()
249 int ModApiServer::l_get_ban_list(lua_State *L)
250 {
251         NO_MAP_LOCK_REQUIRED;
252         lua_pushstring(L, getServer(L)->getBanDescription("").c_str());
253         return 1;
254 }
255
256 // get_ban_description()
257 int ModApiServer::l_get_ban_description(lua_State *L)
258 {
259         NO_MAP_LOCK_REQUIRED;
260         const char * ip_or_name = luaL_checkstring(L, 1);
261         lua_pushstring(L, getServer(L)->getBanDescription(std::string(ip_or_name)).c_str());
262         return 1;
263 }
264
265 // ban_player()
266 int ModApiServer::l_ban_player(lua_State *L)
267 {
268         NO_MAP_LOCK_REQUIRED;
269         const char * name = luaL_checkstring(L, 1);
270         Player *player = getEnv(L)->getPlayer(name);
271         if(player == NULL)
272         {
273                 lua_pushboolean(L, false); // no such player
274                 return 1;
275         }
276         try
277         {
278                 Address addr = getServer(L)->getPeerAddress(getEnv(L)->getPlayer(name)->peer_id);
279                 std::string ip_str = addr.serializeString();
280                 getServer(L)->setIpBanned(ip_str, name);
281         }
282         catch(con::PeerNotFoundException) // unlikely
283         {
284                 dstream << FUNCTION_NAME << ": peer was not found" << std::endl;
285                 lua_pushboolean(L, false); // error
286                 return 1;
287         }
288         lua_pushboolean(L, true);
289         return 1;
290 }
291
292 // kick_player(name, [reason]) -> success
293 int ModApiServer::l_kick_player(lua_State *L)
294 {
295         NO_MAP_LOCK_REQUIRED;
296         const char *name = luaL_checkstring(L, 1);
297         std::string message;
298         if (lua_isstring(L, 2))
299         {
300                 message = std::string("Kicked: ") + lua_tostring(L, 2);
301         }
302         else
303         {
304                 message = "Kicked.";
305         }
306         Player *player = getEnv(L)->getPlayer(name);
307         if (player == NULL)
308         {
309                 lua_pushboolean(L, false); // No such player
310                 return 1;
311         }
312         getServer(L)->DenyAccess_Legacy(player->peer_id, utf8_to_wide(message));
313         lua_pushboolean(L, true);
314         return 1;
315 }
316
317 // unban_player_or_ip()
318 int ModApiServer::l_unban_player_or_ip(lua_State *L)
319 {
320         NO_MAP_LOCK_REQUIRED;
321         const char * ip_or_name = luaL_checkstring(L, 1);
322         getServer(L)->unsetIpBanned(ip_or_name);
323         lua_pushboolean(L, true);
324         return 1;
325 }
326
327 // show_formspec(playername,formname,formspec)
328 int ModApiServer::l_show_formspec(lua_State *L)
329 {
330         NO_MAP_LOCK_REQUIRED;
331         const char *playername = luaL_checkstring(L, 1);
332         const char *formname = luaL_checkstring(L, 2);
333         const char *formspec = luaL_checkstring(L, 3);
334
335         if(getServer(L)->showFormspec(playername,formspec,formname))
336         {
337                 lua_pushboolean(L, true);
338         }else{
339                 lua_pushboolean(L, false);
340         }
341         return 1;
342 }
343
344 // get_current_modname()
345 int ModApiServer::l_get_current_modname(lua_State *L)
346 {
347         NO_MAP_LOCK_REQUIRED;
348         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
349         return 1;
350 }
351
352 // get_modpath(modname)
353 int ModApiServer::l_get_modpath(lua_State *L)
354 {
355         NO_MAP_LOCK_REQUIRED;
356         std::string modname = luaL_checkstring(L, 1);
357         const ModSpec *mod = getServer(L)->getModSpec(modname);
358         if (!mod) {
359                 lua_pushnil(L);
360                 return 1;
361         }
362         lua_pushstring(L, mod->path.c_str());
363         return 1;
364 }
365
366 // get_modnames()
367 // the returned list is sorted alphabetically for you
368 int ModApiServer::l_get_modnames(lua_State *L)
369 {
370         NO_MAP_LOCK_REQUIRED;
371
372         // Get a list of mods
373         std::vector<std::string> modlist;
374         getServer(L)->getModNames(modlist);
375
376         // Take unsorted items from mods_unsorted and sort them into
377         // mods_sorted; not great performance but the number of mods on a
378         // server will likely be small.
379         std::sort(modlist.begin(), modlist.end());
380
381         // Package them up for Lua
382         lua_createtable(L, modlist.size(), 0);
383         std::vector<std::string>::iterator iter = modlist.begin();
384         for (u16 i = 0; iter != modlist.end(); iter++) {
385                 lua_pushstring(L, iter->c_str());
386                 lua_rawseti(L, -2, ++i);
387         }
388         return 1;
389 }
390
391 // get_worldpath()
392 int ModApiServer::l_get_worldpath(lua_State *L)
393 {
394         NO_MAP_LOCK_REQUIRED;
395         std::string worldpath = getServer(L)->getWorldPath();
396         lua_pushstring(L, worldpath.c_str());
397         return 1;
398 }
399
400 // sound_play(spec, parameters)
401 int ModApiServer::l_sound_play(lua_State *L)
402 {
403         NO_MAP_LOCK_REQUIRED;
404         SimpleSoundSpec spec;
405         read_soundspec(L, 1, spec);
406         ServerSoundParams params;
407         read_server_sound_params(L, 2, params);
408         s32 handle = getServer(L)->playSound(spec, params);
409         lua_pushinteger(L, handle);
410         return 1;
411 }
412
413 // sound_stop(handle)
414 int ModApiServer::l_sound_stop(lua_State *L)
415 {
416         NO_MAP_LOCK_REQUIRED;
417         int handle = luaL_checkinteger(L, 1);
418         getServer(L)->stopSound(handle);
419         return 0;
420 }
421
422 // is_singleplayer()
423 int ModApiServer::l_is_singleplayer(lua_State *L)
424 {
425         NO_MAP_LOCK_REQUIRED;
426         lua_pushboolean(L, getServer(L)->isSingleplayer());
427         return 1;
428 }
429
430 // notify_authentication_modified(name)
431 int ModApiServer::l_notify_authentication_modified(lua_State *L)
432 {
433         NO_MAP_LOCK_REQUIRED;
434         std::string name = "";
435         if(lua_isstring(L, 1))
436                 name = lua_tostring(L, 1);
437         getServer(L)->reportPrivsModified(name);
438         return 0;
439 }
440
441 // get_last_run_mod()
442 int ModApiServer::l_get_last_run_mod(lua_State *L)
443 {
444         NO_MAP_LOCK_REQUIRED;
445         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
446         const char *current_mod = lua_tostring(L, -1);
447         if (current_mod == NULL || current_mod[0] == '\0') {
448                 lua_pop(L, 1);
449                 lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
450         }
451         return 1;
452 }
453
454 // set_last_run_mod(modname)
455 int ModApiServer::l_set_last_run_mod(lua_State *L)
456 {
457         NO_MAP_LOCK_REQUIRED;
458 #ifdef SCRIPTAPI_DEBUG
459         const char *mod = lua_tostring(L, 1);
460         getScriptApiBase(L)->setOriginDirect(mod);
461         //printf(">>>> last mod set from Lua: %s\n", mod);
462 #endif
463         return 0;
464 }
465
466 #ifndef NDEBUG
467 // cause_error(type_of_error)
468 int ModApiServer::l_cause_error(lua_State *L)
469 {
470         NO_MAP_LOCK_REQUIRED;
471         std::string type_of_error = "none";
472         if(lua_isstring(L, 1))
473                 type_of_error = lua_tostring(L, 1);
474
475         errorstream << "Error handler test called, errortype=" << type_of_error << std::endl;
476
477         if(type_of_error == "segv") {
478                 volatile int* some_pointer = 0;
479                 errorstream << "Cause a sigsegv now: " << (*some_pointer) << std::endl;
480
481         } else if (type_of_error == "zerodivision") {
482
483                 unsigned int some_number = porting::getTimeS();
484                 unsigned int zerovalue = 0;
485                 unsigned int result = some_number / zerovalue;
486                 errorstream << "Well this shouldn't ever be shown: " << result << std::endl;
487
488         } else if (type_of_error == "exception") {
489                 throw BaseException("Errorhandler test fct called");
490         }
491
492         return 0;
493 }
494 #endif
495
496 void ModApiServer::Initialize(lua_State *L, int top)
497 {
498         API_FCT(request_shutdown);
499         API_FCT(get_server_status);
500         API_FCT(get_worldpath);
501         API_FCT(is_singleplayer);
502
503         API_FCT(get_current_modname);
504         API_FCT(get_modpath);
505         API_FCT(get_modnames);
506
507         API_FCT(chat_send_all);
508         API_FCT(chat_send_player);
509         API_FCT(show_formspec);
510         API_FCT(sound_play);
511         API_FCT(sound_stop);
512
513         API_FCT(get_player_information);
514         API_FCT(get_player_privs);
515         API_FCT(get_player_ip);
516         API_FCT(get_ban_list);
517         API_FCT(get_ban_description);
518         API_FCT(ban_player);
519         API_FCT(kick_player);
520         API_FCT(unban_player_or_ip);
521         API_FCT(notify_authentication_modified);
522
523         API_FCT(get_last_run_mod);
524         API_FCT(set_last_run_mod);
525 #ifndef NDEBUG
526         API_FCT(cause_error);
527 #endif
528 }