/* * 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.miscfeatures; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe; import io.github.moulberry.notenoughupdates.events.SlotClickEvent; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiChest; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.event.entity.player.ItemTooltipEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; import org.lwjgl.input.Keyboard; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @NEUAutoSubscribe public class EnchantingSolvers { public static SolverType currentSolver = SolverType.NONE; public enum SolverType { NONE, CHRONOMATRON, ULTRASEQUENCER, SUPERPAIRS } private static final NBTTagCompound enchTag = new NBTTagCompound() {{ setTag("ench", new NBTTagList()); }}; // Chronomatron private static boolean addToChronomatron = false; private static boolean chronomatronStartSeq = false; private static final List chronomatronOrder = new ArrayList<>(); private static int chronomatronReplayIndex = 0; private static int lastChronomatronSize = 0; private static long millisLastClick = 0; // Ultrasequencer private static class UltrasequencerItem { ItemStack stack; int containerIndex; public UltrasequencerItem(ItemStack stack, int containerIndex) { this.stack = stack; this.containerIndex = containerIndex; } } private static final Map ultraSequencerOrder = new HashMap<>(); private static int ultrasequencerReplayIndex = 0; // Superpairs private static final Map superpairStacks = new HashMap<>(); private static int lastSlotClicked = -1; private static final HashSet successfulMatches = new HashSet<>(); private static final HashSet possibleMatches = new HashSet<>(); private static final HashSet powerupMatches = new HashSet<>(); @SubscribeEvent public void onGuiOpen(GuiOpenEvent event) { chronomatronOrder.clear(); currentSolver = SolverType.NONE; if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { return; } String openChestName = Utils.getOpenChestName(); if (!openChestName.contains("Stakes")) { if (openChestName.startsWith("Chronomatron")) { currentSolver = SolverType.CHRONOMATRON; } else if (openChestName.startsWith("Ultrasequencer")) { currentSolver = SolverType.ULTRASEQUENCER; } else if (openChestName.startsWith("Superpairs")) { currentSolver = SolverType.SUPERPAIRS; } } } public static ItemStack overrideStack(IInventory inventory, int slotIndex, ItemStack stack) { if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableEnchantingSolvers) { return null; } if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { return null; } if (stack != null && stack.getDisplayName() != null) { if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) { GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; ContainerChest container = (ContainerChest) chest.inventorySlots; IInventory lower = container.getLowerChestInventory(); if (lower != inventory) { return null; } String displayName = stack.getDisplayName(); if (currentSolver == SolverType.CHRONOMATRON) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return null; } boolean yepClock = timerStack.getItem() == Items.clock; if (yepClock && (addToChronomatron && chronomatronOrder.size() >= lastChronomatronSize + 1)) { if (chronomatronReplayIndex < chronomatronOrder.size()) { String chronomatronCurrent = chronomatronOrder.get(chronomatronReplayIndex); if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass) || stack.getItem() == Item.getItemFromBlock(Blocks.stained_hardened_clay)) { long currentTime = System.currentTimeMillis(); boolean lastSame = chronomatronReplayIndex > 0 && chronomatronCurrent.equals(chronomatronOrder.get(chronomatronReplayIndex - 1)); if (chronomatronCurrent.equals(displayName)) { if (!lastSame || currentTime - millisLastClick > 300) { ItemStack retStack = new ItemStack( Item.getItemFromBlock(Blocks.stained_hardened_clay), 1, stack.getItemDamage() ); retStack.setTagCompound(enchTag); retStack.setStackDisplayName(stack.getDisplayName()); return retStack; } else { ItemStack retStack = new ItemStack( Item.getItemFromBlock(Blocks.stained_glass), 1, stack.getItemDamage() ); retStack.setStackDisplayName(stack.getDisplayName()); return retStack; } } else { if (chronomatronReplayIndex + 1 < chronomatronOrder.size() && NotEnoughUpdates.INSTANCE.config.enchantingSolvers.showNextClick) { String chronomatronNext = chronomatronOrder.get(chronomatronReplayIndex + 1); if (chronomatronNext.equals(displayName)) { ItemStack retStack = new ItemStack( Item.getItemFromBlock(Blocks.stained_glass), 1, stack.getItemDamage() ); retStack.setStackDisplayName(stack.getDisplayName()); return retStack; } } ItemStack retStack = new ItemStack(Item.getItemFromBlock(Blocks.stained_glass), 1, 8); retStack.setStackDisplayName(stack.getDisplayName()); return retStack; } } } } } else if (currentSolver == SolverType.ULTRASEQUENCER) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return null; } boolean yepClock = timerStack.getItem() == Items.clock; if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) && stack.getItemDamage() != 15) { if (yepClock) { for (int solveIndex : ultraSequencerOrder.keySet()) { UltrasequencerItem item = ultraSequencerOrder.get(solveIndex); if (item.containerIndex == slotIndex) { ItemStack newStack = item.stack; if (solveIndex == ultrasequencerReplayIndex) { newStack.setTagCompound(enchTag); } else { newStack.setTagCompound(null); } return newStack; } } ItemStack retStack = new ItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), 1, 15); retStack.setStackDisplayName(stack.getDisplayName()); return retStack; } } } else if (currentSolver == SolverType.SUPERPAIRS) { if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass) && superpairStacks.containsKey(slotIndex)) { return superpairStacks.get(slotIndex); } } } } return null; } public static boolean onStackRender(ItemStack stack, IInventory inventory, int slotIndex, int x, int y) { if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableEnchantingSolvers) { return false; } if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { return false; } if (stack != null && stack.getDisplayName() != null) { if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) { GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; ContainerChest container = (ContainerChest) chest.inventorySlots; IInventory lower = container.getLowerChestInventory(); if (lower != inventory) { return false; } if (currentSolver == SolverType.ULTRASEQUENCER) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return false; } boolean yepClock = timerStack.getItem() == Items.clock; if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) && stack.getItemDamage() != 15) { if (yepClock) { for (int solveIndex : ultraSequencerOrder.keySet()) { UltrasequencerItem item = ultraSequencerOrder.get(solveIndex); if (item.containerIndex == slotIndex) { int meta = 0; if (solveIndex == ultrasequencerReplayIndex) { meta = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.seqNext; } else if (solveIndex == ultrasequencerReplayIndex + 1) { meta = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.seqUpcoming; } if (meta > 0) { Utils.drawItemStack( new ItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), 1, meta - 1), x, y ); } if (NotEnoughUpdates.INSTANCE.config.enchantingSolvers.seqNumbers && solveIndex >= ultrasequencerReplayIndex) { int w = Minecraft.getMinecraft().fontRendererObj.getStringWidth((solveIndex + 1) + ""); GlStateManager.disableDepth(); GlStateManager.enableBlend(); GlStateManager.disableLighting(); Utils.drawStringScaled((solveIndex + 1) + "", x + 8.5f - w / 2f, y + 8.5f - 4, true, 0xffc0c0c0, 1f ); return true; } } } } } } else if (currentSolver == SolverType.SUPERPAIRS) { int meta = 0; if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass) && superpairStacks.containsKey(slotIndex)) { if (possibleMatches.contains(slotIndex)) { meta = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.supPossible; } else { meta = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.supUnmatched; } } else { if (powerupMatches.contains(slotIndex)) { meta = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.supPower; } else if (successfulMatches.contains(slotIndex)) { meta = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.supMatched; } } if (meta > 0) { Utils.drawItemStack(new ItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), 1, meta - 1), x, y); } } } } return false; } @SubscribeEvent public void onStackClick(SlotClickEvent event) { if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableEnchantingSolvers || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { return; } ItemStack stack = event.slot.getStack(); if (stack == null || stack.getDisplayName() == null) { return; } String displayName = stack.getDisplayName(); if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) { return; } GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; ContainerChest container = (ContainerChest) chest.inventorySlots; IInventory lower = container.getLowerChestInventory(); if (currentSolver == SolverType.CHRONOMATRON) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return; } boolean yepClock = timerStack.getItem() == Items.clock; if (timerStack.getItem() == Item.getItemFromBlock(Blocks.glowstone) || (yepClock && (!addToChronomatron || chronomatronOrder.size() < lastChronomatronSize + 1))) { event.setCanceled(true); return; } if (yepClock) { long currentTime = System.currentTimeMillis(); if (currentTime - millisLastClick < 150) { event.setCanceled(true); return; } if (chronomatronReplayIndex < chronomatronOrder.size()) { String chronomatronCurrent = chronomatronOrder.get(chronomatronReplayIndex); if ((!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.preventMisclicks1 || chronomatronCurrent.equals(displayName) || Keyboard.getEventKey() == Keyboard.KEY_LSHIFT) && stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane) && event.slotId != 4 && event.slotId != 49) { chronomatronReplayIndex++; millisLastClick = currentTime; event.usePickblockInstead(); return; } } event.setCanceled(true); return; } } if (currentSolver == SolverType.ULTRASEQUENCER) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return; } boolean yepClock = timerStack.getItem() == Items.clock; if (yepClock) { UltrasequencerItem current = ultraSequencerOrder.get(ultrasequencerReplayIndex); long currentTime = System.currentTimeMillis(); if (current == null) { event.setCanceled(true); return; } if (currentTime - millisLastClick > 150 && (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.preventMisclicks1 || current.containerIndex == event.slotId || Keyboard.getEventKey() == Keyboard.KEY_LSHIFT) && (event.slotId < 45 && event.slotId > 8)) { ultrasequencerReplayIndex++; millisLastClick = currentTime; event.usePickblockInstead(); return; } } event.setCanceled(true); } else if (currentSolver == SolverType.SUPERPAIRS) { lastSlotClicked = event.slotId; } } public static void processInventoryContents(boolean fromTick) { if (currentSolver != SolverType.CHRONOMATRON && !fromTick) return; if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableEnchantingSolvers) { return; } if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { return; } if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) { GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen; ContainerChest container = (ContainerChest) chest.inventorySlots; IInventory lower = container.getLowerChestInventory(); if (currentSolver == SolverType.CHRONOMATRON) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return; } String stainedHardenedClayName = null; for (int index = 0; index < lower.getSizeInventory(); index++) { ItemStack stack = lower.getStackInSlot(index); if (stack != null && stack.getItem() == Item.getItemFromBlock(Blocks.stained_hardened_clay)) { if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("ench")) { if (stainedHardenedClayName != null && !stack.getDisplayName().equals(stainedHardenedClayName)) { return; } stainedHardenedClayName = stack.getDisplayName(); } } } boolean yepClock = timerStack.getItem() == Items.clock; if (timerStack.getItem() == Item.getItemFromBlock(Blocks.glowstone) || (yepClock && (!addToChronomatron || chronomatronOrder.size() < lastChronomatronSize + 1))) { if (chronomatronStartSeq) { chronomatronStartSeq = false; addToChronomatron = false; lastChronomatronSize = chronomatronOrder.size(); chronomatronOrder.clear(); } if (stainedHardenedClayName != null) { if (addToChronomatron) { chronomatronOrder.add(stainedHardenedClayName); } addToChronomatron = false; } else { addToChronomatron = true; chronomatronReplayIndex = 0; } } else if (yepClock) { chronomatronStartSeq = true; } } else { chronomatronStartSeq = true; addToChronomatron = true; } if (currentSolver == SolverType.ULTRASEQUENCER) { ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5); if (timerStack == null) { return; } if (timerStack.getItem() == Item.getItemFromBlock(Blocks.glowstone)) { ultrasequencerReplayIndex = 0; } for (int index = 0; index < lower.getSizeInventory(); index++) { ItemStack stack = lower.getStackInSlot(index); if (stack != null && stack.getItem() == Items.dye) { if (ultraSequencerOrder.containsKey(stack.stackSize - 1)) { UltrasequencerItem ultrasequencerItem = ultraSequencerOrder.get(stack.stackSize - 1); ultrasequencerItem.containerIndex = index; ultrasequencerItem.stack = stack; } else { ultraSequencerOrder.put(stack.stackSize - 1, new UltrasequencerItem(stack, index)); } } } } else { ultraSequencerOrder.clear(); } if (currentSolver == SolverType.SUPERPAIRS) { successfulMatches.clear(); possibleMatches.clear(); powerupMatches.clear(); out: for (int index = 0; index < lower.getSizeInventory(); index++) { ItemStack stack = lower.getStackInSlot(index); if (stack == null) continue; if (stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass) && stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane)) { superpairStacks.put(index, stack); NBTTagCompound tag = stack.getTagCompound(); if (tag != null) { NBTTagCompound display = tag.getCompoundTag("display"); if (display.hasKey("Lore", 9)) { NBTTagList list = display.getTagList("Lore", 8); for (int i = 0; i < list.tagCount(); i++) { if (list.getStringTagAt(i).toLowerCase(Locale.ROOT).contains("powerup")) { powerupMatches.add(index); continue out; } } } } int numMatches = 0; for (int index2 = 0; index2 < lower.getSizeInventory(); index2++) { ItemStack stack2 = lower.getStackInSlot(index2); if (stack2 != null && stack2.getDisplayName().equals(stack.getDisplayName()) && stack.getItem() == stack2.getItem() && stack.getItemDamage() == stack2.getItemDamage()) { numMatches++; } } boolean oddMatches = (numMatches % 2) == 1; if ((!oddMatches || index != lastSlotClicked) && !successfulMatches.contains(index)) { for (int index2 = 0; index2 < lower.getSizeInventory(); index2++) { if (index == index2) continue; if (oddMatches && index2 == lastSlotClicked) continue; ItemStack stack2 = lower.getStackInSlot(index2); if (stack2 != null && stack2.getDisplayName().equals(stack.getDisplayName()) && stack.getItem() == stack2.getItem() && stack.getItemDamage() == stack2.getItemDamage()) { successfulMatches.add(index); successfulMatches.add(index2); } } } } else { if (superpairStacks.containsKey(index) && superpairStacks.get(index) != null && !possibleMatches.contains(index)) { ItemStack stack1 = superpairStacks.get(index); for (int index2 = 0; index2 < lower.getSizeInventory(); index2++) { if (index == index2) continue; if (superpairStacks.containsKey(index2) && superpairStacks.get(index2) != null) { ItemStack stack2 = superpairStacks.get(index2); if (stack1.getDisplayName().equals(stack2.getDisplayName()) && stack1.getItem() == stack2.getItem() && stack1.getItemDamage() == stack2.getItemDamage()) { possibleMatches.add(index); possibleMatches.add(index2); } } } } } } } else { superpairStacks.clear(); successfulMatches.clear(); powerupMatches.clear(); lastSlotClicked = -1; } } } @SubscribeEvent public void onItemTooltip(ItemTooltipEvent event) { if (NotEnoughUpdates.INSTANCE.config.enchantingSolvers.hideTooltips && (currentSolver == SolverType.CHRONOMATRON || currentSolver == SolverType.ULTRASEQUENCER)) { String internal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack); if (internal == null && event.toolTip.size() > 0 && !event.toolTip .get(0) .trim() .replaceAll("\\(#.+\\)$", "") .trim() .contains(" ")) { event.toolTip.clear(); } } } @SubscribeEvent public void onTick(TickEvent.ClientTickEvent event) { if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) { currentSolver = SolverType.NONE; } if (event.phase != TickEvent.Phase.END) { return; } processInventoryContents(true); } public static boolean disableButtons() { return currentSolver != SolverType.NONE && NotEnoughUpdates.INSTANCE.config.enchantingSolvers.hideButtons; } }