变异树布局与渲染

基本信息

属性 值
类 hellfirepvp.beebetteratbees.client.gui.CachedBeeMutationTree
基类 CachedRecipe(供 NEI 读取结果 / 原料堆栈)
树结构 SimpleBinaryTree<IAllele>,构造深度上限 4
渲染迭代深度 iterationDepth = 3
蜜蜂类型常量 BEE_TYPE_PRINCESS = 1、BEE_TYPE_DRONE = 0

从 mutation 到树

构造器接收一个 IBeeMutation,以其模板主位(getTemplate()[0],即结果物种) 为根,用 SimpleBinaryTree.RootProvider 递归向下展开(:153-169):

  • 展开规则是"取第一个能以该物种为结果的 mutation",用它的 getAllele0() / getAllele1() 作为左右子节点;没有可用 mutation 时返回 null,SimpleBinaryTree 据此把节点降级为 Leaf。
  • SimpleBinaryTree 的 buildSubTree 要么同时建左右子节点,要么建成 Leaf,不存在单边节点。
  • showDuplicateTrees = false 时,removeAndReplaceDuplicates() 先把已出现过的物种 从树上摘掉(:171-174、:307-322),命中且该物种确实还有 mutation 时才摘。

坐标与层高

常量 值 含义
MIN_X / MAX_X 15 / 135 横向渲染区间,跨度 120
Y_OFFSET 0 根节点纵坐标
X_SEPERATION_THRESHOLD 7 过窄判定阈值
OFFSET_CORRECTION 8 图标中心修正
POSSIBLE_CHILD_OFFSET 16 叶子节点"可能有子代"分叉的纵向长度

层高在构造器里算出(:178-187):

int iterationDepth = 3;
int maxTotalDepth = Math.min(iterationDepth, mutationTree.getRoot().getMaxFollowingDepth());
int yStep = 110 / maxTotalDepth;

maxTotalDepth <= 0(根是叶子)时构造器直接 return,此时只有根、不渲染任何节点—— 所以"查不到下级"的表现是完全空白而不是报错。

yStep 是整数除法,除不尽时向下取整(110 / 3 = 36)。 横向按二分中点递归:父节点在 [minX, maxX] 的中点,左子树占 [minX, center], 右子树占 [center, maxX]。

蜜蜂类型:根是公主蜂,其余全是雄蜂

根节点用 BEE_TYPE_PRINCESS(:227),而 placeInRenderBuffer 里所有 下级节点——无论叶子还是内部节点——都用 BEE_TYPE_DRONE(:348、:374)。

这是因为父代在 Forestry 的杂交公式里本来就该是雄蜂;结果个体(根)才需要公主蜂。

概率标签

每个节点的 baseChance 来自"第一个能产出该物种的 mutation"的 getBaseChance(); 没有这种 mutation 时为哨兵值 -1。标签只在 baseChance > 0 时生成(:251、:281), 所以 -1 与 0 都不会显示文字。

显示规则(ChanceInfoNode 构造器,:107-111):

条件 显示文本
chance < 1 加粗的 <1%
chance >= 1 加粗的 ((int) chance) + %

chance 是 float,(int) 直接截断,1.9 会显示成 1%。 悬浮命中判定是 x ∈ [x, x+16] 且 y ∈ [y+1, y+6](:115-117), 且只在 currenttip.isEmpty() 时才返回(见 NEI 配方树处理器),即自己会吞掉原版 tooltip。

连线与配色

颜色取自 ColorUtils(GTNHLib ColorResource,资源域 beebetteratbees), 全部只有两档:

用途 颜色 触发条件
连线 / 标签 默认 0x000000 黑 该节点 requirements 为空或 null
连线 / 标签 警示 0xA9000A 红 requirements 非空(该变异带特殊条件)

连线以 GL_LINE_STRIP 绘制,glLineWidth(3.0F)、开启 GL_LINE_SMOOTH、 alpha 固定 127(LineNode#renderNode,:62-83),绘制完把线宽复位为 2.0F。

源码缺陷

oversized 字段算了但从不读。 checkSeparationWidth()(:324-328, 判据 120 / 2^(depth+1) < 7)的结果写进 public final boolean oversized (:184、:189),但全仓库对该字段只有这两处赋值、零处读取—— grep -rn "oversized" 只命中声明和这两行。也就是说"树太宽挤不下"的判定 被完整计算后直接丢弃,不会触发任何降级或提示。

每层只画一条变异路径。 展开时固定取 mutations.get(0)(:162、:216、:364), 同一物种若有多个不同父代组合的 mutation,配方树只会展示注册顺序里的第一个。 这不是渲染 bug,是设计取舍,但会让人以为某条杂交路径不存在。

注释声明的画布高度与实际面板不符。 文件头注释写 Y = 10 to 100 (Size: 90)(:130),但 drawBackground 只画 166 x 65 的 neiBlank.png(AbstractTreeGUIHandler.java:132), 而 yStep = 110 / maxTotalDepth 在 maxTotalDepth = 1 时是 110,远超 65px 面板。

相关条目