panel v0.9.2 — open-source game server manager
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Package regionmedic detects and surgically repairs corrupted 7 Days to Die
|
||||
// region (".7rg") files using the panel's own backups.
|
||||
//
|
||||
// Background
|
||||
//
|
||||
// 7DTD stores the world as a grid of 512×512-block "region" files, each
|
||||
// holding a 32×32 grid of chunks. When the server process dies mid-save (a
|
||||
// bare `docker stop` SIGKILL with no `saveworld`, an OOM kill, a crash) a
|
||||
// region file can be left with a torn chunk: the chunk's bytes no longer begin
|
||||
// with the expected header. On the next load 7DTD logs "Wrong chunk header!",
|
||||
// writes an `error_backup_<cx>_<cz>` salvage file, and drops the chunk — so a
|
||||
// base straddling the damaged region loses exactly the half that lived in it.
|
||||
//
|
||||
// This package reproduces, as deterministic code, the manual recovery that
|
||||
// works: localize the damaged region(s) from the error_backup files, find the
|
||||
// newest pre-corruption backup whose copy of that region validates clean,
|
||||
// snapshot the corrupt live file, swap the clean copy in (in place, preserving
|
||||
// permissions), and quarantine the error_backup salvage files.
|
||||
//
|
||||
// The .7rg on-disk format (reverse-engineered + verified byte-for-byte against
|
||||
// real region files, see RE notes in the repo history):
|
||||
//
|
||||
// Sector size = 4096 bytes; file size is always a multiple of 4096.
|
||||
// Region = 32×32 = 1024 chunks.
|
||||
// Sector 0 = header: magic "7rg"+0x01 at 0x000; bytes 0x004..0xFFF zero.
|
||||
// Sector 1 = location table at 0x1000: 1024 entries × 4 bytes, each
|
||||
// [3-byte little-endian sector offset][1-byte sector count];
|
||||
// an absent chunk is 0x00000000. Table index = localX + localZ*32
|
||||
// (X varies fastest). Chunk blob lives at sectorOffset*4096.
|
||||
// Chunk blob = [u32 LE blockLength][12 bytes zero][magic "ttc\0"]
|
||||
// [u32 LE const 47][raw DEFLATE stream].
|
||||
// blockLength = 8 + len(deflate); the on-disk blob occupies
|
||||
// 16 + blockLength bytes, rounded up to whole sectors (the
|
||||
// stored sector count may be one larger — allocator slack).
|
||||
// The decompressed payload begins int32 chunkX, int32 0,
|
||||
// int32 chunkZ.
|
||||
//
|
||||
// The "ttc\0" magic at blob offset 0x10 is the exact byte sequence 7DTD checks
|
||||
// when it logs "Wrong chunk header!", so it is both what Validate flags and the
|
||||
// minimal faithful corruption used by the test harness.
|
||||
//
|
||||
// Frozen API surface (do not break callers — the agent dispatch handler, the
|
||||
// region-medic CLI, and the unit tests all depend on these signatures):
|
||||
//
|
||||
// Validation: ValidateRegionBytes, ValidateRegionFile -> RegionReport
|
||||
// Localize: RegionCoord, RegionForChunk, ParseErrorBackup, ParseRegionFileName
|
||||
// Scan: ScanRegionDir -> RegionDirScan / AffectedRegion
|
||||
// Backups: BackupRef, ListPanelBackups, ExtractRegionFromBackup,
|
||||
// FindLastGoodRegion -> Candidate
|
||||
// Heal: PlanHeal -> HealPlan; ApplyHeal -> HealResult
|
||||
//
|
||||
// Everything here is pure (filesystem + archive/tar + compress/flate, stdlib
|
||||
// only). It performs no Docker or network actions; orchestration (graceful
|
||||
// save, stop, start, log-watch) is the caller's job, which keeps the decision
|
||||
// logic fully unit-testable.
|
||||
package regionmedic
|
||||
Reference in New Issue
Block a user