]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_mainmenu.cpp
Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[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 "guiEngine.h"
24 #include "guiMainMenu.h"
25 #include "guiKeyChangeMenu.h"
26 #include "guiFileSelectMenu.h"
27 #include "subgame.h"
28 #include "porting.h"
29 #include "filesys.h"
30 #include "convert_json.h"
31 #include "serverlist.h"
32 #include "sound.h"
33 #include "settings.h"
34 #include "main.h" // for g_settings
35
36 #include <IFileArchive.h>
37 #include <IFileSystem.h>
38
39 /******************************************************************************/
40 std::string ModApiMainMenu::getTextData(lua_State *L, std::string name)
41 {
42         lua_getglobal(L, "gamedata");
43
44         lua_getfield(L, -1, name.c_str());
45
46         if(lua_isnil(L, -1))
47                 return "";
48
49         return luaL_checkstring(L, -1);
50 }
51
52 /******************************************************************************/
53 int ModApiMainMenu::getIntegerData(lua_State *L, std::string name,bool& valid)
54 {
55         lua_getglobal(L, "gamedata");
56
57         lua_getfield(L, -1, name.c_str());
58
59         if(lua_isnil(L, -1)) {
60                 valid = false;
61                 return -1;
62                 }
63
64         valid = true;
65         return luaL_checkinteger(L, -1);
66 }
67
68 /******************************************************************************/
69 int ModApiMainMenu::getBoolData(lua_State *L, std::string name,bool& valid)
70 {
71         lua_getglobal(L, "gamedata");
72
73         lua_getfield(L, -1, name.c_str());
74
75         if(lua_isnil(L, -1)) {
76                 valid = false;
77                 return false;
78                 }
79
80         valid = true;
81         return lua_toboolean(L, -1);
82 }
83
84 /******************************************************************************/
85 int ModApiMainMenu::l_update_formspec(lua_State *L)
86 {
87         GUIEngine* engine = getGuiEngine(L);
88         assert(engine != 0);
89
90         if (engine->m_startgame)
91                 return 0;
92
93         //read formspec
94         std::string formspec(luaL_checkstring(L, 1));
95
96         if (engine->m_formspecgui != 0) {
97                 engine->m_formspecgui->setForm(formspec);
98         }
99
100         return 0;
101 }
102
103 /******************************************************************************/
104 int ModApiMainMenu::l_start(lua_State *L)
105 {
106         GUIEngine* engine = getGuiEngine(L);
107         assert(engine != 0);
108
109         //update c++ gamedata from lua table
110
111         bool valid = false;
112
113
114         engine->m_data->selected_world          = getIntegerData(L, "selected_world",valid) -1;
115         engine->m_data->simple_singleplayer_mode = getBoolData(L,"singleplayer",valid);
116         engine->m_data->name                            = getTextData(L,"playername");
117         engine->m_data->password                        = getTextData(L,"password");
118         engine->m_data->address                         = getTextData(L,"address");
119         engine->m_data->port                            = getTextData(L,"port");
120         engine->m_data->serverdescription       = getTextData(L,"serverdescription");
121         engine->m_data->servername                      = getTextData(L,"servername");
122
123         //close menu next time
124         engine->m_startgame = true;
125         return 0;
126 }
127
128 /******************************************************************************/
129 int ModApiMainMenu::l_close(lua_State *L)
130 {
131         GUIEngine* engine = getGuiEngine(L);
132         assert(engine != 0);
133
134         engine->m_data->kill = true;
135
136         //close menu next time
137         engine->m_startgame = true;
138         engine->m_menu->quitMenu();
139         return 0;
140 }
141
142 /******************************************************************************/
143 int ModApiMainMenu::l_set_background(lua_State *L)
144 {
145         GUIEngine* engine = getGuiEngine(L);
146         assert(engine != 0);
147
148         std::string backgroundlevel(luaL_checkstring(L, 1));
149         std::string texturename(luaL_checkstring(L, 2));
150
151         bool retval = false;
152
153         if (backgroundlevel == "background") {
154                 retval |= engine->setTexture(TEX_LAYER_BACKGROUND,texturename);
155         }
156
157         if (backgroundlevel == "overlay") {
158                 retval |= engine->setTexture(TEX_LAYER_OVERLAY,texturename);
159         }
160
161         if (backgroundlevel == "header") {
162                 retval |= engine->setTexture(TEX_LAYER_HEADER,texturename);
163         }
164
165         if (backgroundlevel == "footer") {
166                 retval |= engine->setTexture(TEX_LAYER_FOOTER,texturename);
167         }
168
169         lua_pushboolean(L,retval);
170         return 1;
171 }
172
173 /******************************************************************************/
174 int ModApiMainMenu::l_set_clouds(lua_State *L)
175 {
176         GUIEngine* engine = getGuiEngine(L);
177         assert(engine != 0);
178
179         bool value = lua_toboolean(L,1);
180
181         engine->m_clouds_enabled = value;
182
183         return 0;
184 }
185
186 /******************************************************************************/
187 int ModApiMainMenu::l_get_textlist_index(lua_State *L)
188 {
189         GUIEngine* engine = getGuiEngine(L);
190         assert(engine != 0);
191
192         std::string listboxname(luaL_checkstring(L, 1));
193
194         int selection = engine->m_menu->getListboxIndex(listboxname);
195
196         if (selection >= 0)
197                 selection++;
198
199         lua_pushinteger(L, selection);
200         return 1;
201 }
202
203 /******************************************************************************/
204 int ModApiMainMenu::l_get_worlds(lua_State *L)
205 {
206         GUIEngine* engine = getGuiEngine(L);
207         assert(engine != 0);
208
209         std::vector<WorldSpec> worlds = getAvailableWorlds();
210
211         lua_newtable(L);
212         int top = lua_gettop(L);
213         unsigned int index = 1;
214
215         for (unsigned int i = 0; i < worlds.size(); i++)
216         {
217                 lua_pushnumber(L,index);
218
219                 lua_newtable(L);
220                 int top_lvl2 = lua_gettop(L);
221
222                 lua_pushstring(L,"path");
223                 lua_pushstring(L,worlds[i].path.c_str());
224                 lua_settable(L, top_lvl2);
225
226                 lua_pushstring(L,"name");
227                 lua_pushstring(L,worlds[i].name.c_str());
228                 lua_settable(L, top_lvl2);
229
230                 lua_pushstring(L,"gameid");
231                 lua_pushstring(L,worlds[i].gameid.c_str());
232                 lua_settable(L, top_lvl2);
233
234                 lua_settable(L, top);
235                 index++;
236         }
237         return 1;
238 }
239
240 /******************************************************************************/
241 int ModApiMainMenu::l_get_games(lua_State *L)
242 {
243         GUIEngine* engine = getGuiEngine(L);
244         assert(engine != 0);
245
246         std::vector<SubgameSpec> games = getAvailableGames();
247
248         lua_newtable(L);
249         int top = lua_gettop(L);
250         unsigned int index = 1;
251
252         for (unsigned int i = 0; i < games.size(); i++)
253         {
254                 lua_pushnumber(L,index);
255                 lua_newtable(L);
256                 int top_lvl2 = lua_gettop(L);
257
258                 lua_pushstring(L,"id");
259                 lua_pushstring(L,games[i].id.c_str());
260                 lua_settable(L, top_lvl2);
261
262                 lua_pushstring(L,"path");
263                 lua_pushstring(L,games[i].path.c_str());
264                 lua_settable(L, top_lvl2);
265
266                 lua_pushstring(L,"gamemods_path");
267                 lua_pushstring(L,games[i].gamemods_path.c_str());
268                 lua_settable(L, top_lvl2);
269
270                 lua_pushstring(L,"name");
271                 lua_pushstring(L,games[i].name.c_str());
272                 lua_settable(L, top_lvl2);
273
274                 lua_pushstring(L,"menuicon_path");
275                 lua_pushstring(L,games[i].menuicon_path.c_str());
276                 lua_settable(L, top_lvl2);
277
278                 lua_pushstring(L,"addon_mods_paths");
279                 lua_newtable(L);
280                 int table2 = lua_gettop(L);
281                 int internal_index=1;
282                 for (std::set<std::string>::iterator iter = games[i].addon_mods_paths.begin();
283                                 iter != games[i].addon_mods_paths.end(); iter++) {
284                         lua_pushnumber(L,internal_index);
285                         lua_pushstring(L,(*iter).c_str());
286                         lua_settable(L, table2);
287                         internal_index++;
288                 }
289                 lua_settable(L, top_lvl2);
290                 lua_settable(L, top);
291                 index++;
292         }
293         return 1;
294 }
295 /******************************************************************************/
296 int ModApiMainMenu::l_get_modstore_details(lua_State *L)
297 {
298         const char *modid       = luaL_checkstring(L, 1);
299
300         if (modid != 0) {
301                 Json::Value details;
302                 std::string url = "";
303                 try{
304                         url = g_settings->get("modstore_details_url");
305                 }
306                 catch(SettingNotFoundException &e) {
307                         lua_pushnil(L);
308                         return 1;
309                 }
310
311                 size_t idpos = url.find("*");
312                 url.erase(idpos,1);
313                 url.insert(idpos,modid);
314
315                 details = getModstoreUrl(url);
316
317                 ModStoreModDetails current_mod = readModStoreModDetails(details);
318
319                 if ( current_mod.valid) {
320                         lua_newtable(L);
321                         int top = lua_gettop(L);
322
323                         lua_pushstring(L,"id");
324                         lua_pushnumber(L,current_mod.id);
325                         lua_settable(L, top);
326
327                         lua_pushstring(L,"title");
328                         lua_pushstring(L,current_mod.title.c_str());
329                         lua_settable(L, top);
330
331                         lua_pushstring(L,"basename");
332                         lua_pushstring(L,current_mod.basename.c_str());
333                         lua_settable(L, top);
334
335                         lua_pushstring(L,"description");
336                         lua_pushstring(L,current_mod.description.c_str());
337                         lua_settable(L, top);
338
339                         lua_pushstring(L,"author");
340                         lua_pushstring(L,current_mod.author.username.c_str());
341                         lua_settable(L, top);
342
343                         lua_pushstring(L,"download_url");
344                         lua_pushstring(L,current_mod.versions[0].file.c_str());
345                         lua_settable(L, top);
346
347                         lua_pushstring(L,"screenshot_url");
348                         lua_pushstring(L,current_mod.titlepic.file.c_str());
349                         lua_settable(L, top);
350
351                         lua_pushstring(L,"license");
352                         lua_pushstring(L,current_mod.license.shortinfo.c_str());
353                         lua_settable(L, top);
354
355                         lua_pushstring(L,"rating");
356                         lua_pushnumber(L,current_mod.rating);
357                         lua_settable(L, top);
358
359                         //TODO depends
360
361                         //TODO softdepends
362                         return 1;
363                 }
364         }
365         return 0;
366 }
367
368 /******************************************************************************/
369 int ModApiMainMenu::l_get_modstore_list(lua_State *L)
370 {
371         GUIEngine* engine = getGuiEngine(L);
372         assert(engine != 0);
373
374         std::string listtype = "local";
375
376         if (!lua_isnone(L,1)) {
377                 listtype = luaL_checkstring(L,1);
378         }
379         Json::Value mods;
380         std::string url = "";
381         try{
382                 url = g_settings->get("modstore_listmods_url");
383         }
384         catch(SettingNotFoundException &e) {
385                 lua_pushnil(L);
386                 return 1;
387         }
388
389         mods = getModstoreUrl(url);
390
391         std::vector<ModStoreMod> moddata = readModStoreList(mods);
392
393         lua_newtable(L);
394         int top = lua_gettop(L);
395         unsigned int index = 1;
396
397         for (unsigned int i = 0; i < moddata.size(); i++)
398         {
399                 if (moddata[i].valid) {
400                         lua_pushnumber(L,index);
401                         lua_newtable(L);
402
403                         int top_lvl2 = lua_gettop(L);
404
405                         lua_pushstring(L,"id");
406                         lua_pushnumber(L,moddata[i].id);
407                         lua_settable(L, top_lvl2);
408
409                         lua_pushstring(L,"title");
410                         lua_pushstring(L,moddata[i].title.c_str());
411                         lua_settable(L, top_lvl2);
412
413                         lua_pushstring(L,"basename");
414                         lua_pushstring(L,moddata[i].basename.c_str());
415                         lua_settable(L, top_lvl2);
416
417                         lua_settable(L, top);
418                         index++;
419                 }
420         }
421         return 1;
422 }
423
424 /******************************************************************************/
425 int ModApiMainMenu::l_get_favorites(lua_State *L)
426 {
427         GUIEngine* engine = getGuiEngine(L);
428         assert(engine != 0);
429
430         std::string listtype = "local";
431
432         if (!lua_isnone(L,1)) {
433                 listtype = luaL_checkstring(L,1);
434         }
435
436         std::vector<ServerListSpec> servers;
437 #if USE_CURL
438         if(listtype == "online") {
439                 servers = ServerList::getOnline();
440         } else {
441                 servers = ServerList::getLocal();
442         }
443 #else
444         servers = ServerList::getLocal();
445 #endif
446
447         lua_newtable(L);
448         int top = lua_gettop(L);
449         unsigned int index = 1;
450
451         for (unsigned int i = 0; i < servers.size(); i++)
452         {
453                 lua_pushnumber(L,index);
454
455                 lua_newtable(L);
456                 int top_lvl2 = lua_gettop(L);
457
458                 if (servers[i]["clients"].asString().size()) {
459
460                         const char* clients_raw = servers[i]["clients"].asString().c_str();
461                         char* endptr = 0;
462                         int numbervalue = strtol(clients_raw,&endptr,10);
463
464                         if ((*clients_raw != 0) && (*endptr == 0)) {
465                                 lua_pushstring(L,"clients");
466                                 lua_pushnumber(L,numbervalue);
467                                 lua_settable(L, top_lvl2);
468                         }
469                 }
470
471                 if (servers[i]["clients_max"].asString().size()) {
472
473                         const char* clients_max_raw = servers[i]["clients_max"].asString().c_str();
474                         char* endptr = 0;
475                         int numbervalue = strtol(clients_max_raw,&endptr,10);
476
477                         if ((*clients_max_raw != 0) && (*endptr == 0)) {
478                                 lua_pushstring(L,"clients_max");
479                                 lua_pushnumber(L,numbervalue);
480                                 lua_settable(L, top_lvl2);
481                         }
482                 }
483
484                 if (servers[i]["version"].asString().size()) {
485                         lua_pushstring(L,"version");
486                         lua_pushstring(L,servers[i]["version"].asString().c_str());
487                         lua_settable(L, top_lvl2);
488                 }
489
490                 if (servers[i]["password"].asString().size()) {
491                         lua_pushstring(L,"password");
492                         lua_pushboolean(L,true);
493                         lua_settable(L, top_lvl2);
494                 }
495
496                 if (servers[i]["creative"].asString().size()) {
497                         lua_pushstring(L,"creative");
498                         lua_pushboolean(L,true);
499                         lua_settable(L, top_lvl2);
500                 }
501
502                 if (servers[i]["damage"].asString().size()) {
503                         lua_pushstring(L,"damage");
504                         lua_pushboolean(L,true);
505                         lua_settable(L, top_lvl2);
506                 }
507
508                 if (servers[i]["pvp"].asString().size()) {
509                         lua_pushstring(L,"pvp");
510                         lua_pushboolean(L,true);
511                         lua_settable(L, top_lvl2);
512                 }
513
514                 if (servers[i]["description"].asString().size()) {
515                         lua_pushstring(L,"description");
516                         lua_pushstring(L,servers[i]["description"].asString().c_str());
517                         lua_settable(L, top_lvl2);
518                 }
519
520                 if (servers[i]["name"].asString().size()) {
521                         lua_pushstring(L,"name");
522                         lua_pushstring(L,servers[i]["name"].asString().c_str());
523                         lua_settable(L, top_lvl2);
524                 }
525
526                 if (servers[i]["address"].asString().size()) {
527                         lua_pushstring(L,"address");
528                         lua_pushstring(L,servers[i]["address"].asString().c_str());
529                         lua_settable(L, top_lvl2);
530                 }
531
532                 if (servers[i]["port"].asString().size()) {
533                         lua_pushstring(L,"port");
534                         lua_pushstring(L,servers[i]["port"].asString().c_str());
535                         lua_settable(L, top_lvl2);
536                 }
537
538                 lua_settable(L, top);
539                 index++;
540         }
541         return 1;
542 }
543
544 /******************************************************************************/
545 int ModApiMainMenu::l_delete_favorite(lua_State *L)
546 {
547         GUIEngine* engine = getGuiEngine(L);
548         assert(engine != 0);
549
550         std::vector<ServerListSpec> servers;
551
552         std::string listtype = "local";
553
554         if (!lua_isnone(L,2)) {
555                 listtype = luaL_checkstring(L,2);
556         }
557
558         if ((listtype != "local") &&
559                 (listtype != "online"))
560                 return 0;
561
562 #if USE_CURL
563         if(listtype == "online") {
564                 servers = ServerList::getOnline();
565         } else {
566                 servers = ServerList::getLocal();
567         }
568 #else
569         servers = ServerList::getLocal();
570 #endif
571
572         int fav_idx     = luaL_checkinteger(L,1) -1;
573
574         if ((fav_idx >= 0) &&
575                         (fav_idx < (int) servers.size())) {
576
577                 ServerList::deleteEntry(servers[fav_idx]);
578         }
579
580         return 0;
581 }
582
583 /******************************************************************************/
584 int ModApiMainMenu::l_show_keys_menu(lua_State *L)
585 {
586         GUIEngine* engine = getGuiEngine(L);
587         assert(engine != 0);
588
589         GUIKeyChangeMenu *kmenu
590                 = new GUIKeyChangeMenu( engine->m_device->getGUIEnvironment(),
591                                                                 engine->m_parent,
592                                                                 -1,
593                                                                 engine->m_menumanager);
594         kmenu->drop();
595         return 0;
596 }
597
598 /******************************************************************************/
599 int ModApiMainMenu::l_create_world(lua_State *L)
600 {
601         GUIEngine* engine = getGuiEngine(L);
602         assert(engine != 0);
603
604         const char *name        = luaL_checkstring(L, 1);
605         int gameidx                     = luaL_checkinteger(L,2) -1;
606
607         std::string path = porting::path_user + DIR_DELIM
608                         "worlds" + DIR_DELIM
609                         + name;
610
611         std::vector<SubgameSpec> games = getAvailableGames();
612
613         if ((gameidx >= 0) &&
614                         (gameidx < (int) games.size())) {
615
616                 // Create world if it doesn't exist
617                 if(!initializeWorld(path, games[gameidx].id)){
618                         lua_pushstring(L, "Failed to initialize world");
619
620                 }
621                 else {
622                 lua_pushnil(L);
623                 }
624         }
625         else {
626                 lua_pushstring(L, "Invalid game index");
627         }
628         return 1;
629 }
630
631 /******************************************************************************/
632 int ModApiMainMenu::l_delete_world(lua_State *L)
633 {
634         GUIEngine* engine = getGuiEngine(L);
635         assert(engine != 0);
636
637         int worldidx    = luaL_checkinteger(L,1) -1;
638
639         std::vector<WorldSpec> worlds = getAvailableWorlds();
640
641         if ((worldidx >= 0) &&
642                 (worldidx < (int) worlds.size())) {
643
644                 WorldSpec spec = worlds[worldidx];
645
646                 std::vector<std::string> paths;
647                 paths.push_back(spec.path);
648                 fs::GetRecursiveSubPaths(spec.path, paths);
649
650                 // Delete files
651                 if (!fs::DeletePaths(paths)) {
652                         lua_pushstring(L, "Failed to delete world");
653                 }
654                 else {
655                         lua_pushnil(L);
656                 }
657         }
658         else {
659                 lua_pushstring(L, "Invalid world index");
660         }
661         return 1;
662 }
663
664 /******************************************************************************/
665 int ModApiMainMenu::l_set_topleft_text(lua_State *L)
666 {
667         GUIEngine* engine = getGuiEngine(L);
668         assert(engine != 0);
669
670         std::string text = "";
671
672         if (!lua_isnone(L,1) && !lua_isnil(L,1))
673                 text = luaL_checkstring(L, 1);
674
675         engine->setTopleftText(text);
676         return 0;
677 }
678
679 /******************************************************************************/
680 int ModApiMainMenu::l_get_modpath(lua_State *L)
681 {
682         std::string modpath
683                         = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods" + DIR_DELIM);
684         lua_pushstring(L, modpath.c_str());
685         return 1;
686 }
687
688 /******************************************************************************/
689 int ModApiMainMenu::l_get_gamepath(lua_State *L)
690 {
691         std::string gamepath
692                         = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "games" + DIR_DELIM);
693         lua_pushstring(L, gamepath.c_str());
694         return 1;
695 }
696
697 /******************************************************************************/
698 int ModApiMainMenu::l_get_texturepath(lua_State *L)
699 {
700         std::string gamepath
701                         = fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "textures");
702         lua_pushstring(L, gamepath.c_str());
703         return 1;
704 }
705
706 /******************************************************************************/
707 int ModApiMainMenu::l_get_dirlist(lua_State *L)
708 {
709         const char *path        = luaL_checkstring(L, 1);
710         bool dironly            = lua_toboolean(L, 2);
711
712         std::vector<fs::DirListNode> dirlist = fs::GetDirListing(path);
713
714         unsigned int index = 1;
715         lua_newtable(L);
716         int table = lua_gettop(L);
717
718         for (unsigned int i=0;i< dirlist.size(); i++) {
719                 if ((dirlist[i].dir) || (dironly == false)) {
720                         lua_pushnumber(L,index);
721                         lua_pushstring(L,dirlist[i].name.c_str());
722                         lua_settable(L, table);
723                         index++;
724                 }
725         }
726
727         return 1;
728 }
729
730 /******************************************************************************/
731 int ModApiMainMenu::l_create_dir(lua_State *L) {
732         const char *path        = luaL_checkstring(L, 1);
733
734         if (ModApiMainMenu::isMinetestPath(path)) {
735                 lua_pushboolean(L,fs::CreateAllDirs(path));
736                 return 1;
737         }
738         lua_pushboolean(L,false);
739         return 1;
740 }
741
742 /******************************************************************************/
743 int ModApiMainMenu::l_delete_dir(lua_State *L)
744 {
745         const char *path        = luaL_checkstring(L, 1);
746
747         std::string absolute_path = fs::RemoveRelativePathComponents(path);
748
749         if (ModApiMainMenu::isMinetestPath(absolute_path)) {
750                 lua_pushboolean(L,fs::RecursiveDelete(absolute_path));
751                 return 1;
752         }
753         lua_pushboolean(L,false);
754         return 1;
755 }
756
757 /******************************************************************************/
758 int ModApiMainMenu::l_copy_dir(lua_State *L)
759 {
760         const char *source      = luaL_checkstring(L, 1);
761         const char *destination = luaL_checkstring(L, 2);
762
763         bool keep_source = true;
764
765         if ((!lua_isnone(L,3)) &&
766                         (!lua_isnil(L,3))) {
767                 keep_source = lua_toboolean(L,3);
768         }
769
770         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
771         std::string absolute_source = fs::RemoveRelativePathComponents(source);
772
773         if ((ModApiMainMenu::isMinetestPath(absolute_source)) &&
774                         (ModApiMainMenu::isMinetestPath(absolute_destination))) {
775                 bool retval = fs::CopyDir(absolute_source,absolute_destination);
776
777                 if (retval && (!keep_source)) {
778
779                         retval &= fs::RecursiveDelete(absolute_source);
780                 }
781                 lua_pushboolean(L,retval);
782                 return 1;
783         }
784         lua_pushboolean(L,false);
785         return 1;
786 }
787
788 /******************************************************************************/
789 int ModApiMainMenu::l_extract_zip(lua_State *L)
790 {
791         GUIEngine* engine = getGuiEngine(L);
792         assert(engine != 0);
793
794         const char *zipfile     = luaL_checkstring(L, 1);
795         const char *destination = luaL_checkstring(L, 2);
796
797         std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
798
799         if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
800                 fs::CreateAllDirs(absolute_destination);
801
802                 io::IFileSystem* fs = engine->m_device->getFileSystem();
803
804                 fs->addFileArchive(zipfile,true,false,io::EFAT_ZIP);
805
806                 assert(fs->getFileArchiveCount() > 0);
807
808                 /**********************************************************************/
809                 /* WARNING this is not threadsafe!!                                   */
810                 /**********************************************************************/
811                 io::IFileArchive* opened_zip =
812                         fs->getFileArchive(fs->getFileArchiveCount()-1);
813
814                 const io::IFileList* files_in_zip = opened_zip->getFileList();
815
816                 unsigned int number_of_files = files_in_zip->getFileCount();
817
818                 for (unsigned int i=0; i < number_of_files;  i++) {
819                         std::string fullpath = destination;
820                         fullpath += DIR_DELIM;
821                         fullpath += files_in_zip->getFullFileName(i).c_str();
822
823                         if (files_in_zip->isDirectory(i)) {
824                                 if (! fs::CreateAllDirs(fullpath) ) {
825                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
826                                         lua_pushboolean(L,false);
827                                         return 1;
828                                 }
829                         }
830                         else {
831                                 io::IReadFile* toread = opened_zip->createAndOpenFile(i);
832
833                                 FILE *targetfile = fopen(fullpath.c_str(),"wb");
834
835                                 if (targetfile == NULL) {
836                                         fs->removeFileArchive(fs->getFileArchiveCount()-1);
837                                         lua_pushboolean(L,false);
838                                         return 1;
839                                 }
840
841                                 char read_buffer[1024];
842                                 unsigned int total_read = 0;
843
844                                 while (total_read < toread->getSize()) {
845
846                                         unsigned int bytes_read =
847                                                         toread->read(read_buffer,sizeof(read_buffer));
848                                         unsigned int bytes_written;
849                                         if ((bytes_read < 0 ) ||
850                                                 (bytes_written = fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
851                                         {
852                                                 fclose(targetfile);
853                                                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
854                                                 lua_pushboolean(L,false);
855                                                 return 1;
856                                         }
857                                         total_read += bytes_read;
858                                 }
859
860                                 fclose(targetfile);
861                         }
862
863                 }
864
865                 fs->removeFileArchive(fs->getFileArchiveCount()-1);
866                 lua_pushboolean(L,true);
867                 return 1;
868         }
869
870         lua_pushboolean(L,false);
871         return 1;
872 }
873
874 /******************************************************************************/
875 int ModApiMainMenu::l_get_scriptdir(lua_State *L)
876 {
877         GUIEngine* engine = getGuiEngine(L);
878         assert(engine != 0);
879
880         lua_pushstring(L,engine->getScriptDir().c_str());
881         return 1;
882 }
883
884 /******************************************************************************/
885 bool ModApiMainMenu::isMinetestPath(std::string path)
886 {
887         if (fs::PathStartsWith(path,fs::TempPath()))
888                 return true;
889
890         /* games */
891         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "games")))
892                 return true;
893
894         /* mods */
895         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "mods")))
896                 return true;
897
898         /* worlds */
899         if (fs::PathStartsWith(path,fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM + "worlds")))
900                 return true;
901
902
903         return false;
904 }
905
906 /******************************************************************************/
907 int ModApiMainMenu::l_show_file_open_dialog(lua_State *L)
908 {
909         GUIEngine* engine = getGuiEngine(L);
910         assert(engine != 0);
911
912         const char *formname= luaL_checkstring(L, 1);
913         const char *title       = luaL_checkstring(L, 2);
914
915         GUIFileSelectMenu* fileOpenMenu =
916                 new GUIFileSelectMenu(engine->m_device->getGUIEnvironment(),
917                                                                 engine->m_parent,
918                                                                 -1,
919                                                                 engine->m_menumanager,
920                                                                 title,
921                                                                 formname);
922         fileOpenMenu->setTextDest(engine->m_buttonhandler);
923         fileOpenMenu->drop();
924         return 0;
925 }
926
927 /******************************************************************************/
928 int ModApiMainMenu::l_get_version(lua_State *L)
929 {
930         lua_pushstring(L,VERSION_STRING);
931         return 1;
932 }
933
934 /******************************************************************************/
935 int ModApiMainMenu::l_sound_play(lua_State *L)
936 {
937         GUIEngine* engine = getGuiEngine(L);
938
939         SimpleSoundSpec spec;
940         read_soundspec(L, 1, spec);
941         bool looped = lua_toboolean(L, 2);
942
943         u32 handle = engine->playSound(spec, looped);
944
945         lua_pushinteger(L, handle);
946
947         return 1;
948 }
949
950 /******************************************************************************/
951 int ModApiMainMenu::l_sound_stop(lua_State *L)
952 {
953         GUIEngine* engine = getGuiEngine(L);
954
955         u32 handle = luaL_checkinteger(L, 1);
956         engine->stopSound(handle);
957
958         return 1;
959 }
960
961 /******************************************************************************/
962 int ModApiMainMenu::l_download_file(lua_State *L)
963 {
964         GUIEngine* engine = getGuiEngine(L);
965         assert(engine != 0);
966
967         const char *url    = luaL_checkstring(L, 1);
968         const char *target = luaL_checkstring(L, 2);
969
970         //check path
971         std::string absolute_destination = fs::RemoveRelativePathComponents(target);
972
973         if (ModApiMainMenu::isMinetestPath(absolute_destination)) {
974                 if (engine->downloadFile(url,absolute_destination)) {
975                         lua_pushboolean(L,true);
976                         return 1;
977                 }
978         }
979         lua_pushboolean(L,false);
980         return 1;
981 }
982
983 /******************************************************************************/
984 void ModApiMainMenu::Initialize(lua_State *L, int top)
985 {
986         API_FCT(update_formspec);
987         API_FCT(set_clouds);
988         API_FCT(get_textlist_index);
989         API_FCT(get_worlds);
990         API_FCT(get_games);
991         API_FCT(start);
992         API_FCT(close);
993         API_FCT(get_favorites);
994         API_FCT(show_keys_menu);
995         API_FCT(create_world);
996         API_FCT(delete_world);
997         API_FCT(delete_favorite);
998         API_FCT(set_background);
999         API_FCT(set_topleft_text);
1000         API_FCT(get_modpath);
1001         API_FCT(get_gamepath);
1002         API_FCT(get_texturepath);
1003         API_FCT(get_dirlist);
1004         API_FCT(create_dir);
1005         API_FCT(delete_dir);
1006         API_FCT(copy_dir);
1007         API_FCT(extract_zip);
1008         API_FCT(get_scriptdir);
1009         API_FCT(show_file_open_dialog);
1010         API_FCT(get_version);
1011         API_FCT(download_file);
1012         API_FCT(get_modstore_details);
1013         API_FCT(get_modstore_list);
1014         API_FCT(sound_play);
1015         API_FCT(sound_stop);
1016 }