feat: add putU32Be and readU32Be
This commit is contained in:
1 parent
a7f9263f58
commit
48f48bf57b
1 file changed
+160
@@ -0,0 +1,160 @@
|
|||||||
|
#include "vf/SaveMigration.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "vf/Anvil.h"
|
||||||
|
#include "vf/Block.h"
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::size_t divideUp(std::size_t value, std::size_t unit) {
|
||||||
|
return unit == 0 ? 0 : (value + unit - 1) / unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void putU32Be(std::vector<uint8_t>& out, uint32_t value) {
|
||||||
|
out.push_back(static_cast<uint8_t>((value >> 24) & 0xFFu));
|
||||||
|
out.push_back(static_cast<uint8_t>((value >> 16) & 0xFFu));
|
||||||
|
out.push_back(static_cast<uint8_t>((value >> 8) & 0xFFu));
|
||||||
|
out.push_back(static_cast<uint8_t>(value & 0xFFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t readU32Be(const uint8_t* at) {
|
||||||
|
return (static_cast<uint32_t>(at[0]) << 24) | (static_cast<uint32_t>(at[1]) << 16) |
|
||||||
|
(static_cast<uint32_t>(at[2]) << 8) | static_cast<uint32_t>(at[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PayloadCursor {
|
||||||
|
const uint8_t* data;
|
||||||
|
std::size_t size;
|
||||||
|
std::size_t at = 0;
|
||||||
|
bool bad = false;
|
||||||
|
|
||||||
|
uint32_t u32() {
|
||||||
|
if (bad || at + 4 > size) {
|
||||||
|
bad = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint32_t value = readU32Be(data + at);
|
||||||
|
at += 4;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
uint64_t u64() {
|
||||||
|
uint32_t high = u32();
|
||||||
|
uint32_t low = u32();
|
||||||
|
return (static_cast<uint64_t>(high) << 32) | static_cast<uint64_t>(low);
|
||||||
|
}
|
||||||
|
uint8_t u8() {
|
||||||
|
if (bad || at + 1 > size) {
|
||||||
|
bad = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return data[at++];
|
||||||
|
}
|
||||||
|
bool take(std::size_t count, std::vector<uint8_t>& out) {
|
||||||
|
if (bad || at + count > size) {
|
||||||
|
bad = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out.assign(data + at, data + at + count);
|
||||||
|
at += count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool skip(std::size_t count) {
|
||||||
|
if (bad || at + count > size) {
|
||||||
|
bad = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
at += count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void writeU64Be(std::vector<uint8_t>& out, uint64_t value) {
|
||||||
|
putU32Be(out, static_cast<uint32_t>(value >> 32));
|
||||||
|
putU32Be(out, static_cast<uint32_t>(value & 0xFFFFFFFFull));
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildPalette(const Chunk& chunk, std::vector<Block>& palette, std::vector<uint32_t>& indices) {
|
||||||
|
std::array<int, static_cast<std::size_t>(Block::Count)> slotOf;
|
||||||
|
slotOf.fill(-1);
|
||||||
|
palette.clear();
|
||||||
|
indices.clear();
|
||||||
|
indices.reserve(chunkVolume);
|
||||||
|
for (Block block : chunk.raw()) {
|
||||||
|
int& slot = slotOf[static_cast<std::size_t>(block)];
|
||||||
|
if (slot < 0) {
|
||||||
|
slot = static_cast<int>(palette.size());
|
||||||
|
palette.push_back(block);
|
||||||
|
}
|
||||||
|
indices.push_back(static_cast<uint32_t>(slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string versionPair(SaveVersion from, SaveVersion to) {
|
||||||
|
return std::string(saveVersionName(from)) + " -> " + saveVersionName(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const SaveChunkRecord* SaveContainer::find(const Vec3i& coord) const {
|
||||||
|
for (const SaveChunkRecord& record : chunks)
|
||||||
|
if (record.coord == coord) return &record;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveReadU32At(const uint8_t* data, std::size_t size, std::size_t at, uint32_t& out) {
|
||||||
|
if (at + 4 > size) return false;
|
||||||
|
out = readU32Be(data + at);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saveWriteU32At(uint8_t* data, std::size_t size, std::size_t at, uint32_t value) {
|
||||||
|
if (at + 4 > size) return false;
|
||||||
|
data[at + 0] = static_cast<uint8_t>((value >> 24) & 0xFFu);
|
||||||
|
data[at + 1] = static_cast<uint8_t>((value >> 16) & 0xFFu);
|
||||||
|
data[at + 2] = static_cast<uint8_t>((value >> 8) & 0xFFu);
|
||||||
|
data[at + 3] = static_cast<uint8_t>(value & 0xFFu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isKnownSaveVersion(uint32_t version) { return version >= 1u && version <= 4u; }
|
||||||
|
|
||||||
|
bool versionHasPalette(SaveVersion version) { return version >= SaveVersion::V2; }
|
||||||
|
bool versionHasLight(SaveVersion version) { return version >= SaveVersion::V3; }
|
||||||
|
bool versionHasChecksum(SaveVersion version) { return version >= SaveVersion::V3; }
|
||||||
|
bool versionHasMetadata(SaveVersion version) { return version >= SaveVersion::V4; }
|
||||||
|
|
||||||
|
const char* saveVersionName(SaveVersion version) {
|
||||||
|
switch (version) {
|
||||||
|
case SaveVersion::V1: return "v1";
|
||||||
|
case SaveVersion::V2: return "v2";
|
||||||
|
case SaveVersion::V3: return "v3";
|
||||||
|
case SaveVersion::V4: return "v4";
|
||||||
|
}
|
||||||
|
return "v?";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readSaveHeader(const uint8_t* data, std::size_t size, SaveHeader& out) {
|
||||||
|
if (size < saveHeaderBytes) return false;
|
||||||
|
out.magic = readU32Be(data + 0);
|
||||||
|
out.version = readU32Be(data + 4);
|
||||||
|
out.regionX = static_cast<int32_t>(readU32Be(data + 8));
|
||||||
|
out.regionZ = static_cast<int32_t>(readU32Be(data + 12));
|
||||||
|
out.chunkCount = readU32Be(data + 16);
|
||||||
|
out.sectorBytes = readU32Be(data + 20);
|
||||||
|
out.tableChecksum = readU32Be(data + 24);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t saveTableBytes(const SaveHeader& header) {
|
||||||
|
return static_cast<std::size_t>(header.chunkCount) * saveEntryBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t saveHeaderSectors(const SaveHeader& header) {
|
||||||
|
if (header.sectorBytes == 0) return 0;
|
||||||
|
return divideUp(saveHeaderBytes + saveTableBytes(header), header.sectorBytes);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user