架构与 WAILA 接入方式

基本信息

属性 值
@Mod 类 net.darkhax.wawla.Wawla(Wawla.java:14-20)
modid wawla(Constants.MODID,Constants.java:7)
显示名 What Are We Looking At(Constants.java:8)
硬依赖 @Mod(dependencies = "required-after:Waila")(Wawla.java:19)
acceptableRemoteVersions "*"(Wawla.java:18)
源码规模 18 个 .java,共 2388 行
事件处理器 只有 2 个:preInit / init(无 postInit 调用)
入口方法体 preInit 只有 1 行有效代码(proxy.preInit()),另一行是注释掉的 devMode 探测

⚠️ 本 mod 是什么:一个纯 WAILA 插件库

WAWLA 不是 WAILA 的 fork,也不是 WAILA 本体。 它是 Darkhax 写的、依附于 WAILA 运行的插件(addon)包。源码里的硬证据:

证据 位置
@Mod(dependencies = "required-after:Waila") Wawla.java:19
全部 9 处 FMLInterModComms.sendMessage("Waila", "register", "<本类>.registerAddon") Wawla.java:40-78
所有 provider 实现的都是 WAILA 的 API 接口 mcp.mobius.waila.api.IWailaDataProvider / IWailaEntityProvider 13 个 addon 类
源码里没有一个 WAILA 的实现类被复制或修改 全仓

README 也写明 “Required Mods: WAILA”,并把 ProfMobius(WAILA 作者)列为独立致谢对象——若 WAWLA 是 WAILA 的 fork,不会存在这种分离的署名关系。

因此本 mod 在 GTNH 整合包里的定位,与 wailaplugins、wailaharvestability 属于同一类(WAILA 插件),而不是 WAILA 本体。真正的 WAILA 本体是分类 waila。

加载流程

preInit(FMLPreInitializationEvent)
  └─ proxy.preInit()                      ← 仅客户端有实现
       ├─ MinecraftForge.EVENT_BUS.register(new AddonGenericTooltips())   ← 唯一绕过 WAILA 的接入
       ├─ Utilities.currentBlockDamage = ReflectionHelper.findField(PlayerControllerMP, "g", ...)  ← 破坏进度反射
       └─ FMLInterModComms.sendMessage("llibrary", "update-checker", "https://github.com/Darkhax-Minecraft/WAWLA/master/versions.json")

init(FMLInitializationEvent)
  └─ proxy.init()                         ← ProxyCommon 与 ProxyClient 的 init() 都是空的
  └─ 向 "Waila" 发送 9 条 "register" IMC   ← 真正的注册全在这里

⚠️ ProxyCommon.postInit() 与 ProxyClient.postInit() 都存在但 Wawla 类里没有 postInit 事件处理器,两个方法永远不会被调用(死代码)。

⚠️ ProxyClient 里没有任何 @SideOnly 标注,而是靠 @SidedProxy 分离;但 AddonGenericTooltips.onTooltip 直接 import net.minecraft.client.Minecraft 并调用 Minecraft.getMinecraft(),该事件监听器在服务端会随 EVENT_BUS 一起被注册(ProxyClient.preInit 只在客户端跑,故实际安全,但这层保护来自代理分离而非注解)。

代理结构

类 侧 内容
ProxyCommon 通用 preInit / init / postInit 三个空方法
ProxyClient 客户端 3 行 preInit(见上),init 空,postInit 空
静态入口 — Wawla.proxy(@SidedProxy)、Wawla.instance(@Mod.Instance("wawla"))

9 条 IMC 注册(Wawla.init 逐条)

# 条件 注册的类 载入的类
1 无条件 AddonVanillaEntities mcp.mobius.waila.api.IWailaEntityProvider
2 无条件 AddonVanillaTiles IWailaDataProvider
3 无条件 AddonGenericEntities IWailaEntityProvider
4 无条件 AddonGenericTiles IWailaDataProvider
5 Loader.isModLoaded("pixelmon") AddonPixelmonEntities IWailaEntityProvider
6 同上 AddonPixelmonTiles IWailaDataProvider
7 Loader.isModLoaded("Thaumcraft") AddonThaumcraftTiles IWailaDataProvider
8 Loader.isModLoaded("TConstruct") AddonTinkersTiles IWailaDataProvider
9 Loader.isModLoaded("Jewelrycraft") AddonJewelrycraftTiles IWailaDataProvider

⚠️ 这 5 个 Loader.isModLoaded 的判定 modid 与 addon 构造函数内部判定的 modid 有一处不一致——第 9 条在 Wawla.java:75 判 "Jewelrycraft",而 AddonJewelrycraftTiles.java:24 判的是 "Jewelrycraft2"。两者必须同时为真才能工作,实际只取决于 Wawla.java 那一次。详见 JewelryCraft 集成。

⚠️ dependencies 只声明了 required-after:Waila,而 5 个集成分别需要 pixelmon / Thaumcraft / TConstruct / Jewelrycraft / HungerOverhaul。虽然都有 isModLoaded 守卫,但 AddonGenericEntities.java:18 在类层面 import 了 iguanaman.hungeroverhaul.config.IguanaConfig(编译期硬引用),AddonGenericEntities.java:77-78 直接访问其静态字段。若玩家装了 HungerOverhaul 的不兼容版本,字段缺失会在运行时抛 NoSuchFieldError 而非被守卫拦住。

13 个 addon 类的注册状态

包 类 是否被 IMC 注册 条目
vanillamc AddonVanillaEntities ✅ 条件 1 原版实体
vanillamc AddonVanillaTiles ✅ 条件 2 原版方块
generic AddonGenericEntities ✅ 条件 3 通用实体
generic AddonGenericTiles ✅ 条件 4 通用方块
pixelmon AddonPixelmonEntities + AddonPixelmonTiles ✅ 条件 5/6 Pixelmon 集成
thaumcraft AddonThaumcraftTiles ✅ 条件 7 神秘时代集成
tinkersconstruct AddonTinkersTiles ✅ 条件 8 Tinkers 集成
jewelrycraft AddonJewelrycraftTiles ✅ 条件 9 JewelryCraft 集成
generic AddonGenericTooltips ⚠️ 不走 IMC,直接 EVENT_BUS.register 物品悬浮提示
developer AddonDeveloperEntities ❌ 未注册 未接线的 addon
developer AddonDeveloperTiles ❌ 未注册 未接线的 addon
morph AddonMorphEntities ❌ 未注册 未接线的 addon
util Utilities — 工具类 工具类

反射取类机制

所有跨 mod 集成都不用编译期依赖,而是 Class.forName + 静态 Class 字段缓存:

addon 缓存字段数 例外
Pixelmon entities 3(classEntityPixelmon / enumNature / enumGrowth) 另用 Utilities.generateElementArray 把枚举转成 String[]
Pixelmon tiles 2(TileEntity + Block) —
Thaumcraft 12(8 个 TileEntity + 4 个 Block) TileEntity 字段是实例字段,Block 字段是 static
Tinkers 7 个 Class + 2 个 Method getHarvestType / getSecondHarvestType,setAccessible(true)
JewelryCraft 2 判定 modid 与 Wawla.java 不一致(见上)

⚠️ Tinkers 的 isEnabled 在 try 块之前就被置 true(AddonTinkersTiles.java:27)。若后续任一 Class.forName / getDeclaredMethod 抛异常被 catch 掉,isEnabled 仍为 true 而 7 个 Class 字段中部分为 null,canHarvest() 随后在 classDualHarvestTool.isInstance(...)(AddonTinkersTiles.java:205)上 NPE。而 canHarvest 被 AddonGenericTiles.java:59 无条件调用,等于任意 Tinkers 方块的 HUD 刷新都可能崩。详见 Tinkers 集成。

⚠️ Class.forName 失败只 printStackTrace(),不阻止后续 registerBodyProvider(dataProvider, null)(如 AddonPixelmonEntities.java:148、AddonThaumcraftTiles.java:209-216)。此时静态 Class 字段仍为 null,WAILA 侧收到的是 null 类引用。

相关条目