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