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