將模組移植到 b1.7.3_rewrite 加載器
Java 模組無法執行。移植是使用解編譯後的模組作為規格的 Rust 重寫(wasm 客體,b173_api SDK)。
目標:在 b1.7.3 內擁有相同的外觀、感覺和遊戲玩法,從單一檔案在用戶端和伺服器端 mods/ 目錄中生效。當外觀和遊戲玩法不變時,可自由修正原始碼錯誤並進行最佳化。絕不取代原版畫面:額外 UI 是可切換的疊加層。
此檔案是完整的地圖。請勿閱讀加載器設計或進度文件、指南或完整的 SDK 檔案來定位方向。請使用這些工具,然後僅開啟該步驟所需的那一個範例檔案。
工作區
路徑相對於工作區根目錄,即包含 b1.7.3_rewrite/、ports/ 和工具集倉庫 b1.7.3_modport/ 的資料夾。工具集的 install.sh 會將其工具連結到 tools/modport/(下文以 T/ 表示),並將此技能連結到 .claude/skills/modport;從移植資料夾中,T/ 是 ../../tools/modport/。在 b1.7.3_modport/ 中修正或擴充工具,絕不在移植資料夾內進行。在新機器上,或當工具因缺少依賴項而失敗時,執行 T/doctor.sh:它會列印出修正每個間隙的指令。所有工具都是 bash 腳本:在 Windows 上,它們在 Git Bash(Claude Code 在 Windows 上的 bash 工具)中執行,並自行處理 .exe、.py 和路徑。透過 T/py.sh 呼叫 Python 工具,絕不直接使用 python3。
模式
每個工作階段檢查一次:在工作區根目錄中執行 test -f .modport-maintainer。
- 維護者模式(標記存在):加載器、SDK 和工具集倉庫是此使用者的自有倉庫。僅在使用者要求時,才按照下列步驟對它們進行提交和推送。
- 使用者模式(無標記,預設):加載器、SDK 和工具集倉庫屬於其上游作者。
- 加載器和 SDK 的擴充保留在本機工作樹中。絕不將它們提交到那些倉庫,絕不推送到它們的遠端,絕不執行
gh pr create、gh issue create或任何其他對它們的gh寫入操作,即使被要求「分享」或「上游」變更。請告訴使用者自行處理。 - 在
ports/<modid>/LOADER_CHANGES.md中記錄每次對加載器或 SDK 的變更:它新增了什麼、原因、哪些檔案。 - 告知使用者,需要本機加載器變更的移植項目僅在其修補後的加載器上執行,無法在原始加載器上執行。
- 移植資料夾是使用者自己的倉庫:當被要求時提交,僅推送到使用者設定的遠端。
- 絕不建立標記檔案。
- 加載器和 SDK 的擴充保留在本機工作樹中。絕不將它們提交到那些倉庫,絕不推送到它們的遠端,絕不執行
工具
| 工具 | 使用時機 | 輸出 |
|---|---|---|
T/new_port.sh <modid> <jar> [name] | 開始移植。寫入清單檔案、初始化 git、將內容解編譯到 reference/src(使用 Vineflower,首次使用時會下載並驗證)、執行庫存盤點 | ports/<modid>/ |
T/inventory.sh <src> | 列出模組註冊的內容:方塊、物品和實體及其類別、瓷磚、模型、渲染器、GUI、世界生成、事件 | 大型模組約 15 KB,保留在 reference/inventory.txt 中 |
T/api.sh | 在根據 SDK 編寫程式碼之前。sdk <file>(world、register、screen、behavior、events、terrain、config、services)、spec <Struct>、enum <Name>(HostCall、EntityField、ModelOp)、templates、events、console、hooks | 每個簽名一行,附帶 SDK 行號 |
T/py.sh extract_assets.py <jar> <modid> | 從移植資料夾中執行一次。紋理、聲音和語言檔提取到 assets/<modid>,語言鍵對應到 tile.<modid>.x.name、item.<modid>.x.name、<modid>.<key> | 永不提交 |
T/py.sh convert_models.py --out src/models/generated.rs <Model.java>... [--arg Model.scale=0.5] | 模型。ModelBase 建構子(SRG 或 MCP 名稱)轉換為 parts 和 boxes。將呼叫包裝在移植項目的 tools/convert_models.sh 中 | 產生的 Rust 程式碼,禁止手動編輯 |
T/test.sh deploy ports/<modid> [--game] | 每個測試週期。建置、停止測試伺服器、單獨安裝模組、啟動伺服器。--game 會先重新建置遊戲和 cargo-b173(在加載器或 SDK 變更後)。當測試伺服器仍在執行時拒絕:可能被另一個工作階段佔用,詢問後再使用 --force | 伺服器主控台尾部 |
T/test.sh errors [n] | 任何失敗後第一件事 | 兩個日誌中的 panic、trap 和 error 行 |
T/modtest.sh cmd <console line> / log server 80 | 驅動和檢查伺服器 | 僅回覆行 |
T/modtest.sh client / shot <png> | 僅視覺檢查。啟動用戶端前詢問使用者:它會在使用者桌面開啟一個視窗 | 遊戲視窗 PNG |
主控台(T/modtest.sh cmd loader ...,語法來自 T/api.sh console):gen、map(俯視 PNG)、slice(垂直切片 PNG)、column(在 tp 前檢查:傳送到地形的玩家會窒息)、fill、tp、use、interact、close、entities、summon、slot、tile。使用「Read」工具讀取 PNG。將重複的檢查鏈放入 ports/<modid>/tools/ 中的小型腳本,而不是重新輸入。
工作流程
- 設定。 選擇最接近測試版的原始版本(1.7.10 優於 1.12 優於 1.21):其模型、紋理和資料形狀幾乎是 1:1 對應。1.7.10 的 jar 使用 SRG 名稱(
func_、field_):從用途理解含義,不要尋找對應。執行new_port.sh,然後執行extract_assets.py。將模組模型繼承的原版模型類別複製到reference/vanilla/供轉換器使用。特定的資產額外項目(來自 3D 渲染器的精靈圖)放入移植項目自己的tools/腳本中。 - 規劃。 將
reference/inventory.txt轉換為 PORT_STATUS.md 中的待辦事項行,按依賴順序排列:方塊和物品、配方、世界生成和維度、實體、機器與 GUI、結構、Boss、玩家系統、額外欄位、物品行為、聲音與粒子、設定。里程碑以部署和主控台檢查結束。 - 逐模組移植。 閱讀模組的類別,使用
api.sh檢查 SDK,從範例複製模式。在 PORT_STATUS.md 中引用原始類別,而不是在程式碼註解中。 - 僅在
api.sh顯示無任何方法時擴充加載器(請參閱下方清單)。 - 每個模組後進行測試,使用
deploy、cmd、errors。將錯誤清單保留在 PORT_STATUS.md 中,而不是在一個問題上循環;最後修復清單。 - 完成。 更新 PORT_STATUS.md。在移植項目中執行
cargo +nightly fmt,並在b1.7.3_rewrite中執行cargo clippy。僅在被要求時提交:移植項目包含 Rust 原始碼、工具和清單,絕不包含資產、reference/或 AI 檔案。ports/可以是每個移植項目一個 git 倉庫,或是一個資料夾一個模組的單一倉庫;new_port.sh會自動偵測。在使用者模式下,在最終報告中列出移植項目需要的本機加載器變更(來自LOADER_CHANGES.md)。
範例
SDK 範例,始終存在:b1.7.3_rewrite/vendor/b1.7.3-modding-sdk/examples/ 包含 testmod(所有 API 模組在一個檔案中)、ruby(僅資料內容)、energy、energy_api、machines(模組間的服務)。
當工作區中有完成的移植項目時,它是最快的地圖。Aether 移植項目(ports/aether/src):
| 需求 | 檔案 |
|---|---|
| 方塊表、範本、行為 | blocks.rs(每種一個 const 行陣列) |
| 物品、工具、盔甲、食物、配方 | items.rs、tools.rs、gear.rs、recipes.rs |
| 設定選項 | config.rs(移植每個生成率骰子,缺少的會淹沒世界) |
| 實體註冊和輔助函數 | entities/mod.rs |
| 被動生物與坐騎、敵對、飛行器、投射物 | entities/phyg.rs + mount.rs、cockatrice.rs、zephyr.rs、projectile.rs |
| 用戶端可見的實體狀態 | entities/swet.rs、entities/moa.rs (setSynced/synced) |
| 模型與動畫 | models/mod.rs(part、cuboid、Program;複製到新移植項目) |
| Boss、Boss 血條 HUD、對話畫面 | entities/bosses/mod.rs、valkyrie_queen.rs(transparent() 畫面加伺服器端通道) |
| 附帶 GUI 和瓷磚資料的機器 | machines.rs(ScreenBuilder、#[tile_behavior]) |
| 額外裝備欄、渲染圖層 | accessories.rs(screens().overlay("GuiInventory", ..)、playerLayer) |
| 本機玩家移動 | player.rs(用戶端在 TickPost 中,伺服器端在由實體 ID 索引的 thread_local 映射中) |
| 維度、地形、裝飾 | world/mod.rs、world/terrain.rs、world/decorate.rs |
| 結構 | world/dungeons/mod.rs、writer.rs(terrain::structure::candidates、裁剪到 StructureBox::populated、將 256 高高度壓縮為 128) |
| 傳送門和旅行 | portal.rs |
始終適用的形狀:渲染器 GL 呼叫變成 Program 操作(push、translate、rotate、scale、texture、blend、lighting)在實體的 pose 中;onLivingUpdate/updateEntityActionState 移至 onAi(取代模板 AI)或 onTick;terrain::Random 和噪音移植保持種子相同;修改世界前檢查 isAuthority()(單人遊戲會將封包迴送,同一程式碼在兩端);驗證每個伺服器端封包;透過 translate("<modid>.gui.…") 聊天;聲音使用 <modid>.<path.with.dots>;紋理使用 <modid>:<path>。
資料形狀(加載器 API 1.1,ABI 3)。身分始終由名稱識別,絕不使用數值 ID:
-
方塊變體和朝向。 原始 metadata 或方塊狀態變成命名狀態:
ctx.blocks().states(name, BlockStatesSpec)或data/<modid>/states/<block>.toml。- 按原始 metadata 的順序列出每個屬性的值,以便
ctx.meta()程式碼繼續運作。 - 超過 16 個狀態的方塊會從加載器獲得額外的隱藏 ID。僅透過
world.blockState/setBlockState或ctx.state()/setState()讀寫此類方塊。 - 每個狀態的紋理放在
variants中。
- 按原始 metadata 的順序列出每個屬性的值,以便
-
每個堆疊的資料。 物品 NBT 和 capabilities 變成資料組件:使用
StackRef的stackComponent/setStackComponent。- 一個模組僅寫入
<modid>:*組件。 - 具有不同組件的堆疊永不疊加。
- 耐久度維持不變。使用每種變體一個物品,而不是使用耐久度子類型。
- 一個模組僅寫入
-
模組不擁有的東西上的資料。 實體、玩家、瓷磚、區塊和世界的 NBT 或 capabilities 變成每個模組的插槽:
- 實體:
entity.setData或setSynced - 玩家:
player.setData(key, ..) - 瓷磚實體:
world.setTileAttachment - 區塊:
world.setChunkAttachment - 世界:
setWorldData
每個插槽由模組 ID 作為鍵,因此兩個模組永不衝突。
- 實體:
-
對原版或其他模組內容的編輯。 屬性編輯(硬度、亮度、可燃性、工具)變成
ctx.blocks().modify(BlockModifySpec)或data/<modid>/modify/blocks/*.toml。生成列表編輯變成modifySpawns或modify/spawns/*.toml。工具類別的挖掘速度來自minecraft:mineable/<pickaxe|axe|shovel>標籤。衝突的編輯會在模組加載器畫面中顯示。絕不為屬性變更而取代整個原版方塊。 -
世界生成和指令。
- 每個世界生成特性使用唯一名稱。名稱為其隨機數播種,因此其他模組永遠不會移動它。
- 指令回覆
/<modid>:<name>。簡短形式/<name>會分配給第一個註冊它的模組。
擴充加載器
僅限通用特性,絕非一次性模組 hack。以下路徑在 b1.7.3_rewrite/ 內部。依序的接觸點:
- 協定:在
vendor/b1.7.3-modding-sdk/mod_protocol/src/abi.rs中的HostCall、GuestCall、GuestReply或EntityField結尾附加變體;在spec.rs中新增規格欄位作為Option或Default類型(spec 結構體使用#[serde(default)],因此舊模組仍可載入)。已發布的契約永不變更:變更的契約會獲得新版本。 - 主機:在
crates/modloader/src/host/world.rs(執行時期呼叫)或host/register.rs(註冊階段)中的 match 分支;較大的系統放在它們自己的crates/modloader/src/<system>.rs或extensions.rs中。新的模板是crates/modloader/src/entities.rs(ENTITY_TEMPLATES)或content/templates.rs(BLOCK_TEMPLATES)中的行。 - SDK 包裝器放在
b173_api/src/{world,register,screen}.rs中其同類旁邊,如果模組到處使用則放在 prelude 中。 - 用戶端放在
crates/client/src/modded/中。原版程式碼透過帶有// rewrite:註解的一行掛鉤呼叫新行為,該掛鉤在crates/modloader/hooks.toml中列出並帶有版本。 - 開發者主控台工具在
crates/modloader/src/devtools.rs中(新增到USAGE)。 cargo build和cargo clippy,然後T/test.sh deploy ports/<modid> --game。在工作區儲存加載器註記的地方記錄新增。維護者模式:僅在使用者要求時,在 SDK 子模組中提交 SDK 變更,然後在 rewrite 中更新版本。使用者模式:那裡不提交任何內容,變更記錄在LOADER_CHANGES.md中。
範例鏈:World::lightning:HostCall::Lightning (abi.rs) 到其在 host/world.rs 中的分支,再到 b173_api/src/world.rs 中的包裝器。
已知陷阱
-
HostCall、HostReply和 spec 結構體是 postcard 編碼的。絕不向現有結構體新增欄位:ABI 2 客體將無法解碼。新資料需要新的變體或新的結構體。 -
T/modtest.sh驅動一個共享的測試伺服器和用戶端(b1.7.3_rewrite/target/modtest,伺服器在其server/中)。未經使用者詢問,絕不停止、重置或接管另一個工作階段啟動的伺服器。 -
cargo b173 build已經執行 wasm 建置;沒有單獨的cargo build步驟。 -
加載器或 SDK 變更後未執行
deploy --game:伺服器仍然執行沒有新主機呼叫的舊二進位檔。 -
測試用戶端的視窗失去焦點並開啟暫停選單;它是測試台,不是移植項目。