package codechicken.nei.recipe; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumChatFormatting; import org.lwjgl.opengl.GL11; import codechicken.lib.gui.GuiDraw; import codechicken.nei.ItemPanels; import codechicken.nei.ItemsTooltipLineHandler; import codechicken.nei.KeyManager; import codechicken.nei.LayoutManager; import codechicken.nei.NEIClientConfig; import codechicken.nei.NEIClientUtils; import codechicken.nei.PositionedStack; import codechicken.nei.api.IOverlayHandler; import codechicken.nei.bookmark.BookmarkGrid; import codechicken.nei.bookmark.BookmarkPayload; import codechicken.nei.drawable.DrawableBuilder; import codechicken.nei.drawable.DrawableResource; import codechicken.nei.util.NEIMouseUtils; public class GuiOverlayButton extends GuiRecipeButton { protected static DrawableResource notPresent = new DrawableBuilder( "nei:textures/nei_tabbed_sprites.png", 0, 40, 8, 8).build(); protected static DrawableResource present = new DrawableBuilder("nei:textures/nei_tabbed_sprites.png", 8, 40, 8, 8) .build(); public enum ItemOverlayFormat { BACKGROUND, ICON; public static ItemOverlayFormat from(int overlay) { return overlay == 2 ? ItemOverlayFormat.BACKGROUND : ItemOverlayFormat.ICON; } } public static class ItemOverlayState { protected PositionedStack slot; protected boolean isPresent; public ItemOverlayState(PositionedStack slot, boolean isPresent) { this.slot = slot; this.isPresent = isPresent; } public boolean isPresent() { return this.isPresent; } public PositionedStack getSlot() { return this.slot; } public void draw(ItemOverlayFormat format) { if (format == ItemOverlayFormat.BACKGROUND) { NEIClientUtils.gl2DRenderContext( () -> drawRect( this.slot.relx, this.slot.rely, this.slot.width, this.slot.height, isPresent ? 0x8000AA00 : 0x80AA0000)); } else { final DrawableResource icon = isPresent ? present : notPresent; LayoutManager.drawIcon( this.slot.relx + this.slot.width - icon.width, this.slot.rely + this.slot.height - icon.height, icon); } } } protected static final DrawableResource ICON_FILL = new DrawableBuilder( "nei:textures/nei_sprites.png", 28, 76, 9, 10).build(); protected static final DrawableResource ICON_FILL_ERROR = new DrawableBuilder( "nei:textures/nei_sprites.png", 37, 76, 9, 10).build(); protected static final DrawableResource ICON_OVERLAY = new DrawableBuilder( "nei:textures/nei_sprites.png", 46, 76, 9, 10).build(); protected static final int BUTTON_ID_SHIFT = 4; public final GuiContainer firstGui; protected final List itemPresenceCache = new ArrayList<>(); protected ItemsTooltipLineHandler missedMaterialsTooltipLineHandler; protected boolean requireShiftForOverlayRecipe = true; protected boolean canUseOverlayRenderer = false; protected boolean canFillCraftingGrid = false; protected boolean hasOverlay = false; public GuiOverlayButton(GuiContainer firstGui, RecipeHandlerRef handlerRef, int x, int y) { super(handlerRef, x, y, handlerRef.recipeIndex + BUTTON_ID_SHIFT, "+"); this.firstGui = firstGui != null && firstGui.inventorySlots != null ? firstGui : null; IOverlayHandler overlayHandler = null; if (this.firstGui != null) { overlayHandler = this.handlerRef.getOverlayHandler(this.firstGui); this.canUseOverlayRenderer = this.handlerRef.getRecipeOverlayRenderer(this.firstGui) != null; this.canFillCraftingGrid = this.handlerRef.canFillCraftingGrid(this.firstGui); this.hasOverlay = this.canUseOverlayRenderer || overlayHandler != null; } setRequireShiftForOverlayRecipe( overlayHandler != null ? overlayHandler.requireShiftForOverlayRecipe() : NEIClientConfig.requireShiftForOverlayRecipe()); ingredientsOverlay(); } @Override public List handleTooltip(List currenttip) { if (!this.enabled || this.missedMaterialsTooltipLineHandler != null && this.canFillCraftingGrid) { currenttip.add(NEIClientUtils.translate("recipe.overlay") + GuiDraw.TOOLTIP_LINESPACE); } else { currenttip.add(NEIClientUtils.translate("recipe.overlay")); } if (!this.enabled) { currenttip.add(EnumChatFormatting.RED + NEIClientUtils.translate("recipe.overlay.mismatch")); } if (this.missedMaterialsTooltipLineHandler != null && this.canFillCraftingGrid) { if (!requireShiftForOverlayRecipe() || NEIClientUtils.shiftKey()) { this.missedMaterialsTooltipLineHandler.setLabelColor(EnumChatFormatting.RED); } else { this.missedMaterialsTooltipLineHandler.setLabelColor(EnumChatFormatting.GRAY); } currenttip.add(GuiDraw.TOOLTIP_HANDLER + GuiDraw.getTipLineId(this.missedMaterialsTooltipLineHandler)); } return currenttip; } @Override public Map handleHotkeys(int mousex, int mousey, Map hotkeys) { if (requireShiftForOverlayRecipe()) { if (useOverlayRenderer()) { hotkeys.put( NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB), NEIClientUtils.translate("recipe.overlay.overlayRecipe")); } if (canFillCraftingGrid()) { hotkeys.put( NEIClientUtils.getKeyName(NEIClientUtils.SHIFT_HASH, NEIMouseUtils.MOUSE_BTN_LMB), NEIClientUtils.translate("recipe.overlay.fillCraftingGrid")); } } else if (canFillCraftingGrid()) { hotkeys.put( NEIMouseUtils.getKeyName(NEIMouseUtils.MOUSE_BTN_LMB), NEIClientUtils.translate("recipe.overlay.fillCraftingGrid")); } hotkeys.put( KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH), NEIClientUtils.translate("recipe.overlay.bookmarkRecipe")); hotkeys.put( KeyManager.getKeyName("bookmark.add", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH), NEIClientUtils.translate("recipe.overlay.bookmarkRecipeAndCount")); hotkeys.put( KeyManager.getKeyName("bookmark.chat_link", NEIClientUtils.SHIFT_HASH + NEIClientUtils.CTRL_HASH), NEIClientUtils.translate("recipe.overlay.sendRecipeToChat")); return hotkeys; } @Override public void mouseReleased(int mouseX, int mouseY) { if (this.firstGui != null) { this.firstGui.mc.displayGuiScreen(this.firstGui); overlayRecipe(NEIClientUtils.shiftKey()); } } @Override protected void drawContent(Minecraft minecraft, int y, int x, boolean mouseOver) { DrawableResource icon = ICON_OVERLAY; if (this.canFillCraftingGrid && (!requireShiftForOverlayRecipe() || NEIClientUtils.shiftKey())) { icon = this.missedMaterialsTooltipLineHandler == null ? ICON_FILL : ICON_FILL_ERROR; } final int iconX = this.xPosition + (this.width - icon.width - 1) / 2; final int iconY = this.yPosition + (this.height - icon.height) / 2; GL11.glColor4f(1, 1, 1, this.enabled ? 1 : 0.5f); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); icon.draw(iconX, iconY); GL11.glDisable(GL11.GL_BLEND); GL11.glColor4f(1, 1, 1, 1); } @Override public void drawItemOverlay() { final int presenceOverlay = NEIClientConfig.itemPresenceOverlay(); if (presenceOverlay > 0) { final boolean highlightPresentItem = NEIClientConfig.isSlotHighlightPresent(); final ItemOverlayFormat format = ItemOverlayFormat.from(presenceOverlay); for (ItemOverlayState overlay : ingredientsOverlay()) { if (highlightPresentItem || !overlay.isPresent()) { overlay.draw(format); } } } } protected List ingredientsOverlay() { final List ingredients = this.handlerRef.handler .getIngredientStacks(this.handlerRef.recipeIndex); if (this.itemPresenceCache.size() != ingredients.size()) { this.itemPresenceCache.clear(); if (this.firstGui != null) { this.itemPresenceCache.addAll(this.handlerRef.getPresenceOverlay(this.firstGui)); if (this.itemPresenceCache.isEmpty()) { this.itemPresenceCache.addAll(presenceOverlay(ingredients)); } } final List items = this.itemPresenceCache.stream().filter(state -> !state.isPresent()) .map(state -> state.getSlot().item).collect(Collectors.toList()); if (!items.isEmpty()) { this.missedMaterialsTooltipLineHandler = new ItemsTooltipLineHandler( NEIClientUtils.translate("recipe.overlay.missing"), items, true, Integer.MAX_VALUE); } else { this.missedMaterialsTooltipLineHandler = null; } updateEnabled(); } return this.itemPresenceCache; } @Override public void onPermutationsChanged() { this.itemPresenceCache.clear(); } public void setRequireShiftForOverlayRecipe(boolean require) { this.requireShiftForOverlayRecipe = require; updateEnabled(); } private void updateEnabled() { this.enabled = hasOverlay() || this.canFillCraftingGrid && (this.requireShiftForOverlayRecipe || this.missedMaterialsTooltipLineHandler == null); } public void setCanUseOverlayRenderer(boolean use) { this.canUseOverlayRenderer = use; } public boolean useOverlayRenderer() { return this.canUseOverlayRenderer; } public boolean requireShiftForOverlayRecipe() { return this.requireShiftForOverlayRecipe; } public boolean canFillCraftingGrid() { return this.canFillCraftingGrid && this.missedMaterialsTooltipLineHandler == null; } public boolean hasOverlay() { return this.hasOverlay; } public Recipe getRecipe() { return Recipe.of(this.handlerRef); } protected List presenceOverlay(List ingredients) { return NEIClientUtils.presenceOverlay( ingredients, this.firstGui.inventorySlots.inventorySlots.stream() .filter( s -> s != null && s.getStack() != null && s.getStack().stackSize > 0 && s.isItemValid(s.getStack()) && s.canTakeStack(this.firstGui.mc.thePlayer)) .map(s -> s.getStack().copy()).collect(Collectors.toList())); } public void overlayRecipe(boolean shift) { if (!requireShiftForOverlayRecipe() || shift) { if (this.canFillCraftingGrid) { this.handlerRef.fillCraftingGrid(this.firstGui, 0); } } else if (hasOverlay() && useOverlayRenderer()) { this.handlerRef.useOverlayRenderer(this.firstGui); } } @Override public void lastKeyTyped(char keyChar, int keyID) { if (KeyManager.isKeyDown("bookmark.add") && NEIClientUtils.shiftKey()) { saveRecipeInBookmark(); } if (KeyManager.isKeyDown("bookmark.chat_link") && NEIClientUtils.controlKey() && NEIClientUtils.shiftKey()) { sendRecipeChatLink(); } } public void saveRecipeInBookmark() { final Recipe recipe = getRecipe(); if (!ItemPanels.bookmarkPanel.removeRecipe(recipe.getRecipeId(), BookmarkGrid.DEFAULT_GROUP_ID)) { ItemPanels.bookmarkPanel.addRecipe( recipe, NEIClientUtils.controlKey() || NEIClientConfig.getBooleanSetting("inventory.bookmarks.bookmarkRecipeWithCount") ? 1 : 0, BookmarkGrid.DEFAULT_GROUP_ID); } } private void sendRecipeChatLink() { NEIClientUtils.sendChatItemLink(BookmarkPayload.of(getRecipe()).toNBT()); } }