diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 615df567..d686e6cf 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -65,29 +65,29 @@ void AssetsLoader::tryAddSound(std::string name) { if (name.empty()) { return; } - fs::path file = SOUNDS_FOLDER"/"+name+".ogg"; + fs::path file = SOUNDS_FOLDER+"/"+name+".ogg"; add(ASSET_SOUND, file, name); } void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { - loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal"); - loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui"); - loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main"); - loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines"); - 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"/gui/warning.png", "gui/warning"); - loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/error.png", "gui/error"); - loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross"); + loader.add(ASSET_FONT, FONTS_FOLDER+"/font", "normal"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/ui", "ui"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/main", "main"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/lines", "lines"); + 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+"/gui/warning.png", "gui/warning"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER+"/gui/error.png", "gui/error"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER+"/gui/cross.png", "gui/cross"); if (content) { - loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d"); - loader.add(ASSET_SHADER, SHADERS_FOLDER"/screen", "screen"); - loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background"); - loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); - 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_TEXTURE, TEXTURES_FOLDER"/gui/crosshair.png", "gui/crosshair"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/ui3d", "ui3d"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/screen", "screen"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/background", "background"); + loader.add(ASSET_SHADER, SHADERS_FOLDER+"/skybox_gen", "skybox_gen"); + 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_TEXTURE, TEXTURES_FOLDER+"/gui/crosshair.png", "gui/crosshair"); for (auto& entry : content->getBlockMaterials()) { auto& material = entry.second; @@ -104,8 +104,8 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { addLayouts(pack->getEnvironment()->getId(), info.id, folder, loader); } } - loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/blocks", "blocks"); - loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/items", "items"); + loader.add(ASSET_ATLAS, TEXTURES_FOLDER+"/blocks", "blocks"); + loader.add(ASSET_ATLAS, TEXTURES_FOLDER+"/items", "items"); } const ResPaths* AssetsLoader::getPaths() const { diff --git a/src/constants.h b/src/constants.h index 123f115e..8556d7e3 100644 --- a/src/constants.h +++ b/src/constants.h @@ -8,7 +8,7 @@ inline constexpr int ENGINE_VERSION_MAJOR = 0; inline constexpr int ENGINE_VERSION_MINOR = 20; inline constexpr bool ENGINE_VERSION_INDEV = true; -#define ENGINE_VERSION_STRING "0.20" +inline const std::string ENGINE_VERSION_STRING = "0.20"; inline constexpr int BLOCK_AIR = 0; inline constexpr int ITEM_EMPTY = 0; @@ -35,11 +35,10 @@ inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=C return (y * d + z) * w + x; } -//cannot replace defines with const while used for substitution -#define SHADERS_FOLDER "shaders" -#define TEXTURES_FOLDER "textures" -#define FONTS_FOLDER "fonts" -#define LAYOUTS_FOLDER "layouts" -#define SOUNDS_FOLDER "sounds" +inline const std::string SHADERS_FOLDER = "shaders"; +inline const std::string TEXTURES_FOLDER = "textures"; +inline const std::string FONTS_FOLDER = "fonts"; +inline const std::string LAYOUTS_FOLDER = "layouts"; +inline const std::string SOUNDS_FOLDER = "sounds"; #endif // SRC_CONSTANTS_H_ diff --git a/src/data/dynamic.cpp b/src/data/dynamic.cpp index 6f60b3f7..26452151 100644 --- a/src/data/dynamic.cpp +++ b/src/data/dynamic.cpp @@ -67,6 +67,13 @@ bool List::flag(size_t index) const { } } +Value* List::getValueWriteable(size_t index) const { + if (index > values.size()) { + throw std::runtime_error("index error"); + } + return values.at(index).get(); +} + List& List::put(std::string value) { valvalue val; val.str = new std::string(value); diff --git a/src/data/dynamic.h b/src/data/dynamic.h index 304111c4..928ddb60 100644 --- a/src/data/dynamic.h +++ b/src/data/dynamic.h @@ -40,7 +40,7 @@ namespace dynamic { std::string str(size_t index) const; double num(size_t index) const; - int64_t integer(size_t num) const; + int64_t integer(size_t index) const; Map* map(size_t index) const; List* list(size_t index) const; bool flag(size_t index) const; @@ -64,6 +64,8 @@ namespace dynamic { List& put(List* value); List& put(bool value); + Value* getValueWriteable(size_t index) const; + List& putList(); Map& putMap(); diff --git a/src/engine.cpp b/src/engine.cpp index ee6accc5..785ff71f 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -149,6 +149,9 @@ void Engine::mainloop() { Engine::~Engine() { std::cout << "-- shutting down" << std::endl; + if (screen) { + screen->onEngineShutdown(); + } screen.reset(); content.reset(); assets.reset(); diff --git a/src/engine.h b/src/engine.h index aec0df72..1c2d0801 100644 --- a/src/engine.h +++ b/src/engine.h @@ -22,100 +22,86 @@ class ResPaths; namespace fs = std::filesystem; namespace gui { - class GUI; + class GUI; } class initialize_error : public std::runtime_error { public: - initialize_error(const std::string& message) : std::runtime_error(message) {} + initialize_error(const std::string& message) : std::runtime_error(message) {} }; class Engine { - std::unique_ptr assets = nullptr; - std::shared_ptr screen = nullptr; + std::unique_ptr assets = nullptr; + std::shared_ptr screen = nullptr; std::vector contentPacks; - EngineSettings& settings; - std::unique_ptr content = nullptr; - EnginePaths* paths; + EngineSettings& settings; + std::unique_ptr content = nullptr; + EnginePaths* paths; std::unique_ptr resPaths = nullptr; - uint64_t frame = 0; - double lastTime = 0.0; - double delta = 0.0; + uint64_t frame = 0; + double lastTime = 0.0; + double delta = 0.0; - std::unique_ptr gui; + std::unique_ptr gui; void updateTimers(); - void updateHotkeys(); + void updateHotkeys(); public: - Engine(EngineSettings& settings, EnginePaths* paths); - ~Engine(); + Engine(EngineSettings& settings, EnginePaths* paths); + ~Engine(); + + /// @brief Start main engine input/update/render loop. + /// Automatically sets MenuScreen + void mainloop(); - /** - * Start main engine input/update/render loop - * Automatically sets MenuScreen - */ - void mainloop(); - - /** - * Set screen (scene). - * nullptr may be used to delete previous screen before creating new one - * example: - * - * engine->setScreen(nullptr); - * engine->setScreen(std::make_shared<...>(...)); - * - * not-null value must be set before next frame - */ + + /// @brief Set screen (scene). + /// nullptr may be used to delete previous screen before creating new one, + /// not-null value must be set before next frame + /// @param screen nullable screen void setScreen(std::shared_ptr screen); - /** - * Change locale to specified - * @param locale isolanguage_ISOCOUNTRY (example: en_US) - */ - void setLanguage(std::string locale); + /// @brief Change locale to specified + /// @param locale isolanguage_ISOCOUNTRY (example: en_US) + void setLanguage(std::string locale); - /** - * Load all selected content-packs and reload assets - */ + /// @brief Load all selected content-packs and reload assets void loadContent(); - /** - * Collect world content-packs and load content - * @see loadContent - * @param folder world folder - */ + + /// @brief Collect world content-packs and load content + /// @see loadContent + /// @param folder world folder void loadWorldContent(const fs::path& folder); - /** - * Collect all available content-packs from res/content - */ - void loadAllPacks(); + /// @brief Collect all available content-packs from res/content + void loadAllPacks(); - /** Get current frame delta-time */ + /// @brief Get current frame delta-time double getDelta() const; - /** Get active assets storage instance */ - Assets* getAssets(); + /// @brief Get active assets storage instance + Assets* getAssets(); - /** Get main UI controller */ - gui::GUI* getGUI(); + /// @brief Get main UI controller + gui::GUI* getGUI(); - /** Get writeable engine settings structure instance */ - EngineSettings& getSettings(); + /// @brief Get writeable engine settings structure instance + EngineSettings& getSettings(); - /** Get engine filesystem paths source */ - EnginePaths* getPaths(); + /// @brief Get engine filesystem paths source + EnginePaths* getPaths(); - /** Get engine resource paths controller */ + /// @brief Get engine resource paths controller ResPaths* getResPaths(); - /** Get current Content instance */ - const Content* getContent() const; + /// @brief Get current Content instance + const Content* getContent() const; - /** Get selected content packs */ + /// @brief Get selected content packs std::vector& getContentPacks(); - /** Get current screen */ + /// @brief Get current screen std::shared_ptr getScreen(); }; diff --git a/src/files/WorldConverter.cpp b/src/files/WorldConverter.cpp index fe77cfc0..ba30f7bf 100644 --- a/src/files/WorldConverter.cpp +++ b/src/files/WorldConverter.cpp @@ -13,10 +13,12 @@ namespace fs = std::filesystem; -WorldConverter::WorldConverter(fs::path folder, - const Content* content, - std::shared_ptr lut) - : lut(lut), content(content) { +WorldConverter::WorldConverter( + fs::path folder, + const Content* content, + std::shared_ptr lut +) : lut(lut), content(content) +{ DebugSettings settings; wfile = new WorldFiles(folder, settings); diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index e2d3a6ad..46d2bb38 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -29,6 +29,9 @@ #include #include +#define REGION_FORMAT_MAGIC ".VOXREG" +#define WORLD_FORMAT_MAGIC ".VOXWLD" + const size_t BUFFER_SIZE_UNKNOWN = -1; regfile::regfile(fs::path filename) : file(filename) { @@ -91,8 +94,6 @@ uint WorldRegion::getChunkDataSize(uint x, uint z) { return sizes[z * REGION_SIZE + x]; } -const char* WorldFiles::WORLD_FILE = "world.json"; - WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings) : directory(directory), generatorTestMode(settings.generatorTestMode), @@ -161,11 +162,10 @@ int WorldFiles::getVoxelRegionsVersion() { return REGION_FORMAT_VERSION; } -/* - * Compress and store chunk voxels data in region - * @param x chunk.x - * @param z chunk.z - */ + +/// @brief Compress and store chunk voxels data in region +/// @param x chunk.x +/// @param z chunk.z void WorldFiles::put(int x, int z, const ubyte* voxelData) { int regionX = floordiv(x, REGION_SIZE); int regionZ = floordiv(z, REGION_SIZE); @@ -181,9 +181,7 @@ void WorldFiles::put(int x, int z, const ubyte* voxelData) { } } -/* - * Store chunk (voxels and lights) in region (existing or new) - */ +/// @brief Store chunk (voxels and lights) in region (existing or new) void WorldFiles::put(Chunk* chunk){ assert(chunk != nullptr); @@ -201,7 +199,7 @@ void WorldFiles::put(Chunk* chunk){ region->setUnsaved(true); region->put(localX, localZ, data, compressedSize); } - /* Writing lights cache */ + // Writing lights cache if (doWriteLights && chunk->isLighted()) { size_t compressedSize; std::unique_ptr light_data (chunk->lightmap.encode()); @@ -211,7 +209,7 @@ void WorldFiles::put(Chunk* chunk){ region->setUnsaved(true); region->put(localX, localZ, data, compressedSize); } - /* Writing block inventories */ + // Writing block inventories if (!chunk->inventories.empty()){ auto& inventories = chunk->inventories; ByteBuilder builder; @@ -252,13 +250,11 @@ fs::path WorldFiles::getRegionFilename(int x, int z) const { return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin"); } -/* - * Extract X and Z from 'X_Z.bin' region file name. - * @param name source region file name - * @param x parsed X destination - * @param z parsed Z destination - * @return false if std::invalid_argument or std::out_of_range occurred - */ +/// @brief Extract X and Z from 'X_Z.bin' region file name. +/// @param name source region file name +/// @param x parsed X destination +/// @param z parsed Z destination +/// @return false if std::invalid_argument or std::out_of_range occurred bool WorldFiles::parseRegionFilename(const std::string& name, int& x, int& z) { size_t sep = name.find('_'); if (sep == std::string::npos || sep == 0 || sep == name.length()-1) @@ -294,8 +290,8 @@ ubyte* WorldFiles::getChunk(int x, int z){ return getData(regions, getRegionsFolder(), x, z, REGION_LAYER_VOXELS, true); } -/* Get cached lights for chunk at x,z - * @return lights data or nullptr */ +/// @brief Get cached lights for chunk at x,z +/// @return lights data or nullptr light_t* WorldFiles::getLights(int x, int z) { std::unique_ptr data (getData(lights, getLightsFolder(), x, z, REGION_LAYER_LIGHTS, true)); if (data == nullptr) @@ -409,10 +405,9 @@ ubyte* WorldFiles::readChunkData(int x, return data; } -/* Read missing chunks data (null pointers) from region file - * @param layer used as third part of openRegFiles map key - * (see REGION_LAYER_* constants) - */ +/// @brief Read missing chunks data (null pointers) from region file +/// @param layer used as third part of openRegFiles map key +/// (see REGION_LAYER_* constants) void WorldFiles::fetchChunks(WorldRegion* region, int x, int z, fs::path folder, int layer) { ubyte** chunks = region->getChunks(); uint32_t* sizes = region->getSizes(); @@ -426,12 +421,11 @@ void WorldFiles::fetchChunks(WorldRegion* region, int x, int z, fs::path folder, } } -/* Write or rewrite region file - * @param x region X - * @param z region Z - * @param layer used as third part of openRegFiles map key - * (see REGION_LAYER_* constants) - */ +/// @brief Write or rewrite region file +/// @param x region X +/// @param z region Z +/// @param layer used as third part of openRegFiles map key +/// (see REGION_LAYER_* constants) void WorldFiles::writeRegion(int x, int z, WorldRegion* entry, fs::path folder, int layer){ fs::path filename = folder/getRegionFilename(x, z); @@ -501,7 +495,7 @@ void WorldFiles::write(const World* world, const Content* content) { if (generatorTestMode) { return; } - + writeIndices(content->getIndices()); writeRegions(regions, regionsFolder, REGION_LAYER_VOXELS); writeRegions(lights, lightsFolder, REGION_LAYER_LIGHTS); @@ -598,4 +592,26 @@ void WorldFiles::removePack(const World* world, const std::string& id) { ss << pack << "\n"; } files::write_string(file, ss.str()); + + // erase invalid indices + auto prefix = id+":"; + auto root = files::read_json(getIndicesFile()); + auto blocks = root->list("blocks"); + for (uint i = 0; i < blocks->size(); i++) { + auto name = blocks->str(i); + if (name.find(prefix) != 0) + continue; + auto value = blocks->getValueWriteable(i); + *value->value.str = "core:air"; + } + + auto items = root->list("items"); + for (uint i = 0; i < items->size(); i++) { + auto name = items->str(i); + if (name.find(prefix) != 0) + continue; + auto value = items->getValueWriteable(i); + *value->value.str = "core:empty"; + } + files::write_json(getIndicesFile(), root.get()); } diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index d9c3f4e5..5337b73f 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -30,9 +30,6 @@ inline constexpr uint REGION_FORMAT_VERSION = 2; inline constexpr uint WORLD_FORMAT_VERSION = 1; inline constexpr uint MAX_OPEN_REGION_FILES = 16; -#define REGION_FORMAT_MAGIC ".VOXREG" -#define WORLD_FORMAT_MAGIC ".VOXWLD" - class Player; class Content; class ContentIndices; @@ -161,7 +158,7 @@ public: /// @param id pack id void removePack(const World* world, const std::string& id); - static const char* WORLD_FILE; + static const inline std::string WORLD_FILE = "world.json"; }; #endif /* FILES_WORLDFILES_H_ */ diff --git a/src/frontend/LevelFrontend.cpp b/src/frontend/LevelFrontend.cpp index 493b4f80..50267ee4 100644 --- a/src/frontend/LevelFrontend.cpp +++ b/src/frontend/LevelFrontend.cpp @@ -13,14 +13,13 @@ #include "../logic/LevelController.h" #include "../logic/PlayerController.h" -LevelFrontend::LevelFrontend(Level* level, Assets* assets) - : level(level), +LevelFrontend::LevelFrontend(LevelController* controller, Assets* assets) + : level(controller->getLevel()), + controller(controller), assets(assets), contentCache(std::make_unique(level->content, assets)), blocksAtlas(BlocksPreview::build(contentCache.get(), assets, level->content)) -{} - -void LevelFrontend::observe(LevelController* controller) { +{ controller->getPlayerController()->listenBlockInteraction( [=](Player*, glm::ivec3 pos, const Block* def, BlockInteraction type) { auto material = level->content->findBlockMaterial(def->material); @@ -85,3 +84,7 @@ ContentGfxCache* LevelFrontend::getContentGfxCache() const { Atlas* LevelFrontend::getBlocksAtlas() const { return blocksAtlas.get(); } + +LevelController* LevelFrontend::getController() const { + return controller; +} diff --git a/src/frontend/LevelFrontend.h b/src/frontend/LevelFrontend.h index ea8cbe33..f31ac7e0 100644 --- a/src/frontend/LevelFrontend.h +++ b/src/frontend/LevelFrontend.h @@ -12,19 +12,20 @@ class LevelController; class LevelFrontend { Level* level; + LevelController* controller; Assets* assets; std::unique_ptr contentCache; std::unique_ptr blocksAtlas; public: - LevelFrontend(Level* level, Assets* assets); + LevelFrontend(LevelController* controller, Assets* assets); ~LevelFrontend(); - void observe(LevelController* controller); - Level* getLevel() const; Assets* getAssets() const; ContentGfxCache* getContentGfxCache() const; Atlas* getBlocksAtlas() const; + + LevelController* getController() const; }; #endif // FRONTEND_LEVEL_FRONTEND_H_ diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 21800a22..62b456ad 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -547,7 +547,7 @@ void Hud::setPause(bool pause) { auto menu = gui->getMenu(); if (pause) { - menus::create_pause_panel(engine, frontend->getLevel()); + menus::create_pause_panel(engine, frontend->getController()); menu->setPage("pause"); } else { menu->reset(); diff --git a/src/frontend/menu/menu.cpp b/src/frontend/menu/menu.cpp index 34ac5533..ccfc1a0c 100644 --- a/src/frontend/menu/menu.cpp +++ b/src/frontend/menu/menu.cpp @@ -54,7 +54,7 @@ inline uint64_t randU64() { void menus::create_version_label(Engine* engine) { auto gui = engine->getGUI(); auto vlabel = std::make_shared( - util::str2wstr_utf8(ENGINE_VERSION_STRING " development build ") + util::str2wstr_utf8(ENGINE_VERSION_STRING+" development build ") ); vlabel->setZIndex(1000); vlabel->setColor(glm::vec4(1, 1, 1, 0.5f)); @@ -210,9 +210,7 @@ void create_world_generators_panel(Engine* engine) { idlabel->setAlign(Align::right); button->add(idlabel, glm::vec2(80, 4)); - button->add(std::make_shared