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