diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 85f4be56..518aebf0 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -1,27 +1,25 @@ #include "WorldFiles.h" -#include "rle.h" -#include "../window/Camera.h" -#include "../content/Content.h" -#include "../objects/Player.h" -#include "../physics/Hitbox.h" -#include "../voxels/voxel.h" -#include "../voxels/Block.h" -#include "../voxels/Chunk.h" -#include "../typedefs.h" -#include "../maths/voxmaths.h" -#include "../world/World.h" -#include "../lighting/Lightmap.h" - #include "../coders/byte_utils.h" -#include "../util/data_io.h" #include "../coders/json.h" #include "../constants.h" -#include "../items/ItemDef.h" -#include "../items/Inventory.h" - -#include "../data/dynamic.h" +#include "../content/Content.h" #include "../core_defs.h" +#include "../data/dynamic.h" +#include "../items/Inventory.h" +#include "../items/ItemDef.h" +#include "../lighting/Lightmap.h" +#include "../maths/voxmaths.h" +#include "../objects/Player.h" +#include "../physics/Hitbox.h" +#include "../typedefs.h" +#include "../util/data_io.h" +#include "../voxels/Block.h" +#include "../voxels/Chunk.h" +#include "../voxels/voxel.h" +#include "../window/Camera.h" +#include "../world/World.h" +#include "rle.h" #include #include @@ -48,7 +46,8 @@ regfile::regfile(fs::path filename) : file(filename) { version = header[8]; if (uint(version) > REGION_FORMAT_VERSION) { throw illegal_region_format( - "region format "+std::to_string(version)+" is not supported"); + "region format "+std::to_string(version)+" is not supported" + ); } } @@ -95,13 +94,7 @@ uint WorldRegion::getChunkDataSize(uint x, uint z) { return sizes[z * REGION_SIZE + x]; } -WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings) - : directory(directory), - generatorTestMode(settings.generatorTestMode), - doWriteLights(settings.doWriteLights) -{ - compressionBuffer = std::make_unique(CHUNK_DATA_LEN * 2); - // just ignore this +WorldFiles::WorldFiles(fs::path directory) : directory(directory) { for (uint i = 0; i < sizeof(layers)/sizeof(RegionsLayer); i++) { layers[i].layer = i; } @@ -110,6 +103,13 @@ WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings) layers[REGION_LAYER_INVENTORIES].folder = directory/fs::path("inventories"); } +WorldFiles::WorldFiles(fs::path directory, const DebugSettings& settings) + : WorldFiles(directory) +{ + generatorTestMode = settings.generatorTestMode; + doWriteLights = settings.doWriteLights; +} + WorldFiles::~WorldFiles() { } @@ -139,12 +139,13 @@ WorldRegion* WorldFiles::getOrCreateRegion(int x, int z, int layer) { } std::unique_ptr WorldFiles::compress(const ubyte* src, size_t srclen, size_t& len) { - ubyte* buffer = this->compressionBuffer.get(); + auto buffer = bufferPool.get(); + ubyte* bytes = buffer.get(); - len = extrle::encode(src, srclen, buffer); + len = extrle::encode(src, srclen, bytes); auto data = std::make_unique(len); for (size_t i = 0; i < len; i++) { - data[i] = buffer[i]; + data[i] = bytes[i]; } return data; } @@ -164,10 +165,6 @@ inline void calc_reg_coords( localZ = z - (regionZ * REGION_SIZE); } - -/// @brief Store chunk voxels data in region -/// @param x chunk.x -/// @param z chunk.z void WorldFiles::put(int x, int z, int layer, std::unique_ptr data, size_t size, bool rle) { if (rle) { size_t compressedSize; @@ -318,7 +315,7 @@ ubyte* WorldFiles::getData( if (data == nullptr) { auto regfile = getRegFile(glm::ivec3(regionX, regionZ, layer)); if (regfile != nullptr) { - data = readChunkData(x, z, size, regfile.get()); + data = readChunkData(x, z, size, regfile.get()).release(); } if (data != nullptr) { region->put(localX, localZ, data, size); @@ -391,7 +388,7 @@ std::shared_ptr WorldFiles::createRegFile(glm::ivec3 coord) { } } -ubyte* WorldFiles::readChunkData( +std::unique_ptr WorldFiles::readChunkData( int x, int z, uint32_t& length, @@ -405,7 +402,6 @@ ubyte* WorldFiles::readChunkData( int chunkIndex = localZ * REGION_SIZE + localX; files::rafile& file = rfile->file; - size_t file_size = file.length(); size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4; @@ -420,8 +416,8 @@ ubyte* WorldFiles::readChunkData( 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); + auto data = std::make_unique(length); + file.read((char*)data.get(), length); return data; } @@ -434,16 +430,11 @@ void WorldFiles::fetchChunks(WorldRegion* region, int x, int z, regfile* file) { int chunk_x = (i % REGION_SIZE) + x * REGION_SIZE; int chunk_z = (i / REGION_SIZE) + z * REGION_SIZE; if (chunks[i] == nullptr) { - chunks[i] = readChunkData(chunk_x, chunk_z, sizes[i], file); + chunks[i] = readChunkData(chunk_x, chunk_z, sizes[i], file).release(); } } } -/// @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, int layer, WorldRegion* entry){ fs::path filename = layers[layer].folder/getRegionFilename(x, z); @@ -616,3 +607,11 @@ void WorldFiles::processRegionVoxels(int x, int z, regionproc func) { } } } + +fs::path WorldFiles::getFolder() const { + return directory; +} + +fs::path WorldFiles::getRegionsFolder(int layer) const { + return layers[layer].folder; +} diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index 03695eca..41bb0ead 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -6,6 +6,7 @@ #include "../settings.h" #include "../content/ContentPack.h" #include "../voxels/Chunk.h" +#include "../util/BufferPool.h" #include #include @@ -84,13 +85,17 @@ struct RegionsLayer { }; class WorldFiles { + fs::path directory; std::unordered_map> openRegFiles; std::mutex regFilesMutex; std::condition_variable regFilesCv; - RegionsLayer layers[3] {}; + bool generatorTestMode = false; + bool doWriteLights = true; + util::BufferPool bufferPool { + std::max(CHUNK_DATA_LEN, LIGHTMAP_DATA_LEN) * 2 + }; - void writeWorldInfo(const World* world); fs::path getRegionFilename(int x, int y) const; fs::path getWorldFile() const; fs::path getIndicesFile() const; @@ -112,12 +117,13 @@ class WorldFiles { /// @param dstlen max expected length of source buffer /// @return decompressed bytes array std::unique_ptr decompress(const ubyte* src, size_t srclen, size_t dstlen); - - ubyte* readChunkData(int x, int y, uint32_t& length, regfile* file); + std::unique_ptr readChunkData(int x, int y, uint32_t& length, regfile* file); void fetchChunks(WorldRegion* region, int x, int y, regfile* file); + void writeWorldInfo(const World* world); void writeRegions(int layer); + void writeIndices(const ContentIndices* indices); ubyte* getData(int x, int z, int layer, uint32_t& size); @@ -126,20 +132,23 @@ class WorldFiles { std::shared_ptr useRegFile(glm::ivec3 coord); std::shared_ptr createRegFile(glm::ivec3 coord); public: - static bool parseRegionFilename(const std::string& name, int& x, int& y); - fs::path getPlayerFile() const; - - fs::path directory; - std::unique_ptr compressionBuffer; - bool generatorTestMode; - bool doWriteLights; - + WorldFiles(fs::path directory); WorldFiles(fs::path directory, const DebugSettings& settings); ~WorldFiles(); + fs::path getPlayerFile() const; void createDirectories(); + /// @brief Put all chunk data to regions void put(Chunk* chunk); + + /// @brief Store data in specified region + /// @param x chunk.x + /// @param z chunk.z + /// @param layer regions layer + /// @param data target data + /// @param size data size + /// @param rle compress with ext-RLE void put(int x, int z, int layer, std::unique_ptr data, size_t size, bool rle); std::unique_ptr getChunk(int x, int z); @@ -148,6 +157,10 @@ public: bool readWorldInfo(World* world); + /// @brief Write or rewrite region file + /// @param x region X + /// @param z region Z + /// @param layer regions layer void writeRegion(int x, int y, int layer, WorldRegion* entry); /// @brief Write all unsaved data to world files @@ -156,17 +169,17 @@ public: void write(const World* world, const Content* content); void writePacks(const std::vector& packs); - void writeIndices(const ContentIndices* indices); void removeIndices(const std::vector& packs); void processRegionVoxels(int x, int z, regionproc func); - static const inline std::string WORLD_FILE = "world.json"; + /// @return world folder + fs::path getFolder() const; + fs::path getRegionsFolder(int layer) const; - fs::path getRegionsFolder(int layer) { - return layers[layer].folder; - } + static const inline std::string WORLD_FILE = "world.json"; + static bool parseRegionFilename(const std::string& name, int& x, int& y); }; #endif /* FILES_WORLDFILES_H_ */ diff --git a/src/frontend/menu/menu_pause.cpp b/src/frontend/menu/menu_pause.cpp index bb7df2f9..611cc7ff 100644 --- a/src/frontend/menu/menu_pause.cpp +++ b/src/frontend/menu/menu_pause.cpp @@ -112,7 +112,7 @@ std::shared_ptr menus::create_packs_panel( } static void reopen_world(Engine* engine, World* world) { - std::string wname = world->wfile->directory.stem().u8string(); + std::string wname = world->wfile->getFolder().stem().u8string(); engine->setScreen(nullptr); engine->setScreen(std::make_shared(engine)); menus::open_world(wname, engine, true); @@ -140,7 +140,7 @@ void menus::remove_packs( runnable removeFunc = [=]() { controller->saveWorld(); - auto manager = engine->createPacksManager(world->wfile->directory); + auto manager = engine->createPacksManager(world->wfile->getFolder()); manager.scan(); auto names = PacksManager::getNames(world->getPacks()); @@ -199,7 +199,7 @@ void create_content_panel(Engine* engine, LevelController* controller) { auto new_packs = PacksManager::getNames(world->getPacks()); new_packs.push_back(pack.id); - auto manager = engine->createPacksManager(world->wfile->directory); + auto manager = engine->createPacksManager(world->wfile->getFolder()); manager.scan(); try { new_packs = manager.assembly(new_packs); diff --git a/src/util/BufferPool.h b/src/util/BufferPool.h new file mode 100644 index 00000000..36b27517 --- /dev/null +++ b/src/util/BufferPool.h @@ -0,0 +1,37 @@ +#ifndef UTIL_BUFFER_POOL_H_ +#define UTIL_BUFFER_POOL_H_ + +#include "../typedefs.h" + +#include +#include +#include +#include + +namespace util { + template + class BufferPool { + std::vector> buffers; + std::queue freeBuffers; + std::mutex mutex; + size_t bufferSize; + public: + BufferPool(size_t bufferSize) : bufferSize(bufferSize) { + } + + std::shared_ptr get() { + std::lock_guard lock(mutex); + if (freeBuffers.empty()) { + buffers.emplace_back(std::make_unique(bufferSize)); + freeBuffers.push(buffers[buffers.size()-1].get()); + } + auto* buffer = freeBuffers.front(); + freeBuffers.pop(); + return std::shared_ptr(buffer, [this](T* ptr) { + freeBuffers.push(ptr); + }); + } + }; +} + +#endif // UTIL_BUFFER_POOL_H_