Add custom render for PositionedStack (#1002)

This commit is contained in:
slprime authored and GitHub committed 2026-08-13 21:49:05 +03:00
1 parent c6170f9795
commit 7d4c8b82ba
4 files changed
+88 -27

No files matched your search

@@ -13,6 +13,7 @@ import net.minecraftforge.oredict.OreDictionary;
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;
@@ -20,19 +21,21 @@ import codechicken.nei.recipe.StackInfo;
/**
* 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;
public int relx;
public int rely;
public int width = 16;
public int height = 16;
public ItemStack[] items;
// compatibility dummy
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);
@@ -91,6 +94,10 @@ public class PositionedStack {
return null;
}
public List<String> getTooltip() {
return null;
}
public int getChance() {
return this.chance;
}
@@ -100,14 +107,20 @@ public class PositionedStack {
}
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;
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) {
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<ItemStack> getFilteredPermutations() {
@@ -164,7 +177,9 @@ public class PositionedStack {
}
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) {
@@ -192,4 +207,21 @@ public class PositionedStack {
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) {}
}
}
@@ -155,11 +155,16 @@ public class GuiFavoriteButton extends GuiRecipeButton {
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);
}
@@ -247,14 +247,15 @@ public class NEIRecipeWidget extends Widget {
}
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 @@ public class NEIRecipeWidget extends Widget {
final List<Badge> 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));
}
}
@@ -409,14 +410,22 @@ public class NEIRecipeWidget extends Widget {
if (itemstack != null) {
final PositionedStack hovered = getPositionedStackMouseOver(mousex, mousey);
if (hovered != null && this.handlerInfo.getShowBadge()) {
final List<Badge> badges = getBadges(hovered, getOutputs().indexOf(hovered) == -1);
if (hovered != null) {
if (this.handlerInfo.getShowBadge()) {
final List<Badge> badges = getBadges(hovered, getOutputs().indexOf(hovered) == -1);
for (Badge badge : badges) {
if (badge.getTooltip() != null && !badge.getTooltip().isEmpty()) {
tooltip.addAll(badge.getTooltip());
for (Badge badge : badges) {
if (badge.getTooltip() != null && !badge.getTooltip().isEmpty()) {
tooltip.addAll(badge.getTooltip());
}
}
}
final List<String> customTooltip = hovered.getTooltip();
if (customTooltip != null && !customTooltip.isEmpty()) {
tooltip.addAll(customTooltip);
}
}
if (hovered == null || !NEIClientConfig.showCycledIngredientsTooltip()
@@ -288,13 +288,18 @@ public class Recipe {
protected int relx;
protected int rely;
protected int width;
protected int height;
public RecipeIngredient(int relx, int rely, List<ItemStack> items, int chance, int activeIndex) {
public RecipeIngredient(int relx, int rely, int width, int height, List<ItemStack> 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 class Recipe {
}
}
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<ItemStack> 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<ItemStack> stacks, int chance,
int activeIndex) {
return new RecipeIngredient(relx, rely, width, height, stacks, chance, activeIndex);
}
public int getAmount() {
@@ -352,6 +365,8 @@ public class Recipe {
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 @@ public class Recipe {
}
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) {