Pixelmon 集成

基本信息

属性 值
判定 modid pixelmon(Wawla.java:53,大小写敏感)
条件 Loader.isModLoaded("pixelmon"),两个 addon 在同一段 if 里一起注册
文件 AddonPixelmonEntities.java(168 行)+ AddonPixelmonTiles.java(127 行)
配置分类 Pixelmon(10 个键,8 + 2)
跨 mod 依赖 零编译期依赖——全部 Class.forName 反射

GTNH 1.7.10 整合包不含 Pixelmon,因此这两个 addon 在 GTNH 环境下永不加载。本条目记录其源码行为以备参考。

反射缓存的类

缓存字段 目标类 声明位置
classEntityPixelmon com.pixelmonmod.pixelmon.entities.pixelmon.EntityPixelmon Entities:28(public static)
enumNature com.pixelmonmod.pixelmon.enums.EnumNature Entities:29(public static)
enumGrowth com.pixelmonmod.pixelmon.enums.EnumGrowth Entities:30(public static)
classTileEntityApricornTree com.pixelmonmod.pixelmon.blocks.apricornTrees.TileEntityApricornTree Tiles:29(public static)
classBlockApricornTree com.pixelmonmod.pixelmon.blocks.apricornTrees.BlockApricornTree Tiles:31(public static)

⚠️ 5 个字段全部声明为 public static 却在构造函数里赋值(Entities:22-38、Tiles:22-39)。这是"把静态初始化写进实例构造函数"的写法——registerAddon 里恰好是 new AddonPixelmonEntities() 先于使用(Entities:138),所以能工作,但赋值位置与方法职责不匹配。

⚠️ Class.forName 失败只 e.printStackTrace()(Entities:35、Tiles:36),不阻止 registerAddon 继续。

实体 HUD 行(10 个开关中的 8 个)

整体前置:wawla.pixelmon.useSneak 开启时要求玩家潜行(否则整块跳过),且 Utilities.compareByClass(classEntityPixelmon, entity.getClass()) 为真,且 data.getNBTData() != null。

门控键 输出 数据来源
wawla.pixelmon.showNature 天性: <名> natureList[tag.getShort("Nature")]
wawla.pixelmon.showAbility 能力: <名> tag.getString("Ability")
wawla.pixelmon.showSize 成长状态: <名> sizeList[tag.getShort("Growth")]
wawla.pixelmon.showFriendship 心情: <N> tag.getInteger("Friendship")
wawla.pixelmon.showHeldItem 持有物品: <名> ItemStack.loadItemStackFromNBT(tag.getTag("HeldItemStack"))
wawla.pixelmon.showIV IV's - Atk/Def/HP/SpAtk/SpDef/Spd 6 个 getInteger("IVxxx")
wawla.pixelmon.showEV EV's - Atk/Def/HP/SpAtk/SpDef/Spd 6 个 getInteger("EVxxx")
wawla.pixelmon.showApricornGrowth(Tiles) 成长: <N>% 见下
wawla.pixelmon.showApricornProduct(Tiles) 栗子类型: <名> 见下

特性着色:tag.getInteger("AbilitySlot") == 2 用 EnumChatFormatting.GOLD,否则 GRAY。

EV 显示额外要求 !tag.getString("OwnerUUID").isEmpty()——只有被驯服的神奇宝贝才显示努力值。IV 没有这个限制。

枚举 → 字符串数组的转换

registerAddon(Entities:149-150)用 Utilities.generateElementArray(enumClass) 把枚举常量转成 String[]:

Object[] constants = enumClass.getEnumConstants();
String[] elements = new String[constants.length];
for (int i = 0; i < constants.length; i++) elements[i] = constants[i].toString();

⚠️ 调用顺序倒了:registerBodyProvider(dataProvider, classEntityPixelmon) 在 :148,natureList / sizeList 的赋值在 :149-150。如果 WAILA 在注册回调里就触发一次 body 读取,两个数组还是 null——实际因为有 if (natureList != null && ...) 守卫(:64 / :78)而不会崩,但首帧可能缺行。

⚠️ generateElementArray 对非枚举类返回 null(Utilities.java:133),getEnumConstants() 返回 null 时 constants.length 会 NPE——Utilities.java:125-126 没有判 constants == null。

栗子树(Apricorn Tree)的双 TileEntity 读取

Pixelmon 的栗子树是两格方块,上半格没有正确的 TileEntity 信息。AddonPixelmonTiles.getWailaBody(:58-66)因此调用 createApricornTooltip 两次:

  1. 第一次传 data.getTileEntity()(当前格)
  2. 第二次传 data.getWorld().getTileEntity(x, **y - 1**, z)(下一格)

两次都传 data.getBlock() 作为 block 参数。

输出 计算
成长: <N>% Utilities.round(Utilities.getProgression(meta, 5), 0),meta 是该 TileEntity 所在方块的 metadata
栗子类型: <名> Block.blockRegistry.getNameForObject(block) 再做 substring(9, length - 5)

⚠️ 源码缺陷

缺陷 1:natureList[...] / sizeList[...] 是无边界检查的 NBT 驱动数组下标

AddonPixelmonEntities.java:66 与 :80:

natureList[tag.getShort("Nature")]
sizeList[tag.getShort("Growth")]

tag.getShort 返回 short,可以是负数,也可以超出枚举长度。守卫只判了 natureList != null(:64)和 sizeList != null(:78),没有判下标范围。越界或负数 → ArrayIndexOutOfBoundsException,而 getWailaBody 没有 try/catch,一次神奇宝贝 HUD 刷新就会崩。

这与 原版方块 里 Potion.potionTypes[primary] 是同一类缺陷。

缺陷 2:product.substring(9, product.length() - 5) 是硬编码魔数切片

AddonPixelmonTiles.java:118。它假定注册名形如 pixelmon:apricornXxx——固定砍掉前 9 个字符(pixelmon:a)和后 5 个字符。任何更短或不同前缀的注册名都会抛 StringIndexOutOfBoundsException。这是整个 WAWLA 里最脆的一处字符串处理。

缺陷 3:round(x, 0) 是空操作,成长百分比会带浮点误差

AddonPixelmonTiles.java:113 调 Utilities.round(progress, 0),而 Utilities.java:105 的条件是 places > 0,places == 0 直接原样返回。于是 HUD 上会出现 83.333336% 这样的值。见 工具类 缺陷 1。

缺陷 4:HeldItemStack 加载结果未判 null

AddonPixelmonEntities.java:88-89:

+ ItemStack.loadItemStackFromNBT((NBTTagCompound) tag.getTag("HeldItemStack")).getDisplayName()

hasKey("HeldItemStack") 为真但内容畸形时,loadItemStackFromNBT 返回 null → NPE。

缺陷 5:registerBodyProvider 可能收到 null 类

AddonPixelmonEntities.java:148 传 classEntityPixelmon,Tiles:91 传 classBlockApricornTree——两者在 Class.forName 失败时仍是 null,而 catch 只 printStackTrace。此时 WAILA 收到 null 类引用。

缺陷 6:classEntityPixelmon 被注册为 body provider 的目标,但类检查用的是 compareByClass

compareByClass(class1, class2) 是忽略大小写比较类名字符串,不是 isInstance(Utilities.java:174)。这意味着 EntityPixelmon 的子类不会被匹配(getClass() 返回子类名,字符串不等)。Pixelmon 本身有子类层级时可能漏判。

相关条目