From 6f62ddea4ba14989ec7a1d1e111f5b46a46b0ef5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 29 Feb 2024 23:47:07 +0300 Subject: [PATCH] contentpack remove feature WIP --- res/shaders/lib/commons.glsl | 3 +- res/texts/en_US.txt | 1 + res/texts/ru_RU.txt | 2 + res/textures/gui/cross.png | Bin 0 -> 6275 bytes src/assets/AssetsLoader.cpp | 4 +- src/content/Content.cpp | 14 +- src/content/Content.h | 10 +- src/content/ContentLoader.cpp | 5 + src/content/ContentPack.cpp | 2 +- src/content/ContentPack.h | 20 +- src/files/WorldFiles.cpp | 484 +++++++++++++++++---------------- src/files/WorldFiles.h | 139 +++++----- src/frontend/WorldRenderer.cpp | 1 + src/frontend/menu.cpp | 69 +++-- src/frontend/menu.h | 2 + src/frontend/screens.cpp | 25 +- src/window/Events.cpp | 141 +++++----- src/window/Events.h | 52 ++-- 18 files changed, 541 insertions(+), 433 deletions(-) create mode 100644 res/textures/gui/cross.png diff --git a/res/shaders/lib/commons.glsl b/res/shaders/lib/commons.glsl index 291c4cd8..f2f1b3bc 100644 --- a/res/shaders/lib/commons.glsl +++ b/res/shaders/lib/commons.glsl @@ -1,4 +1,5 @@ -// Example of a GLSL library +#define PI 3.1415926535897932384626433832795 +#define PI2 (PI*2) vec4 decompress_light(float compressed_light) { vec4 result; diff --git a/res/texts/en_US.txt b/res/texts/en_US.txt index 26ade5db..99b97604 100644 --- a/res/texts/en_US.txt +++ b/res/texts/en_US.txt @@ -1,6 +1,7 @@ # Menu menu.missing-content=Missing Content! world.convert-request=Content indices have changed! Convert world files? +pack.remove-confirm=Do you want to erase all pack content from the world forever? 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? diff --git a/res/texts/ru_RU.txt b/res/texts/ru_RU.txt index caa5f607..7c03f37b 100644 --- a/res/texts/ru_RU.txt +++ b/res/texts/ru_RU.txt @@ -10,6 +10,8 @@ Add=Добавить error.pack-not-found=Не удалось найти пакет error.dependency-not-found=Используемая зависимость не найдена +pack.remove-confirm=Удалить весь поставляемый паком контент из мира (безвозвратно)? + # Меню menu.New World=Новый Мир menu.Quit=Выход diff --git a/res/textures/gui/cross.png b/res/textures/gui/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..2656b8bc7bc270faf119f39469090114fde92617 GIT binary patch literal 6275 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 w&N((eXgetMainRoot()/fs::path("layouts"), loader); - for (auto& pack : content->getPacks()) { + for (auto& entry : content->getPacks()) { + auto pack = entry.second.get(); auto& info = pack->getInfo(); fs::path folder = info.folder / fs::path("layouts"); addLayouts(pack->getEnvironment()->getId(), info.id, folder, loader); diff --git a/src/content/Content.cpp b/src/content/Content.cpp index cdbf2a1d..99db7f5c 100644 --- a/src/content/Content.cpp +++ b/src/content/Content.cpp @@ -26,7 +26,7 @@ void ContentBuilder::add(ItemDef* def) { } void ContentBuilder::add(ContentPackRuntime* pack) { - packs.push_back(std::unique_ptr(pack)); + packs.emplace(pack->getId(), pack); } Block& ContentBuilder::createBlock(std::string id) { @@ -136,7 +136,7 @@ Content::Content(ContentIndices* indices, std::unique_ptr drawGroups, std::unordered_map blockDefs, std::unordered_map itemDefs, - std::vector> packs) + std::unordered_map> packs) : blockDefs(blockDefs), itemDefs(itemDefs), indices(indices), @@ -179,6 +179,14 @@ ItemDef& Content::requireItem(std::string id) const { return *found->second; } -const std::vector>& Content::getPacks() const { +const ContentPackRuntime* Content::getPackRuntime(std::string id) const { + auto found = packs.find(id); + if (found == packs.end()) { + return nullptr; + } + return found->second.get(); +} + +const std::unordered_map>& Content::getPacks() const { return packs; } diff --git a/src/content/Content.h b/src/content/Content.h index fa0e9c53..32cba96f 100644 --- a/src/content/Content.h +++ b/src/content/Content.h @@ -48,7 +48,7 @@ class ContentBuilder { std::unordered_map itemDefs; std::vector itemIds; - std::vector> packs; + std::unordered_map> packs; public: ~ContentBuilder(); @@ -108,7 +108,7 @@ class Content { std::unordered_map blockDefs; std::unordered_map itemDefs; std::unique_ptr indices; - std::vector> packs; + std::unordered_map> packs; public: std::unique_ptr const drawGroups; @@ -116,7 +116,7 @@ public: std::unique_ptr drawGroups, std::unordered_map blockDefs, std::unordered_map itemDefs, - std::vector> packs); + std::unordered_map> packs); ~Content(); inline ContentIndices* getIndices() const { @@ -129,7 +129,9 @@ public: ItemDef* findItem(std::string id) const; ItemDef& requireItem(std::string id) const; - const std::vector>& getPacks() const; + const ContentPackRuntime* getPackRuntime(std::string id) const; + + const std::unordered_map>& getPacks() const; }; #endif // CONTENT_CONTENT_H_ \ No newline at end of file diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index a06ed489..7efced5e 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -294,6 +294,7 @@ void ContentLoader::load(ContentBuilder& builder) { auto runtime = new ContentPackRuntime(*pack, scripting::create_pack_environment(*pack)); builder.add(runtime); env = runtime->getEnvironment()->getId(); + ContentPackStats& stats = runtime->getStatsWriteable(); fixPackIndices(); @@ -306,6 +307,7 @@ void ContentLoader::load(ContentBuilder& builder) { if (!fs::is_regular_file(pack->getContentFile())) return; + auto root = files::read_json(pack->getContentFile()); auto blocksarr = root->list("blocks"); if (blocksarr) { @@ -314,6 +316,7 @@ void ContentLoader::load(ContentBuilder& builder) { std::string full = pack->id+":"+name; auto& def = builder.createBlock(full); loadBlock(def, full, name); + stats.totalBlocks++; if (!def.hidden) { auto& item = builder.createItem(full+BLOCK_ITEM_SUFFIX); item.generated = true; @@ -324,6 +327,7 @@ void ContentLoader::load(ContentBuilder& builder) { for (uint j = 0; j < 4; j++) { item.emission[j] = def.emission[j]; } + stats.totalItems++; } } } @@ -334,6 +338,7 @@ void ContentLoader::load(ContentBuilder& builder) { std::string name = itemsarr->str(i); std::string full = pack->id+":"+name; loadItem(builder.createItem(full), full, name); + stats.totalItems++; } } } diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 4266f867..5ad8d9ba 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -167,7 +167,7 @@ void ContentPack::readPacks(const EnginePaths* paths, } ContentPackRuntime::ContentPackRuntime( - ContentPack info, + ContentPack info, std::unique_ptr env ) : info(info), env(std::move(env)) { diff --git a/src/content/ContentPack.h b/src/content/ContentPack.h index 952dc65b..c6ce7c86 100644 --- a/src/content/ContentPack.h +++ b/src/content/ContentPack.h @@ -77,15 +77,33 @@ struct ContentPack { ); }; +struct ContentPackStats { + size_t totalBlocks; + size_t totalItems; + + inline bool hasSavingContent() const { + return totalBlocks + totalItems > 0; + } +}; + class ContentPackRuntime { ContentPack info; + ContentPackStats stats {}; std::unique_ptr env; public: ContentPackRuntime( - ContentPack info, + ContentPack info, std::unique_ptr env ); + inline const ContentPackStats& getStats() const { + return stats; + } + + inline ContentPackStats& getStatsWriteable() { + return stats; + } + inline const std::string& getId() { return info.id; } diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 24c3dfe4..11729085 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -49,91 +49,91 @@ regfile::regfile(fs::path filename) : file(filename) { } WorldRegion::WorldRegion() { - chunksData = new ubyte*[REGION_CHUNKS_COUNT]{}; - sizes = new uint32_t[REGION_CHUNKS_COUNT]{}; + chunksData = new ubyte*[REGION_CHUNKS_COUNT]{}; + sizes = new uint32_t[REGION_CHUNKS_COUNT]{}; } WorldRegion::~WorldRegion() { - for (uint i = 0; i < REGION_CHUNKS_COUNT; i++) { - delete[] chunksData[i]; - } - delete[] sizes; - delete[] chunksData; + for (uint i = 0; i < REGION_CHUNKS_COUNT; i++) { + delete[] chunksData[i]; + } + delete[] sizes; + delete[] chunksData; } void WorldRegion::setUnsaved(bool unsaved) { - this->unsaved = unsaved; + this->unsaved = unsaved; } bool WorldRegion::isUnsaved() const { - return unsaved; + return unsaved; } ubyte** WorldRegion::getChunks() const { - return chunksData; + return chunksData; } uint32_t* WorldRegion::getSizes() const { - return sizes; + return sizes; } void WorldRegion::put(uint x, uint z, ubyte* data, uint32_t size) { - size_t chunk_index = z * REGION_SIZE + x; - delete[] chunksData[chunk_index]; - chunksData[chunk_index] = data; - sizes[chunk_index] = size; + size_t chunk_index = z * REGION_SIZE + x; + delete[] chunksData[chunk_index]; + chunksData[chunk_index] = data; + sizes[chunk_index] = size; } ubyte* WorldRegion::getChunkData(uint x, uint z) { - return chunksData[z * REGION_SIZE + x]; + return chunksData[z * REGION_SIZE + x]; } uint WorldRegion::getChunkDataSize(uint x, uint z) { - return sizes[z * REGION_SIZE + x]; + 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), - doWriteLights(settings.doWriteLights) { - compressionBuffer.reset(new ubyte[CHUNK_DATA_LEN * 2]); + : directory(directory), + generatorTestMode(settings.generatorTestMode), + doWriteLights(settings.doWriteLights) { + compressionBuffer.reset(new ubyte[CHUNK_DATA_LEN * 2]); } WorldFiles::~WorldFiles(){ } WorldRegion* WorldFiles::getRegion(regionsmap& regions, int x, int z) { - auto found = regions.find(glm::ivec2(x, z)); - if (found == regions.end()) - return nullptr; - return found->second.get(); + auto found = regions.find(glm::ivec2(x, z)); + if (found == regions.end()) + return nullptr; + return found->second.get(); } WorldRegion* WorldFiles::getOrCreateRegion(regionsmap& regions, int x, int z) { - WorldRegion* region = getRegion(regions, x, z); - if (region == nullptr) { - region = new WorldRegion(); - regions[glm::ivec2(x, z)].reset(region); - } - return region; + WorldRegion* region = getRegion(regions, x, z); + if (region == nullptr) { + region = new WorldRegion(); + regions[glm::ivec2(x, z)].reset(region); + } + return region; } ubyte* WorldFiles::compress(const ubyte* src, size_t srclen, size_t& len) { ubyte* buffer = this->compressionBuffer.get(); - len = extrle::encode(src, srclen, buffer); - ubyte* data = new ubyte[len]; - for (size_t i = 0; i < len; i++) { - data[i] = buffer[i]; - } - return data; + len = extrle::encode(src, srclen, buffer); + ubyte* data = new ubyte[len]; + for (size_t i = 0; i < len; i++) { + data[i] = buffer[i]; + } + return data; } ubyte* WorldFiles::decompress(const ubyte* src, size_t srclen, size_t dstlen) { - ubyte* decompressed = new ubyte[dstlen]; - extrle::decode(src, srclen, decompressed); - return decompressed; + ubyte* decompressed = new ubyte[dstlen]; + extrle::decode(src, srclen, decompressed); + return decompressed; } int WorldFiles::getVoxelRegionVersion(int x, int z) { @@ -168,49 +168,49 @@ int WorldFiles::getVoxelRegionsVersion() { */ void WorldFiles::put(int x, int z, const ubyte* voxelData) { int regionX = floordiv(x, REGION_SIZE); - int regionZ = floordiv(z, REGION_SIZE); - int localX = x - (regionX * REGION_SIZE); - int localZ = z - (regionZ * REGION_SIZE); + int regionZ = floordiv(z, REGION_SIZE); + int localX = x - (regionX * REGION_SIZE); + int localZ = z - (regionZ * REGION_SIZE); - /* Writing Voxels */ { - WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); - region->setUnsaved(true); - size_t compressedSize; - ubyte* data = compress(voxelData, CHUNK_DATA_LEN, compressedSize); - region->put(localX, localZ, data, compressedSize); - } + /* Writing Voxels */ { + WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); + region->setUnsaved(true); + size_t compressedSize; + ubyte* data = compress(voxelData, CHUNK_DATA_LEN, compressedSize); + region->put(localX, localZ, data, compressedSize); + } } /* * Store chunk (voxels and lights) in region (existing or new) */ void WorldFiles::put(Chunk* chunk){ - assert(chunk != nullptr); + assert(chunk != nullptr); - int regionX = floordiv(chunk->x, REGION_SIZE); - int regionZ = floordiv(chunk->z, REGION_SIZE); - int localX = chunk->x - (regionX * REGION_SIZE); - int localZ = chunk->z - (regionZ * REGION_SIZE); + int regionX = floordiv(chunk->x, REGION_SIZE); + int regionZ = floordiv(chunk->z, REGION_SIZE); + int localX = chunk->x - (regionX * REGION_SIZE); + int localZ = chunk->z - (regionZ * REGION_SIZE); - /* Writing voxels */ { + /* Writing voxels */ { size_t compressedSize; std::unique_ptr chunk_data (chunk->encode()); - ubyte* data = compress(chunk_data.get(), CHUNK_DATA_LEN, compressedSize); + ubyte* data = compress(chunk_data.get(), CHUNK_DATA_LEN, compressedSize); - WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); - region->setUnsaved(true); - region->put(localX, localZ, data, compressedSize); - } + WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); + region->setUnsaved(true); + region->put(localX, localZ, data, compressedSize); + } /* Writing lights cache */ - if (doWriteLights && chunk->isLighted()) { + if (doWriteLights && chunk->isLighted()) { size_t compressedSize; std::unique_ptr light_data (chunk->lightmap.encode()); - ubyte* data = compress(light_data.get(), LIGHTMAP_DATA_LEN, compressedSize); + ubyte* data = compress(light_data.get(), LIGHTMAP_DATA_LEN, compressedSize); - WorldRegion* region = getOrCreateRegion(lights, regionX, regionZ); - region->setUnsaved(true); - region->put(localX, localZ, data, compressedSize); - } + WorldRegion* region = getOrCreateRegion(lights, regionX, regionZ); + region->setUnsaved(true); + region->put(localX, localZ, data, compressedSize); + } /* Writing block inventories */ if (!chunk->inventories.empty()){ auto& inventories = chunk->inventories; @@ -237,19 +237,19 @@ void WorldFiles::put(Chunk* chunk){ } fs::path WorldFiles::getRegionsFolder() const { - return directory/fs::path("regions"); + return directory/fs::path("regions"); } fs::path WorldFiles::getLightsFolder() const { - return directory/fs::path("lights"); + return directory/fs::path("lights"); } fs::path WorldFiles::getInventoriesFolder() const { - return directory/fs::path("inventories"); + return directory/fs::path("inventories"); } fs::path WorldFiles::getRegionFilename(int x, int z) const { - return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin"); + return fs::path(std::to_string(x) + "_" + std::to_string(z) + ".bin"); } /* @@ -275,78 +275,78 @@ bool WorldFiles::parseRegionFilename(const std::string& name, int& x, int& z) { } fs::path WorldFiles::getPlayerFile() const { - return directory/fs::path("player.json"); + return directory/fs::path("player.json"); } fs::path WorldFiles::getWorldFile() const { - return directory/fs::path(WORLD_FILE); + return directory/fs::path(WORLD_FILE); } fs::path WorldFiles::getIndicesFile() const { - return directory/fs::path("indices.json"); + return directory/fs::path("indices.json"); } fs::path WorldFiles::getPacksFile() const { - return directory/fs::path("packs.list"); + return directory/fs::path("packs.list"); } ubyte* WorldFiles::getChunk(int x, int z){ - return getData(regions, getRegionsFolder(), x, z, REGION_LAYER_VOXELS, true); + return getData(regions, getRegionsFolder(), x, z, REGION_LAYER_VOXELS, true); } /* 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) - return nullptr; - return Lightmap::decode(data.get()); + std::unique_ptr data (getData(lights, getLightsFolder(), x, z, REGION_LAYER_LIGHTS, true)); + if (data == nullptr) + return nullptr; + return Lightmap::decode(data.get()); } chunk_inventories_map WorldFiles::fetchInventories(int x, int z) { - chunk_inventories_map inventories; - const ubyte* data = getData(storages, getInventoriesFolder(), x, z, REGION_LAYER_INVENTORIES, false); - if (data == nullptr) - return inventories; - ByteReader reader(data, BUFFER_SIZE_UNKNOWN); - int count = reader.getInt32(); - for (int i = 0; i < count; i++) { - uint index = reader.getInt32(); - uint size = reader.getInt32(); - auto map = json::from_binary(reader.pointer(), size); - reader.skip(size); - auto inv = std::make_shared(0, 0); - inv->deserialize(map.get()); - inventories[index] = inv; - } - return inventories; + chunk_inventories_map inventories; + const ubyte* data = getData(storages, getInventoriesFolder(), x, z, REGION_LAYER_INVENTORIES, false); + if (data == nullptr) + return inventories; + ByteReader reader(data, BUFFER_SIZE_UNKNOWN); + int count = reader.getInt32(); + for (int i = 0; i < count; i++) { + uint index = reader.getInt32(); + uint size = reader.getInt32(); + auto map = json::from_binary(reader.pointer(), size); + reader.skip(size); + auto inv = std::make_shared(0, 0); + inv->deserialize(map.get()); + inventories[index] = inv; + } + return inventories; } ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder, int x, int z, int layer, bool compression) { - int regionX = floordiv(x, REGION_SIZE); - int regionZ = floordiv(z, REGION_SIZE); + int regionX = floordiv(x, REGION_SIZE); + int regionZ = floordiv(z, REGION_SIZE); - int localX = x - (regionX * REGION_SIZE); - int localZ = z - (regionZ * REGION_SIZE); + int localX = x - (regionX * REGION_SIZE); + int localZ = z - (regionZ * REGION_SIZE); - WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); - ubyte* data = region->getChunkData(localX, localZ); - if (data == nullptr) { - uint32_t size; - data = readChunkData(x, z, size, folder, layer); - if (data != nullptr) { - region->put(localX, localZ, data, size); - } - } - if (data != nullptr) { + WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ); + ubyte* data = region->getChunkData(localX, localZ); + if (data == nullptr) { + uint32_t size; + data = readChunkData(x, z, size, folder, layer); + if (data != nullptr) { + region->put(localX, localZ, data, size); + } + } + if (data != nullptr) { size_t size = region->getChunkDataSize(localX, localZ); - if (compression) { - return decompress(data, size, CHUNK_DATA_LEN); - } - return data; - } - return nullptr; + if (compression) { + return decompress(data, size, CHUNK_DATA_LEN); + } + return data; + } + return nullptr; } @@ -360,7 +360,7 @@ regfile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) { auto iter = std::next(openRegFiles.begin(), rand() % openRegFiles.size()); openRegFiles.erase(iter); } - fs::path filename = folder / getRegionFilename(coord[0], coord[1]); + fs::path filename = folder / getRegionFilename(coord[0], coord[1]); if (!fs::is_regular_file(filename)) { return nullptr; } @@ -373,14 +373,14 @@ ubyte* WorldFiles::readChunkData(int x, uint32_t& length, fs::path folder, int layer){ - if (generatorTestMode) - return nullptr; - - int regionX = floordiv(x, REGION_SIZE); - int regionZ = floordiv(z, REGION_SIZE); - int localX = x - (regionX * REGION_SIZE); - int localZ = z - (regionZ * REGION_SIZE); - int chunkIndex = localZ * REGION_SIZE + localX; + if (generatorTestMode) + return nullptr; + + int regionX = floordiv(x, REGION_SIZE); + int regionZ = floordiv(z, REGION_SIZE); + int localX = x - (regionX * REGION_SIZE); + int localZ = z - (regionZ * REGION_SIZE); + int chunkIndex = localZ * REGION_SIZE + localX; glm::ivec3 coord(regionX, regionZ, layer); regfile* rfile = WorldFiles::getRegFile(coord, folder); @@ -389,24 +389,24 @@ ubyte* WorldFiles::readChunkData(int x, } files::rafile& file = rfile->file; - size_t file_size = file.length(); - size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4; + size_t file_size = file.length(); + size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4; - uint32_t offset; - file.seekg(table_offset + chunkIndex * 4); - file.read((char*)(&offset), 4); - offset = dataio::read_int32_big((const ubyte*)(&offset), 0); + uint32_t offset; + file.seekg(table_offset + chunkIndex * 4); + file.read((char*)(&offset), 4); + offset = dataio::read_int32_big((const ubyte*)(&offset), 0); - if (offset == 0){ - return nullptr; - } + if (offset == 0){ + return nullptr; + } - file.seekg(offset); - file.read((char*)(&offset), 4); - length = dataio::read_int32_big((const ubyte*)(&offset), 0); - ubyte* data = new ubyte[length]{}; - file.read((char*)data, length); - return data; + file.seekg(offset); + file.read((char*)(&offset), 4); + length = dataio::read_int32_big((const ubyte*)(&offset), 0); + ubyte* data = new ubyte[length]{}; + file.read((char*)data, length); + return data; } /* Read missing chunks data (null pointers) from region file @@ -415,7 +415,7 @@ ubyte* WorldFiles::readChunkData(int x, */ void WorldFiles::fetchChunks(WorldRegion* region, int x, int z, fs::path folder, int layer) { ubyte** chunks = region->getChunks(); - uint32_t* sizes = region->getSizes(); + uint32_t* sizes = region->getSizes(); for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) { int chunk_x = (i % REGION_SIZE) + x * REGION_SIZE; @@ -441,70 +441,70 @@ void WorldFiles::writeRegion(int x, int z, WorldRegion* entry, fs::path folder, openRegFiles.erase(regcoord); } - char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC; - header[8] = REGION_FORMAT_VERSION; - header[9] = 0; // flags - std::ofstream file(filename, std::ios::out | std::ios::binary); - file.write(header, REGION_HEADER_SIZE); + char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC; + header[8] = REGION_FORMAT_VERSION; + header[9] = 0; // flags + std::ofstream file(filename, std::ios::out | std::ios::binary); + file.write(header, REGION_HEADER_SIZE); - size_t offset = REGION_HEADER_SIZE; - char intbuf[4]{}; - uint offsets[REGION_CHUNKS_COUNT]{}; - - ubyte** region = entry->getChunks(); - uint32_t* sizes = entry->getSizes(); + size_t offset = REGION_HEADER_SIZE; + char intbuf[4]{}; + uint offsets[REGION_CHUNKS_COUNT]{}; - for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) { - ubyte* chunk = region[i]; - if (chunk == nullptr){ - offsets[i] = 0; - } else { - offsets[i] = offset; + ubyte** region = entry->getChunks(); + uint32_t* sizes = entry->getSizes(); + + for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) { + ubyte* chunk = region[i]; + if (chunk == nullptr){ + offsets[i] = 0; + } else { + offsets[i] = offset; - size_t compressedSize = sizes[i]; - dataio::write_int32_big(compressedSize, (ubyte*)intbuf, 0); - offset += 4 + compressedSize; + size_t compressedSize = sizes[i]; + dataio::write_int32_big(compressedSize, (ubyte*)intbuf, 0); + offset += 4 + compressedSize; - file.write(intbuf, 4); - file.write((const char*)chunk, compressedSize); - } - } - for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) { - dataio::write_int32_big(offsets[i], (ubyte*)intbuf, 0); - file.write(intbuf, 4); - } + file.write(intbuf, 4); + file.write((const char*)chunk, compressedSize); + } + } + for (size_t i = 0; i < REGION_CHUNKS_COUNT; i++) { + dataio::write_int32_big(offsets[i], (ubyte*)intbuf, 0); + file.write(intbuf, 4); + } } void WorldFiles::writeRegions(regionsmap& regions, const fs::path& folder, int layer) { - for (auto& it : regions){ - WorldRegion* region = it.second.get(); - if (region->getChunks() == nullptr || !region->isUnsaved()) - continue; - glm::ivec2 key = it.first; - writeRegion(key[0], key[1], region, folder, layer); - } + for (auto& it : regions){ + WorldRegion* region = it.second.get(); + if (region->getChunks() == nullptr || !region->isUnsaved()) + continue; + glm::ivec2 key = it.first; + writeRegion(key[0], key[1], region, folder, layer); + } } void WorldFiles::write(const World* world, const Content* content) { - fs::path regionsFolder = getRegionsFolder(); - fs::path lightsFolder = getLightsFolder(); + fs::path regionsFolder = getRegionsFolder(); + fs::path lightsFolder = getLightsFolder(); fs::path inventoriesFolder = getInventoriesFolder(); - fs::create_directories(regionsFolder); + fs::create_directories(regionsFolder); fs::create_directories(inventoriesFolder); - fs::create_directories(lightsFolder); + fs::create_directories(lightsFolder); if (world) { - writeWorldInfo(world); - writePacks(world); - } - if (generatorTestMode) { - return; + writeWorldInfo(world); + writePacks(world); } - - writeIndices(content->getIndices()); - writeRegions(regions, regionsFolder, REGION_LAYER_VOXELS); - writeRegions(lights, lightsFolder, REGION_LAYER_LIGHTS); + if (generatorTestMode) { + return; + } + + writeIndices(content->getIndices()); + writeRegions(regions, regionsFolder, REGION_LAYER_VOXELS); + writeRegions(lights, lightsFolder, REGION_LAYER_LIGHTS); writeRegions(storages, inventoriesFolder, REGION_LAYER_INVENTORIES); } @@ -514,64 +514,64 @@ void WorldFiles::writePacks(const World* world) { 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(packsFile, ss.str()); + 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(packsFile, ss.str()); } void WorldFiles::writeIndices(const ContentIndices* indices) { - dynamic::Map root; + dynamic::Map root; uint count; - auto& blocks = root.putList("blocks"); - count = indices->countBlockDefs(); - for (uint i = 0; i < count; i++) { - const Block* def = indices->getBlockDef(i); - blocks.put(def->name); - } + auto& blocks = root.putList("blocks"); + count = indices->countBlockDefs(); + for (uint i = 0; i < count; i++) { + const Block* def = indices->getBlockDef(i); + blocks.put(def->name); + } auto& items = root.putList("items"); - count = indices->countItemDefs(); - for (uint i = 0; i < count; i++) { - const ItemDef* def = indices->getItemDef(i); - items.put(def->name); - } + count = indices->countItemDefs(); + for (uint i = 0; i < count; i++) { + const ItemDef* def = indices->getItemDef(i); + items.put(def->name); + } - files::write_json(getIndicesFile(), &root); + files::write_json(getIndicesFile(), &root); } void WorldFiles::writeWorldInfo(const World* world) { - files::write_json(getWorldFile(), world->serialize().get()); + files::write_json(getWorldFile(), world->serialize().get()); } bool WorldFiles::readWorldInfo(World* world) { - fs::path file = getWorldFile(); - if (!fs::is_regular_file(file)) { - std::cerr << "warning: world.json does not exists" << std::endl; - return false; - } + fs::path file = getWorldFile(); + if (!fs::is_regular_file(file)) { + std::cerr << "warning: world.json does not exists" << std::endl; + return false; + } - auto root = files::read_json(file); + auto root = files::read_json(file); world->deserialize(root.get()); - return true; + return true; } void WorldFiles::writePlayer(std::shared_ptr player) { - files::write_json(getPlayerFile(), player->serialize().release()); + files::write_json(getPlayerFile(), player->serialize().release()); } bool WorldFiles::readPlayer(std::shared_ptr player) { - fs::path file = getPlayerFile(); - if (!fs::is_regular_file(file)) { - std::cerr << "warning: player.json does not exists" << std::endl; - return false; - } + fs::path file = getPlayerFile(); + if (!fs::is_regular_file(file)) { + std::cerr << "warning: player.json does not exists" << std::endl; + return false; + } - player->deserialize(files::read_json(file).get()); - return true; + player->deserialize(files::read_json(file).get()); + return true; } void WorldFiles::addPack(const World* world, const std::string& id) { @@ -585,10 +585,32 @@ void WorldFiles::addPack(const World* world, const std::string& id) { auto packs = files::read_list(file); packs.push_back(id); - std::stringstream ss; - ss << "# autogenerated; do not modify\n"; - for (const auto& pack : packs) { - ss << pack << "\n"; - } - files::write_string(file, ss.str()); + std::stringstream ss; + ss << "# autogenerated; do not modify\n"; + for (const auto& pack : packs) { + ss << pack << "\n"; + } + files::write_string(file, ss.str()); +} + +void WorldFiles::removePack(const World* world, const std::string& id) { + fs::path file = getPacksFile(); + if (!fs::is_regular_file(file)) { + if (!fs::is_directory(directory)) { + fs::create_directories(directory); + } + writePacks(world); + } + auto packs = files::read_list(file); + auto found = std::find(packs.begin(), packs.end(), id); + if (found != packs.end()) { + packs.erase(found); + } + + std::stringstream ss; + ss << "# autogenerated; do not modify\n"; + for (const auto& pack : packs) { + ss << pack << "\n"; + } + files::write_string(file, ss.str()); } diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index a3a9a483..3269d4dd 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -47,22 +47,22 @@ public: }; class WorldRegion { - ubyte** chunksData; - uint32_t* sizes; - bool unsaved = false; + ubyte** chunksData; + uint32_t* sizes; + bool unsaved = false; public: - WorldRegion(); - ~WorldRegion(); + WorldRegion(); + ~WorldRegion(); - void put(uint x, uint z, ubyte* data, uint32_t size); - ubyte* getChunkData(uint x, uint z); - uint getChunkDataSize(uint x, uint z); + void put(uint x, uint z, ubyte* data, uint32_t size); + ubyte* getChunkData(uint x, uint z); + uint getChunkDataSize(uint x, uint z); - void setUnsaved(bool unsaved); - bool isUnsaved() const; + void setUnsaved(bool unsaved); + bool isUnsaved() const; - ubyte** getChunks() const; - uint32_t* getSizes() const; + ubyte** getChunks() const; + uint32_t* getSizes() const; }; struct regfile { @@ -77,85 +77,94 @@ typedef std::unordered_map> regionsmap; class WorldFiles { std::unordered_map> openRegFiles; - void writeWorldInfo(const World* world); + void writeWorldInfo(const World* world); fs::path getRegionFilename(int x, int y) const; - fs::path getWorldFile() const; - fs::path getIndicesFile() const; - fs::path getPacksFile() const; - - WorldRegion* getRegion(regionsmap& regions, int x, int z); - WorldRegion* getOrCreateRegion(regionsmap& regions, int x, int z); + fs::path getWorldFile() const; + fs::path getIndicesFile() const; + fs::path getPacksFile() const; + + WorldRegion* getRegion(regionsmap& regions, int x, int z); + WorldRegion* getOrCreateRegion(regionsmap& regions, int x, int z); - /* Compress buffer with extrle - @param src source buffer - @param srclen length of source buffer - @param len (out argument) length of result buffer */ - ubyte* compress(const ubyte* src, size_t srclen, size_t& len); + /// @brief Compress buffer with extrle + /// @param src source buffer + /// @param srclen length of the source buffer + /// @param len (out argument) length of result buffer + /// @return compressed bytes array + ubyte* compress(const ubyte* src, size_t srclen, size_t& len); - /* Decompress buffer with extrle - @param src compressed buffer - @param srclen length of compressed buffer - @param dstlen max expected length of source buffer */ - ubyte* decompress(const ubyte* src, size_t srclen, size_t dstlen); + /// @brief Decompress buffer with extrle + /// @param src compressed buffer + /// @param srclen length of compressed buffer + /// @param dstlen max expected length of source buffer + /// @return decompressed bytes array + ubyte* decompress(const ubyte* src, size_t srclen, size_t dstlen); - ubyte* readChunkData(int x, int y, - uint32_t& length, - fs::path folder, - int layer); - void fetchChunks(WorldRegion* region, int x, int y, - fs::path folder, int layer); + ubyte* readChunkData(int x, int y, uint32_t& length, fs::path folder, int layer); - void writeRegions(regionsmap& regions, - const fs::path& folder, int layer); + void fetchChunks(WorldRegion* region, int x, int y, fs::path folder, int layer); - ubyte* getData(regionsmap& regions, - const fs::path& folder, - int x, int z, int layer, bool compression); + void writeRegions(regionsmap& regions, const fs::path& folder, int layer); + + ubyte* getData(regionsmap& regions, const fs::path& folder, int x, int z, int layer, bool compression); regfile* getRegFile(glm::ivec3 coord, const fs::path& folder); fs::path getLightsFolder() const; - fs::path getInventoriesFolder() const; + fs::path getInventoriesFolder() const; public: static bool parseRegionFilename(const std::string& name, int& x, int& y); fs::path getRegionsFolder() const; fs::path getPlayerFile() const; - regionsmap regions; + regionsmap regions; regionsmap storages; - regionsmap lights; - fs::path directory; - std::unique_ptr compressionBuffer; - bool generatorTestMode; - bool doWriteLights; + regionsmap lights; + fs::path directory; + std::unique_ptr compressionBuffer; + bool generatorTestMode; + bool doWriteLights; - WorldFiles(fs::path directory, const DebugSettings& settings); - ~WorldFiles(); + WorldFiles(fs::path directory, const DebugSettings& settings); + ~WorldFiles(); - void put(Chunk* chunk); + void put(Chunk* chunk); void put(int x, int z, const ubyte* voxelData); int getVoxelRegionVersion(int x, int z); int getVoxelRegionsVersion(); - ubyte* getChunk(int x, int z); - light_t* getLights(int x, int z); - chunk_inventories_map fetchInventories(int x, int z); + ubyte* getChunk(int x, int z); + light_t* getLights(int x, int z); + chunk_inventories_map fetchInventories(int x, int z); - bool readWorldInfo(World* world); - bool readPlayer(std::shared_ptr player); + bool readWorldInfo(World* world); + bool readPlayer(std::shared_ptr player); - void writeRegion(int x, int y, - WorldRegion* entry, - fs::path file, - int layer); - void writePlayer(std::shared_ptr player); - /* @param world world info to save (nullable) */ - 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 writeRegion(int x, int y, WorldRegion* entry, fs::path file, int layer); + + /// @brief Write player data to world files + /// @param player target player + void writePlayer(std::shared_ptr player); + + /// @brief Write all unsaved data to world files + /// @param world target world + /// @param content world content + void write(const World* world, const Content* content); + + void writePacks(const World* world); + void writeIndices(const ContentIndices* indices); + + /// @brief Append pack to the packs list without duplicate check and + /// dependencies resolve + /// @param world target world + /// @param id pack id void addPack(const World* world, const std::string& id); + + /// @brief Remove pack from the list (does not remove indices) + /// @param world target world + /// @param id pack id + void removePack(const World* world, const std::string& id); static const char* WORLD_FILE; }; diff --git a/src/frontend/WorldRenderer.cpp b/src/frontend/WorldRenderer.cpp index 64c9a728..109de8f5 100644 --- a/src/frontend/WorldRenderer.cpp +++ b/src/frontend/WorldRenderer.cpp @@ -170,6 +170,7 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible shader->uniform1f("u_gamma", settings.graphics.gamma); shader->uniform1f("u_fogFactor", fogFactor); shader->uniform1f("u_fogCurve", settings.graphics.fogCurve); + shader->uniform1f("u_dayTime", level->world->daytime); shader->uniform3f("u_cameraPos", camera->position); shader->uniform1i("u_cubemap", 1); { diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index 2e69be9b..b053f709 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -342,7 +342,8 @@ std::shared_ptr create_packs_panel( const std::vector& packs, Engine* engine, bool backbutton, - packconsumer callback + packconsumer callback, + packconsumer remover ){ auto assets = engine->getAssets(); auto panel = std::make_shared(vec2(550, 200), vec4(5.0f)); @@ -358,7 +359,12 @@ std::shared_ptr create_packs_panel( callback(pack); }); } - auto idlabel = std::make_shared