]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_mainmenu.cpp
Record MapBlock modification reasons as flags instead of strings
[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_create_dir(lua_State *L) {
758         const char *path        = luaL_checkstring(L, 1);
759
760         if (ModApiMainMenu::isMinetestPath(path)) {
761                 lua_pushboolean(L,fs::CreateAllDirs(path));
762                 return 1;
763         }
764         lua_pushboolean(L,false);
765         return 1;
766 }
767
768 /******************************************************************************/
769 int ModApiMainMenu::l_delete_dir(lua_State *L)
770 {
771         const char *path        = luaL_checkstring(L, 1);
772
773         std::string absolute_path = fs::RemoveRelativePathComponents(path);
774
775         if (ModApiMainMenu::isMinetestPath(absolute_path)) {
776                 lua_pushboolean(L,fs::RecursiveDelete(absolute_path));
777                 return 1;
778         }
779         lua_pushboolean(L,false);
780         return 1;
781 }
782
783 /******************************************************************************/
784 int ModApiMainMenu::l_copy_dir(lua_State *L)
785 {
786         const char *source      = luaL_checkstring(L, 1);
787         const char *destination = luaL_checkstring(L, 2);
788
789         bool keep_source = true;
790
791         if ((!lua_isnone(L,3)) &&
792                         (!lua_isnil(L,3))) {
793                 keep_source = lua_toboolean(L,3);
794         }
795
796         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
797         std::string absolute_source = fs::RemoveRelativePathComponents(source);
798
799         if ((ModApiMainMenu::isMinetestPath(absolute_source)) &&
800                         (ModApiMainMenu::isMinetestPath(absolute_destination))) {
801                 bool retval = fs::CopyDir(absolute_source,absolute_destination);
802
803                 if (retval && (!keep_source)) {
804
805                         retval &= fs::RecursiveDelete(absolute_source);
806                 }
807                 lua_pushboolean(L,retval);
808                 return 1;
809         }
810         lua_pushboolean(L,false);
811         return 1;
812 }
813
814 /******************************************************************************/
815 int ModApiMainMenu::l_extract_zip(lua_State *L)
816 {
817         GUIEngine* engine = getGuiEngine(L);
818         sanity_check(engine);
819
820         const char *zipfile     = luaL_checkstring(L, 1);
821         const char *destination = luaL_checkstring(L, 2);
822
823         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
824
825         if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
826                 fs::CreateAllDirs(absolute_destination);
827
828                 io::IFileSystem* fs = engine->m_device->getFileSystem();
829
830                 if (!fs->addFileArchive(zipfile,true,false,io::EFAT_ZIP)) {
831                         lua_pushboolean(L,false);
832                         return 1;
833                 }
834
835                 sanity_check(fs->getFileArchiveCount() > 0);
836
837                 /**********************************************************************/
838                 /* WARNING this is not threadsafe!!                                   */
839                 /**********************************************************************/
840                 io::IFileArchive* opened_zip =
841                         fs->getFileArchive(fs->getFileArchiveCount()-1);
842
843                 const io::IFileList* files_in_zip = opened_zip->getFileList();
844
845                 unsigned int number_of_files = files_in_zip->getFileCount();
846
847                 for (unsigned int i=0; i < number_of_files; i++) {
848                         std::string fullpath = destination;
849                         fullpath += DIR_DELIM;
850                         fullpath += files_in_zip->getFullFileName(i).c_str();
851                         std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
852
853                         if (!files_in_zip->isDirectory(i)) {
854                                 if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
855                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
856                                         lua_pushboolean(L,false);
857                                         return 1;
858                                 }
859
860                                 io::IReadFile* toread = opened_zip->createAndOpenFile(i);
861
862                                 FILE *targetfile = fopen(fullpath.c_str(),"wb");
863
864                                 if (targetfile == NULL) {
865                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
866                                         lua_pushboolean(L,false);
867                                         return 1;
868                                 }
869
870                                 char read_buffer[1024];
871                                 long total_read = 0;
872
873                                 while (total_read < toread->getSize()) {
874
875                                         unsigned int bytes_read =
876                                                         toread->read(read_buffer,sizeof(read_buffer));
877                                         if ((bytes_read == 0 ) ||
878                                                 (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
879                                         {
880                                                 fclose(targetfile);
881                                                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
882                                                 lua_pushboolean(L,false);
883                                                 return 1;
884                                         }
885                                         total_read += bytes_read;
886                                 }
887
888                                 fclose(targetfile);
889                         }
890
891                 }
892
893                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
894                 lua_pushboolean(L,true);
895                 return 1;
896         }
897
898         lua_pushboolean(L,false);
899         return 1;
900 }
901
902 /******************************************************************************/
903 int ModApiMainMenu::l_get_mainmenu_path(lua_State *L)
904 {
905         GUIEngine* engine = getGuiEngine(L);
906         sanity_check(engine != NULL);
907
908         lua_pushstring(L,engine->getScriptDir().c_str());
909         return 1;
910 }
911
912 /******************************************************************************/
913 bool ModApiMainMenu::isMinetestPath(std::string path)
914 {
915         if (fs::PathStartsWith(path,fs::TempPath()))
916                 return true;
917
918         /* games */
919         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "games")))
920                 return true;
921
922         /* mods */
923         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods")))
924                 return true;
925
926         /* worlds */
927         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "worlds")))
928                 return true;
929
930
931         return false;
932 }
933
934 /******************************************************************************/
935 int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
936 {
937         GUIEngine* engine = getGuiEngine(L);
938         sanity_check(engine != NULL);
939
940         const char *formname= luaL_checkstring(L, 1);
941         const char *title       = luaL_checkstring(L, 2);
942
943         GUIFileSelectMenu* fileOpenMenu =
944                 new GUIFileSelectMenu(engine->m_device->getGUIEnvironment(),
945                                                                 engine->m_parent,
946                                                                 -1,
947                                                                 engine->m_menumanager,
948                                                                 title,
949                                                                 formname);
950         fileOpenMenu->setTextDest(engine->m_buttonhandler);
951         fileOpenMenu->drop();
952         return 0;
953 }
954
955 /******************************************************************************/
956 int ModApiMainMenu::l_get_version(lua_State *L)
957 {
958         lua_pushstring(L, g_version_string);
959         return 1;
960 }
961
962 /******************************************************************************/
963 int ModApiMainMenu::l_sound_play(lua_State *L)
964 {
965         GUIEngine* engine = getGuiEngine(L);
966
967         SimpleSoundSpec spec;
968         read_soundspec(L, 1, spec);
969         bool looped = lua_toboolean(L, 2);
970
971         u32 handle = engine->playSound(spec, looped);
972
973         lua_pushinteger(L, handle);
974
975         return 1;
976 }
977
978 /******************************************************************************/
979 int ModApiMainMenu::l_sound_stop(lua_State *L)
980 {
981         GUIEngine* engine = getGuiEngine(L);
982
983         u32 handle = luaL_checkinteger(L, 1);
984         engine->stopSound(handle);
985
986         return 1;
987 }
988
989 /******************************************************************************/
990 int ModApiMainMenu::l_download_file(lua_State *L)
991 {
992         const char *url    = luaL_checkstring(L, 1);
993         const char *target = luaL_checkstring(L, 2);
994
995         //check path
996         std::string absolute_destination = fs::RemoveRelativePathComponents(target);
997
998         if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
999                 if (GUIEngine::downloadFile(url,absolute_destination)) {
1000                         lua_pushboolean(L,true);
1001                         return 1;
1002                 }
1003         } else {
1004                 errorstream << "DOWNLOAD denied: " << absolute_destination
1005                                 << " isn't a allowed path" << std::endl;
1006         }
1007         lua_pushboolean(L,false);
1008         return 1;
1009 }
1010
1011 /******************************************************************************/
1012 int ModApiMainMenu::l_get_video_drivers(lua_State *L)
1013 {
1014         std::vector<irr::video::E_DRIVER_TYPE> drivers
1015                 = porting::getSupportedVideoDrivers();
1016
1017         lua_newtable(L);
1018         for (u32 i = 0; i != drivers.size(); i++) {
1019                 const char *name  = porting::getVideoDriverName(drivers[i]);
1020                 const char *fname = porting::getVideoDriverFriendlyName(drivers[i]);
1021
1022                 lua_newtable(L);
1023                 lua_pushstring(L, name);
1024                 lua_setfield(L, -2, "name");
1025                 lua_pushstring(L, fname);
1026                 lua_setfield(L, -2, "friendly_name");
1027
1028                 lua_rawseti(L, -2, i + 1);
1029         }
1030
1031         return 1;
1032 }
1033
1034 /******************************************************************************/
1035 int ModApiMainMenu::l_get_video_modes(lua_State *L)
1036 {
1037         std::vector<core::vector3d<u32> > videomodes
1038                 = porting::getSupportedVideoModes();
1039
1040         lua_newtable(L);
1041         for (u32 i = 0; i != videomodes.size(); i++) {
1042                 lua_newtable(L);
1043                 lua_pushnumber(L, videomodes[i].X);
1044                 lua_setfield(L, -2, "w");
1045                 lua_pushnumber(L, videomodes[i].Y);
1046                 lua_setfield(L, -2, "h");
1047                 lua_pushnumber(L, videomodes[i].Z);
1048                 lua_setfield(L, -2, "depth");
1049
1050                 lua_rawseti(L, -2, i + 1);
1051         }
1052
1053         return 1;
1054 }
1055
1056 /******************************************************************************/
1057 int ModApiMainMenu::l_gettext(lua_State *L)
1058 {
1059         std::wstring wtext = wstrgettext((std::string) luaL_checkstring(L, 1));
1060         lua_pushstring(L, wide_to_narrow(wtext).c_str());
1061
1062         return 1;
1063 }
1064
1065 /******************************************************************************/
1066 int ModApiMainMenu::l_get_screen_info(lua_State *L)
1067 {
1068         lua_newtable(L);
1069         int top = lua_gettop(L);
1070         lua_pushstring(L,"density");
1071         lua_pushnumber(L,porting::getDisplayDensity());
1072         lua_settable(L, top);
1073
1074         lua_pushstring(L,"display_width");
1075         lua_pushnumber(L,porting::getDisplaySize().X);
1076         lua_settable(L, top);
1077
1078         lua_pushstring(L,"display_height");
1079         lua_pushnumber(L,porting::getDisplaySize().Y);
1080         lua_settable(L, top);
1081
1082         lua_pushstring(L,"window_width");
1083         lua_pushnumber(L,porting::getWindowSize().X);
1084         lua_settable(L, top);
1085
1086         lua_pushstring(L,"window_height");
1087         lua_pushnumber(L,porting::getWindowSize().Y);
1088         lua_settable(L, top);
1089         return 1;
1090 }
1091
1092 /******************************************************************************/
1093 int ModApiMainMenu::l_get_min_supp_proto(lua_State *L)
1094 {
1095         lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MIN);
1096         return 1;
1097 }
1098
1099 int ModApiMainMenu::l_get_max_supp_proto(lua_State *L)
1100 {
1101         lua_pushinteger(L, CLIENT_PROTOCOL_VERSION_MAX);
1102         return 1;
1103 }
1104
1105 /******************************************************************************/
1106 int ModApiMainMenu::l_do_async_callback(lua_State *L)
1107 {
1108         GUIEngine* engine = getGuiEngine(L);
1109
1110         size_t func_length, param_length;
1111         const char* serialized_func_raw = luaL_checklstring(L, 1, &func_length);
1112
1113         const char* serialized_param_raw = luaL_checklstring(L, 2, &param_length);
1114
1115         sanity_check(serialized_func_raw != NULL);
1116         sanity_check(serialized_param_raw != NULL);
1117
1118         std::string serialized_func = std::string(serialized_func_raw, func_length);
1119         std::string serialized_param = std::string(serialized_param_raw, param_length);
1120
1121         lua_pushinteger(L, engine->queueAsync(serialized_func, serialized_param));
1122
1123         return 1;
1124 }
1125
1126 /******************************************************************************/
1127 void ModApiMainMenu::Initialize(lua_State *L, int top)
1128 {
1129         API_FCT(update_formspec);
1130         API_FCT(set_clouds);
1131         API_FCT(get_textlist_index);
1132         API_FCT(get_table_index);
1133         API_FCT(get_worlds);
1134         API_FCT(get_games);
1135         API_FCT(start);
1136         API_FCT(close);
1137         API_FCT(get_favorites);
1138         API_FCT(show_keys_menu);
1139         API_FCT(create_world);
1140         API_FCT(delete_world);
1141         API_FCT(delete_favorite);
1142         API_FCT(set_background);
1143         API_FCT(set_topleft_text);
1144         API_FCT(get_mapgen_names);
1145         API_FCT(get_modpath);
1146         API_FCT(get_gamepath);
1147         API_FCT(get_texturepath);
1148         API_FCT(get_texturepath_share);
1149         API_FCT(create_dir);
1150         API_FCT(delete_dir);
1151         API_FCT(copy_dir);
1152         API_FCT(extract_zip);
1153         API_FCT(get_mainmenu_path);
1154         API_FCT(show_file_open_dialog);
1155         API_FCT(get_version);
1156         API_FCT(download_file);
1157         API_FCT(get_modstore_details);
1158         API_FCT(get_modstore_list);
1159         API_FCT(sound_play);
1160         API_FCT(sound_stop);
1161         API_FCT(gettext);
1162         API_FCT(get_video_drivers);
1163         API_FCT(get_video_modes);
1164         API_FCT(get_screen_info);
1165         API_FCT(get_min_supp_proto);
1166         API_FCT(get_max_supp_proto);
1167         API_FCT(do_async_callback);
1168 }
1169
1170 /******************************************************************************/
1171 void ModApiMainMenu::InitializeAsync(AsyncEngine& engine)
1172 {
1173
1174         ASYNC_API_FCT(get_worlds);
1175         ASYNC_API_FCT(get_games);
1176         ASYNC_API_FCT(get_favorites);
1177         ASYNC_API_FCT(get_mapgen_names);
1178         ASYNC_API_FCT(get_modpath);
1179         ASYNC_API_FCT(get_gamepath);
1180         ASYNC_API_FCT(get_texturepath);
1181         ASYNC_API_FCT(get_texturepath_share);
1182         ASYNC_API_FCT(create_dir);
1183         ASYNC_API_FCT(delete_dir);
1184         ASYNC_API_FCT(copy_dir);
1185         //ASYNC_API_FCT(extract_zip); //TODO remove dependency to GuiEngine
1186         ASYNC_API_FCT(get_version);
1187         ASYNC_API_FCT(download_file);
1188         ASYNC_API_FCT(get_modstore_details);
1189         ASYNC_API_FCT(get_modstore_list);
1190         //ASYNC_API_FCT(gettext); (gettext lib isn't threadsafe)
1191 }