fix world converter
This commit is contained in:
parent
8f1eae4330
commit
0ad588fd33
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>& worldFiles,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentReport> 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<Task> WorldConverter::startTask(
|
||||
const Content* content,
|
||||
const std::shared_ptr<ContentReport>& report,
|
||||
const runnable& onDone,
|
||||
bool upgradeMode,
|
||||
ConvertMode mode,
|
||||
bool multithreading
|
||||
) {
|
||||
auto converter = std::make_shared<WorldConverter>(
|
||||
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<ubyte[]> voxelsData) {
|
||||
[=](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) {
|
||||
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() {
|
||||
|
||||
@ -37,6 +37,12 @@ struct ConvertTask {
|
||||
RegionLayerIndex layer;
|
||||
};
|
||||
|
||||
enum class ConvertMode {
|
||||
UPGRADE,
|
||||
REINDEX,
|
||||
BLOCK_FIELDS,
|
||||
};
|
||||
|
||||
class WorldConverter : public Task {
|
||||
std::shared_ptr<WorldFiles> wfile;
|
||||
std::shared_ptr<ContentReport> const report;
|
||||
@ -44,7 +50,7 @@ class WorldConverter : public Task {
|
||||
std::queue<ConvertTask> 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>& worldFiles,
|
||||
const Content* content,
|
||||
std::shared_ptr<ContentReport> report,
|
||||
bool upgradeMode
|
||||
ConvertMode mode
|
||||
);
|
||||
~WorldConverter();
|
||||
|
||||
@ -86,7 +93,7 @@ public:
|
||||
const Content* content,
|
||||
const std::shared_ptr<ContentReport>& report,
|
||||
const runnable& onDone,
|
||||
bool upgradeMode,
|
||||
ConvertMode mode,
|
||||
bool multithreading
|
||||
);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,14 @@ public:
|
||||
std::optional<WorldInfo> 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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -67,7 +67,7 @@ struct regfile {
|
||||
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[]>)>;
|
||||
using BlockDataProc = std::function<void(BlocksMetadata*, std::unique_ptr<ubyte[]>)>;
|
||||
|
||||
/// @brief Region file pointer keeping inUse flag on until destroyed
|
||||
class regfile_ptr {
|
||||
|
||||
@ -49,6 +49,14 @@ std::shared_ptr<Task> create_converter(
|
||||
const std::shared_ptr<ContentReport>& 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<Task> 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";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user