代理网络(BungeeCord / Waterfall / Velocity)
ResourcePackManager 可以运行在代理网络上。只有一个 jar — ResourcePackManager.jar — 你在每个后端以及代理上安装的都是同一个 jar。在后端上它以后端角色运行(合并、托管、推送、转换);在 Velocity 或 BungeeCord/Waterfall 代理上,同一个 jar 会自动检测平台加载器并以代理角色运行(网络侧的基岩版分发)。两种角色会通过共享的 plugins/floodgate/key.pem 文件自动发现彼此——没有单独的代理 jar,没有需要解压的 proxy-extension,也没有需要粘贴的密钥。
本页中“代理插件”是对这个以代理角色运行的同一个 ResourcePackManager.jar 的简称。
代理插件的职责
代理插件的工作是基岩版资源包的合并与分发。在拥有多个后端的网络中,每个后端会生成自己的基岩版资源包(其合并后的 Java 资源包的转换版本)。代理插件会:
- 每 5 秒轮询一次每个后端的小型 HTTP 服务器上的
/bedrock.zip与/mappings.json,使用If-Modified-Since,因此未变化的文件几乎不消耗带宽。每个后端都会公告它实际绑定的确切 HTTP 端口,所以代理通常会自动命中正确的端口(参见 后端 HTTP 端口解析)。 - 等待收件箱状态稳定——一旦相邻两次轮询观察到相同的文件哈希集合,它就会立即合并。
- 将每个后端的基岩版资源包合并为一个全网络统一的资源包。
- 把合并后的 Geyser 自定义映射文件复制到代理上的
plugins/Geyser-*/custom_mappings/。 - 在基岩版客户端接入时通过 Geyser 的
SessionLoadResourcePacksEvent分发合并后的资源包。
**代理插件只对基岩版玩家有用。**网络上 Java 资源包的分发仍由各后端通过常规的 setResourcePack / addResourcePack API 完成——Java 客户端看到的是各自所在后端选择发送的资源包。如果你的网络只面向 Java 玩家,根本用不上代理插件。
安装 — 两步走
第 1 步:在代理和每个后端上都安装 Floodgate
Floodgate 是基岩版玩家在代理上完成认证所必需的。RSPM 借用 Floodgate 的 plugins/floodgate/key.pem 来派生网络身份——该文件必须在代理和每个后端上逐字节一致。Floodgate 本身就要求这一点用于基岩版认证,所以如果基岩版玩家目前能在你的网络中正常工作,这一步其实已经完成了。
如果你还没装 Floodgate,请在每个组件上都安装它,然后把一份规范的 key.pem 复制到其余每个组件,再继续下一步。
第 2 步:把 ResourcePackManager.jar 复制到代理
只有一个 jar。你在 Bukkit/Paper 后端上安装的同一个 ResourcePackManager.jar 也就是代理插件——它把 Velocity 和 BungeeCord/Waterfall 的实现一并打进一个 shaded jar,并自动检测自己运行在哪个平台上。没有单独的、按平台区分的代理 jar 需要解压。
把同一个 ResourcePackManager.jar 复制到你代理的 plugins/ 文件夹:
| 代理软件 | 使用此 jar |
|---|---|
| Velocity | ResourcePackManager.jar |
| BungeeCord | ResourcePackManager.jar |
| Waterfall(Bungee 分支) | ResourcePackManager.jar |
你随时可以在后端运行 /rspm status 来确认这一点;其中的 Proxy deployment 部分会打印 Network proxy jar: ResourcePackManager.jar 以及 Use the same jar on Bukkit/Paper, Velocity, and BungeeCord/Waterfall.
重启代理。就这么简单。
故意不留任何需要编辑的配置项、也不需要粘贴密钥。代理插件会在启动时读取代理上的 plugins/floodgate/key.pem 并从中派生网络身份。由于 Floodgate 本身就要求该文件在每个后端与代理上一致,派生出的密钥自动与每个后端的匹配。
代理的首次轮询会在启动约 2 秒后触发,之后每 5 秒一次。结合单周期稳定性门控,在代理至少能看到一个已经在生产内容的后端之后,首次合并大约会在 7 秒后发布。
验证是否工作正常
代理控制台
重启代理大约 10 秒内(假设后端正在运行),你应能看到:
[ResourcePackManager] Network-key auto-derived from Floodgate key.pem ✓
[ResourcePackManager] NetworkSync starting (poll interval 5000 ms, network-http-offset 1 - endpoint announcements preferred, fallback HTTP port = mcPort + offset)
[ResourcePackManager] NetworkSync: inbox stabilized — merging 2 Bedrock zip(s) and 2 mappings file(s) across 2 backend(s).
[ResourcePackManager] Merged Bedrock pack published at .../merged/Bedrock.zip (sha1=...).
[ResourcePackManager] ✔ Network resource pack is now ready (... KB, sha1 ABCD1234)
在代理上运行 /rspm status
打印一份快照:后端列表、各后端各路径的拉取结果(200 / 304 / 404 / CONNECT_FAILED)、连续空轮询计数器、当前合并资源包路径与大小、network-http-offset,以及代理上是否检测到 Floodgate / Geyser。需要 resourcepackmanager.command.status 或 resourcepackmanager.* 权限。控制台总是同时拥有两者;若希望玩家也能运行,请通过你的权限插件授予其一。输出不会泄露任何机密(网络密钥会被遮蔽,没有任何认证令牌),所以可以放心宽松授权。
在后端上运行 /rspm status
Deploy mode 一行应当显示 network-backend。Network key 一行应显示遮蔽后的密钥(只露出最后 4 个字符)——把它与代理上遮蔽后的密钥对比,确认两端一致。
基岩版客户端
用基岩版客户端连接。你应当在进入世界之前看到资源包下载提示。自定义物品会显示为其应有的模型,而不是普通的盔甲架。
配置项参考
后端 plugins/ResourcePackManager/config.yml
网络模式是自动检测的——没有什么 networkMode: true 开关需要设置。检测信号(任一即可):
- 存在 Floodgate,但不存在 Geyser-Spigot — 针对基岩版-经由代理场景最强的信号。
spigot.yml: settings.bungeecord: true— 旧式 BungeeCord / Waterfall 的 IP 转发开关。paper-global.yml: proxies.velocity.enabled: true— 现代 Velocity 转发。
针对网络模式真正有意义的唯一旋钮是 networkHttpOffset-v2,它控制代理将在每个后端轮询的回退 HTTP 端口(即代理在某个后端尚未公告其实际绑定端口之前所猜测的端口)。默认值 1 在几乎所有托管环境下都能用。完整的端口解析说明请参阅 Self-hosting。
在正常运行中,每个后端都会自动把它真实的 HTTP 端口公告给代理(通过 magmaguy.com 端点注册表),所以该偏移仅在启动/失败时作为回退被参考。参见下文的 后端 HTTP 端口解析。
代理 plugins/ResourcePackManager/config.yml
代理插件在首次启动时会写入一份最简默认配置:
# 强制客户端接受资源包(拒绝则踢出)。默认:false。
force-resource-pack: false
# 回退偏移:在某个后端尚未公告其真实的 ResourcePackManager HTTP 端口之前,
# 该代理会把这个偏移加到该后端的 Minecraft 端口上,以推导出它将访问
# /bedrock.zip 与 /mappings.json 的 HTTP 端口。默认 1。
# 正常运行中后端会公告它实际绑定的确切端口,所以这个值仅在启动时或公告
# 失败时才会被用到——但一旦被用到,它应当与每个后端的 networkHttpOffset-v2 一致。
network-http-offset-v2: 1
故意不提供 network-key 条目——该条目在发布前就已被取消,因为手动粘贴是配置错误的主要来源(拼写错误会悄无声息地破坏 proxy↔backend 链接)。密钥会从 plugins/floodgate/key.pem 自动派生。
后端 HTTP 端口解析
代理需要知道在每个后端上轮询 /bedrock.zip 与 /mappings.json 时该用哪个 HTTP 端口。它按以下顺序解析该端口:
- 后端公告的端点(优先)。 每个后端会把它实际绑定的确切 HTTP 端口上传到 magmaguy.com 端点注册表,以网络密钥为键。每次轮询时代理会刷新这份列表,并通过 Minecraft 端口(以及可用时的主机名)把某个后端公告的端口与服务器列表条目匹配起来。这意味着无论管理员在某个后端上显式设置了
selfHostPort,还是该后端自动落在mcPort + 1上,处理方式都完全相同——代理使用后端实际绑定的端口。 mcPort + network-http-offset-v2(回退)。 仅在没有匹配的公告可用时使用(例如任何后端公告之前的第一次轮询,或端点注册表短暂不可达时)。这就是为什么如果你依赖回退,两端的偏移仍应保持一致。
代理特意不把端口扫描后端作为回退手段——那在托管商看来像是滥用行为。当直连拉取根本无法工作时,中继路径(见下文)才是根本性的解决办法。
代理上的 /rspm status 会针对每个后端显示选用了哪个端口,以及它是来自公告还是来自偏移回退。
稳定性与合并节奏
代理在合并前会等待收件箱状态稳定:第一次轮询确定基线文件哈希集合,下一次观察到相同集合的轮询会触发合并(单周期稳定性门控)。在约 2 秒的初始延迟和 5 秒轮询间隔下,这意味着当代理至少能看到一个后端在生产内容之后,首次合并大约会在 7 秒后发生。后续只有在收件箱文件的 SHA-1 集合发生变化时才会重新打包,所以长时间静默几乎零开销。
后端会把它们的 bedrock.zip 写入一个临时文件,然后原子性地重命名,因此 /bedrock.zip 路由始终提供一个完整的 zip——代理永远不必防范读到写了一半的文件,这也是门控只需单周期而非两周期的原因。
直连拉取 vs 中继回退
默认路径是直连拉取:代理对每个后端发起 http://<backend-host>:<mcPort + offset><path> 的 HTTP GET。
如果代理无法直接访问某个后端的 HTTP 端口(在共享 / 托管 Minecraft 服务上很常见,MC 端口对外开放但相邻端口被防火墙屏蔽),后端会在网络命名空间(由 Floodgate 密钥派生)下把 bedrock.zip 与 mappings.json 推送到 magmaguy.com 上的中继端点。当直连拉取硬性失败时,代理会列出并从中继下载。
两条路径最终都汇入同一个合并步骤,因此运维人员无需在两者之间做选择——优先使用直连拉取(对 magmaguy.com 带宽成本为零),需要时中继会透明启用。
中继在服务端有 30 分钟的 TTL。后端每 25 分钟推送一次以保持条目存活;正常关闭会立即丢弃条目,而不必等待 TTL 过期。
常见问题排查
启动时报 "Floodgate key.pem missing"
代理插件找不到 plugins/floodgate/key.pem,进入空转状态。没有它 RSPM 无法链接任何后端。
修复方法:在代理上安装 Floodgate,然后确保代理上的 plugins/floodgate/key.pem 与每个后端上的同名文件逐字节一致。Floodgate 默认会为每次安装自动生成不同的密钥——把任意后端上的一份规范 key.pem 复制到所有其他组件上,再重启所有节点。
大约 20 秒后出现 "No merged pack content" 警告
在连续 4 轮空轮询之后,代理会一次性记录一条多行警告,列出它轮询过的每个后端、尝试访问的 URL,以及结果。警告会解释最常见的修复方法:
- 每个后端都返回
CONNECT_FAILED— 代理根本无法访问后端 HTTP 端口。检查velocity.toml/config.yml中的地址是不是代理真正能访问到的(而不是诸如 Docker 内部名之类、从代理网络解析不到的地址),并确认代理与后端之间后端的 HTTP 端口是放通的。警告会针对每个后端打印它尝试访问的确切 HTTP host:port,以及该端口是来自后端的公告还是来自mcPort + networkHttpOffset-v2回退。如果你完全没有办法放通该端口(托管型服务),请参阅上文的中继回退一节——后端应当会自动上传到中继。 - 每个后端都返回
NOT_FOUND_404— 后端已就绪但没有生成基岩版资源包。在每个后端运行/rspm status;Bedrock Pack 诊断块会告诉你原因(最常见的是:合并后的资源包里没有物品定义,或第一次合并周期还没完成)。
该警告每个卡住期只触发一次。至少有一个后端重新开始返回内容时,会记录一行 NetworkSync: recovered。
第一次启动代理时基岩版玩家看不到任何自定义模型
Geyser 只在代理启动时注册其自定义物品表。如果代理在任何后端生成基岩版资源包之前就启动了,Geyser 就会带着空的映射表运行,并在整个会话期间保持空表。
修复方法:在后端日志中出现第一行 Merged Bedrock pack published 之后,重启一次代理。RSPM 会在每次代理启动时预先部署上一次运行的映射,所以这种情况只会在全新安装时碰到一次——后续启动时 Geyser 扫描前总会有可用的映射就位。
代理启动时报 "Duplicate bedrock_identifier" 警告
两个后端为同一个基础物品发出了相同的基岩版标识符。会采用最后写入者胜出的策略;如果只需要一个后端提供该物品,无害。如果两个后端确实要在同一个基础物品下托管不同的自定义物品,请重命名其中一个源 Java 模型,使自动生成的哈希值不同。
基岩版玩家已连接但看不到资源包
当某个基岩版会话加载但没有可用的 RSPM 资源包时,代理会向所有在线 Java 玩家发出聊天横幅:
⚠ [RSPM] Bedrock player Alice connected before the resource pack was ready — they're seeing plain armor stands instead of custom models. Tell them to disconnect and reconnect; the pack will load on their next session. (Cause: ...)
基岩版玩家本人也会收到一个模态弹窗,代理控制台也会出现一条横幅。如果需要进一步排查,可启用调试日志流(Velocity 与 BungeeCord 都支持):
/rspm debug bedrock on
这会打开 GeyserBinder 输出的详细 [RSPM-BedrockDebug] 日志行。复现问题后,再关闭它:
/rspm debug bedrock off
该设置在代理重启时会重置为关闭,避免被意外保持开启。
在网络上更新 RSPM
升级后端 RSPM jar 后,也请把同一个 ResourcePackManager.jar 重新复制到代理的 plugins/ 文件夹并重启代理。每个后端与代理用的都是同一个 jar,所以请让所有组件保持相同版本。
目前尚未支持的内容
- 通过代理插件在网络上分发 Java 资源包。 Java 客户端通过常规 API 直接从各后端接收资源包。代理侧没有 Java 资源包混合器。
- 跨后端的 Java 资源包合并。 每个后端的 Java 资源包是独立的。玩家切换后端时会收到新后端的资源包。
- 实时重新配置网络密钥。 密钥绑定到 Floodgate 的
key.pem。更改它需要重启代理和每个后端(反正轮换 Floodgate 密钥时本来就要这么做)。