From 0530def2e440b9256a919ca1fe5d5d1c6593747e Mon Sep 17 00:00:00 2001 From: slprime Date: Thu, 13 Aug 2026 20:18:37 +0300 Subject: [PATCH 1/4] Add custom render for PositionedStack --- .../java/codechicken/nei/PositionedStack.java | 15 ++++++++++- .../nei/recipe/GuiFavoriteButton.java | 11 +++++--- .../nei/recipe/NEIRecipeWidget.java | 7 +++--- .../java/codechicken/nei/recipe/Recipe.java | 25 +++++++++++++++---- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/main/java/codechicken/nei/PositionedStack.java b/src/main/java/codechicken/nei/PositionedStack.java index a5155571c..bfd01c024 100644 --- a/src/main/java/codechicken/nei/PositionedStack.java +++ b/src/main/java/codechicken/nei/PositionedStack.java @@ -13,6 +13,7 @@ import codechicken.nei.api.ItemFilter; import codechicken.nei.api.ItemInfo; +import codechicken.nei.guihook.GuiContainerManager; import codechicken.nei.recipe.Badge; import codechicken.nei.recipe.GuiRecipe; import codechicken.nei.recipe.StackInfo; @@ -27,6 +28,8 @@ public class PositionedStack { public int relx; public int rely; + public int width = 16; + public int height = 16; public ItemStack[] items; // compatibility dummy public ItemStack item; @@ -107,9 +110,17 @@ public PositionedStack copy() { false); pStack.permutated = this.permutated; pStack.chance = this.chance; + pStack.width = this.width; + pStack.height = this.height; return pStack; } + public void draw(int mousex, int mousey) { + final int x = this.relx + (this.width - 16) / 2; + final int y = this.rely + (this.height - 16) / 2; + GuiContainerManager.drawItem(x, y, this.item); + } + public List getFilteredPermutations() { return getFilteredPermutations(null); } @@ -164,7 +175,9 @@ public void setPermutationToRender(int index) { } public boolean contains(int mx, int my) { - return mx >= this.relx - 1 && mx < this.relx + 17 && my >= this.rely - 1 && my < this.rely + 17; + return mx >= this.relx - 1 && mx < this.relx + this.width + 1 + && my >= this.rely - 1 + && my < this.rely + this.height + 1; } public boolean contains(ItemStack ingredient) { diff --git a/src/main/java/codechicken/nei/recipe/GuiFavoriteButton.java b/src/main/java/codechicken/nei/recipe/GuiFavoriteButton.java index 2fc7abc24..9340c49aa 100644 --- a/src/main/java/codechicken/nei/recipe/GuiFavoriteButton.java +++ b/src/main/java/codechicken/nei/recipe/GuiFavoriteButton.java @@ -155,11 +155,16 @@ public void drawItemOverlay() { if (this.selectedResult == null) return; NEIClientUtils.gl2DRenderContext( - () -> GuiDraw.drawRect(this.selectedResult.relx, this.selectedResult.rely, 16, 16, 0x66333333)); + () -> GuiDraw.drawRect( + this.selectedResult.relx, + this.selectedResult.rely, + this.selectedResult.width, + this.selectedResult.height, + 0x66333333)); final Image icon = isFavorite() ? ICON_STATE_ON : ICON_STATE_OFF; - final int iconX = this.selectedResult.relx + (16 - icon.width) / 2; - final int iconY = this.selectedResult.rely + (18 - icon.height) / 2; + final int iconX = this.selectedResult.relx + (this.selectedResult.width - icon.width) / 2; + final int iconY = this.selectedResult.rely + (this.selectedResult.height + 2 - icon.height) / 2; LayoutManager.drawIcon(iconX, iconY, icon); } diff --git a/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java b/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java index a9e756d2a..9bc4f0b60 100644 --- a/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java +++ b/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java @@ -247,14 +247,15 @@ public void draw(int mouseX, int mouseY) { } protected void drawItem(PositionedStack pStack, int mouseX, int mouseY, int yShift, boolean input) { - GuiContainerManager.drawItem(pStack.relx, pStack.rely, pStack.item); + pStack.draw(mouseX - this.x, mouseY - this.y - yShift); if (this.handlerInfo.getShowBadge()) { drawBadge(pStack, input); } if (pStack.contains(mouseX - this.x, mouseY - this.y - yShift)) { - NEIClientUtils.gl2DRenderContext(() -> GuiDraw.drawRect(pStack.relx, pStack.rely, 16, 16, 0x80FFFFFF)); + NEIClientUtils.gl2DRenderContext( + () -> GuiDraw.drawRect(pStack.relx, pStack.rely, pStack.width, pStack.height, 0x80FFFFFF)); } } @@ -291,7 +292,7 @@ protected void drawBadge(PositionedStack pStack, boolean input) { final List badges = getBadges(pStack, input); for (Badge badge : badges) { - badge.draw(new Rectangle4i(pStack.relx, pStack.rely, 16, 16)); + badge.draw(new Rectangle4i(pStack.relx, pStack.rely, pStack.width, pStack.height)); } } diff --git a/src/main/java/codechicken/nei/recipe/Recipe.java b/src/main/java/codechicken/nei/recipe/Recipe.java index 269b7ce2b..c0cbc1742 100644 --- a/src/main/java/codechicken/nei/recipe/Recipe.java +++ b/src/main/java/codechicken/nei/recipe/Recipe.java @@ -288,13 +288,18 @@ public static class RecipeIngredient { protected int relx; protected int rely; + protected int width; + protected int height; - public RecipeIngredient(int relx, int rely, List items, int chance, int activeIndex) { + public RecipeIngredient(int relx, int rely, int width, int height, List items, int chance, + int activeIndex) { this.items = items.stream().map(ItemStack::copy).toArray(size -> new ItemStack[size]); this.amount = StackInfo.getAmount(this.items[activeIndex]); this.activeIndex = activeIndex; this.relx = relx; this.rely = rely; + this.width = width; + this.height = height; this.chance = chance; } @@ -314,11 +319,19 @@ public static RecipeIngredient of(PositionedStack positionedStack) { } } - return of(positionedStack.relx, positionedStack.rely, stacks, positionedStack.getChance(), activeIndex); + return of( + positionedStack.relx, + positionedStack.rely, + positionedStack.width, + positionedStack.height, + stacks, + positionedStack.getChance(), + activeIndex); } - public static RecipeIngredient of(int relx, int rely, List stacks, int chance, int activeIndex) { - return new RecipeIngredient(relx, rely, stacks, chance, activeIndex); + public static RecipeIngredient of(int relx, int rely, int width, int height, List stacks, int chance, + int activeIndex) { + return new RecipeIngredient(relx, rely, width, height, stacks, chance, activeIndex); } public int getAmount() { @@ -352,6 +365,8 @@ public RecipeIngredient copy() { return new RecipeIngredient( this.relx, this.rely, + this.width, + this.height, getPermutations().stream().map(ItemStack::copy).collect(Collectors.toList()), this.chance, this.activeIndex); @@ -436,7 +451,7 @@ protected static RecipeIngredient extractItem(Object item) { } if (item instanceof ItemStack stack) { - return RecipeIngredient.of(0, 0, Arrays.asList(stack), PositionedStack.CHANCE_FULL, 0); + return RecipeIngredient.of(0, 0, 16, 16, Arrays.asList(stack), PositionedStack.CHANCE_FULL, 0); } if (item instanceof RecipeIngredient ingr) { From ecb52710d4dc8a37d41d9aa4a5a8743ef0057e2a Mon Sep 17 00:00:00 2001 From: slprime Date: Thu, 13 Aug 2026 21:15:51 +0300 Subject: [PATCH 2/4] add tooltip --- .../java/codechicken/nei/PositionedStack.java | 4 ++++ .../nei/recipe/NEIRecipeWidget.java | 20 +++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/main/java/codechicken/nei/PositionedStack.java b/src/main/java/codechicken/nei/PositionedStack.java index bfd01c024..50bd6ba15 100644 --- a/src/main/java/codechicken/nei/PositionedStack.java +++ b/src/main/java/codechicken/nei/PositionedStack.java @@ -94,6 +94,10 @@ public List getBadges() { return null; } + public List getTooltip() { + return null; + } + public int getChance() { return this.chance; } diff --git a/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java b/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java index 9bc4f0b60..337f0e29e 100644 --- a/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java +++ b/src/main/java/codechicken/nei/recipe/NEIRecipeWidget.java @@ -410,14 +410,22 @@ public List handleItemTooltip(ItemStack itemstack, int mousex, int mouse if (itemstack != null) { final PositionedStack hovered = getPositionedStackMouseOver(mousex, mousey); - if (hovered != null && this.handlerInfo.getShowBadge()) { - final List badges = getBadges(hovered, getOutputs().indexOf(hovered) == -1); - - for (Badge badge : badges) { - if (badge.getTooltip() != null && !badge.getTooltip().isEmpty()) { - tooltip.addAll(badge.getTooltip()); + if (hovered != null) { + if (this.handlerInfo.getShowBadge()) { + final List badges = getBadges(hovered, getOutputs().indexOf(hovered) == -1); + + for (Badge badge : badges) { + if (badge.getTooltip() != null && !badge.getTooltip().isEmpty()) { + tooltip.addAll(badge.getTooltip()); + } } } + + final List customTooltip = hovered.getTooltip(); + + if (customTooltip != null && !customTooltip.isEmpty()) { + tooltip.addAll(customTooltip); + } } if (hovered == null || !NEIClientConfig.showCycledIngredientsTooltip() From 4ad6bf16ad8df6f49ed7cf79e63b792883c498f0 Mon Sep 17 00:00:00 2001 From: slprime Date: Thu, 13 Aug 2026 21:27:32 +0300 Subject: [PATCH 3/4] add placeholder --- .../java/codechicken/nei/PositionedStack.java | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/codechicken/nei/PositionedStack.java b/src/main/java/codechicken/nei/PositionedStack.java index 50bd6ba15..ae63a8c18 100644 --- a/src/main/java/codechicken/nei/PositionedStack.java +++ b/src/main/java/codechicken/nei/PositionedStack.java @@ -35,7 +35,7 @@ public class PositionedStack { public ItemStack item; protected int chance = CHANCE_FULL; - private boolean permutated = false; + protected boolean permutated = false; public PositionedStack(Object object, int x, int y, boolean genPerms) { items = NEIServerUtils.extractRecipeItems(object); @@ -209,4 +209,36 @@ public boolean contains(Item ingred) { public String toString() { return "PositionedStack(output='" + item.toString() + "')"; } + + /** + * A {@link PositionedStack} that keeps its items but never draws them. + */ + public static class Placeholder extends PositionedStack { + + public Placeholder(Object object, int x, int y, boolean genPerms) { + super(object, x, y, genPerms); + } + + public Placeholder(Object object, int x, int y) { + this(object, x, y, true); + } + + @Override + public void draw(int mousex, int mousey) {} + + @Override + public PositionedStack copy() { + Placeholder pStack = new Placeholder( + Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new), + relx, + rely, + false); + + pStack.permutated = this.permutated; + pStack.chance = this.chance; + pStack.width = this.width; + pStack.height = this.height; + return pStack; + } + } } From b56044712c05d0e605579552ded0c513535988e0 Mon Sep 17 00:00:00 2001 From: slprime Date: Thu, 13 Aug 2026 21:40:22 +0300 Subject: [PATCH 4/4] improve copy --- .../java/codechicken/nei/PositionedStack.java | 35 +++++-------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/src/main/java/codechicken/nei/PositionedStack.java b/src/main/java/codechicken/nei/PositionedStack.java index ae63a8c18..302ad8b7e 100644 --- a/src/main/java/codechicken/nei/PositionedStack.java +++ b/src/main/java/codechicken/nei/PositionedStack.java @@ -21,7 +21,7 @@ /** * Simply an {@link ItemStack} with position. Mainly used in the recipe handlers. */ -public class PositionedStack { +public class PositionedStack implements Cloneable { /** Maximum chance value representing 100% probability (1 unit = 0.01%). */ public static final int CHANCE_FULL = 10_000; @@ -107,16 +107,14 @@ public void setChance(int chance) { } public PositionedStack copy() { - PositionedStack pStack = new PositionedStack( - Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new), - relx, - rely, - false); - pStack.permutated = this.permutated; - pStack.chance = this.chance; - pStack.width = this.width; - pStack.height = this.height; - return pStack; + try { + PositionedStack pStack = (PositionedStack) super.clone(); + pStack.items = Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new); + pStack.item = this.item == null ? null : this.item.copy(); + return pStack; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } } public void draw(int mousex, int mousey) { @@ -225,20 +223,5 @@ public Placeholder(Object object, int x, int y) { @Override public void draw(int mousex, int mousey) {} - - @Override - public PositionedStack copy() { - Placeholder pStack = new Placeholder( - Arrays.stream(this.items).map(ItemStack::copy).toArray(ItemStack[]::new), - relx, - rely, - false); - - pStack.permutated = this.permutated; - pStack.chance = this.chance; - pStack.width = this.width; - pStack.height = this.height; - return pStack; - } } }