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 两次:
- 第一次传
data.getTileEntity()(当前格) - 第二次传
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 本身有子类层级时可能漏判。
相关条目
- 配置项 —
Pixelmon分类的 10 个键 - 架构与 WAILA 接入方式 — 反射取类机制
- 工具类 —
generateElementArray/round的缺陷