3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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.
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.
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.
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"
32 #include "l_internal.h"
33 #include "l_clientobject.h"
34 #include "lua_api/l_nodemeta.h"
35 #include "gui/mainmenumanager.h"
37 #include "util/string.h"
39 #include "client/keycode.h"
41 #define checkCSMRestrictionFlag(flag) \
42 ( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) )
44 // Not the same as FlagDesc, which contains an `u32 flag`
51 FIXME: This should eventually be moved somewhere else
52 It also needs to be kept in sync with the definition of CSMRestrictionFlags
53 in network/networkprotocol.h
55 const static CSMFlagDesc flagdesc_csm_restriction[] = {
56 {"load_client_mods", CSM_RF_LOAD_CLIENT_MODS},
57 {"chat_messages", CSM_RF_CHAT_MESSAGES},
58 {"read_itemdefs", CSM_RF_READ_ITEMDEFS},
59 {"read_nodedefs", CSM_RF_READ_NODEDEFS},
60 {"lookup_nodes", CSM_RF_LOOKUP_NODES},
61 {"read_playerinfo", CSM_RF_READ_PLAYERINFO},
65 // get_current_modname()
66 int ModApiClient::l_get_current_modname(lua_State *L)
68 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
72 // get_modpath(modname)
73 int ModApiClient::l_get_modpath(lua_State *L)
75 std::string modname = readParam<std::string>(L, 1);
76 // Client mods use a virtual filesystem, see Client::scanModSubfolder()
77 std::string path = modname + ":";
78 lua_pushstring(L, path.c_str());
83 int ModApiClient::l_get_last_run_mod(lua_State *L)
85 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
86 std::string current_mod = readParam<std::string>(L, -1, "");
87 if (current_mod.empty()) {
89 lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
94 // set_last_run_mod(modname)
95 int ModApiClient::l_set_last_run_mod(lua_State *L)
97 if (!lua_isstring(L, 1))
100 const char *mod = lua_tostring(L, 1);
101 getScriptApiBase(L)->setOriginDirect(mod);
102 lua_pushboolean(L, true);
107 int ModApiClient::l_print(lua_State *L)
109 NO_MAP_LOCK_REQUIRED;
110 std::string text = luaL_checkstring(L, 1);
111 rawstream << text << std::endl;
115 // display_chat_message(message)
116 int ModApiClient::l_display_chat_message(lua_State *L)
118 if (!lua_isstring(L, 1))
121 std::string message = luaL_checkstring(L, 1);
122 getClient(L)->pushToChatQueue(new ChatMessage(utf8_to_wide(message)));
123 lua_pushboolean(L, true);
127 // send_chat_message(message)
128 int ModApiClient::l_send_chat_message(lua_State *L)
130 if (!lua_isstring(L, 1))
133 // If server disabled this API, discard
135 if (checkCSMRestrictionFlag(CSM_RF_CHAT_MESSAGES))
138 std::string message = luaL_checkstring(L, 1);
139 getClient(L)->sendChatMessage(utf8_to_wide(message));
143 // clear_out_chat_queue()
144 int ModApiClient::l_clear_out_chat_queue(lua_State *L)
146 getClient(L)->clearOutChatQueue();
150 // get_player_names()
151 int ModApiClient::l_get_player_names(lua_State *L)
153 if (checkCSMRestrictionFlag(CSM_RF_READ_PLAYERINFO))
156 const std::list<std::string> &plist = getClient(L)->getConnectedPlayerNames();
157 lua_createtable(L, plist.size(), 0);
158 int newTable = lua_gettop(L);
160 std::list<std::string>::const_iterator iter;
161 for (iter = plist.begin(); iter != plist.end(); ++iter) {
162 lua_pushstring(L, (*iter).c_str());
163 lua_rawseti(L, newTable, index);
169 // show_formspec(formspec)
170 int ModApiClient::l_show_formspec(lua_State *L)
172 if (!lua_isstring(L, 1) || !lua_isstring(L, 2))
175 ClientEvent *event = new ClientEvent();
176 event->type = CE_SHOW_LOCAL_FORMSPEC;
177 event->show_formspec.formname = new std::string(luaL_checkstring(L, 1));
178 event->show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
179 getClient(L)->pushToEventQueue(event);
180 lua_pushboolean(L, true);
185 int ModApiClient::l_send_respawn(lua_State *L)
187 getClient(L)->sendRespawn();
192 int ModApiClient::l_disconnect(lua_State *L)
194 // Stops badly written Lua code form causing boot loops
195 if (getClient(L)->isShutdown()) {
196 lua_pushboolean(L, false);
200 g_gamecallback->disconnect();
201 lua_pushboolean(L, true);
206 int ModApiClient::l_gettext(lua_State *L)
208 std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
209 lua_pushstring(L, text.c_str());
214 // get_node_or_nil(pos)
215 // pos = {x=num, y=num, z=num}
216 int ModApiClient::l_get_node_or_nil(lua_State *L)
219 v3s16 pos = read_v3s16(L, 1);
223 MapNode n = getClient(L)->CSMGetNode(pos, &pos_ok);
226 pushnode(L, n, getClient(L)->ndef());
234 int ModApiClient::l_get_language(lua_State *L)
237 char *locale = setlocale(LC_ALL, NULL);
239 char *locale = setlocale(LC_MESSAGES, NULL);
241 std::string lang = gettext("LANG_CODE");
242 if (lang == "LANG_CODE")
245 lua_pushstring(L, locale);
246 lua_pushstring(L, lang.c_str());
251 int ModApiClient::l_get_meta(lua_State *L)
253 v3s16 p = read_v3s16(L, 1);
255 // check restrictions first
257 getClient(L)->CSMGetNode(p, &pos_ok);
261 NodeMetadata *meta = getEnv(L)->getMap().getNodeMetadata(p);
262 NodeMetaRef::createClient(L, meta);
266 // sound_play(spec, parameters)
267 int ModApiClient::l_sound_play(lua_State *L)
269 ISoundManager *sound = getClient(L)->getSoundManager();
271 SimpleSoundSpec spec;
272 read_soundspec(L, 1, spec);
279 if (lua_istable(L, 2)) {
280 getfloatfield(L, 2, "gain", gain);
281 getfloatfield(L, 2, "pitch", pitch);
282 getboolfield(L, 2, "loop", looped);
284 lua_getfield(L, 2, "pos");
285 if (!lua_isnil(L, -1)) {
286 v3f pos = read_v3f(L, -1) * BS;
288 handle = sound->playSoundAt(
289 spec.name, looped, gain * spec.gain, pos, pitch);
290 lua_pushinteger(L, handle);
295 handle = sound->playSound(spec.name, looped, gain * spec.gain, spec.fade, pitch);
296 lua_pushinteger(L, handle);
301 // sound_stop(handle)
302 int ModApiClient::l_sound_stop(lua_State *L)
304 s32 handle = luaL_checkinteger(L, 1);
306 getClient(L)->getSoundManager()->stopSound(handle);
311 // sound_fade(handle, step, gain)
312 int ModApiClient::l_sound_fade(lua_State *L)
314 s32 handle = luaL_checkinteger(L, 1);
315 float step = readParam<float>(L, 2);
316 float gain = readParam<float>(L, 3);
317 getClient(L)->getSoundManager()->fadeSound(handle, step, gain);
322 int ModApiClient::l_get_server_info(lua_State *L)
324 Client *client = getClient(L);
325 Address serverAddress = client->getServerAddress();
327 lua_pushstring(L, client->getAddressName().c_str());
328 lua_setfield(L, -2, "address");
329 lua_pushstring(L, serverAddress.serializeString().c_str());
330 lua_setfield(L, -2, "ip");
331 lua_pushinteger(L, serverAddress.getPort());
332 lua_setfield(L, -2, "port");
333 lua_pushinteger(L, client->getProtoVersion());
334 lua_setfield(L, -2, "protocol_version");
338 // get_item_def(itemstring)
339 int ModApiClient::l_get_item_def(lua_State *L)
341 IGameDef *gdef = getGameDef(L);
344 IItemDefManager *idef = gdef->idef();
347 if (checkCSMRestrictionFlag(CSM_RF_READ_ITEMDEFS))
350 if (!lua_isstring(L, 1))
353 std::string name = readParam<std::string>(L, 1);
354 if (!idef->isKnown(name))
356 const ItemDefinition &def = idef->get(name);
358 push_item_definition_full(L, def);
363 // get_node_def(nodename)
364 int ModApiClient::l_get_node_def(lua_State *L)
366 IGameDef *gdef = getGameDef(L);
369 const NodeDefManager *ndef = gdef->ndef();
372 if (!lua_isstring(L, 1))
375 if (checkCSMRestrictionFlag(CSM_RF_READ_NODEDEFS))
378 std::string name = readParam<std::string>(L, 1);
379 const ContentFeatures &cf = ndef->get(ndef->getId(name));
380 if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
383 push_content_features(L, cf);
388 // get_privilege_list()
389 int ModApiClient::l_get_privilege_list(lua_State *L)
391 const Client *client = getClient(L);
393 for (const std::string &priv : client->getPrivilegeList()) {
394 lua_pushboolean(L, true);
395 lua_setfield(L, -2, priv.c_str());
400 // get_builtin_path()
401 int ModApiClient::l_get_builtin_path(lua_State *L)
403 lua_pushstring(L, BUILTIN_MOD_NAME ":");
407 // get_csm_restrictions()
408 int ModApiClient::l_get_csm_restrictions(lua_State *L)
410 u64 flags = getClient(L)->getCSMRestrictionFlags();
411 const CSMFlagDesc *flagdesc = flagdesc_csm_restriction;
414 for (int i = 0; flagdesc[i].name; i++) {
415 setboolfield(L, -1, flagdesc[i].name, !!(flags & flagdesc[i].flag));
420 // send_damage(damage)
421 int ModApiClient::l_send_damage(lua_State *L)
423 u16 damage = luaL_checknumber(L, 1);
424 getClient(L)->sendDamage(damage);
429 int ModApiClient::l_place_node(lua_State *L)
431 Client *client = getClient(L);
432 ClientMap &map = client->getEnv().getClientMap();
433 LocalPlayer *player = client->getEnv().getLocalPlayer();
434 ItemStack selected_item, hand_item;
435 player->getWieldedItem(&selected_item, &hand_item);
436 const ItemDefinition &selected_def = selected_item.getDefinition(getGameDef(L)->idef());
437 v3s16 pos = read_v3s16(L, 1);
438 PointedThing pointed;
439 pointed.type = POINTEDTHING_NODE;
440 pointed.node_abovesurface = pos;
441 pointed.node_undersurface = pos;
442 NodeMetadata *meta = map.getNodeMetadata(pos);
443 g_game->nodePlacement(selected_def, selected_item, pos, pos, pointed, meta, true);
448 int ModApiClient::l_dig_node(lua_State *L)
450 Client *client = getClient(L);
451 v3s16 pos = read_v3s16(L, 1);
452 PointedThing pointed;
453 pointed.type = POINTEDTHING_NODE;
454 pointed.node_abovesurface = pos;
455 pointed.node_undersurface = pos;
456 client->interact(INTERACT_START_DIGGING, pointed);
457 client->interact(INTERACT_DIGGING_COMPLETED, pointed);
458 client->removeNode(pos);
462 // get_inventory(location)
463 int ModApiClient::l_get_inventory(lua_State *L)
465 Client *client = getClient(L);
466 InventoryLocation inventory_location;
467 Inventory *inventory;
468 std::string location;
470 location = readParam<std::string>(L, 1);
473 inventory_location.deSerialize(location);
474 inventory = client->getInventory(inventory_location);
476 throw SerializationError(std::string("Attempt to access nonexistant inventory (") + location + ")");
477 push_inventory(L, inventory);
478 } catch (SerializationError &) {
485 // set_keypress(key_setting, pressed) -> returns true on success
486 int ModApiClient::l_set_keypress(lua_State *L)
488 std::string setting_name = "keymap_" + readParam<std::string>(L, 1);
489 bool pressed = lua_isboolean(L, 2) && readParam<bool>(L, 2);
491 KeyPress keyCode = getKeySetting(setting_name.c_str());
493 g_game->input->setKeypress(keyCode);
495 g_game->input->unsetKeypress(keyCode);
496 lua_pushboolean(L, true);
497 } catch (SettingNotFoundException &) {
498 lua_pushboolean(L, false);
503 // drop_selected_item()
504 int ModApiClient::l_drop_selected_item(lua_State *L)
506 g_game->dropSelectedItem();
510 // get_objects_inside_radius(pos, radius)
511 int ModApiClient::l_get_objects_inside_radius(lua_State *L)
513 ClientEnvironment &env = getClient(L)->getEnv();
515 v3f pos = checkFloatPos(L, 1);
516 float radius = readParam<float>(L, 2) * BS;
518 std::vector<DistanceSortedActiveObject> objs;
519 env.getActiveObjects(pos, radius, objs);
522 lua_createtable(L, objs.size(), 0);
523 for (const auto obj : objs) {
524 push_objectRef(L, obj.obj->getId());
525 lua_rawseti(L, -2, ++i);
531 int ModApiClient::l_make_screenshot(lua_State *L)
533 getClient(L)->makeScreenshot();
542 * `{type="node", under=pos, above=pos}`
543 * Indicates a pointed node selection box.
544 * `under` refers to the node position behind the pointed face.
545 * `above` refers to the node position in front of the pointed face.
546 * `{type="object", ref=ObjectRef}`
548 Exact pointing location (currently only `Raycast` supports these fields):
550 * `pointed_thing.intersection_point`: The absolute world coordinates of the
551 point on the selection box which is pointed at. May be in the selection box
552 if the pointer is in the box too.
553 * `pointed_thing.box_id`: The ID of the pointed selection box (counting starts
555 * `pointed_thing.intersection_normal`: Unit vector, points outwards of the
556 selected selection box. This specifies which face is pointed at.
557 Is a null vector `{x = 0, y = 0, z = 0}` when the pointer is inside the
561 // interact(action, pointed_thing)
562 int ModApiClient::l_interact(lua_State *L)
564 std::string action_str = readParam<std::string>(L, 1);
565 InteractAction action;
567 if (action_str == "start_digging")
568 action = INTERACT_START_DIGGING;
569 else if (action_str == "stop_digging")
570 action = INTERACT_STOP_DIGGING;
571 else if (action_str == "digging_completed")
572 action = INTERACT_DIGGING_COMPLETED;
573 else if (action_str == "place")
574 action = INTERACT_PLACE;
575 else if (action_str == "use")
576 action = INTERACT_USE;
577 else if (action_str == "activate")
578 action = INTERACT_ACTIVATE;
582 lua_getfield(L, 2, "type");
583 if (! lua_isstring(L, -1))
585 std::string type_str = lua_tostring(L, -1);
588 PointedThingType type;
590 if (type_str == "nothing")
591 type = POINTEDTHING_NOTHING;
592 else if (type_str == "node")
593 type = POINTEDTHING_NODE;
594 else if (type_str == "object")
595 type = POINTEDTHING_OBJECT;
599 PointedThing pointed;
601 ClientObjectRef *obj;
604 case POINTEDTHING_NODE:
605 lua_getfield(L, 2, "under");
606 pointed.node_undersurface = check_v3s16(L, -1);
608 lua_getfield(L, 2, "above");
609 pointed.node_abovesurface = check_v3s16(L, -1);
611 case POINTEDTHING_OBJECT:
612 lua_getfield(L, 2, "ref");
613 obj = ClientObjectRef::checkobject(L, -1);
614 pointed.object_id = obj->getClientActiveObject()->getId();
620 getClient(L)->interact(action, pointed);
621 lua_pushboolean(L, true);
625 StringMap *table_to_stringmap(lua_State *L, int index)
627 StringMap *m = new StringMap;
629 lua_pushvalue(L, index);
632 while (lua_next(L, -2)) {
633 lua_pushvalue(L, -2);
634 std::basic_string<char> key = lua_tostring(L, -1);
635 std::basic_string<char> value = lua_tostring(L, -2);
645 // send_inventory_fields(formname, fields)
646 // Only works if the inventory form was opened beforehand.
647 int ModApiClient::l_send_inventory_fields(lua_State *L)
649 std::string formname = luaL_checkstring(L, 1);
650 StringMap *fields = table_to_stringmap(L, 2);
652 getClient(L)->sendInventoryFields(formname, *fields);
656 // send_nodemeta_fields(position, formname, fields)
657 int ModApiClient::l_send_nodemeta_fields(lua_State *L)
659 v3s16 pos = check_v3s16(L, 1);
660 std::string formname = luaL_checkstring(L, 2);
661 StringMap *m = table_to_stringmap(L, 3);
663 getClient(L)->sendNodemetaFields(pos, formname, *m);
667 void ModApiClient::Initialize(lua_State *L, int top)
669 API_FCT(get_current_modname);
670 API_FCT(get_modpath);
672 API_FCT(display_chat_message);
673 API_FCT(send_chat_message);
674 API_FCT(clear_out_chat_queue);
675 API_FCT(get_player_names);
676 API_FCT(set_last_run_mod);
677 API_FCT(get_last_run_mod);
678 API_FCT(show_formspec);
679 API_FCT(send_respawn);
681 API_FCT(get_node_or_nil);
687 API_FCT(get_server_info);
688 API_FCT(get_item_def);
689 API_FCT(get_node_def);
690 API_FCT(get_privilege_list);
691 API_FCT(get_builtin_path);
692 API_FCT(get_language);
693 API_FCT(get_csm_restrictions);
694 API_FCT(send_damage);
697 API_FCT(get_inventory);
698 API_FCT(set_keypress);
699 API_FCT(drop_selected_item);
700 API_FCT(get_objects_inside_radius);
701 API_FCT(make_screenshot);
703 API_FCT(send_inventory_fields);
704 API_FCT(send_nodemeta_fields);