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