Files
voxelforge/core/src/SaveIntegrity.cpp
T

162 lines
5.5 KiB
C++

#include "vf/SaveIntegrity.h"
#include <algorithm>
#include <array>
#include "vf/Block.h"
#include "vf/Region.h"
namespace vf {
namespace {
std::string decimal(long long value) { return std::to_string(value); }
std::string coordText(const Vec3i& coord) {
return "(" + decimal(coord.x) + ", " + decimal(coord.y) + ", " + decimal(coord.z) + ")";
}
uint64_t mixBits(uint64_t value) {
value += 0x9E3779B97F4A7C15ull;
value = (value ^ (value >> 30)) * 0xBF58476D1CE4E5B9ull;
value = (value ^ (value >> 27)) * 0x94D049BB133111EBull;
return value ^ (value >> 31);
}
uint64_t latticeHash(uint64_t seed, int gx, int gz) {
uint64_t h = seed;
h = mixBits(h ^ (static_cast<uint64_t>(static_cast<uint32_t>(gx)) * 0x2545F4914F6CDD1Dull));
h = mixBits(h ^ (static_cast<uint64_t>(static_cast<uint32_t>(gz)) * 0x9E3779B97F4A7C15ull));
return h;
}
int latticeHeight(uint64_t seed, int gx, int gz) {
return 32 + static_cast<int>(latticeHash(seed, gx, gz) % 33ull);
}
struct SectorSpan {
uint32_t first = 0;
uint32_t last = 0;
int entryIndex = -1;
};
IntegrityIssue makeIssue(IntegrityIssueKind kind, IssueSeverity severity, std::size_t byteOffset,
std::string detail) {
IntegrityIssue issue;
issue.kind = kind;
issue.severity = severity;
issue.byteOffset = byteOffset;
issue.detail = std::move(detail);
return issue;
}
bool actionOutranks(RepairActionKind candidate, RepairActionKind existing) {
auto rank = [](RepairActionKind kind) {
switch (kind) {
case RepairActionKind::RecomputeChecksum: return 0;
case RepairActionKind::RegenerateChunk: return 1;
case RepairActionKind::RemoveOrphanEntry: return 2;
case RepairActionKind::DropChunk: return 3;
case RepairActionKind::TruncateBuffer: return 4;
}
return 0;
};
return rank(candidate) > rank(existing);
}
} // namespace
const char* issueSeverityName(IssueSeverity severity) {
switch (severity) {
case IssueSeverity::Info: return "info";
case IssueSeverity::Warning: return "warning";
case IssueSeverity::Recoverable: return "recoverable";
case IssueSeverity::Fatal: return "fatal";
}
return "unknown";
}
const char* integrityIssueName(IntegrityIssueKind kind) {
switch (kind) {
case IntegrityIssueKind::BadMagic: return "badMagic";
case IntegrityIssueKind::UnknownVersion: return "unknownVersion";
case IntegrityIssueKind::MalformedHeader: return "malformedHeader";
case IntegrityIssueKind::TruncatedBuffer: return "truncatedBuffer";
case IntegrityIssueKind::ChunkCountOverrun: return "chunkCountOverrun";
case IntegrityIssueKind::OrphanEntry: return "orphanEntry";
case IntegrityIssueKind::OverlappingEntries: return "overlappingEntries";
case IntegrityIssueKind::ChunkOutsideRegion: return "chunkOutsideRegion";
case IntegrityIssueKind::ChunkHeightOutOfRange: return "chunkHeightOutOfRange";
case IntegrityIssueKind::MalformedRecord: return "malformedRecord";
case IntegrityIssueKind::PaletteIndexOutOfRange: return "paletteIndexOutOfRange";
case IntegrityIssueKind::ChecksumMismatch: return "checksumMismatch";
case IntegrityIssueKind::LightingInconsistent: return "lightingInconsistent";
case IntegrityIssueKind::TrailingBytes: return "trailingBytes";
}
return "unknown";
}
const char* repairActionName(RepairActionKind kind) {
switch (kind) {
case RepairActionKind::DropChunk: return "dropChunk";
case RepairActionKind::TruncateBuffer: return "truncateBuffer";
case RepairActionKind::RecomputeChecksum: return "recomputeChecksum";
case RepairActionKind::RegenerateChunk: return "regenerateChunk";
case RepairActionKind::RemoveOrphanEntry: return "removeOrphanEntry";
}
return "unknown";
}
bool IntegrityReport::fatal() const {
for (const IntegrityIssue& issue : issues)
if (issue.severity == IssueSeverity::Fatal) return true;
return false;
}
bool IntegrityReport::repairable() const {
if (fatal()) return false;
for (const IntegrityIssue& issue : issues)
if (issue.severity == IssueSeverity::Recoverable) return true;
return false;
}
std::size_t IntegrityReport::countOf(IntegrityIssueKind kind) const {
std::size_t total = 0;
for (const IntegrityIssue& issue : issues)
if (issue.kind == kind) ++total;
return total;
}
std::size_t IntegrityReport::countAtLeast(IssueSeverity severity) const {
std::size_t total = 0;
for (const IntegrityIssue& issue : issues)
if (issue.severity >= severity) ++total;
return total;
}
const IntegrityIssue* IntegrityReport::firstOf(IntegrityIssueKind kind) const {
for (const IntegrityIssue& issue : issues)
if (issue.kind == kind) return &issue;
return nullptr;
}
const RepairAction* RepairPlan::forEntry(int entryIndex) const {
for (const RepairAction& action : actions)
if (action.entryIndex == entryIndex) return &action;
return nullptr;
}
std::size_t RepairPlan::countOf(RepairActionKind kind) const {
std::size_t total = 0;
for (const RepairAction& action : actions)
if (action.kind == kind) ++total;
return total;
}
int regeneratedSurfaceHeight(uint64_t seed, int worldX, int worldZ) {
int gx = floorDiv(worldX, chunkSize);
int gz = floorDiv(worldZ, chunkSize);
int fx = floorMod(worldX, chunkSize);
int fz = floorMod(worldZ, chunkSize);