Info
绘制基类:树形子节点、尺寸测量
基本信息
| 属性 | 值 |
|---|---|
| 路径 | com.github.lunatrius.ingameinfo.client.gui.Info |
| 行数 | 90 |
| 子类 | InfoText、InfoItem、InfoIcon |
三个子类构成的渲染树
public final List<Info> children = new ArrayList<>(); // :14
| 子类 | 渲染对象 |
|---|---|
| InfoText | 一行文本(根节点,持有 Value 列表) |
| InfoItem | 物品堆 |
| InfoIcon | 纹理图集子矩形 |
InfoText 是唯一会挂子节点的:
ValueComplex 的 ValueIcon 生成
InfoIcon 并挂到父 InfoText 上。
draw(:31-40)—— 先自己,后子节点
public void draw() {
drawInfo(); // :32 自己先画
for (Info child : this.children) { // :34
child.offsetX = this.x; // :35 ⚠️ 覆盖而非累加
child.offsetY = this.y; // :36
child.draw();
}
}
⚠️ 子节点的 offsetX/Y 被直接赋值为父的 x/y,不是累加 ——
所以渲染树最多只能有一层深。
若 InfoText → InfoIcon → 再挂子节点,第三层的偏移会变成第二层的
x/y 而非相对坐标,实际会错位。
⚠️ drawInfo() 在 for 循环之前(:32),
所以子节点绘制在自己之上(覆盖)。
位置与偏移
| 字段 | 行 | 说明 |
|---|---|---|
x / y |
:15-16 |
自身绝对坐标 |
offsetX / offsetY |
:17-18 |
父节点坐标,由 draw() 赋值 |
hasPosition |
:21 |
public boolean,初值 false |
getX() |
:44-46 |
x + offsetX |
getY() |
:48-50 |
y + offsetY |
⚠️ hasPosition 是 public 可变字段(不是 private),
子类直接读写(InfoText 的 updateChildren 在 :74、:77 读写它)。
初值 false,由 updateChildren 置 true。
⚠️ Info.draw() 自身不检查 hasPosition ——
只有 InfoText 的 updateChildren 用它来跳过
已定位过的子节点。children 列表(:14)与 attachedValues
(InfoText 的 :19)是两套容器,本类不区分。
尺寸:基类一律返回 0
public int getWidth() { return 0; } // :60-62
public int getHeight() { return 0; } // :64-66
⚠️ 基类不测量自身尺寸,返回 0。 三个子类全部覆写了这两个方法,所以实际使用没问题。 但若新增子类忘记覆写,它的宽度为 0, 在 InfoText 的布局里会被当成「零宽」节点。
oldWidth 与 iconSpacing:图标占位空格
private String iconSpacing = ""; // :20
private int oldWidth; // :22
public String getIconSpacing() { // :52-58
if (oldWidth != getWidth()) { // 宽度变了才重算
setIconSpacing();
oldWidth = getWidth();
}
return iconSpacing;
}
private void setIconSpacing() { // :78-84
String str = "";
for (int i = 0; i < getWidth() && fontRenderer.getStringWidth(str) < getWidth(); i++) {
str += " ";
}
iconSpacing = str;
}
用途:为前置图标占位。
循环同时受 i < getWidth() 与 getStringWidth(str) < getWidth() 双重约束 ——
即空格数既不超过宽度值、也不超过该宽度对应的像素宽度,
所以对宽字符(CJK)会提前停止。
⚠️ oldWidth 初值为 0(Java 默认),
而 getWidth() 在子类里通常非 0,所以首次调用必然触发重算。
若某子类 getWidth() 恒返回 0(如忘记覆写),则永不重算,
iconSpacing 保持 ""。
⚠️ setIconSpacing 是 private(:78),
外部无法强制重算;只能靠改变 getWidth() 的返回值来触发。
⚠️ 用空格而非制表符占位 —— 等宽字体下精确,但比例字体下空格宽度不均, 且末尾空格可能被渲染器裁掉。
文本标识与赋值
| 成员 | 行 | 说明 |
|---|---|---|
identifier |
:19 |
初值 ""(空串,非 null) |
setIdentifier(@NotNull String) |
:68-70 |
覆写时需处理 @NotNull 契约 |
getIdentifier() |
:74-76 |
— |
setValue(@NotNull Object) |
:72 |
空实现,子类覆写 |
toString() |
:86-89 |
固定返回字面量 "Info" |
⚠️ toString() 不输出类型也不输出 identifier,
三个子类若不覆写就都显示 Info。实际
InfoText 等都覆写了 toString(各有专门条目)。
identifier 的实际用途见
TagPlayerPotion 的 shouldUpdate
(:200-203)—— 用 Info.identifier 比对药水 ID
来判断图标是否需要重建。所以 identifier 是缓存失效键。
字体渲染器
protected static final FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; // :13
protected static final —— 类加载时取 Minecraft 单例的 fontRenderer。
三个子类都用它测文本宽度。
相关
- InfoText - 根节点
- InfoItem / InfoIcon - 叶子节点
- TagPlayerPotion -
identifier的实际用途