# ThaumicEnergistics 代码位置速查表 > 说明:本文件所有路径均相对于 `modules/thaumicenergistics-neo/src/main/`。 > 若文件路径以 `java/` 开头 → Java 源码;以 `resources/assets/` 开头 → 资源/JSON。 --- ## 一、物品 / 方块 Java 注册 | 你想找什么 | 文件 | 关键行 | 备注 | |---|---|---|---| | 物品总注册器入口 | `java/thaumicenergistics/init/ModItems.java` | **12** | `DeferredRegister.Items REGISTRY` | | 1k/4k/16k/64k 源质存储单元(带容量的 Cell) | `ModItems.java` | 14~18 | `ESSENTIA_CELL_1K ~ ESSENTIA_CELL_CREATIVE` | | 1k/4k/16k/64k 存储组件(Storage Component) | `ModItems.java` | 19~22 | `STORAGE_COMPONENT_1K ~ 64K` | | 聚变核心 / 扩散核心 | `ModItems.java` | 23~24 | `COALESCENCE_CORE` / `DIFFUSION_CORE` | | 铁齿轮 / 知识核心 / AE扳手核心 | `ModItems.java` | 25~27 | `IRON_GEAR` / `KNOWLEDGE_CORE` / `FOCUS_AEWRENCH` | | 无线源质终端 / 傀儡WiFi背包 | `ModItems.java` | 28~29 | `WIRELESS_ESSENTIA_TERMINAL` / `GOLEM_WIFI_BACKPACK` | | 源质IO总线/存储总线/终端/LevelEmitter/Vis接口/共鸣器 | `ModItems.java` | 30~37 | `ESSENTIA_IMPORT_BUS` 等一整套 | | 方块对应物品(BlockItem) | `ModItems.java` | 39~47 | `ESSENTIA_PROVIDER_ITEM`、`KNOWLEDGE_INSCRIBER_ITEM` 等,与 ModBlocks 一一对应 | | 方块总注册器入口 | `java/thaumicenergistics/init/ModBlocks.java` | **17** | `DeferredRegister.Blocks REGISTRY` | | 源质提供器 Essentia Provider | `ModBlocks.java` | 20 | `ESSENTIA_PROVIDER` | | 注入提供器 Infusion Provider | `ModBlocks.java` | 21 | `INFUSION_PROVIDER` | | 奥术组装机 Arcane Assembler | `ModBlocks.java` | 22 | `ARCANE_ASSEMBLER`(Tile: TileArcaneAssembler) | | 源质振动室 Essentia Vibration Chamber | `ModBlocks.java` | 23 | `ESSENTIA_VIBRATION_CHAMBER`(Tile: TileEssentiaVibrationChamber) | | 知识刻印机 Knowledge Inscriber | `ModBlocks.java` | 24 | `KNOWLEDGE_INSCRIBER`(纯方块,无BE) | | 精馏编码器 Distillation Encoder | `ModBlocks.java` | 25 | `DISTILLATION_ENCODER`(纯方块,无BE) | | 齿轮箱 / 傀儡齿轮箱 | `ModBlocks.java` | 26~27 | `GEAR_BOX` / `GOLEM_GEAR_BOX` | | 源质单元工作台 Essentia Cell Workbench(含 GUI 打开逻辑) | `ModBlocks.java` | 28~38 | 里面直接写了 `useItemOn` 和 `getMenuProvider` | | 方块实体(BlockEntity)注册器 | `java/thaumicenergistics/init/ModBlockEntities.java` | — | (与 ModBlocks 里带 Tile 的对应) | | 菜单类型 / 屏幕注册 | `java/thaumicenergistics/init/ModMenuTypes.java` + `ThaumicEnergistics.java:40~46` | — | `registerScreens` 方法里绑定 GuiXXX::new | --- ## 二、配方注册(1k/4k/16k/64k 组件、奥术、注入、坩埚) | 你想找什么 | 文件 | 关键行 | 备注 | |---|---|---|---| | 配方总入口(commonSetup 里触发) | `java/thaumicenergistics/ThaumicEnergistics.java` | **36~38** | `commonSetup(event) { event.enqueueWork(RecipeRegistration::registerAll); }` | | 配方注册总开关 | `java/thaumicenergistics/common/features/RecipeRegistration.java` | **247~253** | `registerAll()` 调 4 个子方法 + 打日志 | | 有形状奥术合成(1k/4k/16k/64k、齿轮箱、刻印机等 14 条) | `RecipeRegistration.java` | **255~417** | `registerShapedArcane()` | | ⭐ 1k Storage Component(任意天域之华版,for 循环展开) | `RecipeRegistration.java` | 256~267 | `wisps1k.get(i)` 当 'E' | | ⭐ 4k Storage Component(任意天域之华版) | `RecipeRegistration.java` | 269~281 | `wisps4k.get(i)` 当 'E' | | ⭐ 16k Storage Component(任意天域之华版) | `RecipeRegistration.java` | 283~296 | `wisps16k.get(i)` 当 'E' | | 64k Storage Component | `RecipeRegistration.java` | 298~307 | 单配方,不用循环 | | 天域之华名称表 + wispEssenceStacks()(不用 Tag,硬编码 ID 绕过时序) | `RecipeRegistration.java` | **Tag 常量区 + WISP_ESSENCE_VARIANTS 数组**(第 227 行起) | 这是配方「任意天域之华」能生效的核心 | | 无形状奥术合成(核心、总线、终端等 7 条) | `RecipeRegistration.java` | 419~473 | `registerShapelessArcane()` | | 注入配方(Essentia/Infusion Provider、奥术组装机) | `RecipeRegistration.java` | 475~514 | `registerInfusion()` | | 坩埚配方(傀儡齿轮箱 = 齿轮箱熔炼) | `RecipeRegistration.java` | 516~523 | `registerCrucible()` | | 3 个 helper:`stack()` 物品封装 / `tc()` 取 Thaumcraft 物品 / `ae()` 取 AE2 物品 | `RecipeRegistration.java` | 525~537 | 配方里所有 `'X', ae(...)`、`'X', tc(...)` 都走这里 | | 配方乱码前缀 | `RecipeRegistration.java` | 所有 `addXxxRecipe` 第一个参数 | `"th_a€‰"` / `"th_b€‰"` / `"th_c€‰"` / `"th_d€‰"`(不影响功能但建议后续统一换成 `R + "xxx"`) | --- ## 三、资源引用链(材质 / 模型 / BlockState) > 根目录:`resources/assets/thaumicenergistics/` > 规则:**注册名 = 文件名(不含 .json/.png)**。物品/方块在 ModItems/ModBlocks 里用什么 `register("xxx")`, > 下面 4 层 JSON/PNG 就必须都叫 `xxx`。 | 层 | 路径 | 它引用谁 | 关键字段 | |---|---|---|---| | ① BlockState(方块状态→方块模型) | `blockstates/<注册名>.json`(共 9 个) | 指向 `models/block/xxx.json` | `"model": "thaumicenergistics:block/<注册名>"` | | ② Block Model(方块模型→PNG 贴图) | `models/block/<注册名>.json`(共 9 个) | 指向 `textures/block/xxx.png` | `"textures": { "up": "...", "down": "...", "north": "...", ... }` | | ③ Item Model(物品模型→方块模型 **或** 物品 PNG) | `models/item/<注册名>.json`(物品 23 个 + 方块物品 9 个 = 32 个) | 方块物品:parent 到 ②;纯物品:直接写 layer0 | 方块物品:`"parent": "thaumicenergistics:block/<注册名>"`;纯物品:`"textures": { "layer0": "thaumicenergistics:item/<注册名>" }` | | ④ PNG 贴图 | `textures/block/*.png`(9 套方块面)、`textures/item/*.png`(23 个物品贴图) | 被 ② ③ 引用 | 直接对应文件名 | --- ## 四、几个你最常问的具体定位(直接跳) | 问题 | 去哪看 | |---|---| | 1k/4k/16k 组件配方「任意天域之华」怎么实现的 | `RecipeRegistration.java:227~244`(名称表 + `wispEssenceStacks()`) + `255~296`(for 循环注册) | | 为什么要写死 `WISP_ESSENCE_VARIANTS` 数组,不能用 Tag 吗 | Tag 要到 DataPack 加载(比 commonSetup 晚)才填充,commonSetup 里 `getTag()` 返回空 → for 循环 0 次 → 配方直接没了。所以**注册阶段必须绕开 Tag 用硬编码 ID**。 | | 「JEI 里完全没配方」排查顺序 | ① `latest.log` 里搜 `Wisp essence variants loaded` 看数字是不是 0;② 搜 `Invalid arcane recipe ingredient`(Ingredient 传进去就崩);③ 搜 `Mod loading has failed` 看 FMLCommonSetupEvent 是不是中途崩了;④ 确认 `commonSetup` 里是不是 `event.enqueueWork(RecipeRegistration::registerAll)` | | Essentia Provider / Infusion Provider / Knowledge Inscriber / Gear Box「完全没材质」排查顺序 | 层 ①→②→③→④ 依次看:① blockstates 里 model 指向对不对;② models/block 里 textures 每个面都写了且 PNG 存在;③ models/item 里 parent 指回方块模型;④ textures 目录下 PNG 真实存在且命名一致。 | | Essentia Cell Workbench「顶面材质没了,侧面正常」 | 直接打开 `models/block/essentia_cell_workbench.json` 看 `"textures"` 里 `"up"` 字段是不是写对了(应该指向 `textures/block/essentia_cell_workbench_top.png`) | | 想加一个新物品/新方块 | ① 先在 ModItems / ModBlocks 里 `register("xxx", ...)`;② 想办法给物品弄一个 `models/item/xxx.json` + `textures/item/xxx.png`;如果是方块再加 `blockstates/xxx.json` + `models/block/xxx.json` + `textures/block/xxx.png`;③ 想进创造模式 Tab 要去 `ModCreativeTab.java` 里加 `output.accept(ModItems.XXX.get())`;④ 有配方去 `RecipeRegistration.java` 对应子方法里加一条 | | 汉化文本 | `resources/assets/thaumicenergistics/lang/zh_cn.json` | | 创造模式 Tab 物品顺序 | `java/thaumicenergistics/init/ModCreativeTab.java` | | 源质单元容量实现(1k/4k/16k/64k 各自多少字节) | `java/thaumicenergistics/common/items/ItemEssentiaCell.java` 里的 `create1k / create4k / create16k / create64k` 静态工厂 | | 天域之华 Tag 文件(防止主模组未来注册同名产生冲突) | `resources/data/thaumicenergistics/tags/items/wisp_essences.json` (里面写了 `"replace": false` 且包含 `{ "id": "#thaumcraft:wisp_essences", "required": false }` 作为兼容占位) | | 启动崩 `Invalid arcane recipe ingredient: Ingredient@xxxx` | 一定是配方里把 Ingredient 传进了字符映射表(`'E', xxx` 的 xxx 必须是 ItemStack / Item / ResourceLocation,**不能是 Ingredient**),去 `registerShapedArcane()` 里搜 `wispEssenceIngredient`,有就立刻改成 `wisps.get(i)`(ItemStack) | | Gradle 警告 `Space-assignment syntax ... init.gradle:10` | 这个是**全局 Gradle 初始化脚本**(`D:\GradleCache\init.gradle`)里的老写法,把 `url "https://..."` 改成 `url = "https://..."` 就好,跟模组代码无关 | --- ## 五、注册一个方块 — 从 Java 代码 → 材质 PNG 的完整 5 步引用链 > 🎯 例子用现成的 `knowledge_inscriber`(知识刻印机),你加新方块时直接把所有 `knowledge_inscriber` 替换成你的新注册 id 即可。 > > 核心铁律:**注册 id 必须全局一致** — ModBlocks、ModItems、blockstates 文件名、models/block 文件名、models/item 文件名、textures 引用名,**全部都是同一个字符串**(大小写全小写,单词间下划线)。 ### 第 1 步:Java 注册方块本体(决定注册 id) **文件**:`java/thaumicenergistics/init/ModBlocks.java` ```java public static final DeferredBlock KNOWLEDGE_INSCRIBER = REGISTRY.register("knowledge_inscriber", () -> new Block(P)); // ^^^^^^^^^^^^^^^^^^^ ← 这里是「注册 id」,下面 4 层必须全一致 ``` 如果方块有 GUI(比如 Essentia Cell Workbench),就在 `new Block(P) { ... }` 里覆写 `useItemOn` + `getMenuProvider`。 如果方块有 BlockEntity(比如 Essentia Provider),就用 `ThEBaseEntityBlock(P)` 并实现 `newBlockEntity`。 ### 第 2 步:Java 注册方块物品(拿在手里的那个 Item) **文件**:`java/thaumicenergistics/init/ModItems.java` ```java public static final DeferredItem KNOWLEDGE_INSCRIBER_ITEM = REGISTRY.registerSimpleBlockItem(ModBlocks.KNOWLEDGE_INSCRIBER); // ^^^^^^^^^^^^^^^^^^^ ← 直接绑定第 1 步的方块 ``` `registerSimpleBlockItem` 是 NeoForge 封装好的,它会自动用**同一个注册 id**(这里就是 `knowledge_inscriber`)来生成 BlockItem,所以下面第 5 步「物品模型」的文件名也必须是 `knowledge_inscriber.json`。 ### 第 3 步:BlockState(方块状态 → 方块模型的路由表) **文件**:`resources/assets/thaumicenergistics/blockstates/knowledge_inscriber.json` ```json { "variants": { "": { "model": "thaumicenergistics:block/knowledge_inscriber" } } } ``` > 📌 解释:Minecraft 渲染一个方块时,先看方块状态属性(朝向、开关等),再查 blockstates 找到该状态对应哪个**方块模型 JSON**。 > 知识刻印机没有状态属性(不区分朝向),所以用 `""` 表示「默认变体」;如果是有朝向的方块(比如 Essentia Provider),那要写 `facing=north/south/east/west/up/down` 六个变体。 ### 第 4 步:Block Model(方块模型 → 每个面用哪张 PNG) **文件**:`resources/assets/thaumicenergistics/models/block/knowledge_inscriber.json` ```json { "parent": "minecraft:block/cube_bottom_top", "textures": { "top": "thaumicenergistics:block/knowledge_inscriber_top", "bottom": "thaumicenergistics:block/knowledge_inscriber_bottom", "side": "thaumicenergistics:block/knowledge_inscriber_side" } } ``` > 📌 解释:`particle` 是「破坏方块时飞溅的粒子贴图」,一般跟 `north` 用同一张。上面 6 个面(`up/down/north/south/east/west`)的字符串,**不要加 `.png` 后缀**,游戏会自动去 `textures/` 目录下找对应的 PNG。 > > 📌 对应的 3 张贴图必须真实存在: > - `resources/assets/thaumicenergistics/textures/block/knowledge_inscriber_top.png`(顶面) > - `resources/assets/thaumicenergistics/textures/block/knowledge_inscriber_bottom.png`(底面) > - `resources/assets/thaumicenergistics/textures/block/knowledge_inscriber_side.png`(四个侧面共用一张) ### 第 5 步:Item Model(物品模型 — 方块物品最简单写法:直接「继承」方块模型) **文件**:`resources/assets/thaumicenergistics/models/item/knowledge_inscriber.json` ```json { "parent": "thaumicenergistics:block/knowledge_inscriber" } ``` > 📌 解释:99% 的方块物品**不需要独立物品贴图**,直接 `parent` 指回第 4 步的方块模型,Minecraft 会自动把方块渲染器缩放成 3D 物品形态(就是你在背包、物品栏、地上掉落物看到的样子)。 > > 只有当你想让「物品形态」跟「方块形态」长得不一样时(比如 AE2 的接口物品是 2D 图标),才需要单独写 layer0 引用物品 PNG(写法参考下一节纯物品)。 ### ✅ 新方块加完后**还要做的 2 件事**(别漏) 1. **进创造 Tab**:`java/thaumicenergistics/init/ModCreativeTab.java` 的 `displayItems` 里补一行 `output.accept(ModItems.KNOWLEDGE_INSCRIBER_ITEM.get());`(不然拿不到) 2. **汉化**:`resources/assets/thaumicenergistics/lang/zh_cn.json` 里补 `","block.thaumicenergistics.knowledge_inscriber":"知识刻印机"` 3. (可选)**有配方**:去 `RecipeRegistration.java` 的 `registerShapedArcane()` 或 `registerInfusion()` 里加一条。 --- ## 六、注册一个纯物品(不是方块) — 从 Java 代码 → 材质 PNG 的完整 3 步引用链 > 🎯 例子用现成的 `storage_component_1k`(1k 存储组件),加新物品时直接替换 id 即可。 > 核心铁律同上:注册 id = 模型文件名 = PNG 文件名(不加后缀)。 ### 第 1 步:Java 注册物品本体 **文件**:`java/thaumicenergistics/init/ModItems.java` ```java public static final DeferredItem STORAGE_COMPONENT_1K = REGISTRY.registerSimpleItem("storage_component_1k"); // ^^^^^^^^^^^^^^^^^^^^^ ← 注册 id,下面 2 层必须一致 ``` 如果物品有自定义逻辑(比如源质 Cell 带容量读写 NBT、右键使用、背包叠加数量 1 等),就不用 `registerSimpleItem`,改用: ```java public static final DeferredItem ESSENTIA_CELL_1K = REGISTRY.registerItem("essentia_cell_1k", ItemEssentiaCell::create1k); ``` 本质上只是把 `new Item()` 换成你自己的自定义物品构造函数 / 静态工厂。 ### 第 2 步:Item Model(物品模型 → layer0 指向物品 PNG) **文件**:`resources/assets/thaumicenergistics/models/item/storage_component_1k.json` ```json { "parent": "minecraft:item/generated", "textures": { "layer0": "thaumicenergistics:item/storage_component_1k" } } ``` > 📌 解释:所有「普通 2D 贴图物品」的 parent 都是 `item/generated`(MC 内置的平面图标渲染器)。 > `layer0` 就是「主贴图」。字符串**不要加 `.png` 后缀**,游戏会自动找 `textures/item/storage_component_1k.png`。 > > 少数物品有动画(比如 `knowledge_core.png.mcmeta`),那是在 PNG 旁边放一个 `.mcmeta` JSON 描述帧动画,模型文件写法不变。 ### 第 3 步:放真实贴图 PNG **文件**:`resources/assets/thaumicenergistics/textures/item/storage_component_1k.png` > 📌 要求:16×16 或 32×32 或 64×64 的 PNG(尺寸必须是 2 的幂),**文件名必须跟 layer0 写的一样**。