feat: add putU32Be and readU32Be

This commit is contained in:
dualfroz committed 2026-09-09 11:45:14 +02:00
1 parent a7f9263f58
commit 48f48bf57b
1 file changed
+160
+160
View File
@@ -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);
}