/* * Copyright (C) 2022 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * * NotEnoughUpdates is free software: you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * NotEnoughUpdates is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with NotEnoughUpdates. If not, see . */ package io.github.moulberry.notenoughupdates.miscgui; import com.google.common.collect.ImmutableList; import io.github.moulberry.notenoughupdates.NEUManager; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.TooltipTextScrolling; import io.github.moulberry.notenoughupdates.core.util.ArrowPagesUtils; import io.github.moulberry.notenoughupdates.miscfeatures.AhBzKeybind; import io.github.moulberry.notenoughupdates.recipes.NeuRecipe; import io.github.moulberry.notenoughupdates.recipes.RecipeHistory; import io.github.moulberry.notenoughupdates.recipes.RecipeSlot; import io.github.moulberry.notenoughupdates.recipes.RecipeType; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; public class GuiItemRecipe extends GuiScreen { public static final ResourceLocation tabsTexture = new ResourceLocation("notenoughupdates", "textures/gui/tab.png"); public static final int SLOT_SIZE = 16; public static final int SLOT_SPACING = SLOT_SIZE + 2; public static final int TITLE_X = 28; public static final int TITLE_Y = 6; public static final int HOTBAR_SLOT_X = 8; public static final int HOTBAR_SLOT_Y = 197; public static final int PLAYER_INVENTORY_X = 8; public static final int PLAYER_INVENTORY_Y = 140; public static final int TAB_POS_X = -26; public static final int TAB_POS_Y = 8; public static final int TAB_OFFSET_Y = 30; public static final int TAB_SIZE_X = 26; public static final int TAB_SIZE_Y = 30; public static final int TAB_TEXTURE_SIZE_X = 29; private int currentIndex = 0; private int currentTab = 0; private final Map> craftingRecipes = new HashMap<>(); private final List tabs = new ArrayList<>(); private final NEUManager manager; public int guiLeft = 0; public int guiTop = 0; public int xSize = 176; public int ySize = 222; public GuiItemRecipe(List unsortedRecipes, NEUManager manager) { this.manager = manager; for (NeuRecipe recipe : unsortedRecipes) { craftingRecipes.computeIfAbsent(recipe.getType(), ignored -> new ArrayList<>()).add(recipe); if (!tabs.contains(recipe.getType())) tabs.add(recipe.getType()); } tabs.sort(Comparator.naturalOrder()); changeRecipe(0, 0); } @Override public void initGui() { this.guiLeft = (width - this.xSize) / 2; this.guiTop = (height - this.ySize) / 2; } public NeuRecipe getCurrentRecipe() { List currentRecipes = getCurrentRecipeList(); currentIndex = MathHelper.clamp_int(currentIndex, 0, currentRecipes.size() - 1); return currentRecipes.get(currentIndex); } public List getCurrentRecipeList() { return craftingRecipes.get(getCurrentTab()); } public RecipeType getCurrentTab() { currentTab = MathHelper.clamp_int(currentTab, 0, tabs.size() - 1); return tabs.get(currentTab); } public boolean isWithinRect(int x, int y, int topLeftX, int topLeftY, int width, int height) { return topLeftX <= x && x < topLeftX + width && topLeftY <= y && y < topLeftY + height; } private ImmutableList getAllRenderedSlots() { return ImmutableList.builder() .addAll(getPlayerInventory()) .addAll(getCurrentRecipe().getSlots()).build(); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { drawDefaultBackground(); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); NeuRecipe currentRecipe = getCurrentRecipe(); Minecraft.getMinecraft().getTextureManager().bindTexture(currentRecipe.getBackground()); this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, this.xSize, this.ySize); drawTabs(); currentRecipe.drawExtraBackground(this, mouseX, mouseY); List slots = getAllRenderedSlots(); for (RecipeSlot slot : slots) { Utils.drawItemStack(slot.getItemStack(), slot.getX(this), slot.getY(this), true); } int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner(); ArrowPagesUtils.onDraw(guiLeft, guiTop, topLeft, currentIndex, getCurrentRecipeList().size()); Utils.drawStringScaledMaxWidth( currentRecipe.getTitle(), guiLeft + TITLE_X, guiTop + TITLE_Y, false, xSize - 38, 0x404040 ); currentRecipe.drawExtraInfo(this, mouseX, mouseY); super.drawScreen(mouseX, mouseY, partialTicks); for (RecipeSlot slot : slots) { if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { if (slot.getItemStack() == null) continue; Utils.drawHoveringText( slot.getItemStack().getTooltip(Minecraft.getMinecraft().thePlayer, false), mouseX, mouseY, width, height, -1 ); } } currentRecipe.drawHoverInformation(this, mouseX, mouseY); drawTabHoverInformation(mouseX, mouseY); } private void drawTabHoverInformation(int mouseX, int mouseY) { if (tabs.size() < 2) return; for (int i = 0; i < tabs.size(); i++) { if (isWithinRect( mouseX - guiLeft, mouseY - guiTop, TAB_POS_X, TAB_POS_Y + TAB_OFFSET_Y * i, TAB_SIZE_X, TAB_SIZE_Y )) { RecipeType type = tabs.get(i); Utils.drawHoveringText( Arrays.asList( "" + EnumChatFormatting.RESET + EnumChatFormatting.GREEN + type.getLabel(), "" + EnumChatFormatting.RESET + EnumChatFormatting.GRAY + craftingRecipes.get(type).size() + " Recipes" ), mouseX, mouseY, width, height, -1 ); return; } } } private void drawTabs() { if (tabs.size() < 2) return; for (int i = 0; i < tabs.size(); i++) { RecipeType recipeType = tabs.get(i); int tabPosX = guiLeft + TAB_POS_X, tabPosY = guiTop + TAB_OFFSET_Y * i + TAB_POS_Y; int textureOffset = 0; if (currentTab == i) { textureOffset = 30; } Minecraft.getMinecraft().getTextureManager().bindTexture(tabsTexture); drawTexturedModalRect( tabPosX, tabPosY, 0, textureOffset, TAB_TEXTURE_SIZE_X, TAB_SIZE_Y ); Utils.drawItemStack(recipeType.getIcon(), tabPosX + 7, tabPosY + 7); } } public List getPlayerInventory() { List slots = new ArrayList<>(); ItemStack[] inventory = Minecraft.getMinecraft().thePlayer.inventory.mainInventory; int hotbarSize = InventoryPlayer.getHotbarSize(); for (int i = 0; i < inventory.length; i++) { ItemStack item = inventory[i]; if (item == null || item.stackSize == 0) continue; int row = i / hotbarSize; int col = i % hotbarSize; if (row == 0) slots.add(new RecipeSlot(HOTBAR_SLOT_X + i * SLOT_SPACING, HOTBAR_SLOT_Y + 1, item)); else slots.add(new RecipeSlot( PLAYER_INVENTORY_X + col * SLOT_SPACING, PLAYER_INVENTORY_Y + (row - 1) * SLOT_SPACING, item )); } return slots; } @Override public void handleKeyboardInput() throws IOException { super.handleKeyboardInput(); ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledResolution.getScaledWidth(); int height = scaledResolution.getScaledHeight(); int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; int keyPressed = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey(); if (Keyboard.getEventKeyState()) return; for (RecipeSlot slot : getAllRenderedSlots()) { if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { ItemStack itemStack = slot.getItemStack(); if (keyPressed == manager.keybindViewRecipe.getKeyCode()) { manager.displayGuiItemRecipeKeybind(manager.getInternalNameForItem(itemStack)); } else if (keyPressed == manager.keybindViewUsages.getKeyCode()) { manager.displayGuiItemUsagesKeybind(manager.getInternalNameForItem(itemStack)); } else if (keyPressed == NotEnoughUpdates.INSTANCE.config.misc.openAHKeybind) { AhBzKeybind.onKeyPressed(itemStack); } } } if (keyPressed == manager.keybindPreviousRecipe.getKeyCode()) { NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getPrevious(); } else if (keyPressed == manager.keybindNextRecipe.getKeyCode()) { NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getNext(); } } public void changeRecipe(int tabIndex, int recipeIndex) { buttonList.removeAll(getCurrentRecipe().getExtraButtons(this)); currentTab = tabIndex; currentIndex = recipeIndex; buttonList.addAll(getCurrentRecipe().getExtraButtons(this)); } @Override protected void actionPerformed(GuiButton p_actionPerformed_1_) { getCurrentRecipe().actionPerformed(p_actionPerformed_1_); } @Override protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { super.mouseClicked(mouseX, mouseY, mouseButton); NeuRecipe currentRecipe = getCurrentRecipe(); int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner(); if (mouseButton == 3) { NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getPrevious(); } else if (mouseButton == 4) { NotEnoughUpdates.INSTANCE.openGui = RecipeHistory.getNext(); } if (ArrowPagesUtils.onPageSwitchMouse( guiLeft, guiTop, topLeft, currentIndex, getCurrentRecipeList().size(), pageChange -> changeRecipe(currentTab, pageChange) )) return; for (int i = 0; i < tabs.size(); i++) { if (isWithinRect( mouseX - guiLeft, mouseY - guiTop, TAB_POS_X, TAB_POS_Y + TAB_OFFSET_Y * i, TAB_SIZE_X, TAB_SIZE_Y )) { changeRecipe(i, 0); Utils.playPressSound(); return; } } for (RecipeSlot slot : getAllRenderedSlots()) { if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) { ItemStack itemStack = slot.getItemStack(); if (mouseButton == 0) { manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack)); return; } else if (mouseButton == 1) { manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack)); return; } } } currentRecipe.mouseClicked(this, mouseX, mouseY, mouseButton); } @Override public void handleMouseInput() throws IOException { super.handleMouseInput(); ScaledResolution scaledResolution = Utils.peekGuiScale(); int mouseX = Mouse.getX() * scaledResolution.getScaledWidth() / Minecraft.getMinecraft().displayWidth; int mouseY = scaledResolution.getScaledHeight() - Mouse.getY() * scaledResolution.getScaledHeight() / Minecraft.getMinecraft().displayHeight - 1; getCurrentRecipe().genericMouseInput(mouseX, mouseY); // Allow Paging with Scroll-Wheel // Block scrolling while Tooltip is displayed if (TooltipTextScrolling.didRenderTooltip) return; if (Mouse.getEventDWheel() != 0) { ArrowPagesUtils.onPageSwitchScroll(currentIndex, getCurrentRecipeList().size(), pageChange -> changeRecipe(currentTab, pageChange)); } } public void arrowKeyboardInput() { ArrowPagesUtils.onPageSwitchKey(currentIndex, getCurrentRecipeList().size(), pageChange -> changeRecipe(currentTab, pageChange)); } }