]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_client.cpp
b9a8f77a87bab396ed6ee146cf237d922dd90621
[dragonfireclient.git] / src / script / lua_api / l_client.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "l_client.h"
22 #include "chatmessage.h"
23 #include "client/client.h"
24 #include "client/clientevent.h"
25 #include "client/sound.h"
26 #include "client/clientenvironment.h"
27 #include "client/game.h"
28 #include "common/c_content.h"
29 #include "common/c_converter.h"
30 #include "cpp_api/s_base.h"
31 #include "gettext.h"
32 #include "l_internal.h"
33 #include "lua_api/l_nodemeta.h"
34 #include "gui/mainmenumanager.h"
35 #include "map.h"
36 #include "util/string.h"
37 #include "nodedef.h"
38 #include "client/keycode.h"
39
40 #define checkCSMRestrictionFlag(flag) \
41         ( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) )
42
43 // Not the same as FlagDesc, which contains an `u32 flag`
44 struct CSMFlagDesc {
45         const char *name;
46         u64 flag;
47 };
48
49 /*
50         FIXME: This should eventually be moved somewhere else
51         It also needs to be kept in sync with the definition of CSMRestrictionFlags
52         in network/networkprotocol.h
53 */
54 const static CSMFlagDesc flagdesc_csm_restriction[] = {
55         {"load_client_mods",  CSM_RF_LOAD_CLIENT_MODS},
56         {"chat_messages",     CSM_RF_CHAT_MESSAGES},
57         {"read_itemdefs",     CSM_RF_READ_ITEMDEFS},
58         {"read_nodedefs",     CSM_RF_READ_NODEDEFS},
59         {"lookup_nodes",      CSM_RF_LOOKUP_NODES},
60         {"read_playerinfo",   CSM_RF_READ_PLAYERINFO},
61         {NULL,      0}
62 };
63
64 // get_current_modname()
65 int ModApiClient::l_get_current_modname(lua_State *L)
66 {
67         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
68         return 1;
69 }
70
71 // get_modpath(modname)
72 int ModApiClient::l_get_modpath(lua_State *L)
73 {
74         std::string modname = readParam<std::string>(L, 1);
75         // Client mods use a virtual filesystem, see Client::scanModSubfolder()
76         std::string path = modname + ":";
77         lua_pushstring(L, path.c_str());
78         return 1;
79 }
80
81 // get_last_run_mod()
82 int ModApiClient::l_get_last_run_mod(lua_State *L)
83 {
84         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
85         std::string current_mod = readParam<std::string>(L, -1, "");
86         if (current_mod.empty()) {
87                 lua_pop(L, 1);
88                 lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
89         }
90         return 1;
91 }
92
93 // set_last_run_mod(modname)
94 int ModApiClient::l_set_last_run_mod(lua_State *L)
95 {
96         if (!lua_isstring(L, 1))
97                 return 0;
98
99         const char *mod = lua_tostring(L, 1);
100         getScriptApiBase(L)->setOriginDirect(mod);
101         lua_pushboolean(L, true);
102         return 1;
103 }
104
105 // print(text)
106 int ModApiClient::l_print(lua_State *L)
107 {
108         NO_MAP_LOCK_REQUIRED;
109         std::string text = luaL_checkstring(L, 1);
110         rawstream << text << std::endl;
111         return 0;
112 }
113
114 // display_chat_message(message)
115 int ModApiClient::l_display_chat_message(lua_State *L)
116 {
117         if (!lua_isstring(L, 1))
118                 return 0;
119
120         std::string message = luaL_checkstring(L, 1);
121         getClient(L)->pushToChatQueue(new ChatMessage(utf8_to_wide(message)));
122         lua_pushboolean(L, true);
123         return 1;
124 }
125
126 // send_chat_message(message)
127 int ModApiClient::l_send_chat_message(lua_State *L)
128 {
129         if (!lua_isstring(L, 1))
130                 return 0;
131
132         // If server disabled this API, discard
133
134         if (checkCSMRestrictionFlag(CSM_RF_CHAT_MESSAGES))
135                 return 0;
136
137         std::string message = luaL_checkstring(L, 1);
138         getClient(L)->sendChatMessage(utf8_to_wide(message));
139         return 0;
140 }
141
142 // clear_out_chat_queue()
143 int ModApiClient::l_clear_out_chat_queue(lua_State *L)
144 {
145         getClient(L)->clearOutChatQueue();
146         return 0;
147 }
148
149 // get_player_names()
150 int ModApiClient::l_get_player_names(lua_State *L)
151 {
152         if (checkCSMRestrictionFlag(CSM_RF_READ_PLAYERINFO))
153                 return 0;
154
155         const std::list<std::string> &plist = getClient(L)->getConnectedPlayerNames();
156         lua_createtable(L, plist.size(), 0);
157         int newTable = lua_gettop(L);
158         int index = 1;
159         std::list<std::string>::const_iterator iter;
160         for (iter = plist.begin(); iter != plist.end(); ++iter) {
161                 lua_pushstring(L, (*iter).c_str());
162                 lua_rawseti(L, newTable, index);
163                 index++;
164         }
165         return 1;
166 }
167
168 // show_formspec(formspec)
169 int ModApiClient::l_show_formspec(lua_State *L)
170 {
171         if (!lua_isstring(L, 1) || !lua_isstring(L, 2))
172                 return 0;
173
174         ClientEvent *event = new ClientEvent();
175         event->type = CE_SHOW_LOCAL_FORMSPEC;
176         event->show_formspec.formname = new std::string(luaL_checkstring(L, 1));
177         event->show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
178         getClient(L)->pushToEventQueue(event);
179         lua_pushboolean(L, true);
180         return 1;
181 }
182
183 // send_respawn()
184 int ModApiClient::l_send_respawn(lua_State *L)
185 {
186         getClient(L)->sendRespawn();
187         return 0;
188 }
189
190 // disconnect()
191 int ModApiClient::l_disconnect(lua_State *L)
192 {
193         // Stops badly written Lua code form causing boot loops
194         if (getClient(L)->isShutdown()) {
195                 lua_pushboolean(L, false);
196                 return 1;
197         }
198
199         g_gamecallback->disconnect();
200         lua_pushboolean(L, true);
201         return 1;
202 }
203
204 // gettext(text)
205 int ModApiClient::l_gettext(lua_State *L)
206 {
207         std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
208         lua_pushstring(L, text.c_str());
209
210         return 1;
211 }
212
213 // get_node_or_nil(pos)
214 // pos = {x=num, y=num, z=num}
215 int ModApiClient::l_get_node_or_nil(lua_State *L)
216 {
217         // pos
218         v3s16 pos = read_v3s16(L, 1);
219
220         // Do it
221         bool pos_ok;
222         MapNode n = getClient(L)->CSMGetNode(pos, &pos_ok);
223         if (pos_ok) {
224                 // Return node
225                 pushnode(L, n, getClient(L)->ndef());
226         } else {
227                 lua_pushnil(L);
228         }
229         return 1;
230 }
231
232 // get_langauge()
233 int ModApiClient::l_get_language(lua_State *L)
234 {
235 #ifdef _WIN32
236         char *locale = setlocale(LC_ALL, NULL);
237 #else
238         char *locale = setlocale(LC_MESSAGES, NULL);
239 #endif
240         std::string lang = gettext("LANG_CODE");
241         if (lang == "LANG_CODE")
242                 lang = "";
243
244         lua_pushstring(L, locale);
245         lua_pushstring(L, lang.c_str());
246         return 2;
247 }
248
249 // get_meta(pos)
250 int ModApiClient::l_get_meta(lua_State *L)
251 {
252         v3s16 p = read_v3s16(L, 1);
253
254         // check restrictions first
255         bool pos_ok;
256         getClient(L)->CSMGetNode(p, &pos_ok);
257         if (!pos_ok)
258                 return 0;
259
260         NodeMetadata *meta = getEnv(L)->getMap().getNodeMetadata(p);
261         NodeMetaRef::createClient(L, meta);
262         return 1;
263 }
264
265 // sound_play(spec, parameters)
266 int ModApiClient::l_sound_play(lua_State *L)
267 {
268         ISoundManager *sound = getClient(L)->getSoundManager();
269
270         SimpleSoundSpec spec;
271         read_soundspec(L, 1, spec);
272
273         float gain = 1.0f;
274         float pitch = 1.0f;
275         bool looped = false;
276         s32 handle;
277
278         if (lua_istable(L, 2)) {
279                 getfloatfield(L, 2, "gain", gain);
280                 getfloatfield(L, 2, "pitch", pitch);
281                 getboolfield(L, 2, "loop", looped);
282
283                 lua_getfield(L, 2, "pos");
284                 if (!lua_isnil(L, -1)) {
285                         v3f pos = read_v3f(L, -1) * BS;
286                         lua_pop(L, 1);
287                         handle = sound->playSoundAt(
288                                         spec.name, looped, gain * spec.gain, pos, pitch);
289                         lua_pushinteger(L, handle);
290                         return 1;
291                 }
292         }
293
294         handle = sound->playSound(spec.name, looped, gain * spec.gain, spec.fade, pitch);
295         lua_pushinteger(L, handle);
296
297         return 1;
298 }
299
300 // sound_stop(handle)
301 int ModApiClient::l_sound_stop(lua_State *L)
302 {
303         s32 handle = luaL_checkinteger(L, 1);
304
305         getClient(L)->getSoundManager()->stopSound(handle);
306
307         return 0;
308 }
309
310 // sound_fade(handle, step, gain)
311 int ModApiClient::l_sound_fade(lua_State *L)
312 {
313         s32 handle = luaL_checkinteger(L, 1);
314         float step = readParam<float>(L, 2);
315         float gain = readParam<float>(L, 3);
316         getClient(L)->getSoundManager()->fadeSound(handle, step, gain);
317         return 0;
318 }
319
320 // get_server_info()
321 int ModApiClient::l_get_server_info(lua_State *L)
322 {
323         Client *client = getClient(L);
324         Address serverAddress = client->getServerAddress();
325         lua_newtable(L);
326         lua_pushstring(L, client->getAddressName().c_str());
327         lua_setfield(L, -2, "address");
328         lua_pushstring(L, serverAddress.serializeString().c_str());
329         lua_setfield(L, -2, "ip");
330         lua_pushinteger(L, serverAddress.getPort());
331         lua_setfield(L, -2, "port");
332         lua_pushinteger(L, client->getProtoVersion());
333         lua_setfield(L, -2, "protocol_version");
334         return 1;
335 }
336
337 // get_item_def(itemstring)
338 int ModApiClient::l_get_item_def(lua_State *L)
339 {
340         IGameDef *gdef = getGameDef(L);
341         assert(gdef);
342
343         IItemDefManager *idef = gdef->idef();
344         assert(idef);
345
346         if (checkCSMRestrictionFlag(CSM_RF_READ_ITEMDEFS))
347                 return 0;
348
349         if (!lua_isstring(L, 1))
350                 return 0;
351
352         std::string name = readParam<std::string>(L, 1);
353         if (!idef->isKnown(name))
354                 return 0;
355         const ItemDefinition &def = idef->get(name);
356
357         push_item_definition_full(L, def);
358
359         return 1;
360 }
361
362 // get_node_def(nodename)
363 int ModApiClient::l_get_node_def(lua_State *L)
364 {
365         IGameDef *gdef = getGameDef(L);
366         assert(gdef);
367
368         const NodeDefManager *ndef = gdef->ndef();
369         assert(ndef);
370
371         if (!lua_isstring(L, 1))
372                 return 0;
373
374         if (checkCSMRestrictionFlag(CSM_RF_READ_NODEDEFS))
375                 return 0;
376
377         std::string name = readParam<std::string>(L, 1);
378         const ContentFeatures &cf = ndef->get(ndef->getId(name));
379         if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
380                 return 0;
381
382         push_content_features(L, cf);
383
384         return 1;
385 }
386
387 // get_privilege_list()
388 int ModApiClient::l_get_privilege_list(lua_State *L)
389 {
390         const Client *client = getClient(L);
391         lua_newtable(L);
392         for (const std::string &priv : client->getPrivilegeList()) {
393                 lua_pushboolean(L, true);
394                 lua_setfield(L, -2, priv.c_str());
395         }
396         return 1;
397 }
398
399 // get_builtin_path()
400 int ModApiClient::l_get_builtin_path(lua_State *L)
401 {
402         lua_pushstring(L, BUILTIN_MOD_NAME ":");
403         return 1;
404 }
405
406 // get_csm_restrictions()
407 int ModApiClient::l_get_csm_restrictions(lua_State *L)
408 {
409         u64 flags = getClient(L)->getCSMRestrictionFlags();
410         const CSMFlagDesc *flagdesc = flagdesc_csm_restriction;
411
412         lua_newtable(L);
413         for (int i = 0; flagdesc[i].name; i++) {
414                 setboolfield(L, -1, flagdesc[i].name, !!(flags & flagdesc[i].flag));
415         }
416         return 1;
417 }
418
419 // send_damage(damage)
420 int ModApiClient::l_send_damage(lua_State *L)
421 {
422         u16 damage = luaL_checknumber(L, 1);
423         getClient(L)->sendDamage(damage);
424         return 0;       
425 }
426
427 // place_node(pos)
428 int ModApiClient::l_place_node(lua_State *L)
429 {
430         Client *client = getClient(L);
431         ClientMap &map = client->getEnv().getClientMap();
432         LocalPlayer *player = client->getEnv().getLocalPlayer();
433         ItemStack selected_item, hand_item;
434         player->getWieldedItem(&selected_item, &hand_item);
435         const ItemDefinition &selected_def = selected_item.getDefinition(getGameDef(L)->idef());
436         v3s16 pos = read_v3s16(L, 1);
437         PointedThing pointed;
438         pointed.type = POINTEDTHING_NODE;
439         pointed.node_abovesurface = pos;
440         pointed.node_undersurface = pos;
441         NodeMetadata *meta = map.getNodeMetadata(pos);
442         g_game->nodePlacement(selected_def, selected_item, pos, pos, pointed, meta);
443         return 0;
444 }
445
446 // dig_node(pos)
447 int ModApiClient::l_dig_node(lua_State *L)
448 {
449         Client *client = getClient(L);
450         v3s16 pos = read_v3s16(L, 1);
451         PointedThing pointed;
452         pointed.type = POINTEDTHING_NODE;
453         pointed.node_abovesurface = pos;
454         pointed.node_undersurface = pos;
455         client->interact(INTERACT_START_DIGGING, pointed);
456         client->interact(INTERACT_DIGGING_COMPLETED, pointed);
457         return 0;
458 }
459
460 // get_inventory(location)
461 int ModApiClient::l_get_inventory(lua_State *L)
462 {
463         Client *client = getClient(L);
464         InventoryLocation inventory_location;
465         Inventory *inventory;
466         std::string location;
467         
468         location = readParam<std::string>(L, 1);
469
470         try {
471                 inventory_location.deSerialize(location);
472                 inventory = client->getInventory(inventory_location);
473                 push_inventory(L, inventory);
474         } catch (SerializationError &) {
475                 lua_pushnil(L);
476         }
477         
478         return 1;
479 }
480
481 // set_keypress(key_setting, pressed) -> returns true on success
482 int ModApiClient::l_set_keypress(lua_State *L)
483 {
484         std::string setting_name = "keymap_" + readParam<std::string>(L, 1);
485         bool pressed = lua_isboolean(L, 2) && readParam<bool>(L, 2);
486         try {
487                 KeyPress keyCode = getKeySetting(setting_name.c_str());
488                 if (pressed)
489                         g_game->input->setKeypress(keyCode);
490                 else
491                         g_game->input->unsetKeypress(keyCode);
492                 lua_pushboolean(L, true);
493         } catch (SettingNotFoundException &) {
494                 lua_pushboolean(L, false);
495         }
496         return 1;
497 }
498
499 void ModApiClient::Initialize(lua_State *L, int top)
500 {
501         API_FCT(get_current_modname);
502         API_FCT(get_modpath);
503         API_FCT(print);
504         API_FCT(display_chat_message);
505         API_FCT(send_chat_message);
506         API_FCT(clear_out_chat_queue);
507         API_FCT(get_player_names);
508         API_FCT(set_last_run_mod);
509         API_FCT(get_last_run_mod);
510         API_FCT(show_formspec);
511         API_FCT(send_respawn);
512         API_FCT(gettext);
513         API_FCT(get_node_or_nil);
514         API_FCT(disconnect);
515         API_FCT(get_meta);
516         API_FCT(sound_play);
517         API_FCT(sound_stop);
518         API_FCT(sound_fade);
519         API_FCT(get_server_info);
520         API_FCT(get_item_def);
521         API_FCT(get_node_def);
522         API_FCT(get_privilege_list);
523         API_FCT(get_builtin_path);
524         API_FCT(get_language);
525         API_FCT(get_csm_restrictions);
526         API_FCT(send_damage);
527         API_FCT(place_node);
528         API_FCT(dig_node);
529         API_FCT(get_inventory);
530         API_FCT(set_keypress);
531 }