世界守护者

世界守护者

Hytale 服务器的智能分层备份保留策略。

实用

WorldKeeper

适用于 Hytale 服务器的智能分层备份保留系统。

问题所在

Hytale 默认的备份系统(AdminUI)每隔 X 分钟备份一次,并保留最近的 Y 份副本。以典型配置为例:每 30 分钟备份一次,保留 10 份,你只有 5 小时 的恢复窗口。如果问题在夜间未被发现,你最早的备份也已经被污染了。

WorldKeeper 如何解决

WorldKeeper 使用分层保留策略(祖-父-子),既保留频繁的近期备份,也保留较旧的恢复点:

层级 默认间隔 默认保留量 覆盖范围
快照 30 分钟 12 份 最近 6 小时
日备份 每日 7 份 最近 7 天
归档 每周 4 份 最近 4 周

总计:23 份备份(按每份 304 MB 计算约 7 GB),覆盖长达 4 周的历史记录。

新的备份始终以快照形式开始。当最早的快照超过 24 小时后,它会被提升为日备份;当最早的日备份超过 7 天后,它会被提升为归档。每个层级中多余的备份会被自动删除。所有间隔和保留数量均可配置。

功能特点

  • 分层保留 —— 快照、日备份和归档,自动提升
  • 网页仪表盘 —— 通过浏览器查看、下载、创建和删除备份
  • 活动配置显示 —— Web UI 精确显示当前配置,无需猜测
  • 前后钩子 —— 在每次备份前后运行服务器命令或 Shell 脚本
  • AdminUI 冲突检测 —— 启动时警告两个系统是否同时运行
  • 可配置恢复 —— 基于 Web 的恢复功能默认关闭,可通过配置开启

安装

前置要求

  • Java 21+
  • Maven 3.6+
  • Hytale 专用服务器

构建

# 将 Hytale 服务器 API 安装到本地 Maven 仓库(一次性设置)
mvn install:install-file \
  -Dfile=/path/to/HytaleServer.jar \
  -DgroupId=com.hypixel.hytale \
  -DartifactId=Server \
  -Dversion=0.0.1 \
  -Dpackaging=jar

# 构建模组
mvn clean package

输出:target/hytale-gfs-backup-1.0.0.jar

部署

# 复制到服务器模组文件夹
cp target/hytale-gfs-backup-1.0.0.jar /path/to/Server/mods/

# 重启 Hytale 服务器

首次启动时,WorldKeeper 会在 mods/com.gfsbackup_WorldKeeper/config.json 创建其配置文件。

禁用 AdminUI 备份

WorldKeeper 独立于内置的 AdminUI 备份系统运行。同时运行两者意味着两个系统会将备份写入同一个 backups/ 文件夹。如果检测到 AdminUI 备份仍处于启用状态,WorldKeeper 会在启动时记录一条警告。

要禁用 AdminUI 备份,请编辑 Server/AdminUI/Backup.json

{
  "enabled": false
}

配置

所有设置位于 mods/com.gfsbackup_WorldKeeper/config.json。首次运行时使用默认值创建。

{
  "enabled": true,
  "backupFolder": "backups",
  "worldFolder": "universe",
  "tiers": {
    "son": {
      "enabled": true,
      "intervalMinutes": 30,
      "retentionCount": 12,
      "description": "30-minute backups for 6 hours"
    },
    "father": {
      "enabled": true,
      "intervalMinutes": 1440,
      "retentionCount": 7,
      "description": "Daily backups for 7 days"
    },
    "grandfather": {
      "enabled": true,
      "intervalMinutes": 10080,
      "retentionCount": 4,
      "description": "Weekly backups for 4 weeks"
    }
  },
  "hooks": {
    "preBackup": [
      "say [WorldKeeper] Starting backup..."
    ],
    "postBackup": [
      "say [WorldKeeper] Backup complete!"
    ]
  },
  "webServer": {
    "enabled": true,
    "port": 8081,
    "allowRestore": false,
    "allowedIPs": []
  },
  "advanced": {
    "serverSaveBeforeBackup": true,
    "deleteEmptyBackups": true,
    "asyncBackup": true
  }
}

配置参考

默认值 描述
enabled true 整个模组的总开关
backupFolder "backups" 备份 ZIP 文件存放目录,相对于 Server/
worldFolder "universe" 要备份的世界目录,相对于 Server/

层级

配置内部使用 sonfathergrandfather。它们在 Web UI 中对应 快照日备份归档

描述
enabled 启用/禁用此层级
intervalMinutes 备份运行的频率(son 层级驱动调度器)
retentionCount 此层级中保留的最大备份数量

Web 服务器

默认值 描述
enabled true 启用 Web UI
port 8081 Web UI 的 HTTP 端口
allowRestore false 允许从 Web UI 恢复备份
allowedIPs [] IP 白名单(空列表 = 允许所有 IP)

高级设置

默认值 描述
serverSaveBeforeBackup true 备份前将世界数据刷新到磁盘
deleteEmptyBackups true 删除 0 字节的备份
asyncBackup true 异步运行备份

Web UI

通过 http://localhost:8081(或你配置的端口)访问仪表盘。

  • 每个层级的备份表格,表头显示活动配置(例如:"快照 -- 每 30 分钟,保留 12 份")
  • 可折叠的配置面板,显示完整的活动配置
  • 总计备份数量、大小和上次备份时间
  • 创建、下载和删除备份
  • 恢复备份(当 allowRestore 启用时)
  • 每 30 秒自动刷新

REST API

端点 方法 描述
/api/backups GET 列出所有备份及统计信息和配置
/api/backups/create POST 触发手动备份
/api/backups/download/:filename GET 下载备份 ZIP 文件
/api/backups/restore/:filename POST 恢复备份(需要 allowRestore 为 true)
/api/backups/delete/:filename DELETE 删除备份

钩子

钩子可以在每次备份前后运行服务器命令或系统命令。

  • say/ 开头的行作为 服务器命令 执行
  • 所有其他行作为 系统命令 通过 Shell 执行(30 秒超时)

变量替换

变量 描述
{{backup_file}} 备份 ZIP 文件的完整路径
{{backup_filename}} 仅文件名(例如 2026-02-01_09-31-10.zip
{{backup_tier}} 层级名称(SONFATHERGRANDFATHER
{{backup_size}} 文件大小(字节)

示例

{
  "hooks": {
    "preBackup": [
      "say [WorldKeeper] Starting world backup..."
    ],
    "postBackup": [
      "say [WorldKeeper] Complete!",
      "/usr/local/bin/notify-discord.sh 'Backup done: {{backup_filename}} ({{backup_tier}})'"
    ]
  }
}

恢复备份

备份是 universe/ 目录的 ZIP 压缩包,包含世界、区块、玩家数据、传送点和记忆。

手动恢复过程:

  1. 停止 Hytale 服务器
  2. 重命名或移动当前的 Server/universe/ 目录
  3. 将备份 ZIP 解压到 Server/(它将重新创建 universe/ 文件夹)
  4. 启动服务器

Web UI 的恢复功能(通过 allowRestore 启用)会安全地将备份解压到 temp-restore/ 目录。你仍然需要手动交换文件夹并重启服务器。

存储估算

存储空间取决于你的世界大小。假设世界大小约为 304 MB:

配置文件 快照 日备份 归档 总计
默认 12 (3.6 GB) 7 (2.1 GB) 4 (1.2 GB) 约 7 GB
激进 6 (1.8 GB) 3 (0.9 GB) 2 (0.6 GB) 约 3.3 GB
保守 24 (7.3 GB) 14 (4.3 GB) 8 (2.4 GB) 约 14 GB

项目结构

src/main/
├── java/com/gfsbackup/hytale/
│   ├── GFSBackupPlugin.java        # 插件生命周期
│   ├── config/
│   │   ├── BackupConfig.java       # 配置 POJO
│   │   └── ConfigManager.java      # JSON 加载/保存
│   ├── backup/
│   │   ├── BackupManager.java      # 备份创建/恢复/删除
│   │   ├── ZipUtility.java         # ZIP 压缩 + 校验和
│   │   └── HookExecutor.java       # 前后钩子执行
│   ├── retention/
│   │   ├── BackupTier.java         # SON/FATHER/GRANDFATHER 枚举
│   │   ├── BackupMetadata.java     # 每份备份的元数据
│   │   ├── BackupIndex.java        # 索引持久化
│   │   └── RetentionPolicy.java    # GFS 提升 + 清理
│   ├── scheduler/
│   │   └── BackupScheduler.java    # ScheduledExecutorService 定时器
│   └── web/
│       ├── WebServer.java          # 嵌入式 Jetty 设置
│       └── servlets/               # REST API 处理器
└── resources/
    ├── manifest.json               # Hytale 模组清单
    ├── default-config.json         # 默认配置模板
    └── webapp/                     # Web UI (HTML/CSS/JS)

安全性

WorldKeeper 运行一个 无认证 的 HTTP 服务器。任何能够访问该端口的人都可以查看、创建、下载和删除你的备份。请谨慎对待。

让端口远离公共互联网

最重要的一点:不要将 8081 端口(或你配置的任何端口)暴露到互联网上。 你的防火墙应该阻止来自外部流量的访问。如果你需要远程访问,请使用以下方式之一:

  • SSH 隧道ssh -L 8081:localhost:8081 user@your-server,然后在本地打开 http://localhost:8081
  • 带认证的反向代理:在 Nginx/Caddy 前面加上 HTTP Basic 认证或 SSO

IP 白名单

WorldKeeper 支持可选的 IP 白名单。默认情况下列表为空,这意味着所有 IP 都被允许。 如果你向列表中添加 IP,则只有这些地址可以访问 Web UI——其他所有请求都会收到 403 Forbidden 并记录警告。

要将其限制为仅本地访问:

{
  "webServer": {
    "allowedIPs": ["127.0.0.1"]
  }
}

要允许特定 IP:

{
  "webServer": {
    "allowedIPs": ["127.0.0.1", "192.168.50.10"]
  }
}

注意:白名单检查的是精确 IP 匹配。它不支持 CIDR 范围——请逐个列出每个 IP,或者使用反向代理来处理更复杂的规则。

如果暴露可能存在的风险

端点 风险
POST /api/backups/create 通过备份垃圾请求耗尽磁盘空间
DELETE /api/backups/delete/* 所有备份被删除
GET /api/backups/download/* 世界数据被窃取
POST /api/backups/restore/* 触发恢复操作(如果 allowRestore 已开启)

建议

  • 保持 allowRestore 设置为 false,除非你确实需要它
  • 监控磁盘使用情况——即使有保留限制,快速的重复备份创建也可能在清理程序运行前填满磁盘
  • 检查服务器日志中的 "Blocked request from unauthorized IP" 警告——如果你看到它们,说明有人在探测这个端口

使用 Claude Code 构建

本模组使用 Claude Code 构建。我们包含了该过程中的制品,以便你了解其过程并根据自己的项目进行调整:

  • PLAN.md —— 在生成任何代码之前编写和批准的全部实施计划。一些细节在实施过程中有所变化(错误的 Java 版本、错误的 Jetty 依赖名称、未记录的插件 API 怪癖),但整体架构得以保持。
  • PROMPT.md —— 一个可复用的提示词,你可以将其提供给大语言模型,为自己的游戏服务器构建类似工具,以及关于哪些方法有效、需要注意什么的提示。

技术栈

  • Java 21
  • Hytale 服务器 API
  • 嵌入式 Jetty 12.1.4(Web 服务器)
  • Gson(JSON 序列化)
  • Maven 及 shade 插件(生成 Uber JAR)

许可证

MIT