Witchery++(WitcheryExtras)
[!INFO] Git Commit:
ce2dfbe| Updated: 2026-10-01
modid:WitcheryExtras(core/WitcheryExtras.java:40
public static final String MODID = "WitcheryExtras";,
由 @Mod(modid = WitcheryExtras.MODID, ...) 在 WitcheryExtras.java:34 引用)。
gradle.properties 的 modId = WitcheryExtras 一致。
注意大小写混合(Witchery + Extras 首字母大写),不是全小写。
⚠️ mcmod.info 全是构建期占位符,无法从这里读 modid:
"modid": "${modId}", "name": "${modName}",
"version": "${modVersion}", "mcversion": "${minecraftVersion}"
真正的 description 是唯一手写字段:"Extends Witchery."
(src/main/resources/mcmod.info:6)。
显示名:Witchery++(WitcheryExtras.java:41 NAME = "Witchery++",
gradle.properties 的 modName = Witchery++)
网址: https://github.com/GTNewHorizons/WitcheryExtras
作者: Alkalus / Draknyte1(mcmod.info 的 authorList)
根包名: alkalus.main(gradle.properties 的 modGroup)
一句话:Witchery 的补丁包,不是内容附属
59 个 Java 文件里,本 mod 自己注册的内容极少:
| 项目 | 数量 | 说明 |
|---|---|---|
| 注册方块 / TileEntity / 物品 / 实体 | 0 / 0 / 0 / 0 | 全部靠 Mixin 改 Witchery 的类和注册表 |
| Mixin 类 | 22(11 个组) | 见 Mixin 补丁总表 |
| 巫师大蒜相关修复 | 2 组(4 件铠甲 + 1 本书) | 见 大蒜配方修复 |
| 烤炉配方 | 11 | 见 巫师烤炉配方 |
| 预言权重开关 | 15 个 | 见 预言权重重写 |
| 配置项 | 18 | 见 配置项 |
| NEI 配方处理器 | 5 | Oven / Distillery / Kettle / Cauldron / SpinningWheel |
| 插件 API 嵌套类 | 9 | 见 插件注册 API |
| 自有网络包 | 1 | network/EntitySizeSyncPacket.java |
| 资源文件 | 6 | 2 个 lang + mcmod.info + 3 个 mixin 清单 |
它做的事:
- 给 Witchery 的烤炉加 11 条配方,并把烤炉的配方查找表整个换掉
- 修复 Witchery 大蒜配方只认自家大蒜的问题(改走
cropGarlic矿石字典) - 调整 15 类预言的触发权重
- 修 Resizing 缩小药水在客户端的相机/眼高/同步
- 放宽祭坛多方块的 TileEntity 数量限制
- 改若干机器的 GUI 标题与槽位判定
- 提供人偶架区块加载开关
- 让 Witchery 的钥匙与人偶能装进 Baubles Expanded 饰品栏
- 开放 8 类注册表的插件 API
依赖声明
@Mod(dependencies = "required-after:witchery;required-after:spongemixins;")
(WitcheryExtras.java:37)
| 依赖 | 级别 | 说明 | 在本 wiki 收录范围? |
|---|---|---|---|
witchery |
required-after | 唯一硬前置。本 mod 全部逻辑都建立在 Witchery 的类与注册表上 | ❌ 不在(data/relation.md 无该分类,本 wiki 未收录) |
spongemixins |
required-after | Mixin 框架 | ❌ 不在 |
Baubles|Expanded |
隐式(addRequiredMod) |
门控 3 个 Mixin + 槽位申请 | ✅ 在(分类 baubles-expanded) |
NotEnoughItems |
隐式 | dependencies.gradle 的 devOnlyNonPublishable,仅编译期 |
✅ 在 |
⚠️ 关于 witchery 不在本 wiki 收录范围
Witchery 本体不在本 wiki 的收录范围内(data/relation.md 中没有 witchery 分类)。
因此以下内容本 wiki 不提供,本分类的所有条目都只记录 「Witchery++ 对它做了什么改动」,不复述 Witchery 自身的机制:
- 祭坛的等级、放置规则、旋转与拆除方式
- 烤炉/蒸馏器/纺车/坩埚/茶壶的完整工作流程与产出
- 预言系统的完整语义(15 类预言分别代表什么)
ItemGeneric子物品的完整清单- 人偶(Poppet)10 种类型的具体行为
涉及多方块时特别说明:本 mod 不拥有任何多方块结构。 唯一涉及多方块的是 祭坛多方块结构放宽补丁, 它改的是Witchery 的祭坛,本 mod 只施加两处常量/返回值改写。
modid 陷阱
本 mod 有 3 处 modid 相关的坑:
| 坑 | 正确值 | 出现位置 |
|---|---|---|
mcmod.info 全是 ${modId} 占位符 |
必须从 WitcheryExtras.java:40 读 |
src/main/resources/mcmod.info |
| modid 大小写混合 | WitcheryExtras(不是 witcheryextras) |
WitcheryExtras.java:40 |
| Baubles 的父 modid | Baubles|Expanded(带竖线),不是 Baubles |
TargetedMod.java:10、WitcheryExtras.java:63 |
生命周期
core/WitcheryExtras.java:56-95,@Mod.EventHandler 四个:
| 阶段 | 行 | 动作 |
|---|---|---|
preInit |
56-67 |
调 proxy.preInit;跑 mPreInitEvents 插件;Baubles Expanded 已加载时申请 belt / charm 各至少 1 槽 |
init |
69-77 |
调 proxy.init;new GarlicRecipes()(构造即删+建配方);OvenRecipes.generateDefaultOvenRecipes()(11 条);跑 mInitEvents 插件 |
postInit |
79-90 |
调 proxy.postInit;FMLCommonHandler.bus().register(this);仅客户端注册 TooltipHandler;跑 mPostInitEvents 插件;PredictionHandler.adjustPredictions() |
onServerStopped |
92-95 |
清空 PowerSources 的 powerSources / nullSources 两个 List(反射) |
ClientProxy.init 另注册 ClientSizeHandler(proxy/ClientProxy.java:11-14)。
⚠️ onServerStopped 清理逻辑的风险
private static void clearPowerSources(PowerSources instance) {
if (instance == null) return;
try {
final Field powerField = instance.getClass().getDeclaredField("powerSources");
...
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e); // WitcheryExtras.java:112
}
}
(WitcheryExtras.java:102-114)
Witchery 一旦改名这两个字段,服务端关闭事件会直接抛 RuntimeException。
客户端断线走 @SubscribeEvent onClientDisconnect(WitcheryExtras.java:97-100),
调用同一个方法。
已确认的源码缺陷
| # | 位置 | 问题 |
|---|---|---|
| 1 | core/entities/PredictionHandler.java:89-92 |
数组越界。aNewValues 实测 17 个元素,循环 i = 0..17(18 次),下标取 aNewValues[i - 1] → i=0 触发 ArrayIndexOutOfBoundsException;且下标 17 无对应配置项。详见 预言权重重写 |
| 2 | core/entities/PredictionHandler.java:101、93 |
未覆盖的 PredictionAlwaysForced 子类会让 aNewPrediction 保持 null,而 remove(aOld) 已执行 → 该预言被静默删除,无兜底分支 |
| 3 | core/types/Witchery_Predictions.java:22 |
catch (Throwable t) {} 空 catch,反射失败返回空表且不报错 |
| 4 | assets/witcheryextras/lang/zh_CN.lang |
4 个 GUI 标题键 gui.witcheryextras.*.title 直接复制英文原文,中文环境仍显示 Witches Oven / Distillery / Spinning Wheel / Leonard's Urn |
| 5 | 同上 | 4 个 tile.* 键(witchesovenexidle / witchesovenexburning / fumefunnelex / filteredfumefunnelex)指向本 mod 根本不注册的方块——旧版本遗留的死字符串 |
| 6 | config/AsmConfig.java:154 |
prop.comment = "Adjusts weight for "; 注释没写完 |
| 7 | config/AsmConfig.java:46、179 |
propOrderDebug 传给 setCategoryPropertyOrder("debug", ...),但全代码库无任何 debug 分类属性 → 永远为空的分类 |
| 8 | config/AsmConfig.java:184-186 |
catch (Exception) 吞掉全部配置异常后,静态字段保留 Java 默认值(int = 0),与配置默认(2/3/8/13)差距极大 |
| 9 | core/crafting/OvenRecipes.java:206、245 |
logWood / meatRaw 在矿石字典无条目时打 ERROR 并返回 null,默认 11 条配方可能少于 11 条 |
| 10 | core/recipe/fixes/GarlicRecipes.java:18-23 |
cropGarlic 未注册时 mGarlics 为空数组 → 原配方已删、新配方未加,4 件铠甲 + 吸血鬼书无法合成,且无任何日志 |
| 11 | core/util/Utils.java:71-78 |
removeAllCraftingRecipesByOutputItem 对全局配方表 removeIf,会连带删除其它 mod 为这 5 个物品提供的配方 |
| 12 | core/WitcheryExtras.java:112 |
clearPowerSources 反射失败时 throw new RuntimeException(e),Witchery 改字段名即导致关服崩溃 |
| 13 | mixins/Mixins.java:58 |
悬空注释 // configs handle individual blocks to disable,但 AsmConfig 并无逐方块开关 |
| 14 | mixins/late/witchery/ItemGeneral$3$1Mixin.java:13 |
目标写成字符串 "com.emoniph.witchery.item.ItemGeneral$3$1"(匿名类序号),Witchery 重排内部类即失效 |
| 15 | mixins/late/witchery/PotionResizingMixin.java:15 |
@At("MIXINEXTRAS:EXPRESSION") 不指定目标,靠表达式匹配,脆弱 |
| 16 | api/plugin/ExamplePlugin.java |
示例类位于主源码集会被打进正式 jar,且无任何代码加载它 |
| 17 | mixins/hooks/EntitySizeManager.java:87-88 |
PacketSyncEntitySize 连续 sendToAll 两次(两行几乎相同) |
| 18 | mixins/late/witchery/BlockAltarMixin.java:24 |
@ModifyConstant(ordinal = 1) 依赖方法内常量出现顺序,Witchery 改版易打错 |
| 19 | config/AsmConfig.java:185 |
异常文案仍用旧名 "Witchery++ ASM",且 it's 应为 its |
📌 可读性隐患(非行为缺陷):
mixins/late/witchery/TileEntityWitchesOvenMixin.java:108-109同时存在itemStack与itemstack两个仅首字母大小写不同的变量。 逻辑正确(熔炼产物stackSize == 1时等价于N → N+1),但极易误改。
条目索引
机制补丁
- 祭坛多方块结构放宽补丁 - 移除
BlockAltar的te > 3检查(3→999),并把结构尺寸 9 改判为 6 - 机器容器与 TileEntity 补丁 - 烤炉 2 个
@Overwrite换配方表、蒸馏器槽位常量 3→2、纺车原料整批扣除、人偶架区块加载开关、4 个 GUI 标题键、银缸整块禁用 - 变形(Resizing)缩放的同步与相机修复 - 5 个 Mixin + 1 个自有包 + 2 个事件处理器,Y 偏移公式
1.8F × (1 − defaultHeight/1.8F × amp) - 预言(Predictions)权重重写 - 反射覆写 17 个数组槽的权重,9 种预言类型重建;含数组越界缺陷
配方
- 巫师烤炉配方 - 11 条默认配方(6 原版树苗 + 3 Witchery 树苗 + 2 矿石字典),空罐 =
ItemGenericmeta 27 - 大蒜配方修复 - 删原配方后按
cropGarlic矿石字典重建:4 件猎人大蒜铠甲 + 吸血鬼书
配置
- 配置项 -
config/WitcheryExtras/asm.cfg共 18 项(general 2 + predictions 15 + blocks 1),含空的 debug 分类 - Mixin 补丁总表 - 11 个组 / 22 个类,EARLY 4 组打原版类、LATE 7 组打 Witchery 类
兼容
- Baubles Expanded 兼容 - 门控 3 个 Mixin;女巫门钥匙、罗温钥匙/钥匙串(3 种槽位)、人偶(仅挂饰槽,优先搜背包)
API
- 插件注册 API(RecipeManager) - 8 个注册表嵌套类 +
PluginManager3 个生命周期入口;底层WitcheryRecipeHandlerInternal8 对 add/remove
覆盖率
| 维度 | 注册真源实测 | 已收录 |
|---|---|---|
| 方块 / TileEntity / 物品 / 实体 | 0 / 0 / 0 / 0 | — |
| Mixin 类 | 22(Mixins.java 11 组) |
22(全部 11 组在 Mixin 补丁总表 有归属,4 个有专页) |
| 烤炉配方 | 11(OvenRecipes.java:23-88) |
11(全部列出) |
| 大蒜配方组 | 2(5 件物品) | 2 |
| 配置项 | 18(AsmConfig.java) |
18(配置项 全部列出默认值) |
| 插件 API 嵌套类 | 9(RecipeManager.java) |
9 |
| NEI 处理器 | 5(nei/) |
5(在 机器容器补丁 与 烤炉配方 提及) |
| 自有网络包 | 1 | 1 |
方块/物品覆盖率不适用(注册数为 0)。