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