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