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