节点列表界面
按节点列表热键打开的主界面:列出当前维度所有已记录的节点,可按侧重点筛选、按距离或侧重点数量排序、标记导航。
入口
com.dyonovan.tcnodetracker.gui.GuiMain extends GuiScreen,在 KeyInputEvent.onKeyInput
(events/KeyInputEvent.java:18-20)用 displayGuiScreen(new GuiMain()) 打开。
类上标注 @SideOnly(Side.CLIENT)(gui/GuiMain.java:34)。
界面尺寸
| 项 | 值 | 源码 |
|---|---|---|
内容区宽度 display |
425 像素 | gui/GuiMain.java:62 |
start(左边缘) |
(width - 425) / 2 |
:63 |
| 每页行数 | 10(high = min(aspectList.size(), 10)) |
:311 |
| 行高 | 14 像素,行起点 l = 70 |
:358、:438 |
| 是否暂停游戏 | 否(doesGuiPauseGame() 返回 false) |
:200-202 |
| 关闭键 | I 或 Esc |
:193-197 |
顶部六边形按钮条由贴图 tcnodetracker:textures/gui/nodes.png 绘制
(:215,只画 (width-204)/2, 1 处的 204×35 区域)。
维度选择
initGui 遍历 DimensionManager.getStaticDimensionIDs() 建立 List<DimList>
(:66-84),每个维度用 WorldProvider.getDimensionName() 取名字,
取名失败(catch (Throwable t))时回落成 Integer.toString(i)(:73-75、:79-81)。
列表按 dimID 升序排(:84),默认选中玩家当前所在维度(:86)。
翻页由贴图 small_arrows.png 的两个小箭头点击区实现(:241-262),循环切换
(第一项的左箭头跳到最后一项,最后一项的右箭头跳回第一项)。
每次切维度都会重置筛选为 "ALL" 并按距离排序(dimFunction,:48-58)。
筛选(6 个主侧重点)
顶部 6 个点击区各自对应一个主侧重点(:223-240),点击即把 currentAspect 设为对应 tag 并按距离重排:
点击区 x 范围(相对 w = (width-204)/2) |
currentAspect |
常量 |
|---|---|---|
w+2 ~ w+32 |
aer |
Constants.AIR |
w+35 ~ w+66 |
aqua |
Constants.WATER |
w+70 ~ w+101 |
ignis |
Constants.FIRE |
w+104 ~ w+135 |
ordo |
Constants.ORDER |
w+139 ~ w+170 |
perditio |
Constants.ENTROPY |
w+172 ~ w+203 |
terra |
Constants.EARTH |
表头还有一排侧重点排序按钮(:271-285),第一个是「按距离」,后面 6 个按对应侧重点排序。
排序
sortNodes(String sortBy)(:289-313)分三步:
- 筛选:遍历
TCNodeTracker.nodelist,保留currentAspect为"ALL"或该节点aspect含此 tag, 且n.dim == dimID的记录(:292-298) - 比较器:
switch (sortBy)选AspectLoc的 7 个静态比较器之一(:299-307) - 反转:
if (!sortBy.equals(Constants.DISTANCE)) Collections.reverse(aspectList);(:309)
⚠️ 因此按侧重点排序是降序(多的在前),按距离排序是升序(近的在前)。
7 个比较器都在 lib/AspectLoc.java:48-116,每个都返回 o1.<字段> - o2.<字段>
(int 相减,理论上有溢出风险,但侧重点数量远小于 int 范围,实际不会溢出)。
| 排序依据 | 比较器 | 比较字段 |
|---|---|---|
| 距离 | getDistComparator() |
distance |
| 气 | getAerComparator() |
hasAer |
| 水 | getAquaComparator() |
hasAqua |
| 火 | getIgnisComparator() |
hasIgnis |
| 秩序 | getOrdoComparator() |
hasOrdo |
| 熵 | getPerdComparator() |
hasPerdito |
| 地 | getTerraComparator() |
hasTerra |
排序与筛选结束都会调 guiButtons() 重建按钮,并把 low = 0、high = min(size, 10) 复位到第一页。
每行的字段
表头(:374-382):Dist / X / Y / Z / Type / Aer Aqua Ignis Ordo Perd Terra。
每行渲染(:384-439):
| 列 | 内容 | 备注 |
|---|---|---|
| Dist | a.distance |
见下方距离算法 |
| X / Y / Z | a.x / a.y / a.z |
|
| Type | a.type.substring(0, 1) |
只显示首字母,完整类型靠 tooltip |
| 6 个侧重点列 | 数量 > 0 才显示,否则空串 | compound(复合侧重点)没有独立列 |
距离算法(:344):
(int) Math.round(mc.thePlayer.getDistance(nodes.x, mc.thePlayer.posY, nodes.z))
与屏幕指引箭头一样,Y 分量传的是玩家的 posY,所以是水平距离,
不是到节点的三维距离。
行颜色(:385-388):若该行坐标与 xMarker / yMarker / zMarker 三者全等(即当前标记的节点),
用 Constants.GREEN(0x26AA30);否则 Constants.WHITE(0xFFFFFF)。
按钮
guiButtons(:92-122)为当前页每一行生成一对按钮,ID 从 low 开始每行递增 2:
| 按钮 | ID | 行为 | 源码 |
|---|---|---|---|
Mark(btn.mark.name) |
偶数 ID j+1 |
关闭界面,设 doGui = true 与三个标记坐标 |
:167-189 |
Del(btn.delete.name) |
奇数 ID j |
删除该行节点 | :138-165 |
Clear Arrow(btn.cleararrow.name) |
buttonList.size() - 2 |
清标记并关闭界面 | :127-134 |
Config(btn.config.name) |
buttonList.size() - 1 |
打开配置项界面 | :135-137 |
⚠️ actionPerformed 用 button.id % 2 区分 Mark / Del(:138、:167),
并用 button.id / 2 反推行号,配合 aspectList.get(low + i)(:143、:171)。
这依赖按钮 ID 严格从 0 开始每行 +2 递增;Clear Arrow / Config 用 size()-2 / size()-1
(列表末两位)规避了奇偶判断,逻辑自洽。
Mark
actionPerformed 的奇数分支(:167-189):
displayGuiScreen(null)关掉列表界面doGui = true,xMarker/yMarker/zMarker设为该节点坐标- Navigator 已加载时
setActiveWaypoint(new Waypoint(..., 0xFFFFFF))—— 颜色写死白色(:185) aspectList.clear()
⚠️ 第 3 步的 waypoint 颜色是常量 0xFFFFFF,而 Navigator 图层里由
节点自己转成 waypoint时用的是「最强侧重点的颜色」。
所以通过本界面标记的 waypoint 与在 Navigator 地图上点的 waypoint 颜色不一致。
Del
偶数分支(:138-165)在双重循环里遍历 nodelist × 当前页行号,
比较 x / y / z(不比 dim)来定位记录:
| Navigator 状态 | 行为 | 源码 |
|---|---|---|
| 已加载 | ThaumcraftNodeLayerManager.instance.deleteNode(nodelist.get(k)) |
:155-156 |
| 未加载 | nodelist.remove(k) + JsonUtils.writeJson() |
:157-160 |
删除前会先检查该节点是否正是当前标记的节点,若是则一并清标记(:146-154)。
最后 sortNodes(lastSort) 刷新列表。
⚠️ 定位时不比较 dim,不过因为 aspectList 已被 sortNodes 按 n.dim == dimID 过滤过,
实际结果仍然是当前维度的记录。
Tooltip
两处(都在第二遍渲染循环 :442-476):
| 悬停区域 | 内容 |
|---|---|
Type 列(start+130 ~ start+156) |
复合侧重点列表(无则 None)+ 完整节点类型 + 节点修饰符 |
Dist 列(start+2 ~ start+40) |
Last Scanned + 格式化时间(无则 Unknown) |
Type 列 tooltip(:444-465)用语言键 nodetype.<type>.name 与 nodemod.<mod>.name;
节点修饰符那行只在 mod != null && !mod.equals("BLANK") 时才加。
Dist 列的时间来自 AspectLoc.formattedDate(lib/AspectLoc.java:41-45),
用 DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault())
格式化,即跟随系统语言。