implement blocks data conversion

This commit is contained in:
MihailRis
2024-10-01 19:08:45 +03:00
parent 28d746f371
commit bc05716772
16 changed files with 341 additions and 23 deletions
+50 -1
View File
@@ -13,6 +13,7 @@
#include "util/ThreadPool.hpp"
#include "voxels/Chunk.hpp"
#include "items/Inventory.hpp"
#include "voxels/Block.hpp"
#include "WorldFiles.hpp"
namespace fs = std::filesystem;
@@ -85,6 +86,7 @@ void WorldConverter::createConvertTasks() {
const auto& regions = wfile->getRegions();
for (auto& issue : report->getIssues()) {
switch (issue.issueType) {
case ContentIssueType::BLOCK_DATA_LAYOUTS_UPDATE:
case ContentIssueType::REGION_FORMAT_UPDATE:
break;
case ContentIssueType::MISSING:
@@ -111,8 +113,24 @@ WorldConverter::WorldConverter(
{
if (upgradeMode) {
createUpgradeTasks();
} else {
} else if (report->hasContentReorder()) {
createConvertTasks();
} else {
// blocks data conversion requires correct block indices
// so it must be done AFTER voxels conversion
const auto& regions = wfile->getRegions();
for (auto& issue : report->getIssues()) {
switch (issue.issueType) {
case ContentIssueType::BLOCK_DATA_LAYOUTS_UPDATE:
addRegionsTasks(
REGION_LAYER_BLOCKS_DATA,
ConvertTaskType::CONVERT_BLOCKS_DATA
);
break;
default:
break;
}
}
}
}
@@ -187,6 +205,34 @@ void WorldConverter::convertPlayer(const fs::path& file) const {
files::write_json(file, map);
}
void WorldConverter::convertBlocksData(int x, int z, const ContentReport& report) const {
logger.info() << "converting blocks data";
wfile->getRegions().processBlocksData(x, z,
[=](BlocksMetadata& heap, std::unique_ptr<ubyte[]> voxelsData) {
Chunk chunk(0, 0);
chunk.decode(voxelsData.get());
const auto& indices = content->getIndices()->blocks;
BlocksMetadata newHeap;
for (const auto& entry : heap) {
size_t index = entry.index;
const auto& def = indices.require(chunk.voxels[index].id);
const auto& newStruct = *def.dataStruct;
const auto& found = report.blocksDataLayouts.find(def.name);
if (found == report.blocksDataLayouts.end()) {
logger.error() << "no previous fields layout found for block"
<< def.name << " - discard";
continue;
}
const auto& prevStruct = found->second;
uint8_t* dst = newHeap.allocate(index, newStruct.size());
newStruct.convert(prevStruct, entry.data(), dst, true);
}
heap = std::move(newHeap);
});
}
void WorldConverter::convert(const ConvertTask& task) const {
if (!fs::is_regular_file(task.file)) return;
@@ -203,6 +249,9 @@ void WorldConverter::convert(const ConvertTask& task) const {
case ConvertTaskType::PLAYER:
convertPlayer(task.file);
break;
case ConvertTaskType::CONVERT_BLOCKS_DATA:
convertBlocksData(task.x, task.z, *report);
break;
}
}
+3
View File
@@ -24,6 +24,8 @@ enum class ConvertTaskType {
PLAYER,
/// @brief refresh region file version
UPGRADE_REGION,
/// @brief convert blocks data to updated layouts
CONVERT_BLOCKS_DATA,
};
struct ConvertTask {
@@ -49,6 +51,7 @@ class WorldConverter : public Task {
void convertPlayer(const fs::path& file) const;
void convertVoxels(const fs::path& file, int x, int z) const;
void convertInventories(const fs::path& file, int x, int z) const;
void convertBlocksData(int x, int z, const ContentReport& report) const;
void addRegionsTasks(
RegionLayerIndex layerid,
+10
View File
@@ -21,6 +21,7 @@
#include "objects/EntityDef.hpp"
#include "objects/Player.hpp"
#include "physics/Hitbox.hpp"
#include "data/StructLayout.hpp"
#include "settings.hpp"
#include "typedefs.hpp"
#include "util/data_io.hpp"
@@ -116,6 +117,15 @@ void WorldFiles::writeIndices(const ContentIndices* indices) {
write_indices(indices->blocks, root.list("blocks"));
write_indices(indices->items, root.list("items"));
write_indices(indices->entities, root.list("entities"));
auto& structsMap = root.object("blocks-data");
for (const auto* def : indices->blocks.getIterable()) {
if (def->dataStruct == nullptr) {
continue;
}
structsMap[def->name] = def->dataStruct->serialize();
}
files::write_json(getIndicesFile(), root);
}
+74 -8
View File
@@ -4,6 +4,7 @@
#include <utility>
#include <vector>
#include "debug/Logger.hpp"
#include "coders/byte_utils.hpp"
#include "coders/rle.hpp"
#include "coders/binary_json.hpp"
@@ -13,6 +14,8 @@
#define REGION_FORMAT_MAGIC ".VOXREG"
static debug::Logger logger("world-regions");
WorldRegion::WorldRegion()
: chunksData(
std::make_unique<std::unique_ptr<ubyte[]>[]>(REGION_CHUNKS_COUNT)
@@ -95,15 +98,21 @@ void WorldRegions::put(
) {
size_t size = srcSize;
auto& layer = layers[layerid];
if (layer.compression != compression::Method::NONE) {
data = compression::compress(
data.get(), size, size, layer.compression);
}
int regionX, regionZ, localX, localZ;
calc_reg_coords(x, z, regionX, regionZ, localX, localZ);
WorldRegion* region = layer.getOrCreateRegion(regionX, regionZ);
region->setUnsaved(true);
if (data == nullptr) {
region->put(localX, localZ, nullptr, 0, 0);
return;
}
if (layer.compression != compression::Method::NONE) {
data = compression::compress(
data.get(), size, size, layer.compression);
}
region->put(localX, localZ, std::move(data), size, srcSize);
}
@@ -251,9 +260,7 @@ BlocksMetadata WorldRegions::getBlocksData(int x, int z) {
return heap;
}
void WorldRegions::processInventories(
int x, int z, const inventoryproc& func
) {
void WorldRegions::processInventories(int x, int z, const InventoryProc& func) {
processRegion(x, z, REGION_LAYER_INVENTORIES,
[=](std::unique_ptr<ubyte[]> data, uint32_t* size) {
auto inventories = load_inventories(data.get(), *size);
@@ -264,6 +271,65 @@ void WorldRegions::processInventories(
});
}
void WorldRegions::processBlocksData(int x, int z, const BlockDataProc& func) {
auto& voxLayer = layers[REGION_LAYER_VOXELS];
auto& datLayer = layers[REGION_LAYER_BLOCKS_DATA];
if (voxLayer.getRegion(x, z) || datLayer.getRegion(x, z)) {
throw std::runtime_error("not implemented for in-memory regions");
}
auto datRegfile = datLayer.getRegFile({x, z});
if (datRegfile == nullptr) {
throw std::runtime_error("could not open region file");
}
auto voxRegfile = voxLayer.getRegFile({x, z});
if (voxRegfile == nullptr) {
logger.warning() << "missing voxels region - discard blocks data for "
<< x << "_" << z;
abort(); // TODO: delete region file
}
for (uint cz = 0; cz < REGION_SIZE; cz++) {
for (uint cx = 0; cx < REGION_SIZE; cx++) {
int gx = cx + x * REGION_SIZE;
int gz = cz + z * REGION_SIZE;
uint32_t datLength;
uint32_t datSrcSize;
auto datData = RegionsLayer::readChunkData(
gx, gz, datLength, datSrcSize, datRegfile.get()
);
if (datData == nullptr) {
continue;
}
uint32_t voxLength;
uint32_t voxSrcSize;
auto voxData = RegionsLayer::readChunkData(
gx, gz, voxLength, voxSrcSize, voxRegfile.get()
);
if (voxData == nullptr) {
logger.warning()
<< "missing voxels for chunk (" << gx << ", " << gz << ")";
put(gx, gz, REGION_LAYER_BLOCKS_DATA, nullptr, 0);
continue;
}
voxData = compression::decompress(
voxData.get(), voxLength, voxSrcSize, voxLayer.compression
);
BlocksMetadata blocksData;
blocksData.deserialize(datData.get(), datLength);
try {
func(blocksData, std::move(voxData));
} catch (const std::exception& err) {
logger.error() << "an error ocurred while processing blocks "
"data in chunk (" << gx << ", " << gz << "): " << err.what();
blocksData = {};
}
auto bytes = blocksData.serialize();
put(gx, gz, REGION_LAYER_BLOCKS_DATA, bytes.release(), bytes.size());
}
}
}
dv::value WorldRegions::fetchEntities(int x, int z) {
if (generatorTestMode) {
return nullptr;
@@ -282,7 +348,7 @@ dv::value WorldRegions::fetchEntities(int x, int z) {
}
void WorldRegions::processRegion(
int x, int z, RegionLayerIndex layerid, const regionproc& func
int x, int z, RegionLayerIndex layerid, const RegionProc& func
) {
auto& layer = layers[layerid];
if (layer.getRegion(x, z)) {
+9 -7
View File
@@ -64,9 +64,10 @@ struct regfile {
std::unique_ptr<ubyte[]> read(int index, uint32_t& size, uint32_t& srcSize);
};
using regionsmap = std::unordered_map<glm::ivec2, std::unique_ptr<WorldRegion>>;
using regionproc = std::function<std::unique_ptr<ubyte[]>(std::unique_ptr<ubyte[]>,uint32_t*)>;
using inventoryproc = std::function<void(Inventory*)>;
using RegionsMap = std::unordered_map<glm::ivec2, std::unique_ptr<WorldRegion>>;
using RegionProc = std::function<std::unique_ptr<ubyte[]>(std::unique_ptr<ubyte[]>,uint32_t*)>;
using InventoryProc = std::function<void(Inventory*)>;
using BlockDataProc = std::function<void(BlocksMetadata&, std::unique_ptr<ubyte[]>)>;
/// @brief Region file pointer keeping inUse flag on until destroyed
class regfile_ptr {
@@ -125,7 +126,7 @@ struct RegionsLayer {
compression::Method compression = compression::Method::NONE;
/// @brief In-memory regions data
regionsmap regions;
RegionsMap regions;
/// @brief In-memory regions map mutex
std::mutex mapMutex;
@@ -231,10 +232,11 @@ public:
/// @param layerid regions layer index
/// @param func processing callback
void processRegion(
int x, int z, RegionLayerIndex layerid, const regionproc& func);
int x, int z, RegionLayerIndex layerid, const RegionProc& func);
void processInventories(
int x, int z, const inventoryproc& func);
void processInventories(int x, int z, const InventoryProc& func);
void processBlocksData(int x, int z, const BlockDataProc& func);
/// @brief Get regions directory by layer index
/// @param layerid layer index