news 2026/9/14 19:08:59

docker-minecraft-server 世界数据管理:存档下载、容器内克隆与 Datapack/VanillaTweaks 自动化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
docker-minecraft-server 世界数据管理:存档下载、容器内克隆与 Datapack/VanillaTweaks 自动化

docker-minecraft-server 世界数据管理:存档下载、容器内克隆与 Datapack/VanillaTweaks 自动化

【免费下载链接】docker-minecraft-serverDocker image that provides a Minecraft Server for Java Edition that automatically installs/upgrades versions, modloaders, modpacks and more at startup项目地址: https://gitcode.com/GitHub_Trending/do/docker-minecraft-server

本篇指南基于 docker-minecraft-server 项目的docs/misc/world-data.md文档展开,讲解如何通过WORLDFORCE_WORLD_COPY等环境变量从 URL 下载或从容器路径克隆 Minecraft 存档,如何为 Multiverse 等场景自定义世界目录,以及DATAPACKS与 VanillaTweaks 两类数据包的安装与清理机制。结合 scripts/start-setupWorld 与 scripts/start-setupDatapack 的源码实现,读者可以完整掌握该镜像“启动时自动准备世界数据”这一能力的全部参数与底层行为。

WORLD:世界数据的三种来源

世界数据的准备工作由 scripts/start-setupWorld 脚本执行。脚本首先确定目标世界目录(源码第 12–20 行):

  • LEVEL为绝对路径时,目标目录就是LEVEL本身;
  • TYPECURSEFORGE时,目标目录为$FTB_DIR/${LEVEL:-world}
  • 其余情况默认为/data/${LEVEL:-world},即世界存放在/data/下以LEVEL命名的子目录中(LEVEL默认值为world)。

在此之上,WORLD变量支持三种输入形态:可访问的 URL容器内的 zip/压缩 tar 归档文件容器内的目录

从 URL 下载存档压缩包

不挂载/data卷时,可以指定一个包含存档的 ZIP 或压缩 TAR 文件的 URL。镜像会先搜索文件level.dat,再把其所在的子目录整体移动到$LEVEL指定的目录中——这意味着绝大多数可从互联网下载的存档已经天然符合格式要求:

docker run -d -e WORLD=http://www.example.com/worlds/MySave.zip ...

两点注意事项(原文档明确强调):

  1. 该 URL 必须能从容器内部访问。因此应使用 IP 地址、可全局解析的 FQDN,或已链接容器的名称,而不是仅宿主机可解析的名称。
  2. 如果归档中包含多个level.dat,可以用WORLD_INDEX选择要取的那一份,默认值为 1。

对照 scripts/start-setupWorld 的源码,URL 分支的处理流程是:下载到临时文件/data/tmp/world.zipworldDownload变量),下载失败则logErrorexit 1,随后把WORLD重定向为该本地临时文件,走统一的解压路径。

从容器内目录或压缩包克隆

WORLD也可以指向容器内的目录、zip 文件或压缩 tar 文件,作为克隆或提取世界目录的来源。以下示例首次启动时会从/worlds/basic克隆世界内容;注意示例使用了只读卷挂载:ro)来保证克隆源保持原样不被修改:

docker run ... -v $HOME/worlds:/worlds:ro -e WORLD=/worlds/basic

在 compose 部署中配合相对目录同样成立,上文图片即演示了这种“宿主机相对目录 → 只读卷 → 容器内WORLD路径”的部署关系。仓库中的测试用例 tests/setuponlytests/world_from_zip/docker-compose.yml 展示了最典型的组合:

environment: EULA: "TRUE" SETUP_ONLY: "TRUE" WORLD: /worlds/world-for-testing.zip volumes: - ./worlds:/worlds:ro - ./data:/data

SETUP_ONLY: "TRUE"让容器只执行启动准备阶段而不真正拉起服务器,便于验证世界是否被正确解压。

解压、选择与维度目录重组

源码 scripts/start-setupWorld 对归档解压后的处理逻辑值得深入理解:

  1. 定位世界根:把归档内容暂存到/data/tmp/world-datatmpWorldData),执行find ... -name "level.dat" -exec dirname找出所有含level.dat的目录;一个都找不到则报错exit 2(“World content is not valid since level.dat could not be found”)。
  2. 多存档消歧:当发现多个level.dat时,先用sed去掉_nether/_the_end后缀去重;若去重后只剩一个,说明这是Spigot 命名约定的同一份世界(world/world_nether/world_the_end/),直接取主维度目录。否则按WORLD_INDEX(默认第 1 个)选取并打印警告 “Multiple levels found, picking: ...”。
  3. 维度目录冲突消解:若同时存在world/DIM-1world_nether/DIM-1(或world/DIM1world_the_end/DIM1),保留_nether/_the_end侧并删除另一侧,避免重复维度数据。
  4. 拷贝落地:用rsync --remove-source-files --recursive --delete "$baseDir/" "$worldDest"将选中的世界根同步到目标目录。
  5. 跨家族布局转换:这是该脚本最有价值的细节之一。
    • FAMILY = SPIGOT(Spigot/Paper/Purpur 等):存在world_nether则一并复制到$worldDest_nether;否则若目标里已有DIM-1,会把它移动到$worldDest_nether/DIM1同理移动到$worldDest_the_end/
    • 若目标是原生布局:world_nether/DIM-1会被复制回$worldDest/DIM-1world_the_end/DIM1同理。

也就是说,vanilla 命名(DIM-1/DIM1)与 Spigot 命名(world_nether/world_the_end)的存档可以互相导入,镜像会自动转换维度目录位置。脚本末尾还会把DIM1/DIM-1统一搬移到 Spigot 位置(第 127–132 行),并在最外层清理/data/tmp/world.zip/data/tmp/world-data临时产物。

仓库内的验证测试印证了上述行为:tests/setuponlytests/vanilla_world_for_vanilla_server/verify.sh 断言 vanilla 服务器下world/level.datworld/DIM-1/some_nether_fileworld/DIM1/some_end_file均存在,而spigot_world_for_spigot_server等用例则覆盖 Spigot 布局的转换。

FORCE_WORLD_COPY:每次启动强制覆盖世界

默认情况下,世界只在目标目录不存在时才执行下载或克隆(源码第 22 行的判断条件:isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ])。设置FORCE_WORLD_COPY=TRUE可强制在每次服务器启动时覆盖世界。

从源码看(scripts/start-setupWorld),强制覆盖并非简单复制,而是先整体删除三处目录:$worldDest${worldDest}_nether${worldDest}_the_end,再重新从WORLD源提取——这保证了旧的_nether/_the_end维度残留不会与新世界混合。

适用场景是“以某个远程存档为唯一事实来源、本地变更不保留”的部署模式;反过来,若希望存档持久化并可编辑,应只挂载/data卷而不设该变量。

EXTRA_ARGS 自定义世界目录(--world-dir)

对于在裸金属服务器上给 Multiverse 插件设置自定义世界目录,通常要在 jar 文件后传--world-dir参数。容器化场景下,等效做法是通过EXTRA_ARGS环境变量传入同样的参数字符串:

docker run -d -e EXTRA_ARGS='--world-dir ./worlds/'

--world-container-W--universe--world-dir的别名,同样可用。

EXTRA_ARGS的官方定义见 docs/variables.md 第 151 行附近:“Arguments that would usually be passed to the jar file (those which are written after the filename)”——即所有会写在 jar 文件名之后的参数。这一通道对“插件自定义参数”类需求是通用入口,世界目录只是其中一种典型用法。

DATAPACKS:数据包的下载、安装与清理

Datapack 的安装方式与 mod/plugin 类似(参见 docs/mods-and-plugins/index.md),相关环境变量如下:

变量说明
DATAPACKS逗号分隔列表,每项为 zip 文件 URL、容器内 zip 文件或容器内目录
DATAPACKS_FILE容器内的文本文件,每行一个 zip URL / 容器内 zip 文件 / 容器内目录
REMOVE_OLD_DATAPACKS设为true时,删除数据包目录中匹配REMOVE_OLD_DATAPACKS_INCLUDE且不属于REMOVE_OLD_DATAPACKS_EXCLUDE、深度不超过REMOVE_OLD_DATAPACKS_DEPTH的内容
REMOVE_OLD_DATAPACKS_DEPTH默认 16
REMOVE_OLD_DATAPACKS_INCLUDE默认*.zip
REMOVE_OLD_DATAPACKS_EXCLUDE默认为空

数据包最终安装在/data/$LEVEL/datapacks

实现位于 scripts/start-setupDatapack,源码可补充几个文档未展开的细节:

  • DATAPACKS的逐项处理(第 25–56 行):isURL判断为 URL 时经get下载到目标目录;为容器内*.zip文件时直接cp;为目录时若含pack.mcmeta则整个目录复制(视作单个数据包),否则复制目录下的*.zip;都不满足则报错exit 2
  • DATAPACKS_FILE的批量处理(第 57–82 行):使用get --uris-file批量下载,并带--skip-existing跳过已存在文件;当REMOVE_OLD_DATAPACKS=true时附加--prune-others ${REMOVE_OLD_DATAPACKS_INCLUDE}--prune-depth ${REMOVE_OLD_DATAPACKS_DEPTH},即下载与剪枝一步完成。
  • 清理行为的适用边界:从源码结构看,第 19 行的find ... -delete清理分支仅在DATAPACKS_FILE为空时执行;DATAPACKS_FILE路径下的清理则走上述--prune-*参数。两条路径的语义一致(按 include/exclude/depth 清理旧包),但触发条件不同。
  • 变量默认值在脚本头部声明:REMOVE_OLD_DATAPACKS默认falseREMOVE_OLD_DATAPACKS_INCLUDE默认*.zipREMOVE_OLD_DATAPACKS_EXCLUDE默认空,REMOVE_OLD_DATAPACKS_DEPTHfind回退值为 16,与文档声明一致。

VanillaTweaks:分享码与 JSON 包文件

VanillaTweaks 风格的数据包、crafting tweaks 与资源包,可通过网站分享码指定包下载安装的 JSON 文件来安装。Datapack 与 crafting tweaks 会安装到$LEVEL指定的当前世界目录;当获取到新版本的包时,旧版本会被自动清理。

分享码取自 URL 中#之后的部分:

https://vanillatweaks.net/share/#MGr52E ------ | +- share code MGr52E

接受的参数:

  • VANILLATWEAKS_FILE:逗号分隔的、容器内可访问的 JSON 包文件列表
  • VANILLATWEAKS_SHARECODE:逗号分隔的分享码列表

注意:ResourcePacks、DataPacks 与 CraftingTweaks 各自拥有独立的分享码,例如三个代码并存时:

VANILLATWEAKS_SHARECODE: MGr52E,tF1zL2,LnEDwT

使用 JSON 文件时,例如挂载三类配置文件:

VANILLATWEAKS_FILE: /config/vt-datapacks.json,/config/vt-craftingtweaks.json,/config/vt-resourcepacks.json

JSON 文件需声明typeversionpacks(按类别分组的包名列表)。三种类型的示例如下:

DataPacks json:

{ "type": "datapacks", "version": "1.21", "packs": { "gameplay changes": [ "graves", "multiplayer sleep", "armored elytra" ], "teleport commands": ["tpa"] } }

ResourcePacks json:

{ "type": "resourcepacks", "version": "1.21", "packs": { "aesthetic": ["CherryPicking", "BlackNetherBricks", "AlternateBlockDestruction"] } }

CraftingTweaks json:

{ "type": "craftingtweaks", "version": "1.21", "packs": { "quality of life": [ "dropper to dispenser", "double slabs", "back to blocks" ] } }

两个实用提示:

  • 数据包名称全部为小写;包名与类别的完整清单以该网站的规格说明为准(文档中引用了 1.21 版本的 dpcategories / ctcategories 规格)。
  • 仓库示例 examples/vanilla-tweaks/docker-compose.yml 展示了三种用法(纯文件、纯分享码、文件三类合一)并行运行的完整 compose 编排,且统一搭配了REMOVE_OLD_VANILLATWEAKS: "TRUE"与只读挂载:ro的 JSON 配置卷;配套的 vanillatweaks-datapacks.json 还包含一个"result": "ok"字段,是工具链对处理结果的记录。

实现上,当VANILLATWEAKS_FILEVANILLATWEAKS_SHARECODE任一非空时,scripts/start-setupDatapack 会调用mc-image-helper vanillatweaks子命令,参数为--output-directory=/data--world-subdir=${LEVEL:-world}--share-codes--pack-files,即实际的包解析、下载与旧版本清理由镜像内置 helper 完成,shell 脚本只负责传参。

测试用例 tests/setuponlytests/vanilla-tweaks-sharecode/verify.sh 验证了分享码安装后的落盘结果:

mc-image-helper assert fileExists "/data/world/datapacks/afk*" mc-image-helper assert fileExists "/data/world/datapacks/graves*" mc-image-helper assert fileExists "/data/world/datapacks/VanillaTweaks_488158f.zip" mc-image-helper assert fileExists "/data/resourcepacks/VanillaTweaks_d1d810f.zip"

可以看出:datapack 落在/data/world/datapacks(与/data/$LEVEL/datapacks规则一致),而资源包落在/data/resourcepacks

小结

围绕世界数据,该镜像在启动阶段按start-setupWorldstart-setupDatapackstart-setupModpack的顺序串联处理(两个脚本末尾均以exec衔接到下一个阶段)。核心要点可归纳为:

  • WORLD接受 URL、容器内归档或目录三种来源,按level.dat定位世界根,支持WORLD_INDEX多存档选择,并自动完成 vanilla/Spigot 维度目录布局的双向转换;
  • FORCE_WORLD_COPY=TRUE触发启动前对$worldDest_nether_the_end三目录的整体清除重建;
  • LEVEL决定世界落盘位置(默认/data/world,CURSEFORGE 类型位于$FTB_DIR下,绝对路径LEVEL则直接作为目标目录);
  • EXTRA_ARGS是把--world-dir等 jar 后置参数传入容器的通用通道;
  • DATAPACKS/DATAPACKS_FILE负责数据包的安装,REMOVE_OLD_DATAPACKS*系列变量控制旧包清理的匹配、排除与深度;
  • VanillaTweaks 分享码与 JSON 包文件通过mc-image-helper vanillatweaks完成解析、安装与旧版本清理,datapack 入/data/$LEVEL/datapacks,资源包入/data/resourcepacks

【免费下载链接】docker-minecraft-serverDocker image that provides a Minecraft Server for Java Edition that automatically installs/upgrades versions, modloaders, modpacks and more at startup项目地址: https://gitcode.com/GitHub_Trending/do/docker-minecraft-server

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 19:08:26

Linux设备驱动开发实战:字符设备框架、设备树与中断处理详解

做Linux驱动开发这行也有十几年了,从最早的2.6内核一路折腾到现在的6.x,踩过的坑比我写过的代码还多。最近带了好几个新人,发现大家拿到“Linux设备驱动开发”这个题目,第一反应都是去啃《Linux设备驱动开发详解》那本大部头&…

作者头像 李华
网站建设 2026/9/14 19:08:17

Obtainium 如何用 standardize.mjs 同步各语言翻译文件的键?

Obtainium 如何用 standardize.mjs 同步各语言翻译文件的键? 【免费下载链接】Obtainium Get Android app updates straight from the source. 项目地址: https://gitcode.com/GitHub_Trending/ob/Obtainium Obtainium 是一个 Flutter(Android-fi…

作者头像 李华
网站建设 2026/9/14 19:07:45

Telegraf TopK 处理器深度解析:按聚合函数筛选 Top N 指标序列

Telegraf TopK 处理器深度解析:按聚合函数筛选 Top N 指标序列 【免费下载链接】telegraf Agent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data. 项目地址: https://gitcode.com/GitHub_Trending/te/telegraf …

作者头像 李华