fix world converter

This commit is contained in:
MihailRis 2024-10-03 02:38:57 +03:00
parent 8f1eae4330
commit 0ad588fd33
8 changed files with 109 additions and 53 deletions

View File

@ -46,10 +46,14 @@ static void process_blocks_data(
report.dataLoss.push_back(name + ": discard data"); report.dataLoss.push_back(name + ": discard data");
continue; continue;
} }
auto incapatibility = layout.checkCompatibility(*def->dataStruct); if (layout != *def->dataStruct) {
if (!incapatibility.empty()) {
ContentIssue issue {ContentIssueType::BLOCK_DATA_LAYOUTS_UPDATE}; ContentIssue issue {ContentIssueType::BLOCK_DATA_LAYOUTS_UPDATE};
report.issues.push_back(issue); report.issues.push_back(issue);
report.dataLayoutsUpdated = true;
}
auto incapatibility = layout.checkCompatibility(*def->dataStruct);
if (!incapatibility.empty()) {
for (const auto& error : incapatibility) { for (const auto& error : incapatibility) {
report.dataLoss.push_back( report.dataLoss.push_back(
"[" + name + "] field " + error.name + " - " + "[" + 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); report.blocksDataLayouts[name] = std::move(layout);
} }
} }

View File

@ -100,22 +100,7 @@ void WorldConverter::createConvertTasks() {
tasks.push(ConvertTask {ConvertTaskType::PLAYER, wfile->getPlayerFile()}); tasks.push(ConvertTask {ConvertTaskType::PLAYER, wfile->getPlayerFile()});
} }
WorldConverter::WorldConverter( void WorldConverter::createBlockFieldsConvertTasks() {
const std::shared_ptr<WorldFiles>& worldFiles,
const Content* content,
std::shared_ptr<ContentReport> reportPtr,
bool upgradeMode
)
: wfile(worldFiles),
report(std::move(reportPtr)),
content(content),
upgradeMode(upgradeMode)
{
if (upgradeMode) {
createUpgradeTasks();
} else if (report->hasContentReorder()) {
createConvertTasks();
} else {
// blocks data conversion requires correct block indices // blocks data conversion requires correct block indices
// so it must be done AFTER voxels conversion // so it must be done AFTER voxels conversion
const auto& regions = wfile->getRegions(); const auto& regions = wfile->getRegions();
@ -132,6 +117,29 @@ WorldConverter::WorldConverter(
} }
} }
} }
WorldConverter::WorldConverter(
const std::shared_ptr<WorldFiles>& worldFiles,
const Content* content,
std::shared_ptr<ContentReport> reportPtr,
ConvertMode mode
)
: wfile(worldFiles),
report(std::move(reportPtr)),
content(content),
mode(mode)
{
switch (mode) {
case ConvertMode::UPGRADE:
createUpgradeTasks();
break;
case ConvertMode::REINDEX:
createConvertTasks();
break;
case ConvertMode::BLOCK_FIELDS:
createBlockFieldsConvertTasks();
break;
}
} }
WorldConverter::~WorldConverter() { WorldConverter::~WorldConverter() {
@ -142,11 +150,11 @@ std::shared_ptr<Task> WorldConverter::startTask(
const Content* content, const Content* content,
const std::shared_ptr<ContentReport>& report, const std::shared_ptr<ContentReport>& report,
const runnable& onDone, const runnable& onDone,
bool upgradeMode, ConvertMode mode,
bool multithreading bool multithreading
) { ) {
auto converter = std::make_shared<WorldConverter>( auto converter = std::make_shared<WorldConverter>(
worldFiles, content, report, upgradeMode); worldFiles, content, report, mode);
if (!multithreading) { if (!multithreading) {
converter->setOnComplete([=]() { converter->setOnComplete([=]() {
converter->write(); 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 { void WorldConverter::convertBlocksData(int x, int z, const ContentReport& report) const {
logger.info() << "converting blocks data"; logger.info() << "converting blocks data";
wfile->getRegions().processBlocksData(x, z, wfile->getRegions().processBlocksData(x, z,
[=](BlocksMetadata& heap, std::unique_ptr<ubyte[]> voxelsData) { [=](BlocksMetadata* heap, std::unique_ptr<ubyte[]> voxelsData) {
Chunk chunk(0, 0); Chunk chunk(0, 0);
chunk.decode(voxelsData.get()); chunk.decode(voxelsData.get());
const auto& indices = content->getIndices()->blocks; const auto& indices = content->getIndices()->blocks;
BlocksMetadata newHeap; BlocksMetadata newHeap;
for (const auto& entry : heap) { for (const auto& entry : *heap) {
size_t index = entry.index; size_t index = entry.index;
const auto& def = indices.require(chunk.voxels[index].id); const auto& def = indices.require(chunk.voxels[index].id);
const auto& newStruct = *def.dataStruct; 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()); uint8_t* dst = newHeap.allocate(index, newStruct.size());
newStruct.convert(prevStruct, entry.data(), dst, true); 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() { void WorldConverter::write() {
if (upgradeMode) { logger.info() << "applying changes";
logger.info() << "refreshing version";
wfile->patchIndicesVersion("region-version", REGION_FORMAT_VERSION); auto patch = dv::object();
} else { switch (mode) {
logger.info() << "writing world"; case ConvertMode::UPGRADE:
wfile->write(nullptr, content); 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() { void WorldConverter::waitForEnd() {

View File

@ -37,6 +37,12 @@ struct ConvertTask {
RegionLayerIndex layer; RegionLayerIndex layer;
}; };
enum class ConvertMode {
UPGRADE,
REINDEX,
BLOCK_FIELDS,
};
class WorldConverter : public Task { class WorldConverter : public Task {
std::shared_ptr<WorldFiles> wfile; std::shared_ptr<WorldFiles> wfile;
std::shared_ptr<ContentReport> const report; std::shared_ptr<ContentReport> const report;
@ -44,7 +50,7 @@ class WorldConverter : public Task {
std::queue<ConvertTask> tasks; std::queue<ConvertTask> tasks;
runnable onComplete; runnable onComplete;
uint tasksDone = 0; uint tasksDone = 0;
bool upgradeMode; ConvertMode mode;
void upgradeRegion( void upgradeRegion(
const fs::path& file, int x, int z, RegionLayerIndex layer) const; const fs::path& file, int x, int z, RegionLayerIndex layer) const;
@ -60,12 +66,13 @@ class WorldConverter : public Task {
void createUpgradeTasks(); void createUpgradeTasks();
void createConvertTasks(); void createConvertTasks();
void createBlockFieldsConvertTasks();
public: public:
WorldConverter( WorldConverter(
const std::shared_ptr<WorldFiles>& worldFiles, const std::shared_ptr<WorldFiles>& worldFiles,
const Content* content, const Content* content,
std::shared_ptr<ContentReport> report, std::shared_ptr<ContentReport> report,
bool upgradeMode ConvertMode mode
); );
~WorldConverter(); ~WorldConverter();
@ -86,7 +93,7 @@ public:
const Content* content, const Content* content,
const std::shared_ptr<ContentReport>& report, const std::shared_ptr<ContentReport>& report,
const runnable& onDone, const runnable& onDone,
bool upgradeMode, ConvertMode mode,
bool multithreading bool multithreading
); );
}; };

View File

@ -25,6 +25,7 @@
#include "settings.hpp" #include "settings.hpp"
#include "typedefs.hpp" #include "typedefs.hpp"
#include "util/data_io.hpp" #include "util/data_io.hpp"
#include "util/stringutil.hpp"
#include "voxels/Block.hpp" #include "voxels/Block.hpp"
#include "voxels/Chunk.hpp" #include "voxels/Chunk.hpp"
#include "voxels/voxel.hpp" #include "voxels/voxel.hpp"
@ -111,13 +112,17 @@ static void write_indices(
} }
} }
void WorldFiles::writeIndices(const ContentIndices* indices) { void WorldFiles::createContentIndicesCache(
dv::value root = dv::object(); const ContentIndices* indices, dv::value& root
root["region-version"] = REGION_FORMAT_VERSION; ) {
write_indices(indices->blocks, root.list("blocks")); write_indices(indices->blocks, root.list("blocks"));
write_indices(indices->items, root.list("items")); write_indices(indices->items, root.list("items"));
write_indices(indices->entities, root.list("entities")); write_indices(indices->entities, root.list("entities"));
}
void WorldFiles::createBlockFieldsIndices(
const ContentIndices* indices, dv::value& root
) {
auto& structsMap = root.object("blocks-data"); auto& structsMap = root.object("blocks-data");
for (const auto* def : indices->blocks.getIterable()) { for (const auto* def : indices->blocks.getIterable()) {
if (def->dataStruct == nullptr) { if (def->dataStruct == nullptr) {
@ -125,6 +130,14 @@ void WorldFiles::writeIndices(const ContentIndices* indices) {
} }
structsMap[def->name] = def->dataStruct->serialize(); 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); files::write_json(getIndicesFile(), root);
} }
@ -178,14 +191,17 @@ bool WorldFiles::readResourcesData(const Content* content) {
return true; return true;
} }
void WorldFiles::patchIndicesVersion(const std::string& field, uint version) { void WorldFiles::patchIndicesFile(const dv::value& map) {
fs::path file = getIndicesFile(); fs::path file = getIndicesFile();
if (!fs::is_regular_file(file)) { if (!fs::is_regular_file(file)) {
logger.error() << file.filename().u8string() << " does not exists"; logger.error() << file.filename().u8string() << " does not exists";
return; return;
} }
auto root = files::read_json(file); 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); files::write_json(file, root, true);
} }

View File

@ -51,7 +51,14 @@ public:
std::optional<WorldInfo> readWorldInfo(); std::optional<WorldInfo> readWorldInfo();
bool readResourcesData(const Content* content); 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 /// @brief Write all unsaved data to world files
/// @param world target world /// @param world target world

View File

@ -318,7 +318,7 @@ void WorldRegions::processBlocksData(int x, int z, const BlockDataProc& func) {
BlocksMetadata blocksData; BlocksMetadata blocksData;
blocksData.deserialize(datData.get(), datLength); blocksData.deserialize(datData.get(), datLength);
try { try {
func(blocksData, std::move(voxData)); func(&blocksData, std::move(voxData));
} catch (const std::exception& err) { } catch (const std::exception& err) {
logger.error() << "an error ocurred while processing blocks " logger.error() << "an error ocurred while processing blocks "
"data in chunk (" << gx << ", " << gz << "): " << err.what(); "data in chunk (" << gx << ", " << gz << "): " << err.what();

View File

@ -67,7 +67,7 @@ struct regfile {
using RegionsMap = std::unordered_map<glm::ivec2, std::unique_ptr<WorldRegion>>; 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 RegionProc = std::function<std::unique_ptr<ubyte[]>(std::unique_ptr<ubyte[]>,uint32_t*)>;
using InventoryProc = std::function<void(Inventory*)>; using InventoryProc = std::function<void(Inventory*)>;
using BlockDataProc = std::function<void(BlocksMetadata&, std::unique_ptr<ubyte[]>)>; using BlockDataProc = std::function<void(BlocksMetadata*, std::unique_ptr<ubyte[]>)>;
/// @brief Region file pointer keeping inUse flag on until destroyed /// @brief Region file pointer keeping inUse flag on until destroyed
class regfile_ptr { class regfile_ptr {

View File

@ -49,6 +49,14 @@ std::shared_ptr<Task> create_converter(
const std::shared_ptr<ContentReport>& report, const std::shared_ptr<ContentReport>& report,
const runnable& postRunnable 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( return WorldConverter::startTask(
worldFiles, worldFiles,
content, content,
@ -59,7 +67,7 @@ std::shared_ptr<Task> create_converter(
menu->setPage("main", false); menu->setPage("main", false);
engine->getGUI()->postRunnable([=]() { postRunnable(); }); engine->getGUI()->postRunnable([=]() { postRunnable(); });
}, },
report->isUpgradeRequired(), mode,
true true
); );
} }
@ -79,9 +87,9 @@ void show_convert_request(
); );
}; };
std::wstring message = L"world.convert-request"; std::wstring message = L"world.convert-block-layouts";
if (report->hasUpdatedLayouts()) { if (report->hasContentReorder()) {
message = L"world.convert-block-layouts"; message = L"world.convert-request";
} }
if (report->isUpgradeRequired()) { if (report->isUpgradeRequired()) {
message = L"world.upgrade-request"; message = L"world.upgrade-request";