#include "l_client.h"
#include "chatmessage.h"
-#include "clientenvironment.h"
+#include "client/client.h"
+#include "client/clientevent.h"
+#include "client/sound.h"
+#include "client/clientenvironment.h"
+#include "client/game.h"
#include "common/c_content.h"
#include "common/c_converter.h"
#include "cpp_api/s_base.h"
#include "gettext.h"
#include "l_internal.h"
-#include "lua_api/l_item.h"
+#include "l_clientobject.h"
#include "lua_api/l_nodemeta.h"
-#include "mainmenumanager.h"
+#include "gui/mainmenumanager.h"
#include "map.h"
#include "util/string.h"
#include "nodedef.h"
+#include "client/keycode.h"
-extern MainGameCallback *g_gamecallback;
+#define checkCSMRestrictionFlag(flag) \
+ ( getClient(L)->checkCSMRestrictionFlag(CSMRestrictionFlags::flag) )
+// Not the same as FlagDesc, which contains an `u32 flag`
+struct CSMFlagDesc {
+ const char *name;
+ u64 flag;
+};
+
+/*
+ FIXME: This should eventually be moved somewhere else
+ It also needs to be kept in sync with the definition of CSMRestrictionFlags
+ in network/networkprotocol.h
+*/
+const static CSMFlagDesc flagdesc_csm_restriction[] = {
+ {"load_client_mods", CSM_RF_LOAD_CLIENT_MODS},
+ {"chat_messages", CSM_RF_CHAT_MESSAGES},
+ {"read_itemdefs", CSM_RF_READ_ITEMDEFS},
+ {"read_nodedefs", CSM_RF_READ_NODEDEFS},
+ {"lookup_nodes", CSM_RF_LOOKUP_NODES},
+ {"read_playerinfo", CSM_RF_READ_PLAYERINFO},
+ {NULL, 0}
+};
+
+// get_current_modname()
int ModApiClient::l_get_current_modname(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
return 1;
}
+// get_modpath(modname)
+int ModApiClient::l_get_modpath(lua_State *L)
+{
+ std::string modname = readParam<std::string>(L, 1);
+ // Client mods use a virtual filesystem, see Client::scanModSubfolder()
+ std::string path = modname + ":";
+ lua_pushstring(L, path.c_str());
+ return 1;
+}
+
// get_last_run_mod()
int ModApiClient::l_get_last_run_mod(lua_State *L)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
- const char *current_mod = lua_tostring(L, -1);
- if (current_mod == NULL || current_mod[0] == '\0') {
+ std::string current_mod = readParam<std::string>(L, -1, "");
+ if (current_mod.empty()) {
lua_pop(L, 1);
lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
}
return 0;
// If server disabled this API, discard
- if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_CHAT_MESSAGES))
+
+ if (checkCSMRestrictionFlag(CSM_RF_CHAT_MESSAGES))
return 0;
std::string message = luaL_checkstring(L, 1);
// get_player_names()
int ModApiClient::l_get_player_names(lua_State *L)
{
+ if (checkCSMRestrictionFlag(CSM_RF_READ_PLAYERINFO))
+ return 0;
+
const std::list<std::string> &plist = getClient(L)->getConnectedPlayerNames();
lua_createtable(L, plist.size(), 0);
int newTable = lua_gettop(L);
if (!lua_isstring(L, 1) || !lua_isstring(L, 2))
return 0;
- ClientEvent event;
- event.type = CE_SHOW_LOCAL_FORMSPEC;
- event.show_formspec.formname = new std::string(luaL_checkstring(L, 1));
- event.show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
+ ClientEvent *event = new ClientEvent();
+ event->type = CE_SHOW_LOCAL_FORMSPEC;
+ event->show_formspec.formname = new std::string(luaL_checkstring(L, 1));
+ event->show_formspec.formspec = new std::string(luaL_checkstring(L, 2));
getClient(L)->pushToEventQueue(event);
lua_pushboolean(L, true);
return 1;
return 1;
}
-// get_node(pos)
+// get_node_or_nil(pos)
// pos = {x=num, y=num, z=num}
int ModApiClient::l_get_node_or_nil(lua_State *L)
{
// Do it
bool pos_ok;
- MapNode n = getClient(L)->getNode(pos, &pos_ok);
+ MapNode n = getClient(L)->CSMGetNode(pos, &pos_ok);
if (pos_ok) {
// Return node
pushnode(L, n, getClient(L)->ndef());
return 1;
}
-int ModApiClient::l_get_wielded_item(lua_State *L)
+// get_langauge()
+int ModApiClient::l_get_language(lua_State *L)
{
- Client *client = getClient(L);
-
- Inventory local_inventory(client->idef());
- client->getLocalInventory(local_inventory);
-
- InventoryList *mlist = local_inventory.getList("main");
-
- if (mlist && client->getPlayerItem() < mlist->getSize()) {
- LuaItemStack::create(L, mlist->getItem(client->getPlayerItem()));
- } else {
- LuaItemStack::create(L, ItemStack());
- }
- return 1;
+#ifdef _WIN32
+ char *locale = setlocale(LC_ALL, NULL);
+#else
+ char *locale = setlocale(LC_MESSAGES, NULL);
+#endif
+ std::string lang = gettext("LANG_CODE");
+ if (lang == "LANG_CODE")
+ lang = "";
+
+ lua_pushstring(L, locale);
+ lua_pushstring(L, lang.c_str());
+ return 2;
}
// get_meta(pos)
int ModApiClient::l_get_meta(lua_State *L)
{
v3s16 p = read_v3s16(L, 1);
- NodeMetadata *meta = getClient(L)->getEnv().getMap().getNodeMetadata(p);
+
+ // check restrictions first
+ bool pos_ok;
+ getClient(L)->CSMGetNode(p, &pos_ok);
+ if (!pos_ok)
+ return 0;
+
+ NodeMetadata *meta = getEnv(L)->getMap().getNodeMetadata(p);
NodeMetaRef::createClient(L, meta);
return 1;
}
+// sound_play(spec, parameters)
int ModApiClient::l_sound_play(lua_State *L)
{
ISoundManager *sound = getClient(L)->getSoundManager();
SimpleSoundSpec spec;
read_soundspec(L, 1, spec);
+
float gain = 1.0f;
float pitch = 1.0f;
bool looped = false;
}
}
- handle = sound->playSound(spec.name, looped, gain * spec.gain, 0.0f, pitch);
+ handle = sound->playSound(spec.name, looped, gain * spec.gain, spec.fade, pitch);
lua_pushinteger(L, handle);
return 1;
}
+// sound_stop(handle)
int ModApiClient::l_sound_stop(lua_State *L)
{
- u32 handle = luaL_checkinteger(L, 1);
+ s32 handle = luaL_checkinteger(L, 1);
getClient(L)->getSoundManager()->stopSound(handle);
return 0;
}
+// sound_fade(handle, step, gain)
+int ModApiClient::l_sound_fade(lua_State *L)
+{
+ s32 handle = luaL_checkinteger(L, 1);
+ float step = readParam<float>(L, 2);
+ float gain = readParam<float>(L, 3);
+ getClient(L)->getSoundManager()->fadeSound(handle, step, gain);
+ return 0;
+}
+
// get_server_info()
int ModApiClient::l_get_server_info(lua_State *L)
{
IItemDefManager *idef = gdef->idef();
assert(idef);
- if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_READ_ITEMDEFS))
+ if (checkCSMRestrictionFlag(CSM_RF_READ_ITEMDEFS))
return 0;
if (!lua_isstring(L, 1))
return 0;
- const std::string &name(lua_tostring(L, 1));
+ std::string name = readParam<std::string>(L, 1);
if (!idef->isKnown(name))
return 0;
const ItemDefinition &def = idef->get(name);
IGameDef *gdef = getGameDef(L);
assert(gdef);
- INodeDefManager *ndef = gdef->ndef();
+ const NodeDefManager *ndef = gdef->ndef();
assert(ndef);
if (!lua_isstring(L, 1))
return 0;
- if (getClient(L)->checkCSMFlavourLimit(CSMFlavourLimit::CSM_FL_READ_NODEDEFS))
+ if (checkCSMRestrictionFlag(CSM_RF_READ_NODEDEFS))
return 0;
- const std::string &name = lua_tostring(L, 1);
+ std::string name = readParam<std::string>(L, 1);
const ContentFeatures &cf = ndef->get(ndef->getId(name));
if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore
return 0;
return 1;
}
-int ModApiClient::l_take_screenshot(lua_State *L)
-{
- Client *client = getClient(L);
- client->makeScreenshot();
- return 0;
-}
-
+// get_privilege_list()
int ModApiClient::l_get_privilege_list(lua_State *L)
{
const Client *client = getClient(L);
return 1;
}
+// get_csm_restrictions()
+int ModApiClient::l_get_csm_restrictions(lua_State *L)
+{
+ u64 flags = getClient(L)->getCSMRestrictionFlags();
+ const CSMFlagDesc *flagdesc = flagdesc_csm_restriction;
+
+ lua_newtable(L);
+ for (int i = 0; flagdesc[i].name; i++) {
+ setboolfield(L, -1, flagdesc[i].name, !!(flags & flagdesc[i].flag));
+ }
+ return 1;
+}
+
+// send_damage(damage)
+int ModApiClient::l_send_damage(lua_State *L)
+{
+ u16 damage = luaL_checknumber(L, 1);
+ getClient(L)->sendDamage(damage);
+ return 0;
+}
+
+// place_node(pos)
+int ModApiClient::l_place_node(lua_State *L)
+{
+ Client *client = getClient(L);
+ ClientMap &map = client->getEnv().getClientMap();
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ ItemStack selected_item, hand_item;
+ player->getWieldedItem(&selected_item, &hand_item);
+ const ItemDefinition &selected_def = selected_item.getDefinition(getGameDef(L)->idef());
+ v3s16 pos = read_v3s16(L, 1);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos;
+ NodeMetadata *meta = map.getNodeMetadata(pos);
+ g_game->nodePlacement(selected_def, selected_item, pos, pos, pointed, meta);
+ return 0;
+}
+
+// dig_node(pos)
+int ModApiClient::l_dig_node(lua_State *L)
+{
+ Client *client = getClient(L);
+ v3s16 pos = read_v3s16(L, 1);
+ PointedThing pointed;
+ pointed.type = POINTEDTHING_NODE;
+ pointed.node_abovesurface = pos;
+ pointed.node_undersurface = pos;
+ client->interact(INTERACT_START_DIGGING, pointed);
+ client->interact(INTERACT_DIGGING_COMPLETED, pointed);
+ return 0;
+}
+
+// get_inventory(location)
+int ModApiClient::l_get_inventory(lua_State *L)
+{
+ Client *client = getClient(L);
+ InventoryLocation inventory_location;
+ Inventory *inventory;
+ std::string location;
+
+ location = readParam<std::string>(L, 1);
+
+ try {
+ inventory_location.deSerialize(location);
+ inventory = client->getInventory(inventory_location);
+ push_inventory(L, inventory);
+ } catch (SerializationError &) {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+// set_keypress(key_setting, pressed) -> returns true on success
+int ModApiClient::l_set_keypress(lua_State *L)
+{
+ std::string setting_name = "keymap_" + readParam<std::string>(L, 1);
+ bool pressed = lua_isboolean(L, 2) && readParam<bool>(L, 2);
+ try {
+ KeyPress keyCode = getKeySetting(setting_name.c_str());
+ if (pressed)
+ g_game->input->setKeypress(keyCode);
+ else
+ g_game->input->unsetKeypress(keyCode);
+ lua_pushboolean(L, true);
+ } catch (SettingNotFoundException &) {
+ lua_pushboolean(L, false);
+ }
+ return 1;
+}
+
+// drop_selected_item()
+int ModApiClient::l_drop_selected_item(lua_State *L)
+{
+ g_game->dropSelectedItem();
+ return 0;
+}
+
+// get_objects_inside_radius(pos, radius)
+int ModApiClient::l_get_objects_inside_radius(lua_State *L)
+{
+ ClientEnvironment &env = getClient(L)->getEnv();
+
+ v3f pos = checkFloatPos(L, 1);
+ float radius = readParam<float>(L, 2) * BS;
+
+ std::vector<DistanceSortedActiveObject> objs;
+ env.getActiveObjects(pos, radius, objs);
+
+ int i = 0;
+ lua_createtable(L, objs.size(), 0);
+ for (const auto obj : objs) {
+ ClientObjectRef::create(L, obj.obj); // TODO: getObjectRefOrCreate
+ lua_rawseti(L, -2, ++i);
+ }
+ return 1;
+}
+
void ModApiClient::Initialize(lua_State *L, int top)
{
API_FCT(get_current_modname);
+ API_FCT(get_modpath);
API_FCT(print);
API_FCT(display_chat_message);
API_FCT(send_chat_message);
API_FCT(send_respawn);
API_FCT(gettext);
API_FCT(get_node_or_nil);
- API_FCT(get_wielded_item);
API_FCT(disconnect);
API_FCT(get_meta);
API_FCT(sound_play);
API_FCT(sound_stop);
+ API_FCT(sound_fade);
API_FCT(get_server_info);
API_FCT(get_item_def);
API_FCT(get_node_def);
- API_FCT(take_screenshot);
API_FCT(get_privilege_list);
API_FCT(get_builtin_path);
+ API_FCT(get_language);
+ API_FCT(get_csm_restrictions);
+ API_FCT(send_damage);
+ API_FCT(place_node);
+ API_FCT(dig_node);
+ API_FCT(get_inventory);
+ API_FCT(set_keypress);
+ API_FCT(drop_selected_item);
+ API_FCT(get_objects_inside_radius);
}