Fix HEI Handler Tooltip (#8)

This commit is contained in:
slprime authored and GitHub committed 2026-05-14 22:25:29 +02:00
1 parent e4f19ece07
commit e3f577da4b
3 files changed
+195 -148

No files matched your search

+2 -2
View File
@@ -34,6 +34,6 @@
* For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph
*/
dependencies {
api("com.github.GTNewHorizons:NotEnoughItems:2.7.69-GTNH:dev")
api("com.github.GTNewHorizons:ForestryMC:4.10.16:dev")
api("com.github.GTNewHorizons:NotEnoughItems:2.8.98-GTNH:dev")
api("com.github.GTNewHorizons:ForestryMC:4.11.23:dev")
}
@@ -1,25 +1,13 @@
package hellfirepvp.beebetteratbees.client.gui;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.recipe.GuiRecipe;
@@ -30,6 +18,8 @@ import forestry.api.genetics.IAllele;
import forestry.api.genetics.IAlleleSpecies;
import forestry.api.genetics.IIndividual;
import forestry.api.genetics.ISpeciesRoot;
import hellfirepvp.beebetteratbees.client.gui.CachedBeeMutationTree.ChanceInfoNode;
import hellfirepvp.beebetteratbees.client.gui.CachedBeeMutationTree.IMutationNode;
import hellfirepvp.beebetteratbees.common.BeeBetterAtBees;
import hellfirepvp.beebetteratbees.common.ModConfig;
@@ -112,158 +102,34 @@ public class BBABGuiRecipeTreeHandler extends AbstractTreeGUIHandler {
cleanupDuplicateRecipes();
}
/**
* Tooltip rectangles, where list index is the recipe index of this page
*/
private final ArrayList<Map<Rectangle, Collection<String>>> tipBoxes = new ArrayList<>(2); // 1-2 recipes/pg
@Override
public void drawExtras(int recipe) {
CachedRecipe rec = this.arecipes.get(recipe);
if (rec instanceof CachedBeeMutationTree cachedTree) {
Map<Rectangle, Collection<String>> boxes = new HashMap<>(4);
CachedBeeMutationTree.PositionedMutationNodeStack root = cachedTree.getRootStack();
drawExtrasFrom(root, boxes);
this.tipBoxes.add(boxes);
cachedTree.getMutationNodesToRender()
.forEach(node -> node.renderNode());
}
}
private static final Color lineColorBlack = new Color(0, 0, 0), lineColorRed = new Color(169, 0, 10);
private static final int offsetCorrection = 8;
private static final int possibleChildOffset = 16;
public static void drawExtrasFrom(CachedBeeMutationTree.PositionedMutationNodeStack nodeStack,
Map<Rectangle, Collection<String>> infoBoxes) {
int nodeX = nodeStack.relx;
int nodeY = nodeStack.rely;
if (nodeStack.leftChild == null || nodeStack.rightChild == null) {
if (nodeStack.hasPossibleChildren) {
Color drawColor = lineColorBlack;
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
drawColor = lineColorRed;
}
float chance = nodeStack.baseChance;
if (chance > 0) {
int length = drawChanceInfo(nodeX, nodeY, chance, Minecraft.getMinecraft().fontRenderer, drawColor);
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
Rectangle rec = new Rectangle(nodeX + 4, nodeY + 17, (int) (length * 0.75F), 5);
infoBoxes.put(rec, nodeStack.requirements);
}
}
drawLine(
nodeX + offsetCorrection,
nodeY + offsetCorrection,
nodeX + offsetCorrection - 4,
nodeY + offsetCorrection + possibleChildOffset,
drawColor);
drawLine(
nodeX + offsetCorrection,
nodeY + offsetCorrection,
nodeX + offsetCorrection + 4,
nodeY + offsetCorrection + possibleChildOffset,
drawColor);
}
return; // Has no children anymore.
}
Color drawColor = lineColorBlack;
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
drawColor = lineColorRed;
}
float chance = nodeStack.baseChance;
if (chance > 0) {
int length = drawChanceInfo(nodeX, nodeY, chance, Minecraft.getMinecraft().fontRenderer, drawColor);
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
Rectangle rec = new Rectangle(nodeX + 4, nodeY + 17, (int) (length * 0.75F), 5);
infoBoxes.put(rec, nodeStack.requirements);
}
}
CachedBeeMutationTree.PositionedMutationNodeStack left = nodeStack.leftChild;
drawLine(
nodeX + offsetCorrection,
nodeY + offsetCorrection,
left.relx + offsetCorrection,
left.rely + offsetCorrection,
drawColor);
CachedBeeMutationTree.PositionedMutationNodeStack right = nodeStack.rightChild;
drawLine(
nodeX + offsetCorrection,
nodeY + offsetCorrection,
right.relx + offsetCorrection,
right.rely + offsetCorrection,
drawColor);
drawExtrasFrom(left, infoBoxes);
drawExtrasFrom(right, infoBoxes);
}
private static int drawChanceInfo(int nodeX, int nodeY, float chance, FontRenderer fr, Color drawColor) {
GL11.glPushMatrix();
GL11.glTranslatef(nodeX + 4, nodeY + 17, 0);
GL11.glScalef(0.65F, 0.65F, 0.65F);
int chAsInt = (int) (chance);
StringBuilder sb = new StringBuilder().append(EnumChatFormatting.BOLD);
if (chAsInt <= 0) {
sb.append("<1%");
} else {
sb.append(chAsInt)
.append("%");
}
int length = fr.drawString(sb.toString(), 0, 0, drawColor.getRGB());
GL11.glPopMatrix();
return length;
}
@Override
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip, int recipe) {
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.isEmpty()) {
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.isEmpty()
&& this.arecipes.get(recipe) instanceof CachedBeeMutationTree cachedTree) {
Point pos = GuiDraw.getMousePosition();
Point guiOffset = new Point(gui.guiLeft, gui.guiTop);
Point recipeOffset = gui.getRecipePosition(recipe);
Point relMouse = new Point(pos.x - guiOffset.x - recipeOffset.x, pos.y - guiOffset.y - recipeOffset.y);
for (Rectangle rec : this.tipBoxes.get(recipe)
.keySet()) {
if (rec.contains(relMouse)) {
return new LinkedList<>(
this.tipBoxes.get(recipe)
.get(rec));
for (IMutationNode mutation : cachedTree.getMutationNodesToRender()) {
if (mutation instanceof ChanceInfoNode chanceInfoNode && chanceInfoNode
.containsPoint(pos.x - guiOffset.x - recipeOffset.x, pos.y - guiOffset.y - recipeOffset.y)) {
return new LinkedList<>(chanceInfoNode.infoLines);
}
}
}
return super.handleTooltip(gui, currenttip, recipe);
}
private static void drawLine(double lx, double ly, double hx, double hy, Color color) {
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glLineWidth(3.0F);
GL11.glEnable(GL11.GL_LINE_SMOOTH);
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
Tessellator tes = Tessellator.instance;
tes.startDrawing(GL11.GL_LINE_STRIP);
tes.setColorRGBA(color.getRed(), color.getGreen(), color.getBlue(), 127);
tes.addVertex(lx, ly, 0);
tes.addVertex(hx, hy, 0);
tes.draw();
GL11.glDisable(GL11.GL_LINE_SMOOTH);
GL11.glLineWidth(2.0F);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
@Override
public void loadUsageRecipes(String inputId, Object... ingredients) {
if (speciesRoot == null) return;
@@ -2,12 +2,20 @@ package hellfirepvp.beebetteratbees.client.gui;
import static hellfirepvp.beebetteratbees.client.gui.BBABGuiRecipeTreeHandler.*;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.nei.PositionedStack;
import forestry.api.apiculture.IBeeMutation;
import forestry.api.genetics.IAllele;
@@ -23,6 +31,99 @@ import hellfirepvp.beebetteratbees.common.ModConfig;
*/
public class CachedBeeMutationTree extends CachedRecipe {
protected static interface IMutationNode {
boolean containsPoint(int x, int y);
void renderNode();
}
protected static class LineNode implements IMutationNode {
public final double lx;
public final double ly;
public final double hx;
public final double hy;
public final Color color;
public LineNode(double lx, double ly, double hx, double hy, Color color) {
this.lx = lx;
this.ly = ly;
this.hx = hx;
this.hy = hy;
this.color = color;
}
public boolean containsPoint(int x, int y) {
return false;
}
public void renderNode() {
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glLineWidth(3.0F);
GL11.glEnable(GL11.GL_LINE_SMOOTH);
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
Tessellator tes = Tessellator.instance;
tes.startDrawing(GL11.GL_LINE_STRIP);
tes.setColorRGBA(color.getRed(), color.getGreen(), color.getBlue(), 127);
tes.addVertex(lx, ly, 0);
tes.addVertex(hx, hy, 0);
tes.draw();
GL11.glDisable(GL11.GL_LINE_SMOOTH);
GL11.glLineWidth(2.0F);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
}
protected static class ChanceInfoNode implements IMutationNode {
public final int x;
public final int y;
public final float chance;
public Color drawColor = LINE_BLACK;
public final String displayString;
public Collection<String> infoLines;
public ChanceInfoNode(int x, int y, PositionedMutationNodeStack nodeStack) {
this.x = x;
this.y = y;
this.chance = nodeStack.baseChance;
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
this.drawColor = LINE_RED;
this.infoLines = nodeStack.requirements;
} else {
this.infoLines = Collections.emptyList();
}
if (chance < 1) {
this.displayString = EnumChatFormatting.BOLD + "<1%";
} else {
this.displayString = EnumChatFormatting.BOLD.toString() + ((int) chance) + "%";
}
}
public boolean containsPoint(int x, int y) {
return x >= this.x && x <= this.x + 16 && y >= this.y + 1 && y <= this.y + 6;
}
public void renderNode() {
GL11.glPushMatrix();
GL11.glTranslatef(this.x + 8, this.y + 1, 0);
GL11.glScalef(0.65F, 0.65F, 0.65F);
GuiDraw.drawStringC(this.displayString, 0, 0, drawColor.getRGB(), false);
GL11.glPopMatrix();
}
}
// RENDERING BB
// X = 15 to 135 (Size: 120)
// Y = 10 to 100 (Size: 90)
@@ -30,12 +131,18 @@ public class CachedBeeMutationTree extends CachedRecipe {
private static final int MIN_X = 15, MAX_X = 135;
private static final int X_SEPERATION_THRESHOLD = 7;
private static final int Y_OFFSET = 0;
private static final Color LINE_BLACK = new Color(0, 0, 0);
private static final Color LINE_RED = new Color(169, 0, 10);
private static final int OFFSET_CORRECTION = 8;
private static final int POSSIBLE_CHILD_OFFSET = 16;
private final SimpleBinaryTree<IAllele> mutationTree;
private final List<PositionedMutationNodeStack> evaluatedBeePositions;
private int evaluatedMaxX;
public final boolean oversized;
private PositionedMutationNodeStack rootStack;
private List<IMutationNode> mutationNodesToRender = new LinkedList<>();
public CachedBeeMutationTree(IBeeMutation parentMutation) {
// parentMutation.getTemplate() Gets results primary at array[0], secondary at array[1]
@@ -122,6 +229,76 @@ public class CachedBeeMutationTree extends CachedRecipe {
leftChild,
rightChild,
true);
generateMutationNodes(rootStack);
}
private void generateMutationNodes(PositionedMutationNodeStack nodeStack) {
int nodeX = nodeStack.relx;
int nodeY = nodeStack.rely;
if (nodeStack.leftChild == null || nodeStack.rightChild == null) {
if (nodeStack.hasPossibleChildren) {
Color drawColor = LINE_BLACK;
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
drawColor = LINE_RED;
}
if (nodeStack.baseChance > 0) {
this.mutationNodesToRender.add(new ChanceInfoNode(nodeX, nodeY + 16, nodeStack));
}
this.mutationNodesToRender.add(
new LineNode(
nodeX + OFFSET_CORRECTION,
nodeY + OFFSET_CORRECTION,
nodeX + OFFSET_CORRECTION - 4,
nodeY + OFFSET_CORRECTION + POSSIBLE_CHILD_OFFSET,
drawColor));
this.mutationNodesToRender.add(
new LineNode(
nodeX + OFFSET_CORRECTION,
nodeY + OFFSET_CORRECTION,
nodeX + OFFSET_CORRECTION + 4,
nodeY + OFFSET_CORRECTION + POSSIBLE_CHILD_OFFSET,
drawColor));
}
} else {
PositionedMutationNodeStack left = nodeStack.leftChild;
PositionedMutationNodeStack right = nodeStack.rightChild;
Color drawColor = LINE_BLACK;
if (nodeStack.requirements != null && !nodeStack.requirements.isEmpty()) {
drawColor = LINE_RED;
}
if (nodeStack.baseChance > 0) {
this.mutationNodesToRender.add(new ChanceInfoNode(nodeX, nodeY + 16, nodeStack));
}
this.mutationNodesToRender.add(
new LineNode(
nodeX + OFFSET_CORRECTION,
nodeY + OFFSET_CORRECTION,
left.relx + OFFSET_CORRECTION,
left.rely + OFFSET_CORRECTION,
drawColor));
this.mutationNodesToRender.add(
new LineNode(
nodeX + OFFSET_CORRECTION,
nodeY + OFFSET_CORRECTION,
right.relx + OFFSET_CORRECTION,
right.rely + OFFSET_CORRECTION,
drawColor));
generateMutationNodes(left);
generateMutationNodes(right);
}
}
private void removeAndReplaceDuplicates(SimpleBinaryTree.Node<IAllele> node, List<IAllele> discoveredMutations) { // Replace
@@ -229,6 +406,10 @@ public class CachedBeeMutationTree extends CachedRecipe {
return rootStack;
}
public List<IMutationNode> getMutationNodesToRender() {
return mutationNodesToRender;
}
@Override
public List<PositionedStack> getIngredients() {
return new ArrayList<>(evaluatedBeePositions);