// // Created by aurailus on 2020-06-24. // // File Format: // 12 bytes -- Region Location Vec3 // 2 * 4096 bytes - Chunk offset within the file. -1 means it doesn't exist // 1024 byte subsections for containing Chunks. // // Chunk Format: // 4 bytes - Data length // [remaining] - Serialized Chunk data // #include #include #include #include "FileManipulator.h" #include "util/net/Serializer.h" #include "util/net/Deserializer.h" #include "world/dim/chunk/Chunk.h" FileManipulator::FileManipulator(const std::string& worldPath) : path(worldPath) { } void FileManipulator::commitChunk(Chunk& chunk) { glm::ivec3 reg = Space::Region::world::fromChunk(chunk.getPos()); unsigned int chunkInd = Space::Chunk::index(chunk.getPos()); std::string fileName = std::to_string(reg.x) + "_" + std::to_string(reg.y) + "_" + std::to_string(reg.z); std::string filePath = path + "/" + fileName; createRegionFileIfNotExists(reg); std::string chunkData = chunk.compressToString(); unsigned int dataBlockSize = floor(chunkData.length() / BLOCK_SIZE); std::fstream file(filePath, std::ios::in | std::ios::out | std::ios::binary); if (!file.is_open()) throw std::runtime_error("Couldn't open file."); std::array chunkOffsets{}; populateChunkOffsets(file, chunkOffsets); unsigned int currentBlock = chunkOffsets[chunkInd]; unsigned int nextBlock = (chunkInd == 63 ? 10000 : chunkOffsets[chunkInd + 1]); if (dataBlockSize > nextBlock - currentBlock) shiftChunks(file, chunkOffsets, chunkInd + 1, dataBlockSize - (nextBlock - currentBlock)); writeChunk(file, chunkOffsets[chunkInd], chunkData); file.close(); } void FileManipulator::writeChunk(std::fstream& file, unsigned int offset, const std::string& data) { file.seekp(META_OFFSET + offset * BLOCK_SIZE); file.write(data.data(), data.length()); } void FileManipulator::shiftChunks(std::fstream& file, std::array& offsets, unsigned int ind, unsigned int amt) { std::cout << "Shifting by " << amt << std::endl; unsigned int startPos = offsets[ind] * BLOCK_SIZE + META_OFFSET; unsigned int endPos; { char* buff = new char[4]; file.seekg(META_OFFSET + offsets[63] * BLOCK_SIZE); file.read(buff, 4); endPos = META_OFFSET + BLOCK_SIZE * offsets[63] + Deserializer(buff, 4).read(); } unsigned int len = endPos - startPos; char* buff = new char[len]; file.seekg(offsets[ind]); file.read(buff, len); file.seekp(offsets[ind] + amt * BLOCK_SIZE); file.write(buff, len); delete[] buff; for (unsigned int i = ind; i < 4096; i++) { offsets[i] += amt; Serializer s; s.append(offsets[i]); file.seekp(12 + i * 2); file.write(s.data.data(), s.data.length()); file.close(); } std::cout << "Shift done" << std::endl; } void FileManipulator::populateChunkOffsets(std::fstream& file, std::array& offsets) { file.seekg(12); char* buff = new char[2]; for (unsigned int i = 0; i < 4096; i++) { file.read(buff, 2); offsets[i] = Deserializer(buff, 2).read(); } delete[] buff; } void FileManipulator::createRegionFileIfNotExists(glm::ivec3 pos) { std::string fileName = std::to_string(pos.x) + "_" + std::to_string(pos.y) + "_" + std::to_string(pos.z); std::string filePath = path + fileName; if (std::filesystem::exists(filePath.data())) return; std::fstream file(filePath, std::ios::out | std::ios::binary); if (!file.is_open()) throw std::runtime_error("Couldn't open file."); file.seekp(0); Serializer s; s.append(pos); for (int i = 0; i < 4096; i++) s.append(i); for (int i = 0; i < 4096 * BLOCK_SIZE; i++) s.append(0); file.write(s.data.data(), s.data.length()); file.close(); }