diff --git a/res/content/base/icon.png b/res/content/base/icon.png new file mode 100644 index 00000000..eadccdbc Binary files /dev/null and b/res/content/base/icon.png differ diff --git a/res/texts/en_US.txt b/res/texts/en_US.txt index f26803bd..3a25444c 100644 --- a/res/texts/en_US.txt +++ b/res/texts/en_US.txt @@ -2,6 +2,7 @@ menu.missing-content=Missing Content! world.convert-request=Content indices have changed! Convert world files? error.pack-not-found=Could not to find pack +error.dependency-not-found=Dependency pack is not found world.delete-confirm=Do you want to delete world forever? # Bindings diff --git a/res/texts/ru_RU.txt b/res/texts/ru_RU.txt index 61a33233..65085d46 100644 --- a/res/texts/ru_RU.txt +++ b/res/texts/ru_RU.txt @@ -5,8 +5,10 @@ Ok=Ок Cancel=Отмена Back=Назад Continue=Продолжить +Add=Добавить error.pack-not-found=Не удалось найти пакет +error.dependency-not-found=Используемая зависимость не найдена # Меню menu.New World=Новый Мир diff --git a/res/textures/gui/no_icon.png b/res/textures/gui/no_icon.png new file mode 100644 index 00000000..f2229a0e Binary files /dev/null and b/res/textures/gui/no_icon.png differ diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 0087389d..9ef4696d 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -60,6 +60,7 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, bool allAssets) { loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/menubg.png", "gui/menubg"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/delete_icon.png", "gui/delete_icon"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/no_icon.png", "gui/no_icon"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun"); loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal"); diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 3053d697..087eb6cb 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -67,8 +67,17 @@ ContentPack ContentPack::read(fs::path folder) { root->str("id", pack.id); root->str("title", pack.title); root->str("version", pack.version); + root->str("creator", pack.creator); + root->str("description", pack.description); pack.folder = folder; + auto dependencies = root->list("dependencies"); + if (dependencies) { + for (size_t i = 0; i < dependencies->size(); i++) { + pack.dependencies.push_back(dependencies->str(i)); + } + } + if (pack.id == "none") throw contentpack_error(pack.id, folder, "content-pack id is not specified"); @@ -92,6 +101,12 @@ void ContentPack::scan(fs::path rootfolder, } } +void ContentPack::scan(EnginePaths* paths, + std::vector& packs) { + scan(paths->getResources()/fs::path("content"), packs); + scan(paths->getWorldFolder()/fs::path("content"), packs); +} + std::vector ContentPack::worldPacksList(fs::path folder) { fs::path listfile = folder / fs::path("packs.list"); if (!fs::is_regular_file(listfile)) { @@ -111,8 +126,7 @@ fs::path ContentPack::findPack(const EnginePaths* paths, fs::path worldDir, std: if (fs::is_directory(folder)) { return folder; } - throw contentpack_error(name, folder, - "could not to find pack '"+name+"'"); + return folder; } void ContentPack::readPacks(const EnginePaths* paths, @@ -121,6 +135,10 @@ void ContentPack::readPacks(const EnginePaths* paths, fs::path worldDir) { for (const auto& name : packnames) { fs::path packfolder = ContentPack::findPack(paths, worldDir, name); + if (!fs::is_directory(packfolder)) { + throw contentpack_error(name, packfolder, + "could not to find pack '"+name+"'"); + } packs.push_back(ContentPack::read(packfolder)); } } diff --git a/src/content/ContentPack.h b/src/content/ContentPack.h index c233532a..6f82519a 100644 --- a/src/content/ContentPack.h +++ b/src/content/ContentPack.h @@ -24,7 +24,10 @@ struct ContentPack { std::string id = "none"; std::string title = "untitled"; std::string version = "0.0"; + std::string creator = ""; + std::string description = "no description"; std::filesystem::path folder; + std::vector dependencies; std::filesystem::path getContentFile() const; @@ -36,8 +39,12 @@ struct ContentPack { static bool is_pack(std::filesystem::path folder); static ContentPack read(std::filesystem::path folder); + static void scan(std::filesystem::path folder, std::vector& packs); + static void scan(EnginePaths* paths, + std::vector& packs); + static std::vector worldPacksList(std::filesystem::path folder); static std::filesystem::path findPack( diff --git a/src/engine.cpp b/src/engine.cpp index 8b39b825..32673e11 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -176,7 +176,7 @@ void Engine::loadWorldContent(const fs::path& folder) { void Engine::loadAllPacks() { auto resdir = paths->getResources(); contentPacks.clear(); - ContentPack::scan(resdir/fs::path("content"), contentPacks); + ContentPack::scan(paths, contentPacks); } void Engine::setScreen(std::shared_ptr screen) { @@ -212,3 +212,7 @@ std::vector& Engine::getContentPacks() { EnginePaths* Engine::getPaths() { return paths; } + +std::shared_ptr Engine::getScreen() { + return screen; +} \ No newline at end of file diff --git a/src/engine.h b/src/engine.h index d4b98b91..595b80da 100644 --- a/src/engine.h +++ b/src/engine.h @@ -63,6 +63,8 @@ public: void loadContent(); void loadWorldContent(const fs::path& folder); void loadAllPacks(); + + std::shared_ptr getScreen(); }; #endif // SRC_ENGINE_H_ \ No newline at end of file diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 95449b46..2de7829b 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -453,13 +453,18 @@ void WorldFiles::write(const World* world, const Content* content) { } void WorldFiles::writePacks(const World* world) { + auto packsFile = getPacksFile(); + if (fs::is_regular_file(packsFile)) { + return; + } + const auto& packs = world->getPacks(); std::stringstream ss; ss << "# autogenerated; do not modify\n"; for (const auto& pack : packs) { ss << pack.id << "\n"; } - files::write_string(getPacksFile(), ss.str()); + files::write_string(packsFile, ss.str()); } void WorldFiles::writeIndices(const ContentIndices* indices) { @@ -574,3 +579,15 @@ bool WorldFiles::readPlayer(Player* player) { } return true; } + +void WorldFiles::addPack(const std::string& id) { + auto packs = files::read_list(getPacksFile()); + packs.push_back(id); + + std::stringstream ss; + ss << "# autogenerated; do not modify\n"; + for (const auto& pack : packs) { + ss << pack << "\n"; + } + files::write_string(getPacksFile(), ss.str()); +} diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index 3b76bf7b..291604dc 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -146,6 +146,8 @@ public: void write(const World* world, const Content* content); void writePacks(const World* world); void writeIndices(const ContentIndices* indices); + /* Append pack to packs.list without duplicate check */ + void addPack(const std::string& id); static const char* WORLD_FILE; }; diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index 482ff029..a657a3ca 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -43,6 +43,10 @@ fs::path EnginePaths::getWorldsFolder() { return userfiles/fs::path("worlds"); } +fs::path EnginePaths::getWorldFolder() { + return worldFolder; +} + std::vector EnginePaths::scanForWorlds() { std::vector folders; diff --git a/src/files/engine_paths.h b/src/files/engine_paths.h index 29b3b2e7..760a1ba5 100644 --- a/src/files/engine_paths.h +++ b/src/files/engine_paths.h @@ -12,7 +12,7 @@ namespace fs = std::filesystem; class EnginePaths { fs::path userfiles {"."}; fs::path resources {"res"}; - fs::path worldFolder {""}; + fs::path worldFolder; std::vector* contentPacks = nullptr; public: fs::path getUserfiles() const; @@ -20,6 +20,7 @@ public: fs::path getScreenshotFile(std::string ext); fs::path getWorldsFolder(); + fs::path getWorldFolder(); bool isWorldNameUsed(std::string name); void setUserfiles(fs::path folder); diff --git a/src/frontend/WorldRenderer.cpp b/src/frontend/WorldRenderer.cpp index d61394b4..7cd2f0f2 100644 --- a/src/frontend/WorldRenderer.cpp +++ b/src/frontend/WorldRenderer.cpp @@ -37,8 +37,6 @@ using glm::vec3; using glm::vec4; using glm::mat4; -using std::string; -using std::shared_ptr; WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend) : engine(engine), @@ -76,7 +74,7 @@ bool WorldRenderer::drawChunk(size_t index, if (!chunk->isLighted()) { return false; } - shared_ptr mesh = renderer->getOrRender(chunk.get()); + auto mesh = renderer->getOrRender(chunk.get()); if (mesh == nullptr) { return false; } @@ -102,16 +100,15 @@ void WorldRenderer::drawChunks(Chunks* chunks, Shader* shader) { std::vector indices; for (size_t i = 0; i < chunks->volume; i++){ - shared_ptr chunk = chunks->chunks[i]; - if (chunk == nullptr) + if (chunks->chunks[i] == nullptr) continue; indices.push_back(i); } float px = camera->position.x / (float)CHUNK_W; float pz = camera->position.z / (float)CHUNK_D; std::sort(indices.begin(), indices.end(), [this, chunks, px, pz](size_t i, size_t j) { - shared_ptr a = chunks->chunks[i]; - shared_ptr b = chunks->chunks[j]; + auto a = chunks->chunks[i]; + auto b = chunks->chunks[j]; return ((a->x + 0.5f - px)*(a->x + 0.5f - px) + (a->z + 0.5f - pz)*(a->z + 0.5f - pz) > diff --git a/src/frontend/gui/GUI.h b/src/frontend/gui/GUI.h index df3cdcff..3e159f4a 100644 --- a/src/frontend/gui/GUI.h +++ b/src/frontend/gui/GUI.h @@ -45,6 +45,7 @@ class Camera; namespace gui { typedef std::function runnable; + typedef std::function stringconsumer; class UINode; class Container; diff --git a/src/frontend/gui/UINode.h b/src/frontend/gui/UINode.h index 668e4d97..6f909ba5 100644 --- a/src/frontend/gui/UINode.h +++ b/src/frontend/gui/UINode.h @@ -81,7 +81,7 @@ namespace gui { virtual glm::vec2 contentOffset() {return glm::vec2(0.0f);}; glm::vec2 calcCoord() const; virtual void setCoord(glm::vec2 coord); - glm::vec2 size() const; + virtual glm::vec2 size() const; virtual void size(glm::vec2 size); void _size(glm::vec2 size); virtual void refresh() {}; diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index 626c47de..54188b43 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -22,6 +22,13 @@ const uint KEY_BACKSPACE = 259; using namespace gui; +Label::Label(string text, string fontName) + : UINode(vec2(), vec2(text.length() * 8, 15)), + text_(util::str2wstr_utf8(text)), + fontName_(fontName) { +} + + Label::Label(wstring text, string fontName) : UINode(vec2(), vec2(text.length() * 8, 15)), text_(text), @@ -64,6 +71,7 @@ void Label::size(vec2 sizenew) { // ================================= Image ==================================== Image::Image(string texture, vec2 size) : UINode(vec2(), size), texture(texture) { + setInteractive(false); } void Image::draw(Batch2D* batch, Assets* assets) { diff --git a/src/frontend/gui/controls.h b/src/frontend/gui/controls.h index 60587248..af77863a 100644 --- a/src/frontend/gui/controls.h +++ b/src/frontend/gui/controls.h @@ -32,6 +32,7 @@ namespace gui { std::string fontName_; wstringsupplier supplier = nullptr; public: + Label(std::string text, std::string fontName="normal"); Label(std::wstring text, std::string fontName="normal"); virtual Label& text(std::wstring text); @@ -40,6 +41,9 @@ namespace gui { virtual void draw(Batch2D* batch, Assets* assets) override; virtual Label* textSupplier(wstringsupplier supplier); + virtual glm::vec2 size() const override { + return UINode::size(); + } virtual void size(glm::vec2 size) override; }; diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index a7701e9a..6f8957af 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -11,6 +12,8 @@ #include "gui/panels.h" #include "gui/controls.h" #include "screens.h" + +#include "../coders/png.h" #include "../util/stringutil.h" #include "../files/engine_paths.h" #include "../files/WorldConverter.h" @@ -98,6 +101,25 @@ void show_content_missing(Engine* engine, const Content* content, subpanel->add(hpanel); } } + + for (size_t i = 0; i < lut->countItems(); i++) { + // missing block + if (lut->getItemId(i) == ITEM_VOID) { + auto name = lut->getItemName(i); + Panel* hpanel = new Panel(vec2(500, 30)); + hpanel->color(vec4(0.0f)); + hpanel->orientation(Orientation::horizontal); + + Label* namelabel = new Label(util::str2wstr_utf8(name)); + namelabel->color(vec4(1.0f, 0.2f, 0.2f, 0.5f)); + + Label* typelabel = new Label(L"[item]"); + typelabel->color(vec4(0.5f)); + hpanel->add(typelabel); + hpanel->add(namelabel); + subpanel->add(hpanel); + } + } subpanel->maxLength(400); panel->add(subpanel); @@ -248,10 +270,109 @@ void create_main_menu_panel(Engine* engine, PagesControl* menu) { })); } +typedef std::function packconsumer; + +std::shared_ptr create_packs_panel(const std::vector& packs, Engine* engine, bool backbutton, packconsumer callback) { + auto assets = engine->getAssets(); + auto panel = std::make_shared(vec2(400, 200), vec4(5.0f)); + panel->color(vec4(1.0f, 1.0f, 1.0f, 0.07f)); + panel->maxLength(400); + panel->scrollable(true); + + for (auto& pack : packs) { + auto packpanel = std::make_shared(vec2(390, 80)); + if (callback) { + packpanel->listenAction([=](GUI*) { + callback(pack); + }); + } + auto idlabel = std::make_shared