#include "compatibility.hpp" #include #include "constants.hpp" #include "voxels/voxel.hpp" #include "coders/compression.hpp" #include "coders/byte_utils.hpp" #include "lighting/Lightmap.hpp" #include "util/data_io.hpp" static inline size_t VOXELS_DATA_SIZE_V1 = CHUNK_VOL * 4; static inline size_t VOXELS_DATA_SIZE_V2 = CHUNK_VOL * 4; static util::Buffer convert_voxels_1to2(const ubyte* buffer, uint32_t size) { auto data = compression::decompress( buffer, size, VOXELS_DATA_SIZE_V1, compression::Method::EXTRLE8); util::Buffer dstBuffer(VOXELS_DATA_SIZE_V2); auto dst = reinterpret_cast(dstBuffer.data()); for (size_t i = 0; i < CHUNK_VOL; i++) { ubyte bid1 = data[i]; ubyte bid2 = data[CHUNK_VOL + i]; ubyte bst1 = data[CHUNK_VOL * 2 + i]; ubyte bst2 = data[CHUNK_VOL * 3 + i]; dst[i] = (static_cast(bid1) << 8) | static_cast(bid2); dst[CHUNK_VOL + i] = ( (static_cast(bst1) << 8) | static_cast(bst2) ); } size_t outLen; auto compressed = compression::compress( dstBuffer.data(), VOXELS_DATA_SIZE_V2, outLen, compression::Method::EXTRLE16); return util::Buffer(std::move(compressed), outLen); } util::Buffer compatibility::convert_region_2to3( const util::Buffer& src, RegionLayerIndex layer ) { const size_t REGION_CHUNKS = 1024; const size_t HEADER_SIZE = 10; const size_t OFFSET_TABLE_SIZE = REGION_CHUNKS * sizeof(uint32_t); const ubyte COMPRESS_NONE = 0; const ubyte COMPRESS_EXTRLE8 = 1; const ubyte COMPRESS_EXTRLE16 = 2; const ubyte* const ptr = src.data(); ByteBuilder builder; builder.putCStr(".VOXREG"); builder.put(3); switch (layer) { case REGION_LAYER_VOXELS: builder.put(COMPRESS_EXTRLE16); break; case REGION_LAYER_LIGHTS: builder.put(COMPRESS_EXTRLE8); break; default: builder.put(COMPRESS_NONE); break; } uint32_t offsets[REGION_CHUNKS] {}; size_t chunkIndex = 0; auto tablePtr = reinterpret_cast( ptr + src.size() - OFFSET_TABLE_SIZE ); for (size_t i = 0; i < REGION_CHUNKS; i++) { uint32_t srcOffset = dataio::be2h(tablePtr[i]); if (srcOffset == 0) { continue; } uint32_t size = *reinterpret_cast(ptr + srcOffset); size = dataio::be2h(size); const ubyte* data = ptr + srcOffset + sizeof(uint32_t); offsets[i] = builder.size(); switch (layer) { case REGION_LAYER_VOXELS: { auto dstdata = convert_voxels_1to2(data, size); builder.putInt32(dstdata.size()); builder.putInt32(VOXELS_DATA_SIZE_V2); builder.put(dstdata.data(), dstdata.size()); break; } case REGION_LAYER_LIGHTS: builder.putInt32(size); builder.putInt32(LIGHTMAP_DATA_LEN); builder.put(data, size); break; case REGION_LAYER_ENTITIES: case REGION_LAYER_INVENTORIES: case REGION_LAYER_BLOCKS_DATA: { builder.putInt32(size); builder.putInt32(size); builder.put(data, size); break; case REGION_LAYERS_COUNT: throw std::invalid_argument("invalid enum"); } } } for (size_t i = 0; i < REGION_CHUNKS; i++) { builder.putInt32(offsets[i]); } return util::Buffer(builder.build().data(), builder.size()); }