跳到主要内容

代理网络(BungeeCord / Waterfall / Velocity)

ResourcePackManager 可以运行在代理网络上。只有一个 jarResourcePackManager.jar — 你在每个后端以及代理上安装的都是同一个 jar。在后端上它以后端角色运行(合并、托管、推送、转换);在 Velocity 或 BungeeCord/Waterfall 代理上,同一个 jar 会自动检测平台加载器并以代理角色运行(网络侧的基岩版分发)。两种角色会自行建立链接:代理持有网络密钥,并在玩家首次连接到某个后端时把密钥推送给它——没有按平台区分的代理 jar,也没有需要粘贴的密钥。

本页中“代理插件”是对这个以代理角色运行的同一个 ResourcePackManager.jar 的简称。

代理插件的职责

代理插件的工作是基岩版资源包的合并与分发。在拥有多个后端的网络中,每个后端会生成自己的基岩版资源包(其合并后的 Java 资源包的转换版本)。代理插件会:

  1. 每 5 秒轮询一次每个后端的小型 HTTP 服务器上的 /bedrock.zip/mappings.json,优先使用强 ETag 配合 If-None-Match,同时保留 If-Modified-Since 以兼容较旧的后端。未变化的文件返回 304,因此几乎不消耗带宽。每个后端都会公告它实际绑定的确切 HTTP 端口,所以代理通常会自动命中正确的端口(参见 后端 HTTP 端口解析)。
  2. 等待收件箱状态稳定——一旦相邻两次轮询观察到相同的文件哈希集合,它就会立即合并。
  3. 将每个后端的基岩版资源包合并为一个全网络统一的资源包。
  4. 当存在物品映射时,把合并后的 Geyser 自定义映射文件复制到代理上的 plugins/Geyser-*/custom_mappings/
  5. 在基岩版客户端接入时通过 Geyser 的 SessionLoadResourcePacksEvent 分发合并后的资源包。

**代理插件只对基岩版玩家有用。**网络上 Java 资源包的分发仍由各后端通过常规的 setResourcePack / addResourcePack API 完成——Java 客户端看到的是各自所在后端选择发送的资源包。如果你的网络只面向 Java 玩家,根本用不上代理插件。

安装 — 只需一步(如果需要基岩版支持,再加上 Floodgate)

Floodgate

Floodgate 是基岩版玩家在代理上完成认证所必需的。但它不是 RSPM 把代理与后端链接起来的必需条件——一个纯 Java 的网络完全可以在没有 Floodgate 的情况下运行代理插件。

如果 RSPM 在代理上首次启动的那一刻 Floodgate 确实已安装,RSPM 会一次性地从 plugins/floodgate/key.pem 播种它的网络密钥,这样一个原本已经正常工作的网络在升级后仍保持相同的身份。首次启动之后,密钥就保存在 RSPM 自己的 network-key 文件中,key.pem 不会再被读取。

ResourcePackManager.jar 复制到代理

只有一个 jar。你在 Bukkit/Paper 后端上安装的同一个 ResourcePackManager.jar 也就是代理插件——它把 Velocity 和 BungeeCord/Waterfall 的实现一并打进一个 shaded jar,并自动检测自己运行在哪个平台上。没有单独的、按平台区分的代理 jar 需要解压。

如果你已经启动了后端,却还没在代理上放置 RSPM,你也不必去到处找下载链接:每个位于代理之后、尚未获得密钥的后端都会在 plugins/ResourcePackManager/proxy-extension/ResourcePackManager.jar 暂存一份与自身逐字节相同的 jar 副本,并在控制台打印出这个确切路径。复制那个文件可以确保代理与后端绝不会处于不同版本。

把同一个 ResourcePackManager.jar 复制到你代理的 plugins/ 文件夹:

代理软件使用此 jar
VelocityResourcePackManager.jar
BungeeCordResourcePackManager.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.

重启代理。就这么简单。

没有任何必须编辑的配置项,也没有需要粘贴的密钥。代理会在启动时自行建立网络密钥,并自动把它下发给每个后端——参见下文的 代理与后端如何建立链接。生成的代理 config.yml 只包含两项可选设置,两者都会在后文说明。

代理的首次轮询会在启动约 2 秒后触发,之后每 5 秒一次。结合单周期稳定性门控,在代理至少能看到一个已经在生产内容的后端之后,首次合并大约会在 7 秒后发布。

代理与后端如何建立链接

以下所有流程都无需配置。之所以记录在此,是因为当网络没有链接成功时,了解这个顺序就等于掌握了全部诊断思路。

**1. 代理确立密钥。**启动时它会按以下顺序解析出唯一一个值:

  1. 位于代理插件自身数据文件夹中已保存的 network-key 文件——首次启动之后每次启动的稳定状态;
  2. 一次性地从代理上的 plugins/floodgate/key.pem 派生出的种子(如果该文件存在);
  3. 全新生成的随机密钥。

无论走到哪一个分支,结果都会写入 network-key 并从此长期复用。代理控制台会说明发生了哪一种情况(Network key loaded ✓adopted from Floodgate key.pemNew network key generated)。如果该文件无法写入,代理会以 [ERROR] 级别记录一条错误——这对当前这次启动并不致命,但下次重启会生成一个不同的密钥并悄无声息地解除所有后端的链接,所以请修复文件夹权限。

**2. 代理把密钥推送给每个后端。**一旦有玩家连接到某个后端,代理就会通过 rspm:network 插件通道把密钥发送给它。这个方向是有意为之的:后端在物理上无法主动索取,因为代理不会转发一条玩家客户端从未注册过的通道上的插件消息。

**3. 后端采纳并持久化该密钥。**它会把密钥保存到自己的 data.yml,并报告 Network key received from the proxy; this backend is now linked. 只有在后端尚未持有密钥时授予才会被接受——已经确立密钥的后端会记录一条警告并保留现有密钥,而不会让一条消息把它重新指向另一个网络。

在 **Velocity 的现代转发(modern forwarding)**下,授予会用代理的 forwarding.secret 做 HMAC 签名,而配置为现代转发的后端要求存在该签名。在 BungeeCord、Waterfall 以及旧式转发下没有可用于签名的共享密钥,因此授予是未签名的,并按未签名接受。

一个走到第 2 步却从未走到第 3 步的后端,其密钥来源会一直是 not set。这正是触发 proxy-extension/ 暂存以及基岩版专属警告横幅的状态。

验证是否工作正常

代理控制台

重启代理大约 10 秒内(假设后端正在运行),你应能看到:

[ResourcePackManager] Network key loaded ✓
[ResourcePackManager] Network key provisioning ready on rspm:network; backends are keyed as players connect.
[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

打印一份快照:网络密钥指纹、后端列表、各后端针对 /bedrock.zip/mappings.json/rspm-update.jar 每条路径的拉取结果(200 / 304 / 404 / CONNECT_FAILED)、它已收到的端点公告、它能看到的中继条目、连续空轮询计数器、合并后的基岩版资源包与合并后的映射文件是否已落盘(含各自大小)以及当前合并资源包的 SHA-1 前缀、network-http-offset 回退值、检测到的 Geyser 插件文件夹与已部署的映射文件,还有代理上 Floodgate / Geyser 的存在情况。Velocity 接受 resourcepackmanager.command.statusresourcepackmanager.*;BungeeCord 注册的是确切的 resourcepackmanager.command.status 节点,权限插件可以通过通配符展开来满足它。控制台可以运行该命令。输出不会泄露任何机密(网络密钥只以一段简短的单向哈希指纹出现,也不会打印任何认证令牌),所以可以放心宽松授权。

在后端上运行 /rspm status

Deploy mode 一行应当显示 network-backendNetwork key fingerprint 应显示一段简短哈希——它必须与代理打印的指纹一致。Network key source 会告诉你这个后端是怎样拿到密钥的:

来源行含义
provided by the proxy正常的已链接状态。代理在某次玩家连接时授予了密钥。
saved on this server在之前某次启动时就已获得密钥(或是一台自行生成密钥的独立服务器)。
adopted from Floodgate's key一次性地从该后端本地的 plugins/floodgate/key.pem 播种得到。
not set — the proxy sends one when a player next connects here**未链接。**要么自代理启动以来还没有玩家连接过,要么代理上缺少 RSPM/代理类型不受支持。

基岩版客户端

用基岩版客户端连接。你应当在进入世界之前看到资源包下载提示。自定义物品会显示为其应有的模型,而不是普通的盔甲架。

配置项参考

后端 plugins/ResourcePackManager/config.yml

网络模式是自动检测的——没有什么 networkMode: true 开关需要设置。检测信号(任一即可):

  1. 存在 Floodgate,但不存在 Geyser-Spigot — 针对基岩版-经由代理场景最强的信号。
  2. spigot.yml: settings.bungeecord: true — 旧式 BungeeCord / Waterfall 的 IP 转发开关。
  3. paper-global.yml: proxies.velocity.enabled: true — 现代 Velocity 转发。

针对网络模式真正有意义的唯一旋钮是 networkHttpOffset-v2,它控制代理将在每个后端轮询的回退 HTTP 端口(即代理在某个后端尚未公告其实际绑定端口之前所猜测的端口)。默认值 1 在几乎所有托管环境下都能用。完整的端口解析说明请参阅 自托管

在正常运行中,每个后端都会自动把它真实的 HTTP 端口公告给代理(通过 magmaguy.com 端点注册表),所以该偏移仅在启动/失败时作为回退被参考。参见下文的 后端 HTTP 端口解析

代理 config.yml

代理插件在首次启动时会写入一份最简默认配置。该文件夹因平台而异,因为每种代理都从自己的插件标识符推导它:

代理软件配置路径
Velocityplugins/resourcepackmanager/config.yml
BungeeCord / Waterfallplugins/ResourcePackManager/config.yml

它恰好包含两项设置,都是可选的:

# FALLBACK offset added to each backend's Minecraft port to derive the HTTP
# port this proxy will hit for /bedrock.zip and /mappings.json BEFORE that
# backend has announced its real ResourcePackManager HTTP port. Default 1.
# In normal operation the backend announces the exact port it bound, so this
# value is only used at startup or if announcement fails — but if it IS used,
# it should match each backend's networkHttpOffset-v2.
network-http-offset-v2: 1

# Installs and updates this universal ResourcePackManager.jar in the proxy's
# Geyser extensions folder, which is what makes custom Bedrock ENTITIES render.
# Default true. Setting it to false stops future installation and update
# staging; it does not delete an extension jar that is already installed —
# remove that by hand while Geyser is stopped.
geyser-extension-auto-install: true

后端一侧对应的设置是后端 config.yml 中的 networkHttpOffset-v2geyserExtensionAutoInstall。两侧是彼此独立的设置——在代理上关闭扩展安装并不会在后端上把它关闭,反之亦然。

代理插件除了 config.yml 之外还会在同一个文件夹里写入一个 network-key 文件。那是生成的状态,不是配置:不要编辑它,也不要在不同网络之间复制它。删除它会让代理在下次启动时生成一个全新的密钥,从而解除所有已配发密钥的后端的链接(每个后端都会保留旧密钥,且不会采纳替换密钥)。只有在一种情况下复制它才是正确做法:两个代理位于同一组后端之前,它们必须共用同一个密钥。

代理侧不存在 force-resource-pack 设置。强制客户端接受资源包是后端侧的决定(后端 config.yml 中的 forceResourcePack),因为代理插件只负责基岩版资源包的分发——它从不发送 Java 资源包。如果旧的代理 config.yml 中仍带有 force-resource-pack 这一行,它会被直接忽略,可以删除。

也故意不提供 network-key 配置条目——可粘贴的密钥在发布前就被取消了,因为拼写错误会悄无声息地破坏 proxy↔backend 链接,而且任何地方都不会报错。密钥由代理确立并自动下发给后端,具体见 代理与后端如何建立链接

后端 HTTP 端口解析

代理需要知道在每个后端上轮询 /bedrock.zip/mappings.json 时该用哪个 HTTP 端口。它按以下顺序解析该端口:

  1. 后端公告的端点(优先)。 每个后端会把它实际绑定的确切 HTTP 端口上传到 magmaguy.com 端点注册表,以网络密钥为键。每次轮询时代理会刷新这份列表,并通过 Minecraft 端口(以及可用时的主机名)把某个后端公告的端口与服务器列表条目匹配起来。这意味着无论管理员在某个后端上显式设置了 selfHostPort,还是该后端自动落在 mcPort + 1 上,处理方式都完全相同——代理使用后端实际绑定的端口。
  2. 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 端口对外开放但相邻端口被防火墙屏蔽),后端会在网络命名空间(由网络密钥派生)下把 bedrock.zipmappings.json 推送到 magmaguy.com 上的中继端点。当直连拉取硬性失败时,代理会列出并从中继下载。

两条路径最终都汇入同一个合并步骤,因此运维人员无需在两者之间做选择——优先使用直连拉取(对 magmaguy.com 带宽成本为零),需要时中继会透明启用。

中继在服务端有 30 分钟的 TTL。后端每 25 分钟推送一次以保持条目存活;正常关闭会立即丢弃条目,而不必等待 TTL 过期。

常见问题排查

某个后端始终拿不到网络密钥

症状:该后端上的 /rspm status 显示 Network key source: not set — the proxy sends one when a player next connects here,且后端控制台反复输出:

[ResourcePackManager] This backend is behind a proxy but has no network key yet, so it is not linked to the proxy.
[ResourcePackManager] The proxy sends one automatically the first time a player connects to this server.

请按顺序逐条排查:

  1. **自代理启动以来,真的有人连接过那个后端吗?**密钥授予是随玩家连接一起发生的。一个还没人去过的大厅服处于未获密钥状态是完全合理的。
  2. **代理上到底装了 RSPM 吗?**后端正是为这种情况才在 plugins/ResourcePackManager/proxy-extension/ResourcePackManager.jar 暂存了一份自身 jar 的副本。把它复制到代理的 plugins/ 文件夹并重启代理。
  3. **Velocity 现代转发:后端的转发密钥和代理的一致吗?**配置为现代转发的后端会有意拒绝未签名或签名错误的授予——这项校验是唯一能阻止未授权代理给你的后端配发密钥的机制。后端日志会指明它遇到的是两种情况中的哪一种。在两侧都修正密钥后,下一次玩家连接会自动重试;两边都不需要重启即可重新就绪。
  4. **代理是不是不受支持的代理?**只有 Velocity 与 BungeeCord/Waterfall 会运行代理角色。

请注意 Floodgate 的 key.pem 已不再参与这一流程。代理上缺少 plugins/floodgate/key.pem 是一种完全受支持的状态——代理会改为生成自己的密钥。但基岩版玩家要想连上代理,仍然需要 Floodgate。

两个代理位于同一组后端之前

两个代理必须出示相同的网络密钥,否则每个后端会链接到先到达它的那一个,并拒绝另一个(记录 A proxy offered a network key that differs from the one this backend already uses)。请把主代理 RSPM 数据文件夹中的 network-key 文件复制到另一个代理的对应文件夹,然后重启它。

大约 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

每个后端与代理用的都是同一个 jar,所以请让所有组件保持相同版本。

手动方式是:升级后端 jar,把同一个 ResourcePackManager.jar 重新复制到代理的 plugins/ 文件夹,然后重启代理。

RSPM 也可以自己完成代理这一半。每个后端都会通过一条经过认证的路由(/rspm-update.jar,由从共享网络密钥派生出的令牌保护——密钥本身绝不会被传输)把自己的通用插件 jar 提供给代理。代理会校验所提供的文件确实是一个完整的通用 RSPM jar,其各平台描述符版本一致、入口点符合预期,拒绝降级,并在替换任何文件之前依据所声明的大小与 SHA-256 校验暂存下来的字节。它会为代理插件暂存同一个 jar;当检测到代理上托管着 Geyser 时,也会暂存其内置的 Geyser 扩展。这些文件会在代理关闭时应用,并保留此前的文件作为回滚副本。

这是一条经过认证的网络信任边界,而不是针对 Nightbreak 的独立来源校验:任何已被配发共享网络密钥的后端,都被信任可以提供一个结构有效、版本相同或更新的 RSPM jar。请保护好该密钥,并把共用它的每个后端都视为可信基础设施。

因此实践中,升级各后端然后重启代理通常就足够了——代理会已经为自己暂存好匹配的 jar。被拒绝的更新会记录 Rejected backend-offered ResourcePackManager update: ... 并附上原因。

目前尚未支持的内容

  • 通过代理插件在网络上分发 Java 资源包。 Java 客户端通过常规 API 直接从各后端接收资源包。代理侧没有 Java 资源包混合器。
  • 跨后端的 Java 资源包合并。 每个后端的 Java 资源包是独立的。玩家切换后端时会收到新后端的资源包。
  • 网络密钥的在线轮换。 一个后端只会采纳密钥一次,并且不会接受来自消息的替换密钥。要轮换密钥,需要删除代理的 network-key 文件,并清除每个后端 data.yml 中的 networkKey,然后重启所有节点。