跳至主要內容

Java 轉 Bedrock 轉換

ResourcePackManager 可將合併後的 Java 資源包轉換為 Bedrock 資源包,讓 GeyserMC 用戶端看到與 Java 用戶端相同的自訂內容。此功能預設為啟用。

何時會執行轉換

轉換以「是否存在 Bedrock 目標」為條件。下列任一條件成立時,RSPM 即視為存在目標:

  1. 此後端上安裝了 Geyser-Spigot(Bedrock 玩家在本地連線到 Geyser)。
  2. 此後端上安裝了 Floodgate(典型的代理-後端架構——Floodgate 在本地執行,Geyser 在其他地方)。
  3. 網路模式啟用中——RSPM 偵測到自身位於 Velocity / BungeeCord / Waterfall 代理後方。後端會產出其 Bedrock 資源包,並透過一個小型 HTTP 伺服器公開,讓代理外掛能拉取。

若上述條件皆不成立,轉換器純粹是額外負擔,會被靜默略過。當資源包未產生時,/rspm status 會明確說明原因。

會轉換哪些內容

轉換器與命名空間無關。它會遍歷每個符合 1.21.4+ 物品定義格式的 assets/<namespace>/items/*.json 檔案。對每個葉節點模型會選擇下列其中之一:

  • 產出扁平的 Bedrock 物品欄圖示(適用於一般的 minecraft:item/generated 與類似的扁平內建父模型),或
  • 產出 Bedrock 幾何模型、附掛物、動畫檔以及軟體渲染的 2D 物品欄圖示(適用於真正的 3D 模型)。

每組 (模型 × 基礎物品) 都會產生唯一的 Bedrock 識別碼,因此將同一把劍模型註冊到多個基礎物品時,在 Geyser 端不會發生衝突。

當存在並列的 assets/<namespace>/equipment/<material>.json 時,會偵測到自訂盔甲組。轉換器會串接一個盔甲附掛物,結合原版盔甲幾何與 Java 材質作為可見圖層,因此 Bedrock 玩家穿戴該物品時可看到正確的盔甲材質。

Bedrock 資源包的 manifest header / module UUID 是依外掛版本字串以確定性方式衍生(種子為 rspm_bedrock_header:<pluginVersion>rspm_bedrock_module:<pluginVersion>),因此在同一外掛版本的多次重建之間保持穩定,只有在外掛版本變更時才會改變。資源包名稱本身僅用於 header.name,不用於 UUID。版本三元組會在每次建置時依一個 cache-bust token 遞增,該 token 衍生自暫存 Bedrock 資源包內容的 SHA-256 摘要——相同內容會產生相同版本(因此無變動的重建不會擾動 Geyser 的快取),而真正的內容變更則會讓 Bedrock 以 (uuid, version) 為鍵的資源包快取失效。建置時間(System.currentTimeMillis())僅在無法計算內容摘要時作為後備使用。

每個工作階段即時提供(獨立模式)

當在同一後端上偵測到 Geyser-Spigot 時,RSPM 會註冊一個 SessionLoadResourcePacksEvent 訂閱者。每位在新一次混合之後加入的 Bedrock 玩家,都會直接從磁碟收到最新的 Bedrock 資源包——對現有物品的材質或模型編輯無需重啟伺服器。

Geyser 的自訂物品對應 (custom_mappings/ 中的 JSON) 仍會在啟動時凍結,因此新增自訂物品或移除既有物品時,仍需重啟伺服器才能讓 Bedrock 用戶端看到那些變更。RSPM 會在啟動早期預先佈署上一次執行的對應檔,讓 Geyser 啟動時的自訂物品註冊能自動取得。

目前已連線的 Bedrock 玩家會保留各自加入時收到的資源包——這是 Bedrock 通訊協定的限制,外掛無法在工作階段中途覆寫。

在代理模式下如何運作

在代理網路中,後端本身不會註冊 SessionLoadResourcePacks 訂閱者(本地沒有 Geyser 可供訂閱)。改為:

  1. 後端如同往常產出 output/ResourcePackManager_Bedrock.zipoutput/rspm_geyser_mappings.json
  2. 後端啟動一個小型 HTTP 伺服器(自動衍生連接埠,預設為 mcPort + 1),公開 /bedrock.zip/mappings.json 路由,每次請求都會即時讀取檔案,並向代理通報它實際綁定的確切連接埠。
  3. 代理外掛每 5 秒透過 If-Modified-Since 輪詢一次、在內容變更時下載每個後端的輸出,並等待 inbox 穩定。
  4. 代理外掛將每個後端的 Bedrock 資源包合併為單一的網路級資源包,再透過代理的 Geyser 提供給 Bedrock 用戶端。
  5. 若代理無法直接連到後端的 HTTP 連接埠(在共享 / 代管託管環境中常見,相鄰埠通常被防火牆擋掉),後端會將檔案推送到 magmaguy.com 中繼端點,代理則從那裡取得。

設定方式請參閱代理網路。在代理端,轉換(其實是合併)完全自動進行;Bedrock 管線沒有代理端的設定選項。

輸出檔案

成功混合之後,Bedrock 檔案會位於:

plugins/ResourcePackManager/output/ResourcePackManager_Bedrock.zip
plugins/ResourcePackManager/output/rspm_geyser_mappings.json

若啟用了自動佈署,且在同一 JVM 中偵測到 Geyser,對應檔也會複製到:

<geyser-folder>/custom_mappings/rspm_geyser_mappings.json

Bedrock 資源包的 zip 不會複製到 <geyser-folder>/packs/——而是改為每個工作階段即時提供。RSPM 也會移除舊版外掛在該資料夾中遺留的舊副本,避免 Geyser 重複提供同一個資源包(重複的 UUID 會讓 Bedrock 用戶端混淆)。

當轉換器在合併後的資源包中找不到任何可轉換內容(沒有物品定義)時,RSPM 會刪除前次執行留下的過時 Bedrock 輸出,而非提供空資源包。此時後端的 /bedrock.zip 路由會乾淨地回傳 404,這正是給代理的正確訊號——此後端沒有 Bedrock 內容可提供。

config.yml 設定

# 完全切換 Java 轉 Bedrock 轉換。
bedrockConversionEnabled: true

# 在每次混合時,將 Geyser 自訂對應檔複製到偵測到的 Geyser 資料夾的
# custom_mappings/ 目錄中。
bedrockAutoDeployToGeyser: true

# 手動覆寫 Geyser 資料夾路徑。留空 = 自動偵測。
# 可為絕對路徑,或相對於 plugins/ 目錄的路徑。
bedrockGeyserFolder: ""

# 來自 Bedrock 管線的逐物品 / 逐 bone 詳盡進度日誌。
# 預設 false——一次乾淨的執行會輸出單一行
# 「Bedrock conversion complete: N mappings」摘要,而非數十至上百行的逐物品日誌。
# 在排查特定轉換問題時再開啟。
bedrockConverterDebug: false

自動偵測 Geyser 資料夾時,會依序檢查:

  1. 若有設定 bedrockGeyserFolder(先視為絕對路徑,再視為相對於 plugins/ 的路徑)。
  2. plugins/Geyser-Spigot/
  3. plugins/Geyser-*/(任何變體)
  4. config/Geyser-*/(適用於 Fabric/NeoForge 環境)

調整手持物品顯示:bedrock_display_offsets.yml

Bedrock 透過一個父 bone 來渲染手持物品,而該 bone 的靜止姿勢與 Java 的第一人稱/第三人稱變換不同,因此演算法式轉換必須在 Java 模型 display 變換所指定的內容之上再套用一個基礎偏移。預設偏移適用於一般的右手 Java 模型,但特殊情況可能需要調整。

第一人稱與第三人稱是兩個完全獨立的 Bedrock 渲染流程(不同的父 bone、不同的靜止姿勢),因此各自有獨立的六個調整項。調整其中一邊不會影響另一邊。

# ===== 第一人稱(右手,由持有者看到的視角)=====
firstPersonBaseRotationX: -90.0 # pitch(朝向/遠離鏡頭傾斜)。預設值用於抵消父層旋轉。
firstPersonBaseRotationY: 0.0 # yaw(繞垂直軸旋轉)
firstPersonBaseRotationZ: 0.0 # roll(繞鏡頭前向軸旋轉)
firstPersonBasePositionX: 0.0 # 螢幕上的垂直位置(正值 = 向上)
firstPersonBasePositionY: 12.5 # 深度(正值 = 更深入場景)
firstPersonBasePositionZ: 0.0 # 螢幕上的水平位置(正值 = 向右)

# ===== 第三人稱(右手,由其他玩家/F5 看到的視角)=====
thirdPersonBaseRotationX: 90.0 # 觀察者所見的 pitch
thirdPersonBaseRotationY: 0.0 # yaw
thirdPersonBaseRotationZ: 0.0 # 繞物品長軸的 roll
thirdPersonBasePositionX: 0.0 # 跨持有者身體的水平位置(正值 = 向外)
thirdPersonBasePositionY: 12.5 # 垂直位置(正值 = 抬高模型)
thirdPersonBasePositionZ: 0.0 # 相對於持有者的深度(正值 = 向前)

位置值的單位為像素,其中 1 像素 = 1/16 個方塊。旋轉值的單位為角度。

Bedrock 用戶端會即時重新載入 attachable JSON,無需重新啟動。若有 Bedrock 測試用戶端已登入,改完數值後執行 /rspm reload,下一次 Bedrock 加入(或在某些情況下,目前已連線的玩家在世界中執行一個會重新綁定附掛物的小動作之後)即可看到新的偏移。反覆迭代直到看起來正確。

除錯日誌

有兩個除錯介面可用:

  • 後端:在 config.yml 中設定 bedrockConverterDebug: true 會開啟轉換器的逐物品、逐附掛物、逐對應日誌行。當你需要了解某個特定物品為何沒進入 Bedrock 資源包時相當有用。
  • 代理(Velocity 與 BungeeCord)/rspm debug bedrock on 會切換代理 GeyserBinder 發出的 [RSPM-BedrockDebug] 日誌串流。當 Bedrock 玩家加入代理但看不到資源包時相當有用。此設定會在代理重啟時重置為關閉,因此不會意外被遺留為開啟。

限制與已知行為

  • 3D 物品欄圖示是透過 Java 模型的 display.gui 變換以軟體渲染。渲染結果合理但並非像素級完美;若圖示看起來不對,最常見的原因是模型參照的材質檔案缺失或檔名錯誤。
  • 用作物品圖示的 flipbook 材質會被裁切為第 0 幀——Bedrock 的 item_texture.json 不支援動畫圖示,只有透過 flipbook_textures.json 的方塊/地形材質才支援動畫。
  • 附掛物幾何格式版本固定為 1.21.0;若你的安裝無法解析,請更新 Geyser。
  • 舊版原版物品模型覆寫檔(assets/minecraft/models/item/ 下的任何檔案,包括 shield.jsoncrossbow.json)會跨資源包合併,而非讓單一資源包完全勝出:只有 overrides 陣列會被合併(並依覆寫鍵去除重複),非覆寫欄位則維持「最高優先級勝出」。沒有任何檔案會被挑出來特殊處理。
  • 若轉換器無法解析某個被參照的材質或模型檔,該葉節點會被略過,並記錄一則 [BedrockConverter] 警告(若 bedrockConverterDebug 關閉則為一行除錯日誌);管線其餘部分會繼續執行。
  • 當合併後的資源包不包含任何可轉換物品時,完全不會輸出 Bedrock 資源包,且任何前次執行的輸出都會被刪除。RSPM 不會提供一個附帶提示的無用 ~22 KB 空資源包。