Minecraft-Region-Fixer 源码导读:Minecraft 存档损坏与 region 文件修复工具完整使用指南
【免费下载链接】Minecraft-Region-FixerPython script to fix some of the problems of the Minecraft save files (region files, *.mca).项目地址: https://gitcode.com/gh_mirrors/mi/Minecraft-Region-Fixer
Minecraft-Region-Fixer 是一款专门面向 Minecraft 玩家与服务器管理员的存档修复工具,它的核心能力是定位并修复 Minecraft 世界文件(尤其是 region 文件,即我们常见的*.mca文件)中的各种损坏问题。当你的世界出现区块无法加载、地面塌陷成虚空、服务器频繁报错,甚至世界目录打不开时,这个开源项目往往能把你从"删档重来"的边缘拉回来。本文将从"它能做什么"讲起,逐层拆解其代码架构,再手把手带你完成安装、扫描与修复,最后总结常见坑点,帮助新手快速上手这个Minecraft 存档修复工具。
一、先搞清楚:Region Fixer 到底能修什么
在深入代码之前,我们有必要先理解 Minecraft 的存档结构,因为整个项目的设计都围绕它展开。
Minecraft 世界文件的"解剖图"
一个典型的 Minecraft 世界目录长这样:
world/ ├── level.dat # 世界元数据(世界名、种子、游戏规则等) ├── playerdata/ # 玩家数据文件(UUID.dat) ├── region/ # 主世界区块文件,r.0.0.mca 之类 ├── DIM-1/region/ # 下界 ├── DIM1/region/ # 末地 ├── entities/ # 实体数据(较新版本) └── poi/ # 兴趣点数据(村庄、床等)其中region目录下的*.mca文件就是项目描述里提到的 region 文件。每个 region 文件按32×32的网格存放区块(chunk)数据,文件内部又分成头部(header)和数据区(data)两部分。头部的 8KB 空间记录了每个区块在文件中的偏移量、扇区数和时间戳,数据区则是压缩后的 NBT(Named Binary Tag)格式的区块内容。
为什么要先懂这个结构?因为 Region Fixer 的所有修复逻辑,本质上就是"读头部→校验偏移→解压数据→解析 NBT→判断状态→按策略处理",理解了文件格式,后面看代码会非常轻松。
它能识别的五类区块问题
regionfixer_core/constants.py是整个项目的"问题词典",它用数字常量给每一种区块状态做了编号:
CHUNK_NOT_CREATED = -1 # 区块尚未生成 CHUNK_OK = 0 # 一切正常 CHUNK_CORRUPTED = 1 # 数据损坏,无法解析 CHUNK_WRONG_LOCATED = 2 # 区块内容与文件头记录的坐标不符 CHUNK_TOO_MANY_ENTITIES = 3 # 实体数量超过阈值(默认300) CHUNK_SHARED_OFFSET = 4 # 多个区块共享同一扇区偏移,互相覆盖 CHUNK_MISSING_ENTITIES_TAG = 5 # 缺少 Entities 标签- 损坏(Corrupted):最常见,区块数据解压或解析失败,通常表现为"区块无法加载"。
- 错误定位(Wrong located):区块数据里记录的坐标和它实际存放的位置对不上。
- 实体过多(Too many entities):常见于刷怪塔或卡死的掉落物堆积,严重时会拖垮服务器。
- 共享偏移(Shared offset):文件内部两个区块指向同一段数据,属于结构性错误。
- 缺失 Entities 标签(Missing Entities tag):数据结构不完整,缺了实体列表。
针对每一种问题,项目还预定义了可选的解决方案:删除(remove)、用备份替换(replace)、直接修复(fix)或重新定位(relocate)。这正是 Region Fixer 与"一键删档"类工具最大的不同——它优先尝试把损坏的区块救回来,而不是简单地删掉。
二、核心模块拆解:三层架构一次看懂
整个项目可以看成三条互相协作的"生产线":命令行入口负责调度,核心逻辑负责诊断与治疗,底层 NBT 库负责解析 Minecraft 专有格式。下面我们一层一层看。
第一层:命令行入口regionfixer.py
regionfixer.py是整个工具的调度中心,它做了三件事:解析命令行参数、校验参数合法性、按顺序执行"扫描→删除→修复→输出报告"。
最值得新手学习的是它动态生成命令行参数的技巧。它没有把每个--fix-*参数写死,而是遍历constants.py里的"问题-方案"字典,自动拼接出参数名:
for solvable_status in c.CHUNK_PROBLEMS_SOLUTIONS: if c.CHUNK_SOLUTION_REMOVE in c.CHUNK_PROBLEMS_SOLUTIONS[solvable_status]: parser.add_argument('--delete-' + c.CHUNK_PROBLEMS_ARGS[solvable_status], '--d' + c.CHUNK_PROBLEMS_ABBR[solvable_status], help='[WARNING!] This option deletes! Delete all chunks with ' 'status: ' + c.CHUNK_STATUS_TEXT[solvable_status], action='store_true', default=False) if c.CHUNK_SOLUTION_REPLACE in c.CHUNK_PROBLEMS_SOLUTIONS[solvable_status]: parser.add_argument('--replace-' + c.CHUNK_PROBLEMS_ARGS[solvable_status], '--r' + c.CHUNK_PROBLEMS_ABBR[solvable_status], ...)我们来逐段理解这段代码:
CHUNK_PROBLEMS_SOLUTIONS是一个"问题 → 可选方案列表"的字典,例如损坏区块CHUNK_CORRUPTED对应[CHUNK_SOLUTION_REMOVE, CHUNK_SOLUTION_REPLACE],意思是它既可以被删除,也可以用备份替换。- 代码遍历这个字典,只要某种方案存在,就自动注册一个对应的命令行开关。于是
--delete-corrupted(缩写--dc)、--replace-corrupted(缩写--rc)这些参数就"凭空生成"了。 - 这样的设计好处非常明显:以后新增一种区块问题,只需要在
constants.py里加一行配置,命令行参数会自动同步,业务代码与参数定义解耦,维护成本极低。
紧接着的main()函数里还有一个很有意思的"修复/删除分发器",比如下面这个fix_bad_chunks,它把用户勾选的修复选项和可修复的问题一一配对:
options_fix = [options.fix_corrupted, options.fix_missing_tag, options.fix_wrong_located] fixing = list(zip(options_fix, c.FIXABLE_CHUNK_PROBLEMS)) for fix, problem in fixing: status = c.CHUNK_STATUS_TEXT[problem] total = scanned_obj.count_chunks(problem) if fix and total: counter = scanned_obj.fix_problematic_chunks(problem) print(("Repaired {0} chunks with status: {1}".format(counter, status)))zip把"用户是否勾选"和"问题编号"打包成对,然后逐个判断。count_chunks先统计有这种问题的区块数量,避免无谓操作。fix_problematic_chunks执行真正的修复,并返回成功数量。
这种"配置驱动 + 成对遍历"的写法在批量处理类工具中非常实用,值得写 Python 脚本的新手模仿。
第二层:核心逻辑regionfixer_core/
regionfixer_core目录是项目的"引擎室",包含scan.py(扫描)、world.py(数据模型)、constants.py(常量与配置)等模块。它们之间的关系是:
world.py定义数据模型:World(整个世界)、RegionSet(一组 region 文件)、ScannedRegionFile(单个 region 文件的扫描结果)、ScannedDataFile(level.dat / 玩家文件等)。scan.py负责干活:真正打开文件、解析数据、给每个区块"打分"。
先看world.py里的World类,它一初始化就会把世界目录下的各类文件"登记在册":
class World: def __init__(self, world_path): self.path = world_path self.regionsets = [] self.regionsets.append(RegionSet(join(self.path, "region"))) for directory in glob(join(self.path, "DIM*/region")): self.regionsets.append(RegionSet(directory, overworld=False)) self.regionsets.append(RegionSet(join(self.path, "poi"))) self.regionsets.append(RegionSet(join(self.path, "entities"))) # level.dat ... level_dat_path = join(self.path, "level.dat") if exists(level_dat_path): try: self.level_data = nbt.NBTFile(level_dat_path)["Data"] self.name = self.level_data["LevelName"].value ...- 代码用
glob通配符自动发现DIM*/region,所以主世界、下界、末地会被一次性全部纳入扫描范围,无需手动指定。 - 它还会读取
level.dat,从中提取世界名LevelName,这样报告里就能显示"正在扫描的世界叫什么"。 - 注意
try/except的写法:即使level.dat读不出来,程序也不会崩溃,而是把状态标记为DATAFILE_UNREADABLE继续运行——"不因单点失败而中断整体扫描"是这类工具的重要容错原则。
再看scan.py中真正"逐区块体检"的scan_region_file:
def scan_region_file(scanned_regionfile_obj, entity_limit, remove_entities): try: region_file = region.RegionFile(r.path) except region.NoRegionHeader: r.status = c.REGION_TOO_SMALL r.scanned = True return r except PermissionError: r.status = c.REGION_UNREADABLE_PERMISSION_ERROR r.scanned = True return r for x in range(32): for z in range(32): chunk, tup = scan_chunk(region_file, (x, z), g_coords, entity_limit) if tup: r[(x, z)] = tup- 首先尝试打开 region 文件并解析头部;如果文件太小连头部都没有,直接标记为
REGION_TOO_SMALL;如果是权限问题,则单独标记为权限错误——不同的失败原因被区分对待,方便用户对症下药。 - 然后双重循环遍历
32×32共 1024 个区块位置,逐一调用scan_chunk检查。 - 每个区块的检查结果以元组形式存进
ScannedRegionFile,后续统计、报告、修复全部基于这份"体检表"。
此外,scan.py还实现了基于multiprocessing的并行扫描(AsyncScanner类),通过-p参数可以指定同时使用的进程数,大世界扫描时能显著提速。
第三层:底层解析库nbt/
nbt目录是一个独立的 NBT 格式解析库,虽然它被 Region Fixer 使用,但本身是通用组件。nbt/region.py定义了 region 文件的读取与校验逻辑,其中对"区块数据异常"做了非常细的错误分类:
STATUS_CHUNK_OVERLAPPING = -5 # 区块与其它区块扇区重叠 STATUS_CHUNK_MISMATCHED_LENGTHS = -4 # 头部长度与实际长度不符 STATUS_CHUNK_ZERO_LENGTH = -3 # 区块头长度为0 STATUS_CHUNK_IN_HEADER = -2 # 区块数据落在头部区域内 STATUS_CHUNK_OUT_OF_FILE = -1 # 区块部分或完全超出文件同时它定义了压缩方式的常量(COMPRESSION_NONE、COMPRESSION_GZIP、COMPRESSION_ZLIB),因为 Minecraft 的不同版本、不同区块可能使用不同的压缩算法。这一层把"格式怎么解析"的脏活累活全部封装好,上层只需关心"这个区块健不健康"。
顺带一提,项目还附带
mutf8(Modified UTF-8 编解码)和progressbar(进度条)两个小模块,以及gui/(基于 wxPython 的图形界面)。如果你不想敲命令,regionfixer_gui.py也能提供可视化操作入口,核心逻辑与命令行版完全复用。
三、快速上手:环境要求、获取代码与最快配置方法
在动手运行之前,先确认环境,再选一种获取方式,最后用一条命令跑起来。
环境要求(先检查再动手)
- Python 版本:必须是Python 3.x。代码里有一道硬性检查,用 2.x 运行会直接报错退出:
if sys.version_info[0] != 3: print("Minecraft Region Fixer only works with python 3.x") return c.RV_CRASH- 操作系统:跨平台,Windows / Linux / macOS 均可;Windows 下建议从命令行(cmd 或 PowerShell)运行,而不是双击运行(项目专门做了"裸控制台"检测,双击运行会提示你去命令行执行)。
- 第三方库:核心功能使用 Python 标准库即可运行;GUI 模式需要
wxPython。项目根目录提供了setup.py,也可以用pip install -r requirements.txt安装依赖。
获取代码的两种方式
- 方式一(推荐,直接克隆):在终端执行
git clone https://gitcode.com/gh_mirrors/mi/Minecraft-Region-Fixer cd Minecraft-Region-Fixer- 方式二(离线使用):下载源码压缩包解压即可,项目结构很"扁平",不需要额外编译。
一条命令看懂全部参数
运行python regionfixer.py --help,你会看到所有可用参数。这里先记住最常用的几个:
| 参数 | 缩写 | 作用 |
|---|---|---|
--fix-corrupted | --fc | 尝试修复损坏区块(尽量提取可用数据) |
--fix-missing-tag | --fm | 修复缺失 Entities 标签的区块 |
--fix-wrong-located | --fw | 修复错误定位的区块 |
--delete-entities | --de | 删除实体过多的区块中的实体 |
--entity-limit | --el | 实体数量阈值,默认 300 |
--backups | -b | 指定备份世界目录(用于替换修复) |
--processes | -p | 并行扫描进程数,默认 1 |
--log | -l | 把扫描结果写入日志文件,-表示直接打印 |
--text-file-input | --tf | 从文本文件读取待扫描路径列表 |
新手最容易忽略的配置技巧:参数列表的末尾可以直接跟多个路径,既可以是世界文件夹,也可以是单个
*.mca文件,还可以混合输入。例如python regionfixer.py world1 DIM-1/region/r.-1.1.mca会同时扫描整个世界加一个单独的文件。
四、实战演练:一次完整的"扫描-修复-报告"工作流
纸上谈兵不如动手一次。下面我们用三种典型场景,演示 Region Fixer 的实际用法。
场景一:先体检,只扫描不修改(最安全)
第一次使用、或者只是想确认世界是否健康时,千万不要直接上修复参数,先做一次纯扫描:
python regionfixer.py --processes 4 --log scan_report.txt /home/user/.minecraft/saves/myworld参数逐个说明:
--processes 4:用 4 个进程并行扫描,世界很大时明显加快速度。--log scan_report.txt:把每个问题的详细清单(region 文件名、区块坐标、问题类型)写进文件,方便逐条核查。/home/user/.minecraft/saves/myworld:待扫描的世界目录,请替换成你自己的路径。
扫描结束后,程序会输出一份汇总报告,包含每个维度、每类问题的统计数字。只扫描不会改动任何文件,这一步即使反复运行也绝对安全。
场景二:修复"可救"的区块(核心用法)
当扫描确认存在损坏区块、缺失标签区块和错误定位区块后,可以尝试"就地修复":
python regionfixer.py --fix-corrupted --fix-missing-tag --fix-wrong-located /path/to/world--fix-corrupted会尝试从损坏区块中尽可能提取方块与实体数据,重新生成一个可用区块。--fix-missing-tag会为缺标签的区块补上Entities标签。--fix-wrong-located会把放错位置的区块挪回数据里记录的正确坐标。
这三种操作都是"尽量保留数据"的温和修复,是首选方案。
场景三:用备份替换 + 删除无法修复的区块
如果手头有同一世界的旧备份,可以用备份里完好的区块去替换坏区块,这是数据恢复效果最好的方式:
python regionfixer.py --replace-corrupted --replace-wrong-located \ --backups /path/to/old_backup_world /path/to/broken_world--replace-corrupted:用备份中对应位置的区块替换损坏区块。--backups:指定备份世界目录。注意:Region Fixer 不会校验备份是不是同一个世界,选错备份后果自负,务必确认后再执行。
对于那些备份里也没有、又修复不了的区块,最后的手段是删除,让 Minecraft 重新生成:
python regionfixer.py --delete-corrupted --delete-shared-offset /path/to/world删除会永久移除这些区块数据,区块位置会回归"未生成"状态,游戏进入该区域时会自动重新生成地形。
完整工作流建议:先扫描(场景一)→ 尝试修复(场景二)→ 有备份就替换(场景三)→ 实在不行再删除。修复手段从"最保留数据"到"最激进"依次升级,永远把数据安全放在第一位。
五、常见问题与避坑技巧
最后总结新手最容易踩的坑,以及对应的处理建议。
1. 运行前必须备份,没有例外
项目 README 里用了三个感叹号级别的警告:MAKE A BACKUP OF YOUR WORLD BEFORE RUNNING IT。删除类和替换类操作会直接改写文件,一旦执行不可逆。建议至少保留一份完整的region、entities、poi目录副本。可以顺手把备份路径记下来,因为它同时就是--backups参数要用的东西。
2. 为什么提示"没有可扫描的内容"?
程序返回RV_NOTHING_TO_SCAN通常有三种原因:
- 路径写错,目录下根本没有
region子目录或*.mca文件。 - 传入了文本文件列表(
--text-file-input),但文件里全是空行或#开头的注释行。 - 世界文件夹结构不完整。请确认目标目录里至少存在
region/目录。
3. 参数之间有哪些"硬约束"?
项目在main()里做了严格的参数互斥校验,新手经常在这里被拦下:
--replace-*系列参数必须搭配--backups使用,否则直接报错。--backups只能配合"扫描单个世界"使用;如果你同时传入了多个世界或多个独立 region 文件,会报错。--entity-limit不能为负数。- 删除类参数(
--delete-*)和替换类参数(--replace-*)不应混用在同一轮,建议分两次运行。
4. 扫描世界特别慢 / 内存占用高怎么办?
- 检查是不是存在"实体过多"的区块——解析成千上万实体的区块会消耗大量时间甚至数 GB 内存。
scan.py为此专门做了优化:一旦检测到超量实体,可以直接在扫描过程中顺手删除(--delete-entities),避免反复打开这个"毒区块"。 - 使用
--processes开启并行,例如--processes 4。注意并行扫描的输出是乱序的,配合--log把结果写文件更易读。
5. 修复后世界还是有问题怎么办?
Region Fixer 不是万能的,它对level.dat和玩家*.dat文件只做检查、不做修复(会打印警告)。如果问题集中在这些文件上,需要另寻方案。另外,不同 Minecraft 版本对损坏世界的容忍度不同,新版本游戏自身的恢复机制已经变强,但 Region Fixer 在"用备份替换区块、清理实体、诊断世界"这三件事上依然是社区里最趁手的工具之一。
写在最后:从"会用"到"会改"
回顾一下,我们沿着"问题定义(constants.py)→ 数据模型(world.py)→ 扫描诊断(scan.py)→ 命令行调度(regionfixer.py)→ 格式解析(nbt/)"这条主线,完整走通了 Minecraft-Region-Fixer 的核心链路。看懂这条链路之后,你甚至可以自己动手扩展它:在constants.py里新增一种区块问题、在scan.py里加一个新的检查规则、或者把nbt库单独抽出去做自己的存档分析工具。希望这篇源码导读能帮你从"玩家"进阶为"Minecraft 存档医生"。
【免费下载链接】Minecraft-Region-FixerPython script to fix some of the problems of the Minecraft save files (region files, *.mca).项目地址: https://gitcode.com/gh_mirrors/mi/Minecraft-Region-Fixer
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考