节点列表界面

按节点列表热键打开的主界面:列出当前维度所有已记录的节点,可按侧重点筛选、按距离或侧重点数量排序、标记导航。

入口

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)分三步:

  1. 筛选:遍历 TCNodeTracker.nodelist,保留 currentAspect 为 "ALL" 或该节点 aspect 含此 tag, 且 n.dim == dimID 的记录(:292-298)
  2. 比较器:switch (sortBy) 选 AspectLoc 的 7 个静态比较器之一(:299-307)
  3. 反转: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):

  1. displayGuiScreen(null) 关掉列表界面
  2. doGui = true,xMarker / yMarker / zMarker 设为该节点坐标
  3. Navigator 已加载时 setActiveWaypoint(new Waypoint(..., 0xFFFFFF)) —— 颜色写死白色(:185)
  4. 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()) 格式化,即跟随系统语言。

相关条目