diff --git a/core/src/SaveMigration.cpp b/core/src/SaveMigration.cpp index f022385..a6c412f 100644 --- a/core/src/SaveMigration.cpp +++ b/core/src/SaveMigration.cpp @@ -628,3 +628,80 @@ MigrationPlan SaveMigrator::planFor(SaveVersion from, SaveVersion to) { return plan; } +bool SaveMigrator::applyStep(const ByteBuffer& in, const MigrationStep& step, + MigrationResult& result, ByteBuffer& out) const { + SaveContainer container; + if (!readSaveContainer(in.data(), in.size(), container)) { + result.failure = "container is not readable at " + std::string(saveVersionName(step.from)); + return false; + } + if (container.version != step.from) { + result.failure = "expected " + std::string(saveVersionName(step.from)) + " but found " + + saveVersionName(container.version); + return false; + } + + for (SaveChunkRecord& record : container.chunks) { + if (step.to == SaveVersion::V2) { + std::vector palette; + std::vector indices; + buildPalette(record.blocks, palette, indices); + result.paletteEntriesCreated += palette.size(); + } else if (step.to == SaveVersion::V3) { + record.light = defaultChunkLight(record.blocks, skyLightForNewPlanes); + result.lightCellsInitialized += record.light.size(); + } else { + record.meta = metadataDefaults; + ++result.metadataRecordsCreated; + } + } + + container.version = step.to; + container.compressPayloads = compressMigratedPayloads && step.to == currentSaveVersion; + out = writeSaveContainer(container); + return true; +} + +MigrationResult SaveMigrator::migrate(const uint8_t* data, std::size_t size, + SaveVersion target) const { + MigrationResult result; + result.to = target; + + SaveVersion from = currentSaveVersion; + if (!peekVersion(data, size, from)) { + result.failure = "save header is unreadable: bad magic, short buffer or unknown version"; + return result; + } + result.from = from; + + MigrationPlan plan = planFor(from, target); + if (!plan.possible) { + result.failure = plan.refusal; + return result; + } + + SaveContainer source; + if (!readSaveContainer(data, size, source)) { + result.failure = "save body is unreadable at " + std::string(saveVersionName(from)); + return result; + } + result.chunksMigrated = source.chunks.size(); + + ByteBuffer current(data, data + size); + for (const MigrationStep& step : plan.steps) { + ByteBuffer next; + if (!applyStep(current, step, result, next)) return result; + current = std::move(next); + result.applied.push_back(step); + } + + result.output = std::move(current); + result.ok = true; + return result; +} + +MigrationResult SaveMigrator::migrateToCurrent(const ByteBuffer& buffer) const { + return migrate(buffer.data(), buffer.size(), currentSaveVersion); +} + +} // namespace vf