From 0ad588fd3330450d367369668afc0e79fb01c5d1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 3 Oct 2024 02:38:57 +0300 Subject: [PATCH] fix world converter --- src/content/ContentReport.cpp | 11 +++-- src/files/WorldConverter.cpp | 83 ++++++++++++++++++++-------------- src/files/WorldConverter.hpp | 13 ++++-- src/files/WorldFiles.cpp | 26 +++++++++-- src/files/WorldFiles.hpp | 9 +++- src/files/WorldRegions.cpp | 2 +- src/files/WorldRegions.hpp | 2 +- src/logic/EngineController.cpp | 16 +++++-- 8 files changed, 109 insertions(+), 53 deletions(-) diff --git a/src/content/ContentReport.cpp b/src/content/ContentReport.cpp index 3b8f77cf..605b822c 100644 --- a/src/content/ContentReport.cpp +++ b/src/content/ContentReport.cpp @@ -46,10 +46,14 @@ static void process_blocks_data( report.dataLoss.push_back(name + ": discard data"); continue; } - auto incapatibility = layout.checkCompatibility(*def->dataStruct); - if (!incapatibility.empty()) { + if (layout != *def->dataStruct) { ContentIssue issue {ContentIssueType::BLOCK_DATA_LAYOUTS_UPDATE}; report.issues.push_back(issue); + report.dataLayoutsUpdated = true; + } + + auto incapatibility = layout.checkCompatibility(*def->dataStruct); + if (!incapatibility.empty()) { for (const auto& error : incapatibility) { report.dataLoss.push_back( "[" + name + "] field " + error.name + " - " + @@ -57,9 +61,6 @@ static void process_blocks_data( ); } } - if (layout != *def->dataStruct) { - report.dataLayoutsUpdated = true; - } report.blocksDataLayouts[name] = std::move(layout); } } diff --git a/src/files/WorldConverter.cpp b/src/files/WorldConverter.cpp index 3bd9b7b4..46b85868 100644 --- a/src/files/WorldConverter.cpp +++ b/src/files/WorldConverter.cpp @@ -100,37 +100,45 @@ void WorldConverter::createConvertTasks() { tasks.push(ConvertTask {ConvertTaskType::PLAYER, wfile->getPlayerFile()}); } +void WorldConverter::createBlockFieldsConvertTasks() { + // 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; + } + } +} + WorldConverter::WorldConverter( const std::shared_ptr& worldFiles, const Content* content, std::shared_ptr reportPtr, - bool upgradeMode + ConvertMode mode ) : wfile(worldFiles), report(std::move(reportPtr)), content(content), - upgradeMode(upgradeMode) + mode(mode) { - if (upgradeMode) { - createUpgradeTasks(); - } 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; - } - } + switch (mode) { + case ConvertMode::UPGRADE: + createUpgradeTasks(); + break; + case ConvertMode::REINDEX: + createConvertTasks(); + break; + case ConvertMode::BLOCK_FIELDS: + createBlockFieldsConvertTasks(); + break; } } @@ -142,11 +150,11 @@ std::shared_ptr WorldConverter::startTask( const Content* content, const std::shared_ptr& report, const runnable& onDone, - bool upgradeMode, + ConvertMode mode, bool multithreading ) { auto converter = std::make_shared( - worldFiles, content, report, upgradeMode); + worldFiles, content, report, mode); if (!multithreading) { converter->setOnComplete([=]() { converter->write(); @@ -208,14 +216,14 @@ void WorldConverter::convertPlayer(const fs::path& file) const { 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 voxelsData) { + [=](BlocksMetadata* heap, std::unique_ptr voxelsData) { Chunk chunk(0, 0); chunk.decode(voxelsData.get()); const auto& indices = content->getIndices()->blocks; BlocksMetadata newHeap; - for (const auto& entry : heap) { + for (const auto& entry : *heap) { size_t index = entry.index; const auto& def = indices.require(chunk.voxels[index].id); const auto& newStruct = *def.dataStruct; @@ -229,7 +237,7 @@ void WorldConverter::convertBlocksData(int x, int z, const ContentReport& report uint8_t* dst = newHeap.allocate(index, newStruct.size()); newStruct.convert(prevStruct, entry.data(), dst, true); } - heap = std::move(newHeap); + *heap = std::move(newHeap); }); } @@ -286,13 +294,22 @@ bool WorldConverter::isActive() const { } void WorldConverter::write() { - if (upgradeMode) { - logger.info() << "refreshing version"; - wfile->patchIndicesVersion("region-version", REGION_FORMAT_VERSION); - } else { - logger.info() << "writing world"; - wfile->write(nullptr, content); + logger.info() << "applying changes"; + + auto patch = dv::object(); + switch (mode) { + case ConvertMode::UPGRADE: + patch["region-version"] = REGION_FORMAT_VERSION; + break; + case ConvertMode::REINDEX: + WorldFiles::createContentIndicesCache(content->getIndices(), patch); + break; + case ConvertMode::BLOCK_FIELDS: + WorldFiles::createBlockFieldsIndices(content->getIndices(), patch); + break; } + wfile->patchIndicesFile(patch); + wfile->write(nullptr, nullptr); } void WorldConverter::waitForEnd() { diff --git a/src/files/WorldConverter.hpp b/src/files/WorldConverter.hpp index 6331acb6..b7852c97 100644 --- a/src/files/WorldConverter.hpp +++ b/src/files/WorldConverter.hpp @@ -37,6 +37,12 @@ struct ConvertTask { RegionLayerIndex layer; }; +enum class ConvertMode { + UPGRADE, + REINDEX, + BLOCK_FIELDS, +}; + class WorldConverter : public Task { std::shared_ptr wfile; std::shared_ptr const report; @@ -44,7 +50,7 @@ class WorldConverter : public Task { std::queue tasks; runnable onComplete; uint tasksDone = 0; - bool upgradeMode; + ConvertMode mode; void upgradeRegion( const fs::path& file, int x, int z, RegionLayerIndex layer) const; @@ -60,12 +66,13 @@ class WorldConverter : public Task { void createUpgradeTasks(); void createConvertTasks(); + void createBlockFieldsConvertTasks(); public: WorldConverter( const std::shared_ptr& worldFiles, const Content* content, std::shared_ptr report, - bool upgradeMode + ConvertMode mode ); ~WorldConverter(); @@ -86,7 +93,7 @@ public: const Content* content, const std::shared_ptr& report, const runnable& onDone, - bool upgradeMode, + ConvertMode mode, bool multithreading ); }; diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 7f59e602..c99ee8ef 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -25,6 +25,7 @@ #include "settings.hpp" #include "typedefs.hpp" #include "util/data_io.hpp" +#include "util/stringutil.hpp" #include "voxels/Block.hpp" #include "voxels/Chunk.hpp" #include "voxels/voxel.hpp" @@ -111,13 +112,17 @@ static void write_indices( } } -void WorldFiles::writeIndices(const ContentIndices* indices) { - dv::value root = dv::object(); - root["region-version"] = REGION_FORMAT_VERSION; +void WorldFiles::createContentIndicesCache( + const ContentIndices* indices, dv::value& root +) { write_indices(indices->blocks, root.list("blocks")); write_indices(indices->items, root.list("items")); write_indices(indices->entities, root.list("entities")); +} +void WorldFiles::createBlockFieldsIndices( + const ContentIndices* indices, dv::value& root +) { auto& structsMap = root.object("blocks-data"); for (const auto* def : indices->blocks.getIterable()) { if (def->dataStruct == nullptr) { @@ -125,6 +130,14 @@ void WorldFiles::writeIndices(const ContentIndices* indices) { } structsMap[def->name] = def->dataStruct->serialize(); } +} + +void WorldFiles::writeIndices(const ContentIndices* indices) { + dv::value root = dv::object(); + root["region-version"] = REGION_FORMAT_VERSION; + + createContentIndicesCache(indices, root); + createBlockFieldsIndices(indices, root); files::write_json(getIndicesFile(), root); } @@ -178,14 +191,17 @@ bool WorldFiles::readResourcesData(const Content* content) { return true; } -void WorldFiles::patchIndicesVersion(const std::string& field, uint version) { +void WorldFiles::patchIndicesFile(const dv::value& map) { fs::path file = getIndicesFile(); if (!fs::is_regular_file(file)) { logger.error() << file.filename().u8string() << " does not exists"; return; } auto root = files::read_json(file); - root[field] = version; + for (const auto& [key, value] : map.asObject()) { + logger.info() << "patching indices.json: update " << util::quote(key); + root[key] = value; + } files::write_json(file, root, true); } diff --git a/src/files/WorldFiles.hpp b/src/files/WorldFiles.hpp index 32b64060..7f72e146 100644 --- a/src/files/WorldFiles.hpp +++ b/src/files/WorldFiles.hpp @@ -51,7 +51,14 @@ public: std::optional readWorldInfo(); bool readResourcesData(const Content* content); - void patchIndicesVersion(const std::string& field, uint version); + static void createContentIndicesCache( + const ContentIndices* indices, dv::value& root + ); + static void createBlockFieldsIndices( + const ContentIndices* indices, dv::value& root + ); + + void patchIndicesFile(const dv::value& map); /// @brief Write all unsaved data to world files /// @param world target world diff --git a/src/files/WorldRegions.cpp b/src/files/WorldRegions.cpp index 87ee4351..592eb391 100644 --- a/src/files/WorldRegions.cpp +++ b/src/files/WorldRegions.cpp @@ -318,7 +318,7 @@ void WorldRegions::processBlocksData(int x, int z, const BlockDataProc& func) { BlocksMetadata blocksData; blocksData.deserialize(datData.get(), datLength); try { - func(blocksData, std::move(voxData)); + 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(); diff --git a/src/files/WorldRegions.hpp b/src/files/WorldRegions.hpp index 722e5c48..5e7570f4 100644 --- a/src/files/WorldRegions.hpp +++ b/src/files/WorldRegions.hpp @@ -67,7 +67,7 @@ struct regfile { using RegionsMap = std::unordered_map>; using RegionProc = std::function(std::unique_ptr,uint32_t*)>; using InventoryProc = std::function; -using BlockDataProc = std::function)>; +using BlockDataProc = std::function)>; /// @brief Region file pointer keeping inUse flag on until destroyed class regfile_ptr { diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index c43099cb..c8666d9d 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -49,6 +49,14 @@ std::shared_ptr create_converter( const std::shared_ptr& report, const runnable& postRunnable ) { + ConvertMode mode; + if (report->isUpgradeRequired()) { + mode = ConvertMode::UPGRADE; + } else if (report->hasContentReorder()) { + mode = ConvertMode::REINDEX; + } else { + mode = ConvertMode::BLOCK_FIELDS; + } return WorldConverter::startTask( worldFiles, content, @@ -59,7 +67,7 @@ std::shared_ptr create_converter( menu->setPage("main", false); engine->getGUI()->postRunnable([=]() { postRunnable(); }); }, - report->isUpgradeRequired(), + mode, true ); } @@ -79,9 +87,9 @@ void show_convert_request( ); }; - std::wstring message = L"world.convert-request"; - if (report->hasUpdatedLayouts()) { - message = L"world.convert-block-layouts"; + std::wstring message = L"world.convert-block-layouts"; + if (report->hasContentReorder()) { + message = L"world.convert-request"; } if (report->isUpgradeRequired()) { message = L"world.upgrade-request";