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