111 lines
3.6 KiB
C++
111 lines
3.6 KiB
C++
#include "compatibility.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
#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<ubyte> convert_voxels_1to2(const ubyte* buffer, uint32_t size) {
|
|
auto data = compression::decompress(
|
|
buffer, size, VOXELS_DATA_SIZE_V1, compression::Method::EXTRLE8);
|
|
|
|
util::Buffer<ubyte> dstBuffer(VOXELS_DATA_SIZE_V2);
|
|
auto dst = reinterpret_cast<uint16_t*>(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<blockid_t>(bid1) << 8) | static_cast<blockid_t>(bid2);
|
|
dst[CHUNK_VOL + i] = (
|
|
(static_cast<blockstate_t>(bst1) << 8) |
|
|
static_cast<blockstate_t>(bst2)
|
|
);
|
|
}
|
|
size_t outLen;
|
|
auto compressed = compression::compress(
|
|
dstBuffer.data(), VOXELS_DATA_SIZE_V2, outLen, compression::Method::EXTRLE16);
|
|
return util::Buffer<ubyte>(std::move(compressed), outLen);
|
|
}
|
|
|
|
util::Buffer<ubyte> compatibility::convert_region_2to3(
|
|
const util::Buffer<ubyte>& 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<const uint32_t*>(
|
|
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<const uint32_t*>(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<ubyte>(builder.build().data(), builder.size());
|
|
}
|