PackSync
轻量级资源包同步插件 — 群组服跨子服自动同步 CraftEngine 资源包
为什么需要 PackSync?
在群组服架构中,CraftEngine 资源包通常只在主城服(开发服)上生成。但登录服等其他子服也需要向玩家分发相同的资源包。PackSync 解决了这个痛点:
- 主城服修改资源包后,自动检测变化并复制到所有子服
- 子服收到文件后,自动执行
ce upload上传给在线玩家 - 全程无需人工干预,无需重启服务器
核心功能
安装与部署
环境要求
| 项目 | 要求 |
|---|---|
| 服务端 | Paper / Purpur / Spigot 1.21+ |
| Java | Java 21+ |
| 必须依赖 | 无 |
| 可选依赖 | CraftEngine (资源包来源) |
群组服部署方案
以典型的 登录服 + 主城服 群组为例:
主城服 (Sender) 登录服 (Receiver)
┌─────────────────┐ ┌─────────────────┐
│ CraftEngine │ │ CraftEngine │
│ ↓ 生成资源包 │ PackSync │ ↓ 收到新文件 │
│ resource_pack.zip│ ──复制文件──→ │ resource_pack.zip│
│ │ ──信号文件──→ │ .packsync_signal │
│ PackSync=sender │ │ PackSync=receiver│
└─────────────────┘ │ ↓ 执行 ce upload │
└─────────────────┘安装步骤
1. 主城服 (Sender)
- 将
PackSync-1.0.0.jar放入plugins/ - 启动服务器,自动生成
config.yml - 编辑配置:设置
role: sender - 配置
sender.targets列表,填入登录服资源包的绝对路径 - 执行
/packsync reload
2. 登录服 (Receiver)
- 将
PackSync-1.0.0.jar放入plugins/ - 启动服务器,自动生成
config.yml - 编辑配置:设置
role: receiver - 确认
receiver.command为ce upload(或你的上传命令) - 执行
/packsync reload
targets 路径必须是绝对路径,且 Sender 服务器进程需要对目标目录有写入权限。同一台物理机上的多个子服可以直接使用本地路径。Sender 发送端
Sender 模式运行在资源包的生产端(通常是主城服),负责检测文件变化并同步到所有目标子服。
工作流程
- 插件启动时,计算源文件的 SHA-1 哈希作为基准
- 定时任务每 N 秒 (默认10秒) 重新计算哈希
- 若哈希值发生变化 → 触发同步
- 异步复制文件到所有
targets目标路径 - 在每个目标路径的同级目录放置
.packsync_signal信号文件 - 信号文件内容为当前时间戳,供 Receiver 端检测
配置项
| 配置 | 说明 | 默认值 |
|---|---|---|
sender.source | 源资源包路径 (相对服务器根目录) | ./plugins/CraftEngine/generated/resource_pack.zip |
sender.targets | 目标路径列表 (绝对路径) | [] |
sender.auto-sync | 是否启用自动同步 | true |
sender.watch-interval | 检查间隔 (秒) | 10 |
配置示例
role: sender
sender:
source: "./plugins/CraftEngine/generated/resource_pack.zip"
targets:
- "D:/Server/登录服/plugins/CraftEngine/generated/resource_pack.zip"
- "D:/Server/资源服/plugins/CraftEngine/generated/resource_pack.zip"
auto-sync: true
watch-interval: 10
手动同步
执行 /packsync sync 可立即触发一次同步,不需要等待文件变化。
Receiver 接收端
Receiver 模式运行在资源包的分发端(通常是登录服),负责检测信号文件并执行上传命令。
工作流程
- 定时任务每 N 秒 (默认5秒) 检查信号文件是否存在
- 检测到
.packsync_signal→ 读取并删除信号文件 - 等待配置的延迟时间 (默认3秒,确保文件写入完成)
- 在主线程执行控制台命令 (默认
ce upload) - CraftEngine 重新上传资源包,在线玩家收到新资源包
配置项
| 配置 | 说明 | 默认值 |
|---|---|---|
receiver.command | 收到信号后执行的控制台命令 | ce upload |
receiver.check-interval | 信号检查间隔 (秒) | 5 |
receiver.command-delay | 执行命令前的延迟 (秒) | 3 |
配置示例
role: receiver
receiver:
command: "ce upload"
check-interval: 5
command-delay: 3
信号文件
信号文件 .packsync_signal 位于 sender.source 配置指向的资源包同目录下。文件内容为毫秒时间戳,仅用于触发通知,读取后自动删除。
sender.source 路径 (虽然不作为发送方使用),因为信号文件的位置基于该路径推算。命令
命令列表
| 命令 | 说明 | 权限 |
|---|---|---|
/packsync sync | 手动触发资源包同步 (仅 Sender 模式) | packsync.admin |
/packsync status | 查看当前状态 (模式/文件/哈希/目标数等) | packsync.admin |
/packsync reload | 重载配置文件并重新初始化 | packsync.admin |
/packsync | 显示帮助信息 | packsync.admin |
/packsync 可缩写为 /ps 或 /rpsyncsync 详解
在 Sender 模式下,立即将源文件复制到所有目标路径。会显示每个目标的成功/失败状态及文件大小。
/packsync sync
[PackSync] 开始同步资源包 (12.3 MB)...
[PackSync] ✔ 1.登录服 [ 30000 ]
[PackSync] 同步完成! 成功: 1, 失败: 0
status 详解
显示当前插件状态,Sender 和 Receiver 模式显示不同信息:
Sender 模式
=== PackSync 状态 ===
模式: sender
源文件: D:\Server\主城服\plugins\CraftEngine\generated\resource_pack.zip
文件存在: 是
文件大小: 12.3 MB
SHA-1: 3a7f8b2c1d9e...
目标数: 1
自动同步: 开启
Receiver 模式
=== PackSync 状态 ===
模式: receiver
信号文件: D:\Server\登录服\plugins\CraftEngine\generated\.packsync_signal
执行命令: ce upload
信号存在: 否
配置文件
完整 config.yml
# ============================================
# PackSync v1.0.0 配置文件
# 轻量级资源包同步插件
# ============================================
# 角色模式
# sender - 资源包生产端 (主城服等, 负责CE开发)
# receiver - 资源包接收端 (登录服等, 负责向玩家分发)
role: sender
# ===== Sender (发送端) 配置 =====
sender:
# CE生成的资源包路径 (相对于服务器根目录)
source: "./plugins/CraftEngine/generated/resource_pack.zip"
# 同步目标列表 (使用绝对路径, 指向目标服的CE generated目录)
targets:
- "D:/Server/登录服/plugins/CraftEngine/generated/resource_pack.zip"
# CE生成资源包后自动同步 (监听文件变化)
auto-sync: true
# 自动同步检查间隔 (秒)
watch-interval: 10
# ===== Receiver (接收端) 配置 =====
receiver:
# 检测到同步信号后执行的控制台命令
command: "ce upload"
# 信号检查间隔 (秒)
check-interval: 5
# 执行命令前的延迟 (秒, 等待文件写入完成)
command-delay: 3
配置项速查
| 配置项 | 类型 | 说明 | 默认值 |
|---|---|---|---|
role | String | 工作模式: sender 或 receiver | sender |
sender.source | String | 源资源包路径 (相对服务器根目录) | ./plugins/CraftEngine/generated/resource_pack.zip |
sender.targets | List | 目标文件绝对路径列表 | [] |
sender.auto-sync | Boolean | 是否启用定时自动检测 | true |
sender.watch-interval | Integer | 自动检测间隔 (秒) | 10 |
receiver.command | String | 收到信号后执行的命令 | ce upload |
receiver.check-interval | Integer | 信号文件检查间隔 (秒) | 5 |
receiver.command-delay | Integer | 执行命令前延迟 (秒) | 3 |
权限
| 权限 | 说明 | 默认 |
|---|---|---|
packsync.admin | 允许使用所有 PackSync 管理命令 | op |
架构原理
设计理念
PackSync 采用无中心化的文件信号机制,避免引入额外的消息队列或数据库依赖:
- 文件复制: Sender 直接通过文件系统复制文件到目标路径
- 信号通知: 在目标目录创建
.packsync_signal文件通知 Receiver - 变化检测: SHA-1 哈希比对,只有文件内容真正变化才触发同步
SHA-1 哈希检测
Sender 启动时计算源文件的完整 SHA-1 哈希作为基准值。定时任务每次重新读取文件并计算哈希,与基准值比对:
- 哈希相同 → 文件未变化,跳过
- 哈希不同 → 文件已更新,触发同步并更新基准值
信号文件协议
| 属性 | 说明 |
|---|---|
| 文件名 | .packsync_signal |
| 位置 | 与资源包同目录 (如 plugins/CraftEngine/generated/) |
| 内容 | Unix 毫秒时间戳 (如 1712649600000) |
| 生命周期 | Sender 创建 → Receiver 读取后立即删除 |
异步处理
以下操作全部在异步线程执行,不阻塞服务器主线程:
- SHA-1 哈希计算
- 文件复制 (
Files.copy) - 信号文件读写
唯一在主线程执行的操作是 Receiver 的控制台命令 (Bukkit.dispatchCommand),因为 Bukkit API 要求命令在主线程执行。
适用场景与限制
| ✅ 适用 | ❌ 不适用 |
|---|---|
| 同一台物理机上的多个子服 | 跨物理机/跨网络的服务器 |
| CraftEngine 资源包同步 | 需要双向同步的场景 |
| 少量大文件 (资源包) | 大量小文件同步 |
常见问题
Q: Sender 和 Receiver 可以在同一个服务器上吗?
不可以。每个服务器实例只能配置一种模式。如果主城服同时也需要接收资源包更新,那它应该设为 sender 模式(因为它就是生产端)。
Q: 源文件不存在怎么办?
Sender 启动时会输出警告日志。自动同步任务会跳过不存在的文件。CraftEngine 首次生成资源包后,PackSync 会自动检测到并开始同步。
Q: 目标目录不存在会报错吗?
不会。PackSync 会自动创建目标文件的父目录 (Files.createDirectories)。
Q: 同步大文件时会卡服吗?
不会。文件复制和哈希计算全部在 BukkitScheduler.runTaskAsynchronously 中执行,不占用主线程。
Q: Receiver 的 command 可以是多条命令吗?
目前只支持单条命令。如需多条命令,建议用另一个插件(如 TrMenu/DeluxeMenus)包装成一条,或修改源码。
Q: 如何增加新的目标子服?
编辑 Sender 的 config.yml,在 sender.targets 列表中添加新路径,然后执行 /packsync reload 即可。
Q: 检查间隔设多少合适?
- Sender: 10-30 秒。资源包不会频繁变化,无需太高频率
- Receiver: 3-5 秒。信号文件检测开销极小,可以更频繁