跳到主要内容

Java 到基岩版转换

ResourcePackManager 可以将合并后的 Java 资源包转换为基岩版资源包,让 GeyserMC 客户端看到其中受支持的自定义内容。该功能默认启用。

转换的触发条件​

转换只在存在基岩版目标时才会运行。RSPM 在以下任一条件成立时认为目标存在:

  1. Geyser-Spigot 安装在本后端(基岩版玩家在本地通过 Geyser 接入)。
  2. Floodgate 安装在本后端(典型的代理-后端架构 —— Floodgate 在本地运行,Geyser 部署在其他位置)。
  3. 网络模式处于激活状态 —— RSPM 检测到自身处于 Velocity / BungeeCord 代理之后。后端会生成自己的基岩版资源包,并通过一个小型 HTTP 服务器暴露出来,供代理插件拉取。

还需要通过 bedrockConversionEnabled 启用转换。如果转换已关闭或没有目标,RSPM 会撤回以前的基岩版输出并跳过转换。/rspm status 会说明资源包未生成的原因。

哪些内容会被转换​

转换器与命名空间无关。它会递归遍历每一个符合 1.21.4+ 物品定义格式的 assets/<namespace>/items/**/*.json 文件,包括 minecraft 命名空间。

扁平与 3D 的分流​

对每个叶子模型,转换器会决定走两条流水线中的哪一条。以 minecraft:item/generated 或 minecraft:builtin/generated 为根的模型留在扁平路径上。对于其他所有父链,只有当合并后的模型携带非空的 elements 数组时,该模型才会走 3D 流水线;没有几何体的模型就是 2D 精灵图。

  • 扁平:将模型的 layer0 贴图复制到 textures/items/<hash>.png 并注册为 Geyser 图标。基岩版用这一层作为背包和手持的 2D 精灵图,不会保留任意的其他 Java 图层或模型分支。
  • 3D —— 转换器会拼合一张贴图图集、把 Java 立方体转换为基岩版几何体、生成手持/头部动画、软件渲染一个 64×64 的背包图标,并为每一组 (model × base item × item definition × predicate shape) 映射写出一个可附着物。

为什么几何体检查很重要:一件扁平的手持工具(父模型为 minecraft:item/handheld,只有 layer0 贴图而没有 elements)仍然是 2D 精灵图。早期版本会把扁平手持物品推进 3D 流水线,它们在几何体这一步失败,于是在基岩版上要么消失,要么退回显示原版基础物品的图标。这尤其影响 ItemsAdder 资源包,因为它们提供了大量扁平手持物品。由于 elements 是从合并后的父链中读取的,因此一个非 generated 的模型若从父模型继承了几何体,仍然会被分流到 3D。

RSPM 为每组 (model × base item × item definition × predicate shape) 映射派生基岩版标识符,以区分同一剑模型的不同基础物品和谓词变体,并让复用同一模型的两个物品定义使用各自独立的标识符。生成的文件名使用来源标识符的短哈希,而非文件内容的哈希,避免触发 Geyser 对 80 字符及以上资源包路径的警告。

支持的物品模型分支​

转换支持 model、condition、range_dispatch 和 select 节点,可带或不带 minecraft: 前缀。其他节点类型,包括 composite 和 special,会被跳过。Java 资源包显示正常,并不代表每个分支都能在基岩版重现。

节点支持的属性和回退行为
conditionbroken、damaged、fishing_rod_cast、has_component、custom_model_data。using_item 只保留 on_false 作为空闲模型。其他不受支持的条件会跳过两个分支。
range_dispatchdamage、count、bundle_fullness、custom_model_data。use_duration 和其他不受支持的属性只保留 fallback,如果存在。
selectcharge_type、trim_material、context_dimension、custom_model_data。display_context 保留 gui 分支,没有 GUI 分支时使用回退。其他不受支持的属性只保留回退。

这意味着 Java 的拉弓阶段和不同显示场景的模型不会自动保留。启用 bedrockConverterDebug 查看被跳过的节点和属性,并在基岩版客户端中检查生成的物品。

1.21.4 之前的旧资源包​

旧格式扫描器读取 assets/minecraft/models/item/ 直属的 JSON 文件,根据带有数值 predicate.custom_model_data 的覆盖条目生成范围分派定义。它不会递归扫描旧格式子目录,也不会保留覆盖条目的其他谓词。例如,同时依赖拉弓状态的覆盖条目会丢失这个条件。旧格式物品数量只在启用 bedrockConverterDebug 后显示。对持续维护的资源包,请使用 1.21.4+ 物品定义格式,并根据上表检查其分支。

基础物品​

Geyser 会把每个自定义物品映射到一个或多个 Java 基础物品之下。RSPM 按以下方式选择基础物品:

  • 旧格式的覆盖文件以及根目录下的 assets/minecraft/items/<item>.json 定义会映射到对应的原版物品。
  • 其他定义按文件名匹配。武器和工具相关的词会映射到相关的原版物品:sword 映射到六种剑,pickaxe 映射到六种镐,wand 或 staff 映射到 minecraft:stick,spear 映射到 minecraft:trident,依此类推。盔甲名称使用命名空间的装备文件或 helmet、boots 等槽位词。其他一切使用一组回退物品:纸、木棍、命名牌、指南针和六种剑。
  • freeminecraftmodels 命名空间中的定义还会映射到 minecraft:leather_horse_armor 之下,这是 FreeMinecraftModels 用来显示模型骨骼的物品。
  • 提供资源的插件可以在 assets/<namespace>/rspm_item_bases/<path>.json 中声明真正的基础物品,其中 <path> 与 items/<path>.json 对应。该文件内容为 {"base_items": ["minecraft:blaze_rod"]}。只会读取 minecraft: ID,它们会被添加到按文件名选出的物品中。FreeMinecraftModels 会为每个自定义物品写入一个这样的文件,使用其配置中指定的材质,因此基于 BLAZE_ROD 的魔杖能在基岩版上渲染出模型。

仅限 Java 版的物品​

提供资源的插件可以在 assets/<namespace>/rspm_item_java_only/<path>.json 放置一个文件,让物品不参与转换。只有文件是否存在才重要。它会排除 items/<path>.json 以及 items/<path>/ 下的所有物品定义,因此这些物品不会获得 Geyser 映射、图标或可附着物。FreeMinecraftModels 将其用于粒子效果背后的贴图物品,这些物品只被 Java 版物品展示实体使用;基岩版玩家看到的则是原生粒子。所有物品都仅限 Java 版的资源包不会触发旧格式警告。

手工编写的基岩版实体资源包​

插件可以在 Java 资源包的 assets/<namespace>/rspm_bedrock_pack/ 下放置原生基岩版实体资源。RSPM 将文件导入生成的基岩版资源包。只接受实体目录 entity、models/entity、animations、animation_controllers、render_controllers、materials、particles 和 textures/entity,因此插件不能覆盖清单或图标图集。受支持的路径达到 80 字符时会被缩短,同一资源集合中完全匹配的 JSON 路径引用也会更新。其他文件按原样复制。两个命名空间若在同一输出位置生成不同字节,会导致错误。

这正是实现真正的基岩版自定义实体的机制 —— 参见 Geyser 扩展与自定义实体。只包含实体资源包、完全没有物品映射的资源包同样会被正常分发。

穿戴盔甲转换只在扁平物品路径上针对盔甲或鞘翅基础物品执行。转换器从物品定义文件名中去掉已识别的装备槽后缀,得到 <material>,再在叶子模型的命名空间下查找 assets/<namespace>/equipment/<material>.json。它使用 humanoid 的第一层贴图;护腿使用 humanoid_leggings,鞘翅在存在时使用 wings。合并后的资源包必须包含对应 PNG。生成的可附着物使用基岩版原版盔甲几何体。仅有装备文件、额外贴图层或无关的装备资源 ID,不能证明盔甲可以转换。

基岩版资源包的清单 header / module UUID 是根据插件版本字符串确定性派生的(种子为 rspm_bedrock_header:<pluginVersion> 与 rspm_bedrock_module:<pluginVersion>),因此在同一插件版本的多次重建之间保持稳定,只有插件版本变化时才会改变。可见的 header 名称固定为 ResourcePackManager Bedrock Pack,它不参与 UUID。版本三元组在每次构建时根据一个 cache-bust 令牌递增,该令牌取自暂存基岩版资源包内容的 SHA-256 摘要——内容完全相同则版本相同(因此空操作的重建不会扰动 Geyser 的缓存),而真正的内容变更则会使基岩版以 (uuid, version) 为键的资源包缓存失效。仅在无法计算内容摘要时,才退而使用构建时间(System.currentTimeMillis())作为兜底。

按会话实时分发(独立服务器)​

启用转换且 Geyser-Spigot 位于同一个独立后端时,RSPM 会订阅 SessionLoadResourcePacksEvent,从磁盘向每位加入的玩家提供最新获准发布的基岩版资源包。如果已注册的物品映射不变,贴图或几何体修改可以在下次加入时送达,无需重启服务器。网络模式后端将分发交给代理,即使本地也安装了 Geyser-Spigot。

Geyser 的自定义物品映射,即 custom_mappings/ 中的 JSON,在启动时固定。增删物品、修改模型引用或谓词可能需要新的映射,因此需要重启。启用自动部署时,RSPM 会在启动早期部署之前获准发布的映射文件。首次转换成功后,请重启 Geyser 以加载新映射,然后重新连接基岩版客户端。

当前已连接的基岩版玩家会保留各自加入时收到的资源包——这是基岩版协议的限制,插件无法在会话中途绕过它。

在代理模式下的工作原理​

在代理网络中,后端本身不会注册 SessionLoadResourcePacks 订阅者(本地没有 Geyser 可以订阅)。流程是:

  1. 后端生成 output/ResourcePackManager_Bedrock.zip,并在存在物品映射时生成 output/rspm_geyser_mappings.json。
  2. 后端启动一个小型 HTTP 服务器(端口自动派生,默认为 mcPort + 1),暴露 /bedrock.zip 与 /mappings.json 两个路由,每次请求都会重新读取文件,并把它实际绑定到的确切端口公告给代理。
  3. 代理插件每 5 秒轮询一次,优先使用强 ETag 配合 If-None-Match,同时保留 If-Modified-Since 以兼容较旧的后端。当文件变化时它会下载每个后端的输出,并等待收件箱状态稳定。
  4. 代理插件将每个后端的基岩版资源包合并为一个全网络统一的资源包,并通过代理上的 Geyser 分发给基岩版客户端。
  5. 如果代理无法直接访问某个后端的 HTTP 端口(在共享/托管服务上很常见,相邻端口往往被防火墙屏蔽),后端会把文件推送到 magmaguy.com 的中继端点,代理则通过该中继获取它们。

安装方式请参阅 代理网络。代理侧的合并是自动进行的,没有启用开关。代理配置只有两项设置:network-http-offset-v2,即在后端端点公告可用之前使用的回退端口偏移;以及 geyser-extension-auto-install,它是 geyserExtensionAutoInstall 在代理侧的对应项。

输出文件​

合并成功后,基岩版相关文件位于:

plugins/ResourcePackManager/output/ResourcePackManager_Bedrock.zip
plugins/ResourcePackManager/output/rspm_geyser_mappings.json # only when item mappings exist

如果启用了自动部署并检测到本地 Geyser 数据目录,映射文件还会被复制到:

<geyser-folder>/custom_mappings/rspm_geyser_mappings.json

基岩版资源包的 zip 不会被复制到 <geyser-folder>/packs/ 中——而是按会话实时分发。如果某个较旧的 RSPM 版本曾在 Geyser 的资源包目录中留下 ResourcePackManager_Bedrock.zip,当前插件在 Geyser 运行期间不会删除它:Geyser 已经扫描过该路径,并且可能仍将其保留在内存中。RSPM 会在那次启动中跳过实时分发提供器的注册,并打印出确切的遗留文件路径。请完全停止服务器,只删除那个遗留文件,然后再启动服务器。执行 /reload 是不够的。

没有可转换的物品映射或允许的实体文件时,RSPM 撤回发布,并尝试删除旧的本地输出及其已部署到 Geyser 的映射。被锁定而留下的文件也不再获准分发。后端的 /bedrock.zip 返回 404,表示该后端不提供基岩版内容。仅含实体的资源包仍会发布。单纯替换 Java 方块或原版贴图不会生成转换后的资源包,需要另行制作基岩版资源包。

关闭 bedrockAutoDeployToGeyser 后,RSPM 会在协调配置时移除先前部署的映射。修改 bedrockGeyserFolder 也会清理原先由 RSPM 管理的目标位置。这两种操作都不会改变运行中的 Geyser 已加载的映射;请重启 Geyser 来应用新的映射集合。

config.yml 设置​

# Toggles Java-to-Bedrock conversion altogether.
bedrockConversionEnabled: true

# Copies the Geyser custom mappings file into the detected Geyser folder's
# custom_mappings/ directory on each mix.
bedrockAutoDeployToGeyser: true

# Manual override for the Geyser data folder. Empty = auto-detect.
# Relative values are tried from the server working directory first, then
# relative to plugins/. Absolute paths work directly.
bedrockGeyserFolder: ""

# Installs and updates the universal ResourcePackManager.jar in Geyser's
# extensions/ folder, which is what makes custom Bedrock ENTITIES render
# instead of armor stands. Separate from pack conversion above — items,
# textures and models convert and serve normally either way.
# Setting this false stops future installation and update staging; it does NOT
# remove an extension jar that is already installed. Delete that by hand while
# Geyser is stopped. See the Geyser extension page.
geyserExtensionAutoInstall: true

# Verbose per-item / per-bone progress logging from the Bedrock pipeline.
# Default false — a clean run emits a single "Bedrock conversion complete: N
# mappings" summary instead of dozens to hundreds of per-item lines. Flip on
# when debugging a specific conversion issue.
bedrockConverterDebug: false

自动检测 Geyser 目录会依次查找:

  1. 若 bedrockGeyserFolder 已设置,则先按字面值使用(因此相对路径从服务器工作目录解析;如果该位置不存在,再尝试相对于 plugins/ 解析)。绝对路径同样可用。
  2. plugins/Geyser-Spigot/
  3. plugins/Geyser-*/(任何变体)
  4. config/Geyser-*/(用于 Fabric/NeoForge 部署)

手持物品姿势​

每个 3D 可附着物都会获得第一人称、第三人称和头部动画。手持姿势取自 Java 模型的 display.firstperson_righthand 和 display.thirdperson_righthand 变换。RSPM 会通过原版基岩版玩家骨架映射每个变换,因此手持模型会出现在 Java 版绘制它的位置,位置、朝向和各轴缩放都相同。模型未定义的槽位使用 Java 的单位变换。头部动画取自 display.head。

没有需要调整的地方。要改变物品在手中的位置,请修改 Java 模型的 display 变换;Java 版和基岩版随后都会使用相同的值。该骨架使用宽手臂(Steve),因此使用细手臂皮肤时,基岩版与 Java 版可能相差半个像素。

早期版本会从 plugins/ResourcePackManager/bedrock_display_offsets.yml 添加手动调整的偏移。该文件及其 firstPerson* 和 thirdPerson* 设置已不再读取,更新后 RSPM 会重新生成缓存的基岩版资源包。旧的该文件副本可以删除。

手持物品粒子​

提供资源的插件可以通过位于 assets/<namespace>/rspm_item_particles/<model path>.json 的附属文件,为手持的 3D 物品附加粒子,其中 <model path> 是手持 Java 模型的路径(freeminecraftmodels:display/wand 对应 display/wand)。该附属文件将效果名称映射到插件在其实体资源包中提供的粒子标识符,以 Java 模型像素列出定位器,并包含一条循环粒子时间轴。RSPM 会把定位器添加到物品几何体中,并将该时间轴作为额外的可附着物动画播放,使基岩版客户端在第一人称和第三人称下都把粒子绘制在手部。FreeMinecraftModels 会为带有粒子效果的物品写入这些附属文件。无法读取的附属文件会被跳过,并记录一条警告。

调试日志​

提供两种调试入口:

  • 后端:在 config.yml 中设置 bedrockConverterDebug: true,会启用转换器逐物品、逐可附着物、逐映射的日志行。当你需要知道某个具体物品为什么没有进入基岩版资源包时很有用。它与 verboseLogging 是相互独立的:后者覆盖的是资源包合并与托管,而不是基岩版流水线 —— 排查转换问题你要用的是 bedrockConverterDebug。
  • 代理(Velocity 与 BungeeCord):/rspm debug bedrock on 切换代理端 GeyserBinder 输出的 [RSPM-BedrockDebug] 日志流。适用于基岩版玩家已经接入代理但看不到资源包的情况。该设置在代理重启时会重置为关闭,避免意外保持开启状态。

局限性与已知行为​

  • 3D 背包图标由软件根据 Java 模型的 display.gui 变换渲染。效果合理但并非像素级精确;如果图标看起来不对,最常见的原因是模型引用的贴图文件缺失或命名错误。
  • 用作物品图标的连拍贴图(flipbook)会被裁剪到第 0 帧——基岩版的 item_texture.json 不支持动画图标,只能通过 flipbook_textures.json 支持动画方块/地形贴图。
  • 可附着物几何体的格式版本固定为 1.21.0;如果你的安装无法解析它,请升级 Geyser。
  • 旧式原版物品模型覆盖文件(assets/minecraft/models/item/ 下的任何文件,包括 shield.json 和 crossbow.json)会跨资源包合并,而不是让某一个资源包完全取胜:只有 overrides 数组会被合并(按 override 键去重),而非 override 字段仍然遵循最高优先级取胜。没有任何文件被单独特殊对待。
  • 如果转换器无法解析某个被引用的贴图或模型文件,会跳过该叶子,其余流水线继续执行。启用 bedrockConverterDebug 可获得详细的解析追踪。当某个物品最终完全没有有效的自定义贴图,或某个被引用的模型 JSON 无法解析时,会输出一条普通警告。
  • 无法解析的物品定义 JSON 会以 Bedrock conversion failed: ... 中止转换。有效 JSON 如果缺少模型或包含不支持的节点,则可能只被跳过并记录调试日志。请检查错误和生成的映射数量,不要将每个被跳过的定义都视为致命解析错误。
  • 横幅与红石基础物品会被跳过。 以 16 种染色横幅之一或 minecraft:redstone 为基础物品的自定义物品不会获得 Geyser 自定义物品映射,因为 Geyser 会从这些基础物品推导出无效的方块放置器。基岩版上会为它们显示原版图标。发生这种情况时,控制台会列出受影响的物品。
  • 转换支持协作式取消。RSPM 暂存 ZIP 和映射,再将发布内容作为一组替换。替换过程中失败或取消时,会尝试恢复上一组;替换前的转换失败则撤回旧输出。已发布的哈希和资源组元数据使接收方可以拒绝过期或混合的世代。磁盘上存在 ZIP 并不能证明它当前获准分发,也不能证明基岩版客户端已渲染它。
  • 合并后的资源包既没有可转换映射,也没有允许的实体文件时,RSPM 撤回之前的发布并尝试删除输出。仅含实体的资源包在物品映射为零时也会生成。

资源包体积优化​

在发布基岩版资源包之前,RSPM 会对扩展名相同且字节完全一致的贴图文件去重,并把精确的 JSON 贴图引用重写为保留下来的那个文件。当某个引用存在歧义、嵌入在更长的字符串中,或出现在格式错误/不透明的 JSON 中时,它会有意保留别名,从而确保优化不会悄无声息地破坏资源引用。