Resource Pack Manager 故障排查
本页面只覆盖目前在 ResourcePackManager 代码中已确认的行为。
针对 RSPM 出现的任何问题,最有用的第一步是:
/rspm status
它会打印版本、部署模式(独立 vs network-backend)、一段简短且不含机密的网络密钥指纹以及该密钥的来源、Java 与基岩版资源包状态、当前激活的分发路径与 URL、解析得到的外部主机名 + 自动检测到的公网 IP、所有相关配置开关、一条代理部署提醒(网络代理 jar 就是同一个 ResourcePackManager.jar),以及 Floodgate / Geyser-Spigot 的检测情况。当该 jar 运行在代理上时也有同名命令,会打印代理侧的等价信息(后端列表、各后端的拉取结果、合并后的资源包状态)。
控制台的安静是刻意为之
每当 RSPM 全新初始化一条分发路径时,它只打印一行信息 —— 结果:
[ResourcePackManager] Resource pack is live via self-hosting — http://play.example.com:25566/rspm.zip
[ResourcePackManager] Resource pack is live via automatic hosting — https://magmaguy.com/rsp/<uuid>
其他所有内容 —— 暂存的每个资源包、合并的每个集群、每次稳定性检查、每次自托管探测及其结果 —— 默认都会被抑制。RSPM 能够自行恢复的状况不会作为警告上报。 如果一次自托管探测失败、RSPM 静默切换到远程托管,那是一次成功而不是故障,控制台对此只字不提。
因此:没有警告并不代表什么都没发生,而结果行的出现就意味着玩家能拿到资源包。在报告托管或合并的 bug 之前,请先打开叙述:
/rspm verbose on
然后执行 /rspm reload。该命令会替你把 verboseLogging: true 写入 plugins/ResourcePackManager/config.yml,并且该设置会在重启后保留,所以排查完毕后请执行 /rspm verbose off。手动编辑这个键效果完全相同。基岩版转换器有独立的开关 bedrockConverterDebug,它只能在配置中修改。
你确实可能合理看到的警告都是真正的故障:对某个特定玩家反复下发资源包失败、客户端报告 INVALID_URL、HTTP 端口无法绑定、两条分发路径同时失败,或者代理连续轮询多个周期都没有任何后端产出内容。
玩家收不到资源包
请先检查这些:
- 若希望使用正常的自动分发,必须启用
autoHost(selfHostForce是用于测试的显式覆盖开关) - 合并后的资源包必须存在,并且至少有一条分发路径(自托管或远程)已成功
- 玩家仅在加入服务器时,或在托管首次就绪时触发的首推广播中收到资源包
- Floodgate 玩家会被 Java 分发有意跳过,因为他们的基岩版资源包会话由 Geyser 负责
如有需要:
- 运行
/rspm status,查看 "Hosting" 部分。Active delivery显示当前使用的是自托管、远程,还是都没启用。 - 如果显示 "active delivery: not yet ready" — 合并或上传仍在进行中。当玩家加入过早时,插件会在控制台大字提示,并会在分发就绪的瞬间自动把资源包发给玩家。
- 如果显示 "active delivery: none — hosting disabled or failed" —
autoHost已关闭,或自托管探测和远程上传都失败了。参阅下文 “自托管完整性检查失败” 与 “自动托管无法连接到远程服务器”。 - 设置
verboseLogging: true,运行/rspm reload,在控制台观察上传 / 自托管探测的结果,再用一个测试玩家重新加入。(不打开该开关时不会打印探测步骤——只会打印最终那一行 "Resource pack is live via ..." 的结果。)
加入时的资源包下发会延迟约一秒。如果 Java 客户端报告 FAILED_DOWNLOAD 或 DISCARDED,RSPM 会针对该玩家会话自动重试,最多三次。它不会对玩家主动拒绝或 INVALID_URL 重试;重试次数耗尽和无效 URL 都会作为真正的故障记录下来。
如果你通过自己的外部流水线自托管(autoHost: false),RSPM 不会替你推送自定义 URL。在该模式下你仍需自己负责服务端的资源包分发流程。
已安装 ItemsAdder,但最终资源包里没有它的内容
这通常意味着 ItemsAdder 仍以某种方式阻止了 ResourcePackManager 读取或托管其输出。
请使用:
/rspm itemsadder configure
该命令目前会:
- 启用
resource-pack.hosting.no-host.enabled - 禁用
protection_1、protection_2和protection_3 - 将
resource-pack.zip.compress-json-files设为false - 运行
/iareload,再运行/iazip - 大约 15 秒后重新加载 ResourcePackManager
如果该命令提示 ItemsAdder 已经在自托管资源包,请先手动禁用 ItemsAdder 的托管,再重新运行该命令。
合并后的资源包无效或上传失败
ResourcePackManager 的自动托管集成会显式处理以下服务端错误类型:
- 缺少必需文件
- 文件过大
- 文件格式无效
- 会话缺失
- 远程服务器不可用
遇到其中之一时:
- 运行
/rspm reload重新构建资源包。 - 检查是否有某个源资源包格式错误、被加密或无法读取。
- 检查最终合并后的资源包根目录是否仍然包含有效的
pack.mcmeta和pack.png。
如果某个已启用的资源包无法被解压或暂存,本次合并会中止,控制台会指出出问题的那个资源包。请修复该资源包、移除手动添加的 ZIP,或在其自动集成配置中设置 isEnabled: false,然后再重新加载。
一个损坏的资源包不再永久阻塞一切
一个无法暂存的资源包在每次重试时都会以同样的方式失败,放任不管就会让分发永久卡死——合并永远完不成,同样的错误无限重复。在同一个文件连续失败三次之后,RSPM 会把该资源包从合并中剔除,让其余资源包得以发布,并且会明确、响亮地说明一次:
[ResourcePackManager] Resource pack X.zip failed to stage 3 times in a row and has been excluded
from the merge so the remaining packs can be delivered. The merged pack is now INCOMPLETE ...
请按字面理解这句话:玩家现在拿到的资源包缺少那个插件的内容。常见原因是 zip 损坏或写入不完整。
这种剔除会自行解除。失败记录以该文件的大小和修改时间为键,因此修复或替换该文件会自动解除隔离,该资源包会重新加入下一次合并——无需命令,也无需重启。/rspm reload 同样会把所有隔离记录清零重来。任何一次成功的合并之后,尚未达到三次的失败计数都会被丢弃,因此长时间运行中零散出现的无关瞬时故障不会累积成一次剔除。
当远程 auto-host 报 SESSION_NOT_FOUND 错误时,RSPM 会清掉自己的会话 UUID,并在下一次保活心跳时重新初始化——无需人工干预。
一个插件的资源覆盖了另一个插件的资源
这由下面这个文件中的 priorityOrder 控制:
plugins/ResourcePackManager/config.yml
靠上的条目会胜过靠下的条目。
对于不可合并的文件,ResourcePackManager 会替换低优先级文件。对于可合并的 JSON 文件,则会合并内容。当前可合并的 JSON 类别有:
sounds.json- 语言文件
- 位于
minecraft/models/item的原版物品模型 JSON(非递归合并:跨资源包只合并overrides数组,文件其余部分遵循最高优先级取胜) - 图集(atlas)文件
- 字体(font)文件
- 位于
items/的 1.21.4+ 物品模型定义(格式感知合并,尊重 predicate 树结构)
pack.mcmeta 的合并方式也较特殊:取最高的 pack_format,supported_formats 范围会被扩展(支持整数、双整数数组以及 {min_inclusive, max_inclusive} 对象三种形式),overlay 条目会被合并,非标准顶层键会被保留。Overlay 条目还会针对 1.21.9+ 兼容性进行规范化:缺失时会自动补齐 min_format/max_format 字段。基础 atlas 源也会被合并进 overlay atlas 文件,防止 overlay 屏蔽基础条目。
如需查看最近一次合并发生了什么,请查阅:
plugins/ResourcePackManager/collision_log.txt
GUI 文本或基于字体的元素显示异常
字体文件是 ResourcePackManager 会合并的 JSON 类别之一,但这并不保证两套不同的字体系统在 Minecraft 中能够良好共存。
如果某个基于字体的菜单或 HUD 显示异常:
- 修改
priorityOrder,让你希望胜出的资源包靠前。 - 运行
/rspm reload。 - 检查
collision_log.txt,确认冲突发生在你预期的位置。
资源包变更没有立即生效
ResourcePackManager 对受支持的资源包来源具有看门狗机制。
它会等到某个发生变化的资源包持续 3 秒不再变化为止,然后在所有被监视资源包都稳定之后立即开始重新合并。
如果你正在主动重新生成另一插件的资源包,请在文件写入停止后再给它几秒时间。如果仍不确定,可在上游插件完成后运行 /rspm reload。
/rspm status 显示远程托管,但我预期的是自托管
当 preferSelfHost: true(默认)且三项自托管完整性检查之一失败时,这属于正常行为。RSPM 不会对此发出警告 —— 回退到远程托管是一个成功的结果,因此失败的那项检查会以明确的 "This is OK." 记录在细节级别,除非设置 verboseLogging: true,否则它保持隐藏。默认情况下你得到的唯一一行是 Resource pack is live via automatic hosting — ...。
运行 /rspm verbose on(或设置 verboseLogging: true)并执行 /rspm reload,即可看到是三层中的哪一层失败了:
- 第 1 层(启发式) — 解析得到的外部主机名是 RFC1918 / 回环地址 / 链路本地。请将
selfHostExternalHost设为你真正的公网主机名,或确保插件能访问 api.ipify.org / checkip.amazonaws.com。 - 第 2 层(本地回环自探测) — 对
http://127.0.0.1:<port>/rspm.zip发起的 HEAD 请求没有返回 200 + 非空主体。能捕获端口占用冲突或资源包文件缺失的情况。 - 第 3 层(外部可达性探测) — magmaguy.com 尝试拉取你公告的 URL 但访问不到。最常见原因:HTTP 端口没有在路由器/防火墙上放通。在
verboseLogging下会打印探测 URL 与一个原因代码(PRIVATE_HOST_REJECTED、CONNECT_TIMEOUT、ECONNREFUSED、RATE_LIMITED等)。
修复方式(按推荐顺序):在防火墙 + 路由器上放通 HTTP 端口;将 selfHostExternalHost 设为可路由的主机名;或将 preferSelfHost: false 完全跳过自托管。
当 magmaguy.com 探测本身都不可达(RSPM 连询问的对象都连不上)时,会保留自托管而不是判定失败——理由是回退路径同样需要 magmaguy.com,所以以“无法探测”为由拒绝自托管在逻辑上是自相矛盾的。
完整决策树请参阅自托管。
自动托管无法连接到远程服务器
ResourcePackManager 内置的远程托管会与下面这个地址通信:
https://magmaguy.com/rsp/
如果该连接失败,插件会记录通信警告,并且在重新连接成功之前无法使用远程回退。
你的选项有:
- 修复服务器的出站 HTTPS 连接
- 等待远程服务恢复可达
- 禁用
autoHost,自行托管生成的 zip - 放通你的 HTTP 端口,把
selfHostExternalHost设为你的公网主机名,并保持preferSelfHost: true。显式主机名会跳过公网 IP 自动检测,但 RSPM 仍会尝试第 3 层探测。如果探测服务本身不可达,RSPM 会继续自托管,而不会把那次通信失败当作“你的 URL 不可达”的证据。
我想通过自己的 Web 服务器自托管合并后的资源包
代码层面支持的做法是:
- 设置
autoHost: false。 - 如果希望 ResourcePackManager 额外把一份副本写入某个已存在的文件夹,则设置
resourcePackRerouting。 - 自己托管
ResourcePackManager_RSP.zip。
resourcePackRerouting 相对于 plugins 目录解析,且目标文件夹必须已存在。
如果你想使用 RSPM 内置的自托管 HTTP 服务器(这是另一件事——它与插件运行在同一个 JVM 中),请参阅自托管。
我需要查看本服务器在远程存储了哪些数据
请使用:
/rspm data_compliance_request
如果存在活动的远程托管会话,ResourcePackManager 会把响应下载到:
plugins/ResourcePackManager/data_compliance/data.zip
RSPM 还会在同一个 data_compliance 文件夹中写入 ReadMe.md。
如果没有远程会话(例如你正在使用自托管),该命令会报告当前没有可请求的远程数据。
没有生成基岩版资源包
bedrockConversionEnabled 默认值为 true,因此应当会自动运行。请先运行 /rspm status——Bedrock Pack 部分会告诉你资源包为何不在磁盘上:
- "No Bedrock target detected" — 本地没有 Geyser-Spigot、没有 Floodgate,也不在网络模式下。转换被有意跳过。安装 Floodgate(用于代理部署)或 Geyser-Spigot(用于独立部署)后运行
/rspm reload。 - "Network mode is active so this backend SHOULD produce a Bedrock pack. The file is missing" — 通常是第一次合并周期还没完成(启动后大约等 30 秒),或转换既没找到可转换的物品映射也没找到被允许的实体资源包,或转换抛了异常。在控制台中搜索
[BedrockConverter]警告或Generic scanner: discovered 0 items definition files。
如果 Geyser 自动检测失败:
- 在
config.yml中将bedrockGeyserFolder设为 Geyser 的数据目录路径(例如Geyser-Spigot)。 - 绝对路径可用。相对路径会先从服务器工作目录尝试,再按相对于
plugins目录尝试。
转换器会自动在 plugins/Geyser-Spigot/、任何 plugins/Geyser-*/ 变体,或者 Fabric/NeoForge 部署下的 config/Geyser-*/ 中查找 Geyser。
如需逐物品 / 逐骨骼的日志输出,将 bedrockConverterDebug: true 并重新加载。
基岩版:因存在遗留资源包而跳过了实时分发提供器
如果控制台报告 Legacy RSPM Bedrock pack detected,说明 Geyser 在启动时已经从其资源包目录扫描过一个旧的 ResourcePackManager_Bedrock.zip。在进程运行期间删除那个文件,会让 Geyser 在内存中持有一个指向已不存在路径的编解码器,因此 RSPM 会在那次启动中有意跳过自己的实时资源包提供器。
请完全停止服务器,只删除 RSPM 打印出来的那个确切的遗留文件路径,然后重新启动服务器。不要用 /reload 来完成这次迁移。当前的资源包仍然位于 plugins/ResourcePackManager/output/ 并按会话分发;它不属于 Geyser 的 packs/ 目录。
基岩版玩家看到手持物品位置错误
这是调优问题,而非转换 bug。打开 plugins/ResourcePackManager/bedrock_display_offsets.yml,调整相应的轴,运行 /rspm reload,然后让基岩版测试客户端重新连接,这样它下一次加入时就会收到重建后的资源包。第一人称与第三人称相互独立——调整一个不会影响另一个。完整的旋钮列表及其作用请参阅基岩版转换。
基岩版玩家身上看不到自定义盔甲贴图
自定义盔甲在基岩版上的渲染方式是:将原版盔甲几何体与 Java 贴图组合为可见层。要让它工作,源插件的资源包必须在物品定义旁边提供 assets/<namespace>/equipment/<material>.json 装备文件。如果转换日志中显示了该物品,但游戏中没看到盔甲贴图,请确认该文件存在于合并后的资源包中。
代理:某个后端说它没有网络密钥
在该后端上,/rspm status 显示 Network key source: not set — the proxy sends one when a player next connects here,控制台反复输出 "This backend is behind a proxy but has no network key yet"。
缺少 plugins/floodgate/key.pem 不是原因——那个文件现在是可选的。密钥由代理持有:它会加载自己的 network-key 文件,或在存在 Floodgate key.pem 时一次性地从中播种,或者生成一个全新的密钥,然后在有玩家连接到某个后端时把它推送过去。
请按顺序检查:
- 自代理启动以来,有玩家连接过那个后端吗?密钥授予是随玩家连接一起发生的。
- 代理上真的有
ResourcePackManager.jar吗?后端会替你在plugins/ResourcePackManager/proxy-extension/ResourcePackManager.jar暂存一份自身 jar 的副本并打印该路径——把它复制到代理的plugins/并重启代理。 - 在使用现代转发的 Velocity 上,后端的转发密钥与代理的一致吗?配置为现代转发的后端会有意拒绝未签名或签名错误的授予;它的日志会指明是哪一种。在两侧修正密钥后,下一次玩家连接会自行重试。
- 对比两侧
/rspm status输出的Network key fingerprint行。指纹相同说明链接正常;密钥本身永远不会被打印出来。
完整流程请参阅代理网络。
代理:报 "Could not save the network key"
代理解析出了一个密钥,但无法把它写入自己的 network-key 文件。本次启动仍能正常工作。但下次重启会生成一个不同的密钥,而每个已经配发过密钥的后端都会保留旧密钥并拒绝新密钥——整个网络会悄无声息地解除链接。
请在重启之前修复代理插件数据文件夹的文件系统权限。
代理:经过几轮轮询后仍 "no merged pack"
在代理上经历约 20 秒的空轮询循环后(4 轮 × 默认 5 秒间隔),RSPM 会一次性记录一个诊断横幅,列出它轮询过的每个后端、尝试访问的 HTTP URL,以及结果(200 / 304 / 404 / CONNECT_FAILED / 等)。横幅会解释最常见的修复方法:
- 每个后端都返回
CONNECT_FAILED→ 代理无法访问后端的 HTTP 端口。检查velocity.toml/config.yml中的地址是不是代理真正能访问到的(而不是诸如 Docker 内部名之类、从代理网络解析不到的地址),并确认代理与后端之间后端公告的 HTTP 端口是放通的。横幅会打印它尝试访问的确切 URL;在某个后端公告其端口之前,代理会回退到mcPort + network-http-offset-v2,所以早期的CONNECT_FAILED也可能意味着那个回退端口暂时还不可达。 - 每个后端都返回
NOT_FOUND_404→ 后端已就绪,但没有生成基岩版资源包。在每个后端运行/rspm status;Bedrock Pack 诊断块会告诉你原因。
每个卡住期内横幅只触发一次,当至少有一个后端重新开始返回内容时,会记录一行 "NetworkSync: recovered"。详见代理网络。
代理:第一次启动代理时基岩版玩家看不到任何模型
Geyser 只在代理启动时注册其自定义物品表。如果代理在任何后端生成基岩版资源包之前就启动了,Geyser 就会带着空的映射表运行,并在整个会话期间保持空表。
修复方法:在代理日志中出现 Merged Bedrock pack published at ... 之后,重启一次代理。RSPM 会在代理启动时预先部署上一次运行的映射,所以这种情况只会在全新安装时碰到一次——后续启动时 Geyser 扫描前总会有可用的映射就位。
后端:报 "Backend HTTP server failed to bind on port X"
在网络模式下,后端会通过一个小型 HTTP 服务器暴露其基岩版输出。如果端口被占用或不可用,控制台会出现多行 [ERROR] 块。修复方法:
- 在
config.yml中把selfHostPort设为另一个正整数值。 - 或者修改
networkHttpOffset-v2,把自动派生出的端口避开冲突(例如 RCON 占用了mcPort + 1?改成 2 或 3)。你不需要同步更新代理:一旦后端成功绑定,它会自动把自己实际的 HTTP 端口公告给代理,因此代理自己的network-http-offset-v2仅作为公告之前的猜测才有意义。
在后端 HTTP 服务器无法启动期间,该后端的基岩版资源包无法通过直连方式送达代理。magmaguy.com 中继回退仍然可用(后端把文件推送到中继,代理从中继获取它们)。
清理过时的 v1 配置
从 RSPM v1 升级的运维人员,config.yml 中可能仍有一个已废弃的 networkHttpOffset(不带 -v2)键。RSPM v2 故意不读取旧键——下次启动时会自动把 v2 默认值(1)写入配置。废弃的 v1 键会以无害遗留物的形式留在你的配置中,等你手动清理它。