You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1190 lines
30 KiB

  1. /*
  2. Minetest
  3. Copyright (C) 2013 sapier
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 3.0 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "lua_api/l_mainmenu.h"
  17. #include "lua_api/l_internal.h"
  18. #include "common/c_content.h"
  19. #include "cpp_api/s_async.h"
  20. #include "guiEngine.h"
  21. #include "guiMainMenu.h"
  22. #include "guiKeyChangeMenu.h"
  23. #include "guiFileSelectMenu.h"
  24. #include "subgame.h"
  25. #include "version.h"
  26. #include "porting.h"
  27. #include "filesys.h"
  28. #include "convert_json.h"
  29. #include "serverlist.h"
  30. #include "mapgen.h"
  31. #include "settings.h"
  32. #include "EDriverTypes.h"
  33. #include <IFileArchive.h>
  34. #include <IFileSystem.h>
  35. /******************************************************************************/
  36. std::string ModApiMainMenu::getTextData(lua_State *L, std::string name)
  37. {
  38. lua_getglobal(L, "gamedata");
  39. lua_getfield(L, -1, name.c_str());
  40. if(lua_isnil(L, -1))
  41. return "";
  42. return luaL_checkstring(L, -1);
  43. }
  44. /******************************************************************************/
  45. int ModApiMainMenu::getIntegerData(lua_State *L, std::string name,bool& valid)
  46. {
  47. lua_getglobal(L, "gamedata");
  48. lua_getfield(L, -1, name.c_str());
  49. if(lua_isnil(L, -1)) {
  50. valid = false;
  51. return -1;
  52. }
  53. valid = true;
  54. return luaL_checkinteger(L, -1);
  55. }
  56. /******************************************************************************/
  57. int ModApiMainMenu::getBoolData(lua_State *L, std::string name,bool& valid)
  58. {
  59. lua_getglobal(L, "gamedata");
  60. lua_getfield(L, -1, name.c_str());
  61. if(lua_isnil(L, -1)) {
  62. valid = false;
  63. return false;
  64. }
  65. valid = true;
  66. return lua_toboolean(L, -1);
  67. }
  68. /******************************************************************************/
  69. int ModApiMainMenu::l_update_formspec(lua_State *L)
  70. {
  71. GUIEngine* engine = getGuiEngine(L);
  72. sanity_check(engine != NULL);
  73. if (engine->m_startgame)
  74. return 0;
  75. //read formspec
  76. std::string formspec(luaL_checkstring(L, 1));
  77. if (engine->m_formspecgui != 0) {
  78. engine->m_formspecgui->setForm(formspec);
  79. }
  80. return 0;
  81. }
  82. /******************************************************************************/
  83. int ModApiMainMenu::l_start(lua_State *L)
  84. {
  85. GUIEngine* engine = getGuiEngine(L);
  86. sanity_check(engine != NULL);
  87. //update c++ gamedata from lua table
  88. bool valid = false;
  89. MainMenuData *data = engine->m_data;
  90. data->selected_world = getIntegerData(L, "selected_world",valid) -1;
  91. data->simple_singleplayer_mode = getBoolData(L,"singleplayer",valid);
  92. data->do_reconnect = getBoolData(L, "do_reconnect", valid);
  93. if (!data->do_reconnect) {
  94. data->name = getTextData(L,"playername");
  95. data->password = getTextData(L,"password");
  96. data->address = getTextData(L,"address");
  97. data->port = getTextData(L,"port");
  98. }
  99. data->serverdescription = getTextData(L,"serverdescription");
  100. data->servername = getTextData(L,"servername");
  101. //close menu next time
  102. engine->m_startgame = true;
  103. return 0;
  104. }
  105. /******************************************************************************/
  106. int ModApiMainMenu::l_close(lua_State *L)
  107. {
  108. GUIEngine* engine = getGuiEngine(L);
  109. sanity_check(engine != NULL);
  110. engine->m_kill = true;
  111. return 0;
  112. }
  113. /******************************************************************************/
  114. int ModApiMainMenu::l_set_background(lua_State *L)
  115. {
  116. GUIEngine* engine = getGuiEngine(L);
  117. sanity_check(engine != NULL);
  118. std::string backgroundlevel(luaL_checkstring(L, 1));
  119. std::string texturename(luaL_checkstring(L, 2));
  120. bool tile_image = false;
  121. bool retval = false;
  122. unsigned int minsize = 16;
  123. if (!lua_isnone(L, 3)) {
  124. tile_image = lua_toboolean(L, 3);
  125. }
  126. if (!lua_isnone(L, 4)) {
  127. minsize = lua_tonumber(L, 4);
  128. }
  129. if (backgroundlevel == "background") {
  130. retval |= engine->setTexture(TEX_LAYER_BACKGROUND, texturename,
  131. tile_image, minsize);
  132. }
  133. if (backgroundlevel == "overlay") {
  134. retval |= engine->setTexture(TEX_LAYER_OVERLAY, texturename,
  135. tile_image, minsize);
  136. }
  137. if (backgroundlevel == "header") {
  138. retval |= engine->setTexture(TEX_LAYER_HEADER, texturename,
  139. tile_image, minsize);
  140. }
  141. if (backgroundlevel == "footer") {
  142. retval |= engine->setTexture(TEX_LAYER_FOOTER, texturename,
  143. tile_image, minsize);
  144. }
  145. lua_pushboolean(L,retval);
  146. return 1;
  147. }
  148. /******************************************************************************/
  149. int ModApiMainMenu::l_set_clouds(lua_State *L)
  150. {
  151. GUIEngine* engine = getGuiEngine(L);
  152. sanity_check(engine != NULL);
  153. bool value = lua_toboolean(L,1);
  154. engine->m_clouds_enabled = value;
  155. return 0;
  156. }
  157. /******************************************************************************/
  158. int ModApiMainMenu::l_get_textlist_index(lua_State *L)
  159. {
  160. // get_table_index accepts both tables and textlists
  161. return l_get_table_index(L);
  162. }
  163. /******************************************************************************/
  164. int ModApiMainMenu::l_get_table_index(lua_State *L)
  165. {
  166. GUIEngine* engine = getGuiEngine(L);
  167. sanity_check(engine != NULL);
  168. std::string tablename(luaL_checkstring(L, 1));
  169. GUITable *table = engine->m_menu->getTable(tablename);
  170. s32 selection = table ? table->getSelected() : 0;
  171. if (selection >= 1)
  172. lua_pushinteger(L, selection);
  173. else
  174. lua_pushnil(L);
  175. return 1;
  176. }
  177. /******************************************************************************/
  178. int ModApiMainMenu::l_get_worlds(lua_State *L)
  179. {
  180. std::vector<WorldSpec> worlds = getAvailableWorlds();
  181. lua_newtable(L);
  182. int top = lua_gettop(L);
  183. unsigned int index = 1;
  184. for (unsigned int i = 0; i < worlds.size(); i++)
  185. {
  186. lua_pushnumber(L,index);
  187. lua_newtable(L);
  188. int top_lvl2 = lua_gettop(L);
  189. lua_pushstring(L,"path");
  190. lua_pushstring(L,worlds[i].path.c_str());
  191. lua_settable(L, top_lvl2);
  192. lua_pushstring(L,"name");
  193. lua_pushstring(L,worlds[i].name.c_str());
  194. lua_settable(L, top_lvl2);
  195. lua_pushstring(L,"gameid");
  196. lua_pushstring(L,worlds[i].gameid.c_str());
  197. lua_settable(L, top_lvl2);
  198. lua_settable(L, top);
  199. index++;
  200. }
  201. return 1;
  202. }
  203. /******************************************************************************/
  204. int ModApiMainMenu::l_get_games(lua_State *L)
  205. {
  206. std::vector<SubgameSpec> games = getAvailableGames();
  207. lua_newtable(L);
  208. int top = lua_gettop(L);
  209. unsigned int index = 1;
  210. for (unsigned int i = 0; i < games.size(); i++)
  211. {
  212. lua_pushnumber(L,index);
  213. lua_newtable(L);
  214. int top_lvl2 = lua_gettop(L);
  215. lua_pushstring(L,"id");
  216. lua_pushstring(L,games[i].id.c_str());
  217. lua_settable(L, top_lvl2);
  218. lua_pushstring(L,"path");
  219. lua_pushstring(L,games[i].path.c_str());
  220. lua_settable(L, top_lvl2);
  221. lua_pushstring(L,"gamemods_path");
  222. lua_pushstring(L,games[i].gamemods_path.c_str());
  223. lua_settable(L, top_lvl2);
  224. lua_pushstring(L,"name");
  225. lua_pushstring(L,games[i].name.c_str());
  226. lua_settable(L, top_lvl2);
  227. lua_pushstring(L,"menuicon_path");
  228. lua_pushstring(L,games[i].menuicon_path.c_str());
  229. lua_settable(L, top_lvl2);
  230. lua_pushstring(L,"addon_mods_paths");
  231. lua_newtable(L);
  232. int table2 = lua_gettop(L);
  233. int internal_index=1;
  234. for (std::set<std::string>::iterator iter = games[i].addon_mods_paths.begin();
  235. iter != games[i].addon_mods_paths.end(); ++iter) {
  236. lua_pushnumber(L,internal_index);
  237. lua_pushstring(L,(*iter).c_str());
  238. lua_settable(L, table2);
  239. internal_index++;
  240. }
  241. lua_settable(L, top_lvl2);
  242. lua_settable(L, top);
  243. index++;
  244. }
  245. return 1;
  246. }
  247. /******************************************************************************/
  248. int ModApiMainMenu::l_get_modstore_details(lua_State *L)
  249. {
  250. const char *modid = luaL_checkstring(L, 1);
  251. if (modid != 0) {
  252. Json::Value details;
  253. std::string url = "";
  254. try{
  255. url = g_settings->get("modstore_details_url");
  256. }
  257. catch(SettingNotFoundException &e) {
  258. lua_pushnil(L);
  259. return 1;
  260. }
  261. size_t idpos = url.find("*");
  262. url.erase(idpos,1);
  263. url.insert(idpos,modid);
  264. details = getModstoreUrl(url);
  265. ModStoreModDetails current_mod = readModStoreModDetails(details);
  266. if ( current_mod.valid) {
  267. lua_newtable(L);
  268. int top = lua_gettop(L);
  269. lua_pushstring(L,"id");
  270. lua_pushnumber(L,current_mod.id);
  271. lua_settable(L, top);
  272. lua_pushstring(L,"title");
  273. lua_pushstring(L,current_mod.title.c_str());
  274. lua_settable(L, top);
  275. lua_pushstring(L,"basename");
  276. lua_pushstring(L,current_mod.basename.c_str());
  277. lua_settable(L, top);
  278. lua_pushstring(L,"description");
  279. lua_pushstring(L,current_mod.description.c_str());
  280. lua_settable(L, top);
  281. lua_pushstring(L,"author");
  282. lua_pushstring(L,current_mod.author.username.c_str());
  283. lua_settable(L, top);
  284. lua_pushstring(L,"download_url");
  285. lua_pushstring(L,current_mod.versions[0].file.c_str());
  286. lua_settable(L, top);
  287. lua_pushstring(L,"versions");
  288. lua_newtable(L);
  289. int versionstop = lua_gettop(L);
  290. for (unsigned int i=0;i < current_mod.versions.size(); i++) {
  291. lua_pushnumber(L,i+1);
  292. lua_newtable(L);
  293. int current_element = lua_gettop(L);
  294. lua_pushstring(L,"date");
  295. lua_pushstring(L,current_mod.versions[i].date.c_str());
  296. lua_settable(L,current_element);
  297. lua_pushstring(L,"download_url");
  298. lua_pushstring(L,current_mod.versions[i].file.c_str());
  299. lua_settable(L,current_element);
  300. lua_settable(L,versionstop);
  301. }
  302. lua_settable(L, top);
  303. lua_pushstring(L,"screenshot_url");
  304. lua_pushstring(L,current_mod.titlepic.file.c_str());
  305. lua_settable(L, top);
  306. lua_pushstring(L,"license");
  307. lua_pushstring(L,current_mod.license.shortinfo.c_str());
  308. lua_settable(L, top);
  309. lua_pushstring(L,"rating");
  310. lua_pushnumber(L,current_mod.rating);
  311. lua_settable(L, top);
  312. //TODO depends
  313. //TODO softdepends
  314. return 1;
  315. }
  316. }
  317. return 0;
  318. }
  319. /******************************************************************************/
  320. int ModApiMainMenu::l_get_modstore_list(lua_State *L)
  321. {
  322. Json::Value mods;
  323. std::string url = "";
  324. try{
  325. url = g_settings->get("modstore_listmods_url");
  326. }
  327. catch(SettingNotFoundException &e) {
  328. lua_pushnil(L);
  329. return 1;
  330. }
  331. mods = getModstoreUrl(url);
  332. std::vector<ModStoreMod> moddata = readModStoreList(mods);
  333. lua_newtable(L);
  334. int top = lua_gettop(L);
  335. unsigned int index = 1;
  336. for (unsigned int i = 0; i < moddata.size(); i++)
  337. {
  338. if (moddata[i].valid) {
  339. lua_pushnumber(L,index);
  340. lua_newtable(L);
  341. int top_lvl2 = lua_gettop(L);
  342. lua_pushstring(L,"id");
  343. lua_pushnumber(L,moddata[i].id);
  344. lua_settable(L, top_lvl2);
  345. lua_pushstring(L,"title");
  346. lua_pushstring(L,moddata[i].title.c_str());
  347. lua_settable(L, top_lvl2);
  348. lua_pushstring(L,"basename");
  349. lua_pushstring(L,moddata[i].basename.c_str());
  350. lua_settable(L, top_lvl2);
  351. lua_settable(L, top);
  352. index++;
  353. }
  354. }
  355. return 1;
  356. }
  357. /******************************************************************************/
  358. int ModApiMainMenu::l_get_favorites(lua_State *L)
  359. {
  360. std::string listtype = "local";
  361. if (!lua_isnone(L,1)) {
  362. listtype = luaL_checkstring(L,1);
  363. }
  364. std::vector<ServerListSpec> servers;
  365. if(listtype == "online") {
  366. servers = ServerList::getOnline(g_settings->get("serverlist_url"));
  367. std::string aux_list = g_settings->get("serverlist_url_2");
  368. if (!aux_list.empty()) {
  369. std::vector<ServerListSpec> aux = ServerList::getOnline(aux_list);
  370. servers.insert(servers.end(), aux.begin(), aux.end());
  371. }
  372. } else {
  373. servers = ServerList::getLocal();
  374. }
  375. lua_newtable(L);
  376. int top = lua_gettop(L);
  377. unsigned int index = 1;
  378. for (unsigned int i = 0; i < servers.size(); i++)
  379. {
  380. // only list compatible servers
  381. if (listtype == "online" && (
  382. !servers[i]["proto_min"].asString().size() ||
  383. !servers[i]["proto_max"].asString().size() ||
  384. servers[i]["proto_min"].asInt() > CLIENT_PROTOCOL_VERSION_MAX ||
  385. servers[i]["proto_max"].asInt() < CLIENT_PROTOCOL_VERSION_MIN))
  386. continue;
  387. lua_pushnumber(L,index);
  388. lua_newtable(L);
  389. int top_lvl2 = lua_gettop(L);
  390. if (servers[i]["clients"].asString().size()) {
  391. std::string clients_raw = servers[i]["clients"].asString();
  392. char* endptr = 0;
  393. int numbervalue = strtol(clients_raw.c_str(),&endptr,10);
  394. if ((clients_raw != "") && (*endptr == 0)) {
  395. lua_pushstring(L,"clients");
  396. lua_pushnumber(L,numbervalue);
  397. lua_settable(L, top_lvl2);
  398. }
  399. }
  400. if (servers[i]["clients_max"].asString().size()) {
  401. std::string clients_max_raw = servers[i]["clients_max"].asString();
  402. char* endptr = 0;
  403. int numbervalue = strtol(clients_max_raw.c_str(),&endptr,10);
  404. if ((clients_max_raw != "") && (*endptr == 0)) {
  405. lua_pushstring(L,"clients_max");
  406. lua_pushnumber(L,numbervalue);
  407. lua_settable(L, top_lvl2);
  408. }
  409. }
  410. if (servers[i]["version"].asString().size()) {
  411. lua_pushstring(L,"version");
  412. std::string topush = servers[i]["version"].asString();
  413. lua_pushstring(L,topush.c_str());
  414. lua_settable(L, top_lvl2);
  415. }
  416. if (servers[i]["server_id"].asString().size()) {
  417. lua_pushstring(L,"server_id");
  418. std::string topush = servers[i]["server_id"].asString();
  419. lua_pushstring(L,topush.c_str());
  420. lua_settable(L, top_lvl2);
  421. }
  422. if (servers[i]["proto_min"].asString().size()) {
  423. lua_pushstring(L,"proto_min");
  424. lua_pushinteger(L,servers[i]["proto_min"].asInt());
  425. lua_settable(L, top_lvl2);
  426. }
  427. if (servers[i]["proto_max"].asString().size()) {
  428. lua_pushstring(L,"proto_max");
  429. lua_pushinteger(L,servers[i]["proto_max"].asInt());
  430. lua_settable(L, top_lvl2);
  431. }
  432. if (servers[i]["password"].asString().size()) {
  433. lua_pushstring(L,"password");
  434. lua_pushboolean(L,servers[i]["password"].asBool());
  435. lua_settable(L, top_lvl2);
  436. }
  437. if (servers[i]["creative"].asString().size()) {
  438. lua_pushstring(L,"creative");
  439. lua_pushboolean(L,servers[i]["creative"].asBool());
  440. lua_settable(L, top_lvl2);
  441. }
  442. if (servers[i]["damage"].asString().size()) {
  443. lua_pushstring(L,"damage");
  444. lua_pushboolean(L,servers[i]["damage"].asBool());
  445. lua_settable(L, top_lvl2);
  446. }
  447. if (servers[i]["pvp"].asString().size()) {
  448. lua_pushstring(L,"pvp");
  449. lua_pushboolean(L,servers[i]["pvp"].asBool());
  450. lua_settable(L, top_lvl2);
  451. }
  452. if (servers[i]["description"].asString().size()) {
  453. lua_pushstring(L,"description");
  454. std::string topush = servers[i]["description"].asString();
  455. lua_pushstring(L,topush.c_str());
  456. lua_settable(L, top_lvl2);
  457. }
  458. if (servers[i]["name"].asString().size()) {
  459. lua_pushstring(L,"name");
  460. std::string topush = servers[i]["name"].asString();
  461. lua_pushstring(L,topush.c_str());
  462. lua_settable(L, top_lvl2);
  463. }
  464. if (servers[i]["address"].asString().size()) {
  465. lua_pushstring(L,"address");
  466. std::string topush = servers[i]["address"].asString();
  467. lua_pushstring(L,topush.c_str());
  468. lua_settable(L, top_lvl2);
  469. }
  470. if (servers[i]["port"].asString().size()) {
  471. lua_pushstring(L,"port");
  472. std::string topush = servers[i]["port"].asString();
  473. lua_pushstring(L,topush.c_str());
  474. lua_settable(L, top_lvl2);
  475. }
  476. if (servers[i].isMember("ping")) {
  477. float ping = servers[i]["ping"].asFloat();
  478. lua_pushstring(L, "ping");
  479. lua_pushnumber(L, ping);
  480. lua_settable(L, top_lvl2);
  481. }
  482. lua_settable(L, top);
  483. index++;
  484. }
  485. return 1;
  486. }
  487. /******************************************************************************/
  488. int ModApiMainMenu::l_delete_favorite(lua_State *L)
  489. {
  490. std::vector<ServerListSpec> servers;
  491. std::string listtype = "local";
  492. if (!lua_isnone(L,2)) {
  493. listtype = luaL_checkstring(L,2);
  494. }
  495. if ((listtype != "local") &&
  496. (listtype != "online"))
  497. return 0;
  498. if(listtype == "online") {
  499. servers = ServerList::getOnline(g_settings->get("serverlist_url"));
  500. std::string aux_list = g_settings->get("serverlist_url_2");
  501. if (!aux_list.empty()) {
  502. std::vector<ServerListSpec> aux = ServerList::getOnline(aux_list);
  503. servers.insert(servers.end(), aux.begin(), aux.end());
  504. }
  505. } else {
  506. servers = ServerList::getLocal();
  507. }
  508. int fav_idx = luaL_checkinteger(L,1) -1;
  509. if ((fav_idx >= 0) &&
  510. (fav_idx < (int) servers.size())) {
  511. ServerList::deleteEntry(servers[fav_idx]);
  512. }
  513. return 0;
  514. }
  515. /******************************************************************************/
  516. int ModApiMainMenu::l_show_keys_menu(lua_State *L)
  517. {
  518. GUIEngine* engine = getGuiEngine(L);
  519. sanity_check(engine != NULL);
  520. GUIKeyChangeMenu *kmenu
  521. = new GUIKeyChangeMenu( engine->m_device->getGUIEnvironment(),
  522. engine->m_parent,
  523. -1,
  524. engine->m_menumanager);
  525. kmenu->drop();
  526. return 0;
  527. }
  528. /******************************************************************************/
  529. int ModApiMainMenu::l_create_world(lua_State *L)
  530. {
  531. const char *name = luaL_checkstring(L, 1);
  532. int gameidx = luaL_checkinteger(L,2) -1;
  533. std::string path = porting::path_user + DIR_DELIM
  534. "worlds" + DIR_DELIM
  535. + name;
  536. std::vector<SubgameSpec> games = getAvailableGames();
  537. if ((gameidx >= 0) &&
  538. (gameidx < (int) games.size())) {
  539. // Create world if it doesn't exist
  540. if (!loadGameConfAndInitWorld(path, games[gameidx])) {
  541. lua_pushstring(L, "Failed to initialize world");
  542. } else {
  543. lua_pushnil(L);
  544. }
  545. } else {
  546. lua_pushstring(L, "Invalid game index");
  547. }
  548. return 1;
  549. }
  550. /******************************************************************************/
  551. int ModApiMainMenu::l_delete_world(lua_State *L)
  552. {
  553. int worldidx = luaL_checkinteger(L,1) -1;
  554. std::vector<WorldSpec> worlds = getAvailableWorlds();
  555. if ((worldidx >= 0) &&
  556. (worldidx < (int) worlds.size())) {
  557. WorldSpec spec = worlds[worldidx];
  558. std::vector<std::string> paths;
  559. paths.push_back(spec.path);
  560. fs::GetRecursiveSubPaths(spec.path, paths);
  561. // Delete files
  562. if (!fs::DeletePaths(paths)) {
  563. lua_pushstring(L, "Failed to delete world");
  564. }
  565. else {
  566. lua_pushnil(L);
  567. }
  568. }
  569. else {
  570. lua_pushstring(L, "Invalid world index");
  571. }
  572. return 1;
  573. }
  574. /******************************************************************************/
  575. int ModApiMainMenu::l_set_topleft_text(lua_State *L)
  576. {
  577. GUIEngine* engine = getGuiEngine(L);
  578. sanity_check(engine != NULL);
  579. std::string text = "";
  580. if (!lua_isnone(L,1) && !lua_isnil(L,1))
  581. text = luaL_checkstring(L, 1);
  582. engine->setTopleftText(text);
  583. return 0;
  584. }
  585. /******************************************************************************/
  586. int ModApiMainMenu::l_get_mapgen_names(lua_State *L)
  587. {
  588. std::vector<const char *> names;
  589. Mapgen::getMapgenNames(&names, lua_toboolean(L, 1));
  590. lua_newtable(L);
  591. for (size_t i = 0; i != names.size(); i++) {
  592. lua_pushstring(L, names[i]);
  593. lua_rawseti(L, -2, i + 1);
  594. }
  595. return 1;
  596. }
  597. /******************************************************************************/
  598. int ModApiMainMenu::l_get_modpath(lua_State *L)
  599. {
  600. std::string modpath = fs::RemoveRelativePathComponents(
  601. porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
  602. lua_pushstring(L, modpath.c_str());
  603. return 1;
  604. }
  605. /******************************************************************************/
  606. int ModApiMainMenu::l_get_gamepath(lua_State *L)
  607. {
  608. std::string gamepath = fs::RemoveRelativePathComponents(
  609. porting::path_user + DIR_DELIM + "games" + DIR_DELIM);
  610. lua_pushstring(L, gamepath.c_str());
  611. return 1;
  612. }
  613. /******************************************************************************/
  614. int ModApiMainMenu::l_get_texturepath(lua_State *L)
  615. {
  616. std::string gamepath = fs::RemoveRelativePathComponents(
  617. porting::path_user + DIR_DELIM + "textures");
  618. lua_pushstring(L, gamepath.c_str());
  619. return 1;
  620. }
  621. int ModApiMainMenu::l_get_texturepath_share(lua_State *L)
  622. {
  623. std::string gamepath = fs::RemoveRelativePathComponents(
  624. porting::path_share + DIR_DELIM + "textures");
  625. lua_pushstring(L, gamepath.c_str());
  626. return 1;
  627. }
  628. /******************************************************************************/
  629. int ModApiMainMenu::l_create_dir(lua_State *L) {
  630. const char *path = luaL_checkstring(L, 1);
  631. if (ModApiMainMenu::isMinetestPath(path)) {
  632. lua_pushboolean(L, fs::CreateAllDirs(path));
  633. return 1;
  634. }
  635. lua_pushboolean(L, false);
  636. return 1;
  637. }
  638. /******************************************************************************/
  639. int ModApiMainMenu::l_delete_dir(lua_State *L)
  640. {
  641. const char *path = luaL_checkstring(L, 1);
  642. std::string absolute_path = fs::RemoveRelativePathComponents(path);
  643. if (ModApiMainMenu::isMinetestPath(absolute_path)) {
  644. lua_pushboolean(L, fs::RecursiveDelete(absolute_path));
  645. return 1;
  646. }
  647. lua_pushboolean(L, false);
  648. return 1;
  649. }
  650. /******************************************************************************/
  651. int ModApiMainMenu::l_copy_dir(lua_State *L)
  652. {
  653. const char *source = luaL_checkstring(L, 1);
  654. const char *destination = luaL_checkstring(L, 2);
  655. bool keep_source = true;
  656. if ((!lua_isnone(L,3)) &&
  657. (!lua_isnil(L,3))) {
  658. keep_source = lua_toboolean(L,3);
  659. }
  660. std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
  661. std::string absolute_source = fs::RemoveRelativePathComponents(source);
  662. if ((ModApiMainMenu::isMinetestPath(absolute_source)) &&
  663. (ModApiMainMenu::isMinetestPath(absolute_destination))) {
  664. bool retval = fs::CopyDir(absolute_source,absolute_destination);
  665. if (retval && (!keep_source)) {
  666. retval &= fs::RecursiveDelete(absolute_source);
  667. }
  668. lua_pushboolean(L,retval);
  669. return 1;
  670. }
  671. lua_pushboolean(L,false);
  672. return 1;
  673. }
  674. /******************************************************************************/
  675. int ModApiMainMenu::l_extract_zip(lua_State *L)
  676. {
  677. GUIEngine* engine = getGuiEngine(L);
  678. sanity_check(engine);
  679. const char *zipfile = luaL_checkstring(L, 1);
  680. const char *destination = luaL_checkstring(L, 2);
  681. std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
  682. if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
  683. fs::CreateAllDirs(absolute_destination);
  684. io::IFileSystem* fs = engine->m_device->getFileSystem();
  685. if (!fs->addFileArchive(zipfile,true,false,io::EFAT_ZIP)) {
  686. lua_pushboolean(L,false);
  687. return 1;
  688. }
  689. sanity_check(fs->getFileArchiveCount() > 0);
  690. /**********************************************************************/
  691. /* WARNING this is not threadsafe!! */
  692. /**********************************************************************/
  693. io::IFileArchive* opened_zip =
  694. fs->getFileArchive(fs->getFileArchiveCount()-1);
  695. const io::IFileList* files_in_zip = opened_zip->getFileList();
  696. unsigned int number_of_files = files_in_zip->getFileCount();
  697. for (unsigned int i=0; i < number_of_files; i++) {
  698. std::string fullpath = destination;
  699. fullpath += DIR_DELIM;
  700. fullpath += files_in_zip->getFullFileName(i).c_str();
  701. std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
  702. if (!files_in_zip->isDirectory(i)) {
  703. if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
  704. fs->removeFileArchive(fs->getFileArchiveCount()-1);
  705. lua_pushboolean(L,false);
  706. return 1;
  707. }
  708. io::IReadFile* toread = opened_zip->createAndOpenFile(i);
  709. FILE *targetfile = fopen(fullpath.c_str(),"wb");
  710. if (targetfile == NULL) {
  711. fs->removeFileArchive(fs->getFileArchiveCount()-1);
  712. lua_pushboolean(L,false);
  713. return 1;
  714. }
  715. char read_buffer[1024];
  716. long total_read = 0;
  717. while (total_read < toread->getSize()) {
  718. unsigned int bytes_read =
  719. toread->read(read_buffer,sizeof(read_buffer));
  720. if ((bytes_read == 0 ) ||
  721. (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
  722. {
  723. fclose(targetfile);
  724. fs->removeFileArchive(fs->getFileArchiveCount()-1);
  725. lua_pushboolean(L,false);
  726. return 1;
  727. }
  728. total_read += bytes_read;
  729. }
  730. fclose(targetfile);
  731. }
  732. }
  733. fs->removeFileArchive(fs->getFileArchiveCount()-1);
  734. lua_pushboolean(L,true);
  735. return 1;
  736. }
  737. lua_pushboolean(L,false);
  738. return 1;
  739. }
  740. /******************************************************************************/
  741. int ModApiMainMenu::l_get_mainmenu_path(lua_State *L)
  742. {
  743. GUIEngine* engine = getGuiEngine(L);
  744. sanity_check(engine != NULL);
  745. lua_pushstring(L,engine->getScriptDir().c_str());
  746. return 1;
  747. }
  748. /******************************************************************************/
  749. bool ModApiMainMenu::isMinetestPath(std::string path)
  750. {
  751. if (fs::PathStartsWith(path,fs::TempPath()))
  752. return true;
  753. /* games */
  754. if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "games")))
  755. return true;
  756. /* mods */
  757. if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "files")))
  758. return true;
  759. /* worlds */
  760. if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "worlds")))
  761. return true;
  762. return false;
  763. }
  764. /******************************************************************************/
  765. int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
  766. {
  767. GUIEngine* engine = getGuiEngine(L);
  768. sanity_check(engine != NULL);
  769. const char *formname= luaL_checkstring(L, 1);
  770. const char *title = luaL_checkstring(L, 2);
  771. GUIFileSelectMenu* fileOpenMenu =
  772. new GUIFileSelectMenu(engine->m_device->getGUIEnvironment(),
  773. engine->m_parent,
  774. -1,
  775. engine->m_menumanager,
  776. title,
  777. formname);
  778. fileOpenMenu->setTextDest(engine->m_buttonhandler);
  779. fileOpenMenu->drop();
  780. return 0;
  781. }
  782. /******************************************************************************/
  783. int ModApiMainMenu::l_download_file(lua_State *L)
  784. {
  785. const char *url = luaL_checkstring(L, 1);
  786. const char *target = luaL_checkstring(L, 2);
  787. //check path
  788. std::string absolute_destination = fs::RemoveRelativePathComponents(target);
  789. if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
  790. if (GUIEngine::downloadFile(url,absolute_destination)) {
  791. lua_pushboolean(L,true);
  792. return 1;
  793. }
  794. } else {
  795. errorstream << "DOWNLOAD denied: " << absolute_destination
  796. << " isn't a allowed path" << std::endl;
  797. }
  798. lua_pushboolean(L,false);
  799. return 1;
  800. }
  801. /******************************************************************************/
  802. int ModApiMainMenu::l_get_video_drivers(lua_State *L)
  803. {
  804. std::vector<irr::video::E_DRIVER_TYPE> drivers
  805. = porting::getSupportedVideoDrivers();
  806. lua_newtable(L);
  807. for (u32 i = 0; i != drivers.size(); i++) {
  808. const char *name = porting::getVideoDriverName(drivers[i]);
  809. const char *fname = porting::getVideoDriverFriendlyName(drivers[i]);
  810. lua_newtable(L);
  811. lua_pushstring(L, name);
  812. lua_setfield(L, -2, "name");
  813. lua_pushstring(L, fname);
  814. lua_setfield(L, -2, "friendly_name");
  815. lua_rawseti(L, -2, i + 1);
  816. }
  817. return 1;
  818. }
  819. /******************************************************************************/
  820. int ModApiMainMenu::l_get_video_modes(lua_State *L)
  821. {
  822. std::vector<core::vector3d<u32> > videomodes
  823. = porting::getSupportedVideoModes();
  824. lua_newtable(L);
  825. for (u32 i = 0; i != videomodes.size(); i++) {
  826. lua_newtable(L);
  827. lua_pushnumber(L, videomodes[i].X);
  828. lua_setfield(L, -2, "w");
  829. lua_pushnumber(L, videomodes[i].Y);
  830. lua_setfield(L, -2, "h");
  831. lua_pushnumber(L, videomodes[i].Z);
  832. lua_setfield(L, -2, "depth");
  833. lua_rawseti(L, -2, i + 1);
  834. }
  835. return 1;
  836. }
  837. /******************************************************************************/
  838. int ModApiMainMenu::l_gettext(lua_State *L)
  839. {
  840. std::string text = strgettext(std::string(luaL_checkstring(L, 1)));
  841. lua_pushstring(L, text.c_str());
  842. return 1;
  843. }
  844. /******************************************************************************/
  845. int ModApiMainMenu::l_get_screen_info(lua_State *L)
  846. {
  847. lua_newtable(L);
  848. int top = lua_gettop(L);
  849. lua_pushstring(L,"density");
  850. lua_pushnumber(L,porting::getDisplayDensity());
  851. lua_settable(L, top);
  852. lua_pushstring(L,"display_width");
  853. lua_pushnumber(L,porting::getDisplaySize().X);
  854. lua_settable(L, top);
  855. lua_pushstring(L,"display_height");
  856. lua_pushnumber(L,porting::getDisplaySize().Y);
  857. lua_settable(L, top);
  858. lua_pushstring(L,"window_width");
  859. lua_pushnumber(L,porting::getWindowSize().X);
  860. lua_settable(L, top);
  861. lua_pushstring(L,"window_height");
  862. lua_pushnumber(L,porting::getWindowSize().Y);
  863. lua_settable(L, top);
  864. return 1;
  865. }
  866. /******************************************************************************/
  867. int ModApiMainMenu::l_get_min_supp_proto(lua_State *L)
  868. {
  869. u16 proto_version_min = g_settings->getFlag("send_pre_v25_init") ?
  870. CLIENT_PROTOCOL_VERSION_MIN_LEGACY : CLIENT_PROTOCOL_VERSION_MIN;
  871. lua_pushinteger(L, proto_version_min);
  872. return 1;
  873. }
  874. int ModApiMainMenu::l_get_max_supp_proto(lua_State *L)
  875. {
  876. lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MAX);
  877. return 1;
  878. }
  879. /******************************************************************************/
  880. int ModApiMainMenu::l_do_async_callback(lua_State *L)
  881. {
  882. GUIEngine* engine = getGuiEngine(L);
  883. size_t func_length, param_length;
  884. const char* serialized_func_raw = luaL_checklstring(L, 1, &func_length);
  885. const char* serialized_param_raw = luaL_checklstring(L, 2, &param_length);
  886. sanity_check(serialized_func_raw != NULL);
  887. sanity_check(serialized_param_raw != NULL);
  888. std::string serialized_func = std::string(serialized_func_raw, func_length);
  889. std::string serialized_param = std::string(serialized_param_raw, param_length);
  890. lua_pushinteger(L, engine->queueAsync(serialized_func, serialized_param));
  891. return 1;
  892. }
  893. /******************************************************************************/
  894. void ModApiMainMenu::Initialize(lua_State *L, int top)
  895. {
  896. API_FCT(update_formspec);
  897. API_FCT(set_clouds);
  898. API_FCT(get_textlist_index);
  899. API_FCT(get_table_index);
  900. API_FCT(get_worlds);
  901. API_FCT(get_games);
  902. API_FCT(start);
  903. API_FCT(close);
  904. API_FCT(get_favorites);
  905. API_FCT(show_keys_menu);
  906. API_FCT(create_world);
  907. API_FCT(delete_world);
  908. API_FCT(delete_favorite);
  909. API_FCT(set_background);
  910. API_FCT(set_topleft_text);
  911. API_FCT(get_mapgen_names);
  912. API_FCT(get_modpath);
  913. API_FCT(get_gamepath);
  914. API_FCT(get_texturepath);
  915. API_FCT(get_texturepath_share);
  916. API_FCT(create_dir);
  917. API_FCT(delete_dir);
  918. API_FCT(copy_dir);
  919. API_FCT(extract_zip);
  920. API_FCT(get_mainmenu_path);
  921. API_FCT(show_file_open_dialog);
  922. API_FCT(download_file);
  923. API_FCT(get_modstore_details);
  924. API_FCT(get_modstore_list);
  925. API_FCT(gettext);
  926. API_FCT(get_video_drivers);
  927. API_FCT(get_video_modes);
  928. API_FCT(get_screen_info);
  929. API_FCT(get_min_supp_proto);
  930. API_FCT(get_max_supp_proto);
  931. API_FCT(do_async_callback);
  932. }
  933. /******************************************************************************/
  934. void ModApiMainMenu::InitializeAsync(lua_State *L, int top)
  935. {
  936. API_FCT(get_worlds);
  937. API_FCT(get_games);
  938. API_FCT(get_favorites);
  939. API_FCT(get_mapgen_names);
  940. API_FCT(get_modpath);
  941. API_FCT(get_gamepath);
  942. API_FCT(get_texturepath);
  943. API_FCT(get_texturepath_share);
  944. API_FCT(create_dir);
  945. API_FCT(delete_dir);
  946. API_FCT(copy_dir);
  947. //API_FCT(extract_zip); //TODO remove dependency to GuiEngine
  948. API_FCT(download_file);
  949. API_FCT(get_modstore_details);
  950. API_FCT(get_modstore_list);
  951. //API_FCT(gettext); (gettext lib isn't threadsafe)
  952. }