diff --git a/res/layouts/pages/add_packs.xml b/res/layouts/pages/add_packs.xml
new file mode 100644
index 00000000..defa84d5
--- /dev/null
+++ b/res/layouts/pages/add_packs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/res/layouts/pages/add_packs.xml.lua b/res/layouts/pages/add_packs.xml.lua
new file mode 100644
index 00000000..c27697c3
--- /dev/null
+++ b/res/layouts/pages/add_packs.xml.lua
@@ -0,0 +1,14 @@
+function add_pack(packid, packinfo)
+ local callback = string.format('core.add_packs({%q})', packid)
+ packinfo.id = packid
+ packinfo.callback = callback
+ packinfo.icon = "gui/no_icon"
+ document.packs_panel:add(gui.template("pack", packinfo))
+end
+
+function on_open()
+ local packs = pack.get_available()
+ for i,id in ipairs(packs) do
+ add_pack(id, pack.get_info(id))
+ end
+end
diff --git a/res/layouts/pages/content.xml b/res/layouts/pages/content.xml
index 43c0c566..ea1a9e65 100644
--- a/res/layouts/pages/content.xml
+++ b/res/layouts/pages/content.xml
@@ -1,6 +1,7 @@
-
+
+
diff --git a/res/layouts/pages/content.xml.lua b/res/layouts/pages/content.xml.lua
index be7be84b..fcc85a81 100644
--- a/res/layouts/pages/content.xml.lua
+++ b/res/layouts/pages/content.xml.lua
@@ -1,12 +1,15 @@
function add_pack(packid, packinfo)
- document.packs_panel:add(gui.template("pack", {
- id=packid,
- title=packinfo.title,
- description=packinfo.description,
- icon="gui/no_icon",
- creator=packinfo.creator,
- remover='0'
- }))
+ local remover = ''
+ if packid ~= "base" then
+ remover = string.format('core.remove_packs({%q})', packid)
+ end
+ if packinfo.has_indices then
+ packid = packid.."*"
+ end
+ packinfo.id = packid
+ packinfo.remover = remover
+ packinfo.icon = "gui/no_icon"
+ document.packs_panel:add(gui.template("pack", packinfo))
end
function on_open()
diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua
index cbbf5762..82df4bd7 100644
--- a/res/scripts/stdlib.lua
+++ b/res/scripts/stdlib.lua
@@ -204,7 +204,8 @@ end
function gui.template(name, params)
local text = file.read(file.find("layouts/templates/"..name..".xml"))
for k,v in pairs(params) do
- text = text:gsub("(%%{"..k.."})", tostring(v))
+ local arg = tostring(v):gsub("'", "\\'"):gsub('"', '\\"')
+ text = text:gsub("(%%{"..k.."})", arg)
end
text = text:gsub("if%s*=%s*'%%{%w+}'", "if=''")
text = text:gsub("if%s*=%s*\"%%{%w+}\"", "if=\"\"")
diff --git a/src/engine.cpp b/src/engine.cpp
index d5903f8c..8e5584c7 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -179,8 +179,8 @@ Engine::~Engine() {
logger.info() << "shutting down";
if (screen) {
screen->onEngineShutdown();
+ screen.reset();
}
- screen.reset();
content.reset();
assets.reset();
audio::close();
diff --git a/src/frontend/menu/menu.cpp b/src/frontend/menu/menu.cpp
index a00fe1e3..0d27fdfb 100644
--- a/src/frontend/menu/menu.cpp
+++ b/src/frontend/menu/menu.cpp
@@ -219,11 +219,17 @@ void menus::delete_world(std::string name, Engine* engine) {
});
}
-static void add_page_loader(Engine* engine, const std::string& name) {
+void menus::create_menus(Engine* engine) {
+ menus::generatorID = WorldGenerators::getDefaultGeneratorID();
+ create_new_world_panel(engine);
+ create_settings_panel(engine);
+ create_world_generators_panel(engine);
+
auto menu = engine->getGUI()->getMenu();
- auto file = engine->getResPaths()->find("layouts/pages/"+name+".xml");
- auto fullname = "core:pages/"+name;
- menu->addSupplier(name, [=]() {
+ menu->setPageLoader([=](auto name) {
+ auto file = engine->getResPaths()->find("layouts/pages/"+name+".xml");
+ auto fullname = "core:pages/"+name;
+
auto document = UiDocument::read(0, fullname, file).release();
engine->getAssets()->store(document, fullname);
scripting::on_ui_open(document, nullptr, glm::ivec3());
@@ -231,21 +237,7 @@ static void add_page_loader(Engine* engine, const std::string& name) {
});
}
-void menus::create_menus(Engine* engine) {
- menus::generatorID = WorldGenerators::getDefaultGeneratorID();
- create_new_world_panel(engine);
- create_settings_panel(engine);
- add_page_loader(engine, "languages");
- create_world_generators_panel(engine);
- add_page_loader(engine, "main");
- add_page_loader(engine, "404");
- add_page_loader(engine, "content");
-}
-
void menus::refresh_menus(Engine* engine) {
create_new_world_panel(engine);
create_world_generators_panel(engine);
- add_page_loader(engine, "main");
- add_page_loader(engine, "404");
- add_page_loader(engine, "settings-audio");
}
diff --git a/src/frontend/menu/menu_pause.cpp b/src/frontend/menu/menu_pause.cpp
index 3333a2c6..8c274eb4 100644
--- a/src/frontend/menu/menu_pause.cpp
+++ b/src/frontend/menu/menu_pause.cpp
@@ -19,95 +19,6 @@
using namespace gui;
-std::shared_ptr create_pack_panel(
- const ContentPack& pack,
- Engine* engine,
- packconsumer callback,
- packconsumer remover
-) {
- auto assets = engine->getAssets();
- auto packpanel = std::dynamic_pointer_cast(guiutil::create(
- ""
- ));
- if (callback) {
- packpanel->listenAction([=](GUI*) {
- callback(pack);
- });
- }
- auto runtime = engine->getContent() ? engine->getContent()->getPackRuntime(pack.id) : nullptr;
- auto idtext = (runtime && runtime->getStats().hasSavingContent())
- ? "*["+pack.id+"]"
- : "["+pack.id+"]";
-
- packpanel->add(guiutil::create(
- ""
- ));
- packpanel->add(guiutil::create(
- ""
- ));
-
- if (!pack.creator.empty()) {
- packpanel->add(guiutil::create(
- ""
- ));
- }
-
- packpanel->add(guiutil::create(
- ""
- ));
-
- std::string icon = pack.id+".icon";
- if (assets->getTexture(icon) == nullptr) {
- auto iconfile = pack.folder/fs::path("icon.png");
- if (fs::is_regular_file(iconfile)) {
- auto image = imageio::read(iconfile.string());
- assets->store(Texture::from(image.get()), icon);
- } else {
- icon = "gui/no_icon";
- }
- }
- packpanel->add(std::make_shared(icon, glm::vec2(64)), glm::vec2(8));
-
- if (remover && pack.id != "base") {
- auto rembtn = guiutil::create(
- ""
- );
- rembtn->listenAction([=](GUI* gui) {
- remover(pack);
- });
- packpanel->add(rembtn, glm::vec2(470, 22));
- }
- return packpanel;
-}
-
-std::shared_ptr menus::create_packs_panel(
- const std::vector& packs,
- Engine* engine,
- bool backbutton,
- packconsumer callback,
- packconsumer remover
-){
- auto panel = std::dynamic_pointer_cast(guiutil::create(
- ""
- ""
- ));
- for (auto& pack : packs) {
- panel->add(create_pack_panel(pack, engine, callback, remover));
- }
- if (backbutton) {
- panel->add(guiutil::backButton(engine->getGUI()->getMenu()));
- }
- return panel;
-}
-
static void reopen_world(Engine* engine, World* world) {
std::string wname = world->wfile->getFolder().stem().u8string();
engine->setScreen(nullptr);
@@ -191,43 +102,6 @@ void menus::add_packs(
reopen_world(engine, world);
}
-void create_content_panel(Engine* engine, LevelController* controller) {
- auto level = controller->getLevel();
- auto menu = engine->getGUI()->getMenu();
- auto mainPanel = menus::create_page(engine, "content", 550, 0.0f, 5);
-
- PacksManager manager = engine->createPacksManager(level->getWorld()->wfile->getFolder());
- manager.scan();
-
- std::vector scanned = manager.getAll(manager.getAllNames());
- for (const auto& pack : engine->getContentPacks()) {
- for (size_t i = 0; i < scanned.size(); i++) {
- if (scanned[i].id == pack.id) {
- scanned.erase(scanned.begin()+i);
- i--;
- }
- }
- }
- auto panel = menus::create_packs_panel(
- engine->getContentPacks(), engine, false, nullptr,
- [=](const ContentPack& pack) {
- std::vector packsToRemove {pack.id};
- menus::remove_packs(engine, controller, packsToRemove);
- }
- );
- mainPanel->add(panel);
- mainPanel->add(menus::create_button(
- langs::get(L"Add", L"content"), glm::vec4(10.0f), glm::vec4(1), [=](GUI* gui) {
- auto panel = menus::create_packs_panel(scanned, engine, true,
- [=](const ContentPack& pack) {
- menus::add_packs(engine, controller, {pack.id});
- }, nullptr);
- menu->addPage("content-packs", panel);
- menu->setPage("content-packs");
- }));
- mainPanel->add(guiutil::backButton(menu));
-}
-
void menus::create_pause_panel(Engine* engine, LevelController* controller) {
auto menu = engine->getGUI()->getMenu();
auto panel = create_page(engine, "pause", 400, 0.0f, 1);
@@ -236,7 +110,6 @@ void menus::create_pause_panel(Engine* engine, LevelController* controller) {
menu->reset();
}));
panel->add(create_button(L"Content", glm::vec4(10.0f), glm::vec4(1), [=](GUI*) {
- //create_content_panel(engine, controller);
menu->setPage("content");
}));
panel->add(guiutil::gotoButton(L"Settings", "settings", menu));
diff --git a/src/graphics/ui/elements/containers.cpp b/src/graphics/ui/elements/containers.cpp
index 0b94f675..edb4245d 100644
--- a/src/graphics/ui/elements/containers.cpp
+++ b/src/graphics/ui/elements/containers.cpp
@@ -268,11 +268,14 @@ void Menu::addSupplier(std::string name, supplier> pageS
pageSuppliers[name] = pageSupplier;
}
-std::shared_ptr Menu::fetchPage(std::string name) {
+std::shared_ptr Menu::fetchPage(const std::string& name) {
auto found = pages.find(name);
if (found == pages.end()) {
auto supplier = pageSuppliers.find(name);
if (supplier == pageSuppliers.end()) {
+ if (pagesLoader) {
+ return pagesLoader(name);
+ }
return nullptr;
} else {
return supplier->second();
@@ -318,6 +321,10 @@ void Menu::back() {
setPage(page, false);
}
+void Menu::setPageLoader(page_loader_func loader) {
+ pagesLoader = loader;
+}
+
Page& Menu::getCurrent() {
return current;
}
diff --git a/src/graphics/ui/elements/containers.h b/src/graphics/ui/elements/containers.h
index b70f96a1..09496b0b 100644
--- a/src/graphics/ui/elements/containers.h
+++ b/src/graphics/ui/elements/containers.h
@@ -94,12 +94,15 @@ namespace gui {
}
};
+ using page_loader_func = std::function(const std::string& name)>;
+
class Menu : public Container {
protected:
std::unordered_map pages;
std::stack pageStack;
Page current;
std::unordered_map>> pageSuppliers;
+ page_loader_func pagesLoader = nullptr;
public:
Menu();
@@ -113,13 +116,16 @@ namespace gui {
void setPage(std::string name, bool history=true);
void setPage(Page page, bool history=true);
void addPage(std::string name, std::shared_ptr panel);
- std::shared_ptr fetchPage(std::string name);
+ std::shared_ptr fetchPage(const std::string& name);
/// @brief Add page supplier used if page is not found
/// @param name page name
/// @param pageSupplier page supplier function
void addSupplier(std::string name, supplier> pageSupplier);
+ /// @brief Page loader is called if accessed page is not found
+ void setPageLoader(page_loader_func loader);
+
/// @brief Set page to previous saved in history
void back();
diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp
index 8f3c87e1..01713e35 100644
--- a/src/graphics/ui/gui_xml.cpp
+++ b/src/graphics/ui/gui_xml.cpp
@@ -102,18 +102,20 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no
}
if (element->has("onclick")) {
- auto callback = scripting::create_runnable(
- reader.getEnvironment().getId(),
- element->attr("onclick").getText(),
- reader.getFilename()
- );
- node.listenAction([callback](GUI*) {
- callback();
- });
+ std::string text = element->attr("onclick").getText();
+ if (!text.empty()) {
+ auto callback = scripting::create_runnable(
+ reader.getEnvironment().getId(),
+ text,
+ reader.getFilename()
+ );
+ node.listenAction([callback](GUI*) {
+ callback();
+ });
+ }
}
}
-
static void _readContainer(UiXmlReader& reader, xml::xmlelement element, Container& container) {
_readUINode(reader, element, container);
diff --git a/src/logic/scripting/lua/libcore.cpp b/src/logic/scripting/lua/libcore.cpp
index 6c25500f..91d47b33 100644
--- a/src/logic/scripting/lua/libcore.cpp
+++ b/src/logic/scripting/lua/libcore.cpp
@@ -72,6 +72,21 @@ static int l_remove_packs(lua_State* L) {
return 0;
}
+static int l_add_packs(lua_State* L) {
+ if (!lua_istable(L, 1)) {
+ luaL_error(L, "strings array expected as an argument");
+ }
+ std::vector packs;
+ int len = lua_objlen(L, 1);
+ for (int i = 0; i < len; i++) {
+ lua_rawgeti(L, -1, i+1);
+ packs.push_back(lua_tostring(L, -1));
+ lua_pop(L, 1);
+ }
+ menus::add_packs(scripting::engine, scripting::controller, packs);
+ return 0;
+}
+
static int l_get_bindings(lua_State* L) {
auto& bindings = Events::bindings;
lua_createtable(L, bindings.size(), 0);
@@ -116,6 +131,7 @@ const luaL_Reg corelib [] = {
{"open_world", lua_wrap_errors},
{"close_world", lua_wrap_errors},
{"delete_world", lua_wrap_errors},
+ {"add_packs", lua_wrap_errors},
{"remove_packs", lua_wrap_errors},
{"get_bindings", lua_wrap_errors},
{"get_setting", lua_wrap_errors},
diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp
index 65babefb..7b2d7b53 100644
--- a/src/logic/scripting/lua/libgui.cpp
+++ b/src/logic/scripting/lua/libgui.cpp
@@ -214,11 +214,7 @@ static bool setattr(lua_State* L, gui::Menu* menu, const std::string& attr) {
return false;
if (attr == "page") {
auto page = lua_tostring(L, 4);
- if (menu->has(page)) {
- menu->setPage(page);
- } else {
- menu->setPage("404");
- }
+ menu->setPage(page);
return true;
}
return false;
diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp
index 0086398b..a04dc838 100644
--- a/src/voxel_engine.cpp
+++ b/src/voxel_engine.cpp
@@ -59,10 +59,12 @@ int main(int argc, char** argv) {
catch (const initialize_error& err) {
logger.error() << "could not to initialize engine\n" << err.what();
}
+#ifdef NDEBUG
catch (const std::exception& err) {
logger.error() << "uncaught exception: " << err.what();
debug::Logger::flush();
throw;
}
+#endif
return EXIT_SUCCESS;
}