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