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