FastSync
FastSync 跨服玩家数据同步插件
新一代跨服玩家数据同步插件,只服务高版本 Paper 系服务端,更轻量、更稳、根治"损坏物品导致进不去服 / 物品被删"的老大难问题。
FastSync 是 InvSync 作者面向 Minecraft 1.20.1+ 打造的下一代同步方案。它抛掉了老架构里为了兼容 1.12 一路背到今天的历史包袱(多版本反射、NBTAPI、Redis 硬依赖等),围绕两件事重做:让玩家出生的那一刻数据就已经在身上了,以及再脏的物品也绝不把你的数据搞丢。
🎯 FastSync 是什么 / 定位
- 新一代跨服同步:背包、末影箱、状态、经验、统计、成就、PDC、扩展数据在多个子服之间无缝流转。
- 只支持高版本、更轻量:面向 1.20.1+,不再兼容低版本,砍掉 NBTAPI、Kryo、MongoDB 驱动等一大堆 shade 依赖,产物更小、启动更快。
- 无 Redis:只要一个 MySQL 就能跑起来一个跨服网络,部署门槛大幅降低。
- 根治损坏物品问题:把"未知附魔 / 组件损坏导致反序列化失败"这类问题做成了净化 + 隔离 + 复活的完整闭环,原始数据永不被覆盖丢弃。
FastSync 与 InvSync 是两条产品线:InvSync 继续覆盖 1.12.2 – 26.x 的全版本老服,FastSync 则专注把 1.20.1+ 的现代 Paper 服做到极致。
⚠️ 支持范围(务必先看这里)
这是选型前最重要的两条硬性要求,不满足任何一条都无法使用 FastSync。
- Minecraft 版本:1.20.1 及以上。低于 1.20.1 的服务端请使用 InvSync。
- 服务端类型:仅 Paper 系(Paper / Purpur / Folia / Leaves 等基于 Paper 的分支)。
不支持 Spigot、不支持 CraftBukkit。
为什么这么严格? FastSync 的物品序列化完全依赖 Paper 独有的官方 API ItemStack#serializeAsBytes()(1.20.1 起提供,字节内嵌 DataVersion,官方承诺跨版本自动升级)。Spigot / CraftBukkit 没有这个 API,因此无法运行。这也是 FastSync 能"根治损坏物品"和"旧版本存的物品在新版本服自动升级"的技术根基——门槛换来的是可靠性。
此外,代理端(Velocity / BungeeCord)是必装组件:FastSync 的预加载架构依赖代理提前通知子服,直连后端的玩家会走兜底路径并告警。
✨ 核心特性
🚀 preload-always:玩家出生即数据就绪,切服无卡顿
传统同步是"玩家先进服,再冻结住玩家,然后在主线程一件件 setItem 把背包塞回去",进服瞬间会有一段可感知的卡顿甚至短暂空背包。
FastSync 把同步永远放在玩家出生之前:
- 代理端在玩家切服前 500ms~2s 就通知目标子服提前抢锁、读库、并把原版字段(背包、末影箱、血量、饥饿、经验等)离线写进
playerdata/<uuid>.dat,由服务端自己加载。 - 玩家真正连入时,数据已经在
.dat里,出生即正确,主线程几乎只剩"应用扩展字段"的一点点开销。 - 没有"进服后冻结玩家再 setItem"这个阶段,切服体感接近无缝。
登录屏障(AsyncPreLogin)会等待预载结果,即使预载没赶上,也会在这里现场抢锁+读库兜底,同样保证出生即正确,只是慢一点。
🗄️ 无 Redis:MySQL 租约锁 + 单调版本号
FastSync 用一个 MySQL 就完成了分布式一致性,完全不需要 Redis:
- 租约锁:玩家主表内嵌
lock_owner/lock_expires_at,抢锁 + 读数据一个原子 UPDATE 搞定;崩服后租约到期(默认 60s)其他服自动接管,不会永久锁死。 - data_version 单调版本号:每次保存版本号 +1,保存时乐观写(
WHERE data_version=期望值),旧数据永远盖不掉新数据。切服交接时版本号作为"凭据"传递,目标服读到data_version ≥ 凭据才算读到源服刚存的数据,彻底消灭"抢到锁却读到旧数据"的竞态。 - 部署门槛低、不怕 Redis 断连关服:老架构里 Redis 断连会直接关服,对小服主过于残暴;FastSync 没有这个中间件,少一个运维炸弹。
📦 Paper 官方物品序列化:跨版本自动升级,不再依赖 NBTAPI
物品只走 Paper 官方的 ItemStack#serializeAsBytes() / deserializeBytes():
- 字节内嵌 DataVersion,旧版本服存的物品,在新版本服读取时会自动走原版 DataFixerUpper 升级(和世界存档同一套机制,官方承诺)。
- 彻底不再依赖 NBTAPI(仅迁移工具例外),消灭了 NBTAPI 版本滞后带来的"not supported"告警和兼容风险。
- 容器(背包/末影箱)采用按槽位独立成帧的二进制格式,一个物品字节坏了不影响同一容器里其他物品的解析——这正是下面"单品隔离"的基础。
注意:官方 API 只承诺"旧写新读"的升级方向。混版本网络请让数据只从低版本服流向高版本服;同版本网络无此顾虑。
🛡️ 损坏物品净化 + 隔离复活:数据永不丢
这是 FastSync 相对同类插件最核心的竞争力。1.20.5+ 的组件严格校验、1.21.6+ 更是"一律抛异常",一个带未知附魔的物品在同类插件(如 HuskSync)里会被直接删除并把删除结果回写数据库(issue #596),玩家的东西就这么没了。
FastSync 定下一条红线:解析失败时,原始字节永远不被覆盖丢弃,走三层治理:
- 直接解码 → 成功即返回。
- 净化重试:纯 Java 的 NBT 手术,剥离注册表中不存在的未知附魔(兼容 1.20.5+ 组件两种布局 + 1.20.1 老 tag,递归处理嵌套容器),重新解码 → 成功则物品保住,只丢那个未知附魔(≈原版行为)。
- 隔离 + 复活:净化仍救不回时,把原始字节 + 错误信息存入隔离表,槽位放一个占位屏障物品(写明原因、PDC 记录隔离 id);保存时写回的是隔离表里的原始字节而不是占位物品;等对应附魔/物品插件装回来后,下次加载自动复活原物品。
配套还提供 archive-original 开关:即使净化成功恢复了物品,也可把原始字节存档进隔离表以备回查。
对比:HuskSync 直接删物品 + 回写数据库(不可逆丢失);FastSync 保住能保的、隔离救不回的、并留好复活的路。
🌐 多代理集群
子服可以同时连接多个 Velocity / BungeeCord 代理(proxy.urls 填多个地址,全部保持长连接)。一个玩家同一时刻只属于一个代理,由该代理独立完成它的切服编排,代理之间无需互通;锁与数据一致性全在 MySQL,与代理数量无关。适合多入口 / 多代理的大网拓扑。
💾 备份分级保留 + GUI 回档
内置玩家数据备份系统,可在退出 / 切服 / 关服 / 自动保存时打快照,采用分级保留策略(最近 N 个全留,再按天 / 周 / 月各留若干个,其余清理),防止空数据或误操作把有效备份冲掉。管理员可通过 /fastsync backup <玩家> 打开 GUI,列表 → 预览 → 确认回档,直观安全。
🔌 addon 扩展 + 内置第三方 hook
FastSync 提供对外的 addon API(onSave→bytes / onApply / shouldApply 门禁)和 Bukkit 事件(同步完成 / 进服门禁 / 物品清洗 / 物品隔离),第三方可安全地扩展同步任意自定义字段。开箱内置 5 个第三方 hook:
| Hook | 作用 |
|---|---|
| CMI Fly Charge | 同步 CMI 飞行充能 |
| Vault Economy | 同步 Vault 经济余额(默认关,按需开启) |
| DragonArmourers | 同步龙之时装,同步完成后延迟重贴皮肤 |
| LibsDisguises | 同步伪装,同步完成后按已保存伪装重挂 |
| EpicProfileSwitch | 存档切换门禁(玩家没切档就不覆盖其扩展数据) |
第三方 jar 放 libs/ 目录走 compileOnly,装了对应插件才生效。
🧾 同步内容清单
| 数据 | 说明 | 默认 |
|---|---|---|
| 背包 inventory | 主背包 | ✅ |
| 末影箱 ender-chest | 末影箱 | ✅ |
| 血量 health | 当前生命值 | ✅ |
| 最大血量 max-health | 属性最大血量(跨版本反射兼容) | ❌ |
| 饥饿 food | 饥饿值 | ✅ |
| 饱和 saturation | 饱和度 | ✅ |
| 经验 exp | 经验进度 | ✅ |
| 等级 level | 经验等级 | ✅ |
| 药水效果 effects | 药水效果(type 存 NamespacedKey 字符串最稳) | ✅ |
| 统计 statistics | vanilla 统计数据 | ✅ |
| 成就 advancements | vanilla 成就 | ✅ |
| PDC persistent-data-container | 玩家 PersistentDataContainer(很多插件用它存数据,官方字节序列化) | ❌ |
| 游戏模式 game-mode | 生存 / 创造 / 冒险 / 旁观 | ❌ |
| 手持槽 held-slot | 快捷栏当前选中槽 | ✅ |
| addon 扩展数据 plugin-data | 第三方 hook 数据:经济 / 时装 / 伪装 / 飞行充能等 | ✅ |
通过 addon API 可安全地自行同步任意自定义字段。
⚙️ 配置文件说明(config.yml 挑重点)
# 本服标识(租约锁持有者名 + 代理端注册名)。留空自动用服务端根目录名。
# ⚠️ 同一网络内每台子服必须唯一!
server-name: ''
# 玩家档案目录(离线写 .dat 用)。留空自动用主世界的 playerdata。
player-data-folder: ''
mysql:
host: 127.0.0.1
port: 3306
database: fastsync
user: root
passwd: password
ssl: false
# 同步项开关(见上方"同步内容清单")
sync:
inventory: true
ender-chest: true
# ... 各字段开关
persistent-data-container: false # PDC 按需开启
plugin-data: true # addon 扩展数据
# 损坏物品处理(净化/隔离是默认且唯一行为,不提供"踢人"选项)
invalid-item:
archive-original: true # 净化成功也把原始字节存档进隔离表,可回查
# 租约锁
lock:
ttl-ms: 60000 # 租约有效期,崩服后其他服最多等这么久接管
refresh-interval-ticks: 300 # 在线续约间隔(独立线程按 wall-clock 执行,不受 TPS 影响)
# 登录屏障
login:
preload-await-ms: 5000 # 等代理预载结果的上限
lock-wait-ms: 8000 # 兜底现场加载时等租约的上限
deny-on-failure: true # 数据无法就绪时拒绝登录(强烈建议 true,避免给空数据)
auto-save:
enable: true
interval-ticks: 6000
# 数据备份(快照存档,可回档)
backup:
enable: true
on-disconnect: true # 退出/切服/关服时备份
on-auto-save: false # 每次自动保存也备份(默认关,避免备份表膨胀)
retention: # 分级保留
latest: 10
daily: 7
weekly: 4
monthly: 3
# 代理端连接(FastSyncVelocity / FastSyncBungee 的 WS 服务端)
proxy:
secret: 'change-me' # 必须与代理端配置一致
urls: # 代理集群时把每个代理都填上,子服会全部保持长连接
- 'ws://127.0.0.1:8765'
# 第三方插件同步 hook(装了对应插件才生效)
hook:
cmi-fly-charge: true
init-cmi-fly-charge: true # false: DB 无充能数据则退出不保存,不用本服默认值初始化跨服玩家
vault: false # 经济默认关(跨服并发下有精度/竞态风险)
init-vault: true
dragon-armourers: true
dragon-armourers-delay: 80 # 时装刷新延迟,必须等背包等数据落地后再刷
libs-disguises: true
epic-profile-switch: true
几个必须注意的点:
server-name同一网络内每台子服必须唯一,它同时是租约锁持有者名和代理端注册名,重复会导致锁冲突。login.deny-on-failure强烈建议保持true,否则数据无法就绪时会放行空数据,玩家本次会话不同步。proxy.secret必须和代理端配置一致;代理集群把每个代理地址都填进proxy.urls。hook.vault默认关闭:经济这类高频变动数据在跨服并发下有精度和竞态风险,按需开启。
🕹️ 指令与 GUI
主指令 /fastsync,权限 fastsync.admin。
| 命令 | 作用 | 说明 |
|---|---|---|
/fastsync reload |
重载配置 | — |
/fastsync status |
查看运行状态 | 显示本服标识、持锁玩家数、预载缓存、代理地址 |
/fastsync save <玩家> |
立即保存指定在线玩家数据 | 玩家需在线且数据已加载完成 |
/fastsync backup <玩家> |
打开备份 GUI(后台执行者则打印列表) | 列表 → 预览 → 确认回档 |
/fastsync backup save <玩家> |
手动为在线玩家创建备份 | — |
/fastsync backup restore <id> |
回档到指定备份 | 需玩家离线,防止覆盖在线状态 |
/fastsync quarantine <玩家> |
打开隔离物品 GUI(后台执行者则打印列表) | 查看该玩家的损坏物品隔离记录 |
/fastsync quarantine restore <id> |
尝试解析隔离记录并取回物品到自己背包 | 仅玩家可执行;若仍无法解析会提示原因 |
GUI 操作:/fastsync backup <玩家> 打开备份列表界面,点选可预览并二次确认回档;/fastsync quarantine <玩家> 打开隔离列表界面,可查看并取回被隔离的物品。图形化操作比手敲 id 更直观、更不易误操作。
🔄 与 InvSync 的区别对比
| 维度 | InvSync(2.0) | FastSync(新一代) |
|---|---|---|
| 支持版本 | 1.12.2 – 26.x 全版本 | 仅 1.20.1+ |
| 服务端类型 | Spigot / Paper 系均可 | 仅 Paper 系(不支持 Spigot/CraftBukkit) |
| 中间件 | 需要 Redis(分布式锁 + 热缓存),断连会关服 | 无需 Redis,只要 MySQL |
| 分布式一致性 | Redis 锁 + TTL 续锁 | MySQL 租约锁 + data_version 单调版本号乐观写 |
| 物品序列化 | NBTAPI → SNBT → JSON → GZIP | Paper 官方 serializeAsBytes(字节内嵌 DataVersion,跨版本自动升级) |
| 跨版本升级 | 依赖 NBTAPI + 整 .dat DataFixer | 官方 DFU,旧版本物品在新版本服自动升级 |
| 损坏物品策略 | 默认 deny(整背包中断 + 踢人循环);remove 会永久清洗 |
净化 + 隔离 + 复活,原始字节永不覆盖丢弃 |
| 预加载 | 增值模块,需额外购买 | 默认全程 preload-always,出生即就绪 |
| 冻结机制 | 进服后冻结玩家 + 主线程 setItem | 无冻结阶段(仅 pre-quit 窗口的轻量冻结) |
| 代理端 | 可选 | 必装组件,且支持多代理集群 |
| 包体积 | 约 13MB(shade 大量依赖) | 显著更小(砍掉 NBTAPI/Kryo/Mongo 等) |
📥 从 InvSync 迁移
FastSync 提供独立的一次性迁移工具 project-migrate(打包为 FastSyncMigrate 插件,迁移完可直接卸载)。
用法:
- 把源库(InvSync)和目标库(FastSync)的 JDBC 配置写进迁移插件的
config.yml。 - 服务器空载时执行
/fastsyncmigrate run(别名/fsmigrate,权限fastsync.migrate)。 - 迁移异步执行、幂等(
overwrite=false时只补 FastSync 缺失的玩家,可反复安全重跑),完成后卸载迁移插件即可。
字段兼容说明:
- 会迁移:背包 inventory、末影箱 enderChest、统计 statistic、药水效果 buffs、成就 advancements、血量 health、最大血量 maxHealth、饥饿 food、经验 exp、等级 level。物品字节用 Paper
serializeAsBytes重新序列化,随迁移自动升级到目标版本。 - addon 数据无缝迁移:
pluginData的字节格式(GZIP KV)与 FastSync 完全一致,直接搬字节——CMI 飞行充能、Vault 经济等 addon 数据无需转换,玩家首次进 FastSync 服由对应 addon 自动 apply 回身上。 - 暂不迁移:
persistentData(InvSync 存 NBT 文本,与 FastSync 官方字节格式不同)、otherData(mod 数据)——为避免损坏而跳过。
迁移前建议先备份数据库。迁移期间可双表共存,稳妥切换。
📌 一句话总结
如果你的网络是纯 Paper 系、1.20.1+ 的现代服,想要部署更简单(无 Redis)、切服更顺滑(出生即就绪)、物品数据更安全(净化+隔离+复活),FastSync 就是为你准备的下一代方案。老版本或 Spigot 服请继续使用 InvSync。