工具类
三组互不相关的通用工具:反射字段访问、定长数组列表、CraftTweaker 桥接。
基本信息
| 属性 | 值 |
|---|---|
| 包 | wanion.lib.common |
| 类数量 | 3(Util、FixedSizeList<E>、MineTweakerHelper) |
| 共同点 | Util 与 MineTweakerHelper 为 final + 私有构造 + 全 static;FixedSizeList 可实例化 |
wanion.lib.common.Util
| 成员 | 签名 | 行为 |
|---|---|---|
| 读字段 | public static <T, E extends T> E getField(Class clas, String name, Object instance, Class<T> expectedClass) |
getDeclaredField(name) + setAccessible(true) + expectedClass.cast(field.get(instance));catch (Exception e) → printStackTrace() 后返回 null |
| 写字段 | public static <E> void setField(Class clas, String name, Object instance, E newInstance) |
getDeclaredField(name) + setAccessible(true) + field.set(...);catch (Exception e) → printStackTrace(),无返回值 |
| 取 modid | public static String getModName(ItemStack itemStack) |
GameData.getItemRegistry().getNameForObject(itemStack.getItem()) 后 substring(0, indexOf(58)) |
⚠️
getField的类型参数写法为<T, E extends T>,返回类型是子类E,即调用方可写Util.<ItemStack, ItemStack>getField(...)之类的显式形式;直接Util.getField(cls, "f", o, ItemStack.class)由目标类型推断。⚠️
getField只getDeclaredField,不沿继承链向上找 —— 父类私有/受保护字段取不到,须逐级指定类。indexOf(58)中的58是字符':',故getModName依赖注册名带命名空间;对无命名空间的条目会得到substring(0, -1)并抛StringIndexOutOfBoundsException。
wanion.lib.common.FixedSizeList<E>
public class FixedSizeList<E> extends AbstractList<E> —— 底层是裸 E[],容量构造时固定,add 满后返回 false 而不是抛异常。
| 成员 | 签名 | 行为 |
|---|---|---|
| 默认容量 | private static final int DEFAULT_CAPACITY = 64 |
|
| 构造 | public FixedSizeList() |
capacity = 64 |
| 构造 | public FixedSizeList(int capacity) |
capacity <= 0 时回落到 64(注意:赋给的是形参,this.capacity 由 new Object[this.capacity = capacity] 取已修正值) |
| 构造 | private FixedSizeList(@Nonnull Collection<E> collection) |
私有;capacity = size = collection.size(),精确容量 |
| 大小 | public int size() |
|
| 空判定 | public boolean isEmpty() |
size == 0 |
| 尾部添加 | public boolean add(E e) |
size == capacity 时返回 false;否则写入并 size++ 返回 true |
| 按下标写 | public void add(int index, E e) |
直接覆盖 allTheData[index],不检查越界、不改 size、不检查容量 |
| 读 | public E get(int index) |
index > size 时返回 null;否则返回 allTheData[index] |
| 删 | public E remove(int index) |
index >= size 时 throw new IndexOutOfBoundsException();否则 modCount++、System.arraycopy 左移、末位置 null、size--,返回被删元素 |
| 转数组 | @Nonnull public Object[] toArray() |
Arrays.copyOf(allTheData, size) |
| 清空 | public void clear() |
modCount++,逐个置 null 至 size == 0 |
⚠️
get的边界是index > size(非>=):当index == size且该槽已因remove被置null时返回null(不抛异常);若该槽尚有值则会返回「逻辑上已越界」的元素。AbstractList契约要求越界抛异常,此处未遵守。⚠️
add(int index, E e)与List契约相反:它不插入、不扩容,纯粹是数组下标写。⚠️ 类未覆写
set/addAll/iterator等,继承来的实现可能与底层数组语义不一致。
wanion.lib.common.MineTweakerHelper
把 CraftTweaker 脚本 API 对象还原成 Minecraft 侧对象。依赖是 compileOnly(CraftTweaker 3.4.6 / ZenScript 1.0.1-GTNH),运行时缺 CraftTweaker 则本类不可加载。
| 成员 | 签名 | 行为 |
|---|---|---|
| 取栈 | public static ItemStack toStack(IItemStack item) |
item == null → null;item.getInternal() 非 ItemStack 时 MineTweakerAPI.getLogger().logError("Not a valid item stack: " + item);仍返回 null |
| 批量取 | public static Object[] toObjects(IIngredient[] list) |
list == null → null;逐项 toObject(...) |
| 取实际对象 | public static Object toActualObject(IIngredient ingredient) |
IOreDictEntry → OreDictionary.getOres(name)(ItemStack[]);IItemStack → toStack(...);其余 → null |
| 取通用对象 | public static Object toObject(IIngredient ingredient) |
IOreDictEntry → 矿辞名字符串 name;IItemStack → toStack(...);其余 → null |
| 取矿辞名 | public static String toString(IOreDictEntry entry) |
entry.getName() |
toActualObject 与 toObject 的关键差异:
| 输入 | toActualObject |
toObject |
|---|---|---|
IOreDictEntry |
OreDictionary.getOres(name) → 已解析的 ItemStack[] |
name → String |
IItemStack |
toStack(item) → ItemStack |
toStack(item) → ItemStack |
null |
null |
null |
其它 IIngredient 实现 |
null |
null |
toObject的矿辞分支返回字符串而非解析结果,因此它能安全地喂给 Forge 形状数组(IRecipe接受矿辞名字符串);toActualObject需要的是已展开的物品列表。
相关条目
- MetaItem 物品键编码 - 与
Util.getModName同属物品元数据工具 - 配方形状转换 -
toObject的矿辞字符串可作其非ItemStack键 - 主类入口与依赖注入 -
Instantiator/IRemovable同包 - 模块系统 -
Instantiator的实际用途