From 460b08a0060c3e39feb2ed9492c1c765d35a67a7 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 3 Jan 2024 23:25:58 +0300 Subject: [PATCH] WorldFiles region format and magic check --- src/constants.h | 4 ++-- src/files/WorldFiles.cpp | 46 ++++++++++++++++++++++++++++------------ src/files/WorldFiles.h | 16 ++++++++++---- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/constants.h b/src/constants.h index 00d7f7d5..cf560440 100644 --- a/src/constants.h +++ b/src/constants.h @@ -5,14 +5,14 @@ #include "typedefs.h" const int ENGINE_VERSION_MAJOR = 0; -const int ENGINE_VERSION_MINOR = 16; +const int ENGINE_VERSION_MINOR = 17; const int CHUNK_W = 16; const int CHUNK_H = 256; const int CHUNK_D = 16; /* Chunk volume (count of voxels per Chunk) */ -const int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); +constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); /* BLOCK_VOID is block id used to mark non-existing voxel (voxel of missing chunk) */ const blockid_t BLOCK_VOID = std::numeric_limits::max(); diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index e8722bdf..9b1645f3 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -23,9 +23,27 @@ #include #include #include +#include namespace fs = std::filesystem; +regfile::regfile(fs::path filename) : file(filename) { + if (file.length() < REGION_HEADER_SIZE) + throw std::runtime_error("incomplete region file header"); + char header[REGION_HEADER_SIZE]; + file.read(header, REGION_HEADER_SIZE); + + // avoid of use strcmp_s + if (std::string(header, strlen(REGION_FORMAT_MAGIC)) != REGION_FORMAT_MAGIC) { + throw std::runtime_error("invalid region file magic number"); + } + version = header[8]; + if (version > 2) { + throw std::runtime_error( + "region format "+std::to_string(version)+" is not supported"); + } +} + WorldRegion::WorldRegion() { chunksData = new ubyte*[REGION_CHUNKS_COUNT]{}; sizes = new uint32_t[REGION_CHUNKS_COUNT]{}; @@ -252,7 +270,8 @@ ubyte* WorldFiles::getData(regionsmap& regions, const fs::path& folder, return nullptr; } -files::rafile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) { + +regfile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) { const auto found = openRegFiles.find(coord); if (found != openRegFiles.end()) { return found->second.get(); @@ -266,7 +285,7 @@ files::rafile* WorldFiles::getRegFile(glm::ivec3 coord, const fs::path& folder) if (!fs::is_regular_file(filename)) { return nullptr; } - openRegFiles[coord] = std::make_unique(filename); + openRegFiles[coord] = std::make_unique(filename); return openRegFiles[coord].get(); } @@ -285,26 +304,27 @@ ubyte* WorldFiles::readChunkData(int x, int chunkIndex = localZ * REGION_SIZE + localX; glm::ivec3 coord(regionX, regionZ, layer); - files::rafile* file = WorldFiles::getRegFile(coord, folder); - if (file == nullptr) { + regfile* rfile = WorldFiles::getRegFile(coord, folder); + if (rfile == nullptr) { return nullptr; } + files::rafile& file = rfile->file; - size_t file_size = file->length(); + 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); + 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; } - file->seekg(offset); - file->read((char*)(&offset), 4); + 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); + file.read((char*)data, length); if (data == nullptr) { std::cerr << "ERROR: failed to read data of chunk x("<< x <<"), z("<< z <<")" << std::endl; } @@ -343,13 +363,13 @@ void WorldFiles::writeRegion(int x, int z, WorldRegion* entry, fs::path folder, openRegFiles.erase(regcoord); } - char header[10] = REGION_FORMAT_MAGIC; + 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, 10); + file.write(header, REGION_HEADER_SIZE); - size_t offset = 10; + size_t offset = REGION_HEADER_SIZE; char intbuf[4]{}; uint offsets[REGION_CHUNKS_COUNT]{}; diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index b220e555..d288a26c 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -15,12 +15,13 @@ #include "../typedefs.h" #include "../settings.h" +const uint REGION_HEADER_SIZE = 10; const uint REGION_LAYER_VOXELS = 0; const uint REGION_LAYER_LIGHTS = 1; const uint REGION_SIZE_BIT = 5; const uint REGION_SIZE = (1 << (REGION_SIZE_BIT)); const uint REGION_CHUNKS_COUNT = ((REGION_SIZE) * (REGION_SIZE)); -const uint REGION_FORMAT_VERSION = 1; +const uint REGION_FORMAT_VERSION = 2; const uint WORLD_FORMAT_VERSION = 1; const uint MAX_OPEN_REGION_FILES = 16; @@ -52,9 +53,16 @@ public: uint32_t* getSizes() const; }; +struct regfile { + files::rafile file; + int version; + + regfile(std::filesystem::path filename); +}; + typedef std::unordered_map> regionsmap; class WorldFiles { - std::unordered_map> openRegFiles; + std::unordered_map> openRegFiles; void writeWorldInfo(const World* world); std::filesystem::path getLightsFolder() const; @@ -98,8 +106,8 @@ class WorldFiles { const std::filesystem::path& folder, int x, int z, int layer); - files::rafile* getRegFile(glm::ivec3 coord, - const std::filesystem::path& folder); + regfile* getRegFile(glm::ivec3 coord, + const std::filesystem::path& folder); public: static bool parseRegionFilename(const std::string& name, int& x, int& y); std::filesystem::path getRegionsFolder() const;