aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLulonaut <lulonaut@tutanota.de>2023-03-12 00:54:04 +0100
committerGitHub <noreply@github.com>2023-03-12 10:54:04 +1100
commit193ba468e43bd4db5b5534d17472078708783349 (patch)
tree43532db60d853628242842763c1bf39ccb9d11d7
parent5f147d6adbe9898239a0cb86e4daaa74c9e4c08a (diff)
downloadNotEnoughUpdates-193ba468e43bd4db5b5534d17472078708783349.tar.gz
NotEnoughUpdates-193ba468e43bd4db5b5534d17472078708783349.tar.bz2
NotEnoughUpdates-193ba468e43bd4db5b5534d17472078708783349.zip
cheapest museum item to donate (#522)
Co-authored-by: nea <romangraef@gmail.com> Co-authored-by: nea <nea@nea.moe> Co-authored-by: Roman / Linnea Gräf <roman.graef@gmail.com> Co-authored-by: nopo <nopotheemail@gmail.com> Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java18
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java365
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneFavourites.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java16
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java72
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java16
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java47
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java25
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/events/ButtonExclusionZoneEvent.kt69
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt574
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt75
-rw-r--r--src/test/kotlin/io/github/moulberry/notenoughupdates/util/RectangleTest.kt49
17 files changed, 1026 insertions, 362 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index 7f0136ee..8b6c2255 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -43,6 +43,8 @@ import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBlockSounds;
+import io.github.moulberry.notenoughupdates.miscfeatures.inventory.MuseumCheapestItemOverlay;
+import io.github.moulberry.notenoughupdates.miscfeatures.inventory.MuseumItemHighlighter;
import io.github.moulberry.notenoughupdates.miscfeatures.updater.AutoUpdater;
import io.github.moulberry.notenoughupdates.mixins.AccessorMinecraft;
import io.github.moulberry.notenoughupdates.oneconfig.IOneConfigCompat;
@@ -168,6 +170,13 @@ public class NotEnoughUpdates {
private File neuDir;
private boolean hasSkyblockScoreboard;
+ public NotEnoughUpdates() {
+ // Budget Construction Event
+ ((AccessorMinecraft) FMLClientHandler.instance().getClient())
+ .onGetDefaultResourcePacks()
+ .add(new NEURepoResourcePack(null, "neurepo"));
+ }
+
public File getConfigFile() {
return this.configFile;
}
@@ -180,13 +189,6 @@ public class NotEnoughUpdates {
return this.neuDir;
}
- public NotEnoughUpdates() {
- // Budget Construction Event
- ((AccessorMinecraft) FMLClientHandler.instance().getClient())
- .onGetDefaultResourcePacks()
- .add(new NEURepoResourcePack(null, "neurepo"));
- }
-
/**
* Instantiates NEUIo, NEUManager and NEUOverlay instances. Registers keybinds and adds a shutdown hook to clear tmp folder.
*/
@@ -270,6 +272,8 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(navigation);
MinecraftForge.EVENT_BUS.register(new WorldListener(this));
AutoLoad.INSTANCE.provide(supplier -> MinecraftForge.EVENT_BUS.register(supplier.get()));
+ MinecraftForge.EVENT_BUS.register(MuseumItemHighlighter.INSTANCE);
+ MinecraftForge.EVENT_BUS.register(MuseumCheapestItemOverlay.INSTANCE);
if (Minecraft.getMinecraft().getResourceManager() instanceof IReloadableResourceManager) {
IReloadableResourceManager manager = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
index 03f3a449..5e39aa45 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
@@ -28,12 +28,11 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.auction.CustomAHGui;
import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
import io.github.moulberry.notenoughupdates.dungeons.DungeonWin;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.miscfeatures.AbiphoneWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.AuctionBINWarning;
-import io.github.moulberry.notenoughupdates.miscfeatures.AuctionProfit;
import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
-import io.github.moulberry.notenoughupdates.miscfeatures.DungeonNpcProfitOverlay;
import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
import io.github.moulberry.notenoughupdates.miscfeatures.PresetWarning;
import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
@@ -45,20 +44,18 @@ import io.github.moulberry.notenoughupdates.miscgui.GuiInvButtonEditor;
import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay;
import io.github.moulberry.notenoughupdates.miscgui.TradeWindow;
-import io.github.moulberry.notenoughupdates.miscgui.TrophyRewardOverlay;
import io.github.moulberry.notenoughupdates.miscgui.hex.GuiCustomHex;
-import io.github.moulberry.notenoughupdates.miscgui.minionhelper.MinionHelperManager;
import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
import io.github.moulberry.notenoughupdates.overlays.AuctionSearchOverlay;
import io.github.moulberry.notenoughupdates.overlays.BazaarSearchOverlay;
-import io.github.moulberry.notenoughupdates.overlays.EquipmentOverlay;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
import io.github.moulberry.notenoughupdates.overlays.RancherBootOverlay;
import io.github.moulberry.notenoughupdates.overlays.TextOverlay;
import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import io.github.moulberry.notenoughupdates.util.ItemUtils;
import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
@@ -105,6 +102,7 @@ import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -484,96 +482,68 @@ public class RenderListener {
if (CalendarOverlay.isEnabled() || event.isCanceled()) return;
if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && NotificationHandler.shouldRenderOverlay(event.gui) &&
event.gui instanceof GuiContainer) {
- doInventoryButtons = true;
-
- int zOffset = 50;
-
- GlStateManager.translate(0, 0, zOffset);
-
- int xSize = ((AccessorGuiContainer) event.gui).getXSize();
- int ySize = ((AccessorGuiContainer) event.gui).getYSize();
- int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
- int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
+ renderButtons((GuiContainer) event.gui);
+ }
+ }
- if (!NEUApi.disableInventoryButtons) {
- if (!EnchantingSolvers.disableButtons()) {
- for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
- if (!button.isActive()) continue;
- if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
+ public void iterateButtons(GuiContainer gui, BiConsumer<NEUConfig.InventoryButton, Rectangle> acceptButton) {
+ if (NEUApi.disableInventoryButtons || EnchantingSolvers.disableButtons()) {
+ return;
+ }
- int x = guiLeft + button.x;
- int y = guiTop + button.y;
- if (button.anchorRight) {
- x += xSize;
- }
- if (button.anchorBottom) {
- y += ySize;
- }
- if (AccessoryBagOverlay.isInAccessoryBag()) {
- if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
- x += 80 + 28;
- }
- }
- if (TrophyRewardOverlay.inTrophyFishingInventory()) {
- int diffX = 162;
- if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 120) {
- x += diffX;
- }
- }
- if (MinionHelperManager.getInstance().inCraftedMinionsInventory()) {
- int diffX = 172;
- if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 128) {
- x += diffX;
- }
- }
- if (AuctionProfit.inAuctionPage()) {
- if (x + 18 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
- y < guiTop + 56) {
- x -= 68 - 200;
- }
- }
- if (EquipmentOverlay.isRenderingArmorHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
- x -= 25;
- }
- }
- if (EquipmentOverlay.isRenderingPetHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
- x -= 25;
- }
- }
- if (inDungeonPage || DungeonNpcProfitOverlay.isRendering()) {
- if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
- y < guiTop + 100) {
- x += 185;
- }
- }
+ AccessorGuiContainer accessor = (AccessorGuiContainer) gui;
+ Rectangle guiRectangle = new Rectangle(
+ accessor.getGuiLeft(),
+ accessor.getGuiTop(),
+ accessor.getXSize(),
+ accessor.getYSize()
+ );
+
+ ButtonExclusionZoneEvent buttonExclusionZoneEvent = new ButtonExclusionZoneEvent(gui, guiRectangle);
+ buttonExclusionZoneEvent.post();
+ for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
+ if (!button.isActive()) continue;
+ if (button.playerInvOnly && !(gui instanceof GuiInventory)) continue;
+
+ Rectangle buttonPosition = buttonExclusionZoneEvent.findButtonPosition(new Rectangle(
+ accessor.getGuiLeft() + button.x + (button.anchorRight ? accessor.getXSize() : 0),
+ accessor.getGuiTop() + button.y + (button.anchorBottom ? accessor.getYSize() : 0),
+ 18, 18
+ )
+ );
+ acceptButton.accept(button, buttonPosition);
+ }
+ }
- GlStateManager.color(1, 1, 1, 1f);
-
- GlStateManager.enableDepth();
- GlStateManager.enableAlpha();
- Minecraft.getMinecraft().getTextureManager().bindTexture(EDITOR);
- Utils.drawTexturedRect(
- x,
- y,
- 18,
- 18,
- button.backgroundIndex * 18 / 256f,
- (button.backgroundIndex * 18 + 18) / 256f,
- 18 / 256f,
- 36 / 256f,
- GL11.GL_NEAREST
- );
+ public void renderButtons(GuiContainer gui) {
+ doInventoryButtons = true;
- if (button.icon != null && !button.icon.trim().isEmpty()) {
- GuiInvButtonEditor.renderIcon(button.icon, x + 1, y + 1);
- }
- }
- }
+ int zOffset = 50;
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, 0, zOffset);
+ iterateButtons(gui, (button, buttonPosition) -> {
+ GlStateManager.color(1, 1, 1, 1f);
+ GlStateManager.enableDepth();
+ GlStateManager.enableAlpha();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(EDITOR);
+ Utils.drawTexturedRect(
+ buttonPosition.getX(),
+ buttonPosition.getY(),
+ 18,
+ 18,
+ button.backgroundIndex * 18 / 256f,
+ (button.backgroundIndex * 18 + 18) / 256f,
+ 18 / 256f,
+ 36 / 256f,
+ GL11.GL_NEAREST
+ );
+
+ if (button.icon != null && !button.icon.trim().isEmpty()) {
+ GuiInvButtonEditor.renderIcon(button.icon, buttonPosition.getX() + 1, buttonPosition.getY() + 1);
}
- GlStateManager.translate(0, 0, -zOffset);
- }
+ });
+ GlStateManager.popMatrix();
}
/**
@@ -620,104 +590,50 @@ public class RenderListener {
}
}
- boolean hoveringButton = false;
+ final boolean[] hoveringButton = {false};
if (!doInventoryButtons) return;
if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && NotificationHandler.shouldRenderOverlay(event.gui) &&
event.gui instanceof GuiContainer) {
- int xSize = ((AccessorGuiContainer) event.gui).getXSize();
- int ySize = ((AccessorGuiContainer) event.gui).getYSize();
- int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
- int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
-
- if (!NEUApi.disableInventoryButtons) {
- if (!EnchantingSolvers.disableButtons()) {
- for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
- if (!button.isActive()) continue;
- if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
-
- int x = guiLeft + button.x;
- int y = guiTop + button.y;
- if (button.anchorRight) {
- x += xSize;
- }
- if (button.anchorBottom) {
- y += ySize;
- }
- if (AccessoryBagOverlay.isInAccessoryBag()) {
- if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
- x += 80 + 28;
- }
- }
- if (TrophyRewardOverlay.inTrophyFishingInventory()) {
- int diffX = 162;
- if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 120) {
- x += diffX;
- }
- }
- if (MinionHelperManager.getInstance().inCraftedMinionsInventory()) {
- int diffX = 172;
- if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 128) {
- x += diffX;
- }
- }
- if (AuctionProfit.inAuctionPage()) {
- if (x + 18 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
- y < guiTop + 56) {
- x -= 68 - 200;
- }
- }
- if (EquipmentOverlay.isRenderingArmorHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
- x -= 25;
- }
- }
- if (EquipmentOverlay.isRenderingPetHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
- x -= 25;
- }
- }
+ AccessorGuiContainer acc = (AccessorGuiContainer) event.gui;
+ Rectangle mousePosition = new Rectangle(event.mouseX, event.mouseY, 0, 0);
+ Rectangle craftingTextRectangle = new Rectangle(acc.getGuiLeft() + 85, acc.getGuiTop() + 4, 30, 21);
+ iterateButtons((GuiContainer) guiScreen, (button, buttonPosition) -> {
- if (inDungeonPage || DungeonNpcProfitOverlay.isRendering()) {
- if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
- y < guiTop + 100) {
- x += 185;
- }
- }
+ if (buttonPosition.intersects(craftingTextRectangle)) {
+ disableCraftingText = true;
+ }
- if (x - guiLeft >= 85 && x - guiLeft <= 115 && y - guiTop >= 4 && y - guiTop <= 25) {
- disableCraftingText = true;
- }
+ if (!buttonPosition.intersects(mousePosition)) {
+ return;
+ }
+ hoveringButton[0] = true;
+ long currentTime = System.currentTimeMillis();
- if (event.mouseX >= x && event.mouseX <= x + 18 && event.mouseY >= y && event.mouseY <= y + 18) {
- hoveringButton = true;
- long currentTime = System.currentTimeMillis();
+ if (buttonHovered != button) {
+ buttonHoveredMillis = currentTime;
+ buttonHovered = button;
+ }
- if (buttonHovered != button) {
- buttonHoveredMillis = currentTime;
- buttonHovered = button;
- }
+ if (currentTime - buttonHoveredMillis <= NotEnoughUpdates.INSTANCE.config.inventoryButtons.tooltipDelay) {
+ return;
+ }
+ String command = button.command.trim();
+ if (!command.startsWith("/")) {
+ command = "/" + command;
+ }
- if (currentTime - buttonHoveredMillis > NotEnoughUpdates.INSTANCE.config.inventoryButtons.tooltipDelay) {
- String command = button.command.trim();
- if (!command.startsWith("/")) {
- command = "/" + command;
- }
+ Utils.drawHoveringText(
+ Lists.newArrayList("\u00a77" + command),
+ event.mouseX,
+ event.mouseY,
+ event.gui.width,
+ event.gui.height,
+ -1
+ );
- Utils.drawHoveringText(
- Lists.newArrayList("\u00a77" + command),
- event.mouseX,
- event.mouseY,
- event.gui.width,
- event.gui.height,
- -1
- );
- }
- }
- }
- }
- }
+ });
}
- if (!hoveringButton) buttonHovered = null;
+ if (!hoveringButton[0]) buttonHovered = null;
if (AuctionBINWarning.getInstance().shouldShow()) {
AuctionBINWarning.getInstance().render();
@@ -1121,85 +1037,28 @@ public class RenderListener {
if (!doInventoryButtons) return;
if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && NotificationHandler.shouldRenderOverlay(event.gui) &&
Mouse.getEventButton() >= 0 && event.gui instanceof GuiContainer) {
- int xSize = ((AccessorGuiContainer) event.gui).getXSize();
- int ySize = ((AccessorGuiContainer) event.gui).getYSize();
- int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
- int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
- if (!NEUApi.disableInventoryButtons) {
- if (!EnchantingSolvers.disableButtons()) {
- for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
- if (!button.isActive()) continue;
- if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
-
- int x = guiLeft + button.x;
- int y = guiTop + button.y;
- if (button.anchorRight) {
- x += xSize;
- }
- if (button.anchorBottom) {
- y += ySize;
- }
- if (AccessoryBagOverlay.isInAccessoryBag()) {
- if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
- x += 80 + 28;
- }
- }
- if (TrophyRewardOverlay.inTrophyFishingInventory()) {
- int diffX = 162;
- if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 120) {
- x += diffX;
- }
- }
- if (MinionHelperManager.getInstance().inCraftedMinionsInventory()) {
- int diffX = 172;
- if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 128) {
- x += diffX;
- }
- }
- if (AuctionProfit.inAuctionPage()) {
- if (x + 18 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
- y < guiTop + 56) {
- x -= 68 - 200;
- }
- }
- if (EquipmentOverlay.isRenderingArmorHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
- x -= 25;
- }
+ Rectangle mouseRect = new Rectangle(mouseX, mouseY, 0, 0);
+ iterateButtons((GuiContainer) event.gui, (button, buttonPositon) -> {
+ if (!buttonPositon.intersects(mouseRect)) {
+ return;
+ }
+ if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
+ int clickType = NotEnoughUpdates.INSTANCE.config.inventoryButtons.clickType;
+ if ((clickType == 0 && Mouse.getEventButtonState()) ||
+ (clickType == 1 && !Mouse.getEventButtonState())) {
+ String command = button.command.trim();
+ if (!command.startsWith("/")) {
+ command = "/" + command;
}
- if (EquipmentOverlay.isRenderingPetHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
- x -= 25;
- }
- }
- if (inDungeonPage || DungeonNpcProfitOverlay.isRendering()) {
- if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
- y < guiTop + 100) {
- x += 185;
- }
- }
-
- if (mouseX >= x && mouseX <= x + 18 && mouseY >= y && mouseY <= y + 18) {
- if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
- int clickType = NotEnoughUpdates.INSTANCE.config.inventoryButtons.clickType;
- if ((clickType == 0 && Mouse.getEventButtonState()) ||
- (clickType == 1 && !Mouse.getEventButtonState())) {
- String command = button.command.trim();
- if (!command.startsWith("/")) {
- command = "/" + command;
- }
- if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command) == 0) {
- NotEnoughUpdates.INSTANCE.sendChatMessage(command);
- }
- }
- } else {
- event.setCanceled(true);
- }
- return;
+ if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command) == 0) {
+ NotEnoughUpdates.INSTANCE.sendChatMessage(command);
}
}
+ } else {
+ event.setCanceled(true);
}
- }
+
+ });
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneFavourites.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneFavourites.java
index 3366fd1e..750e674d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneFavourites.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneFavourites.java
@@ -24,6 +24,7 @@ import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.core.config.KeybindHelper;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.events.GuiContainerBackgroundDrawnEvent;
import io.github.moulberry.notenoughupdates.events.ReplaceItemEvent;
import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
@@ -202,10 +203,11 @@ public class AbiphoneFavourites {
return isAbiphoneShowOnlyFavourites() && !getFavouriteContacts().contains(name);
}
- public void onDrawBackground(GuiScreen screen) {
+ @SubscribeEvent
+ public void onDrawBackground(GuiContainerBackgroundDrawnEvent event) {
if (isWrongInventory()) return;
- GuiContainer container = (GuiContainer) screen;
+ GuiContainer container = event.getContainer();
for (Slot slot : container.inventorySlots.inventorySlots) {
if (slot == null) continue;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java
index c0e40ec9..c761f847 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java
@@ -22,7 +22,9 @@ package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -47,6 +49,20 @@ public class AuctionProfit {
new ResourceLocation("notenoughupdates:auction_profit.png");
@SubscribeEvent
+ public void onButtonExclusionZones(ButtonExclusionZoneEvent event) {
+ if (inAuctionPage()) {
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight(),
+ event.getGuiBaseRect().getTop(),
+ 128 /*width*/ + 4 /*space*/, 56
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_RIGHT
+ );
+ }
+ }
+
+ @SubscribeEvent
public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
if (!inAuctionPage()) return;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java
index c4b03b84..c06563c2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DungeonNpcProfitOverlay.java
@@ -24,8 +24,10 @@ import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
@@ -100,6 +102,19 @@ public class DungeonNpcProfitOverlay {
}
@SubscribeEvent
+ public void onButtonExclusionZones(ButtonExclusionZoneEvent event) {
+ if (isRendering())
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight(),
+ event.getGuiBaseRect().getTop(),
+ 180 /*width*/ + 4 /*space*/, 101
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_RIGHT
+ );
+ }
+
+ @SubscribeEvent
public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
if (!NotEnoughUpdates.INSTANCE.config.dungeons.croesusProfitOverlay || !(event.gui instanceof GuiChest)) {
chestProfits = null;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java
index 562eb1e0..908ae307 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java
@@ -25,9 +25,11 @@ import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.auction.APIManager;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.listener.RenderListener;
import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -45,6 +47,7 @@ import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
@@ -73,6 +76,22 @@ public class AccessoryBagOverlay {
private static final int TAB_MISSING = 4;
private static final int TAB_OPTIMIZER = 5;
+ public static final AccessoryBagOverlay INSTANCE = new AccessoryBagOverlay();
+
+ @SubscribeEvent
+ public void onButtonExclusionZones(ButtonExclusionZoneEvent event) {
+ if (isInAccessoryBag()) {
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight(),
+ event.getGuiBaseRect().getTop(),
+ 80 /*pane*/ + 24 /*tabs*/ + 4 /*space*/, 150
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_RIGHT
+ );
+ }
+ }
+
private static final ItemStack[] TAB_STACKS = new ItemStack[]{
Utils.createItemStack(Items.dye, EnumChatFormatting.DARK_AQUA + "Basic Information",
10, EnumChatFormatting.GREEN + "- Talis count by rarity"
@@ -475,15 +494,9 @@ public class AccessoryBagOverlay {
int yIndex = 0;
long currentTime = System.currentTimeMillis();
- int marqueeOffset = (int) (currentTime / 500 % 100);
for (ItemStack missingStack : missing) {
String s = missingStack.getDisplayName();
- //int marueeOffset
- //if(s.length()) {
-
- //}
-
s = Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(s, 70);
String clean = StringUtils.cleanColourNotModifiers(s);
@@ -844,51 +857,8 @@ public class AccessoryBagOverlay {
}
}
- /*private static void renderAlignedString(String first, String second, float x, float y, int length) {
- FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj;
-
- if(fontRendererObj.getStringWidth(first + " " + second) >= length) {
- for(int xOff=-2; xOff<=2; xOff++) {
- for(int yOff=-2; yOff<=2; yOff++) {
- if(Math.abs(xOff) != Math.abs(yOff)) {
- Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(first + " " + second), Minecraft.getMinecraft().fontRendererObj,
- x+length/2f+xOff/2f, y+4+yOff/2f, false, length,
- new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB());
- }
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawStringCenteredScaledMaxWidth(first + " " + second, Minecraft.getMinecraft().fontRendererObj,
- x+length/2f, y+4, false, length, 4210752);
- } else {
- for(int xOff=-2; xOff<=2; xOff++) {
- for(int yOff=-2; yOff<=2; yOff++) {
- if(Math.abs(xOff) != Math.abs(yOff)) {
- fontRendererObj.drawString(Utils.cleanColourNotModifiers(first),
- x+xOff/2f, y+yOff/2f,
- new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB(), false);
- }
- }
- }
-
- int secondLen = fontRendererObj.getStringWidth(second);
- GlStateManager.color(1, 1, 1, 1);
- fontRendererObj.drawString(first, x, y, 4210752, false);
- for(int xOff=-2; xOff<=2; xOff++) {
- for(int yOff=-2; yOff<=2; yOff++) {
- if(Math.abs(xOff) != Math.abs(yOff)) {
- fontRendererObj.drawString(Utils.cleanColourNotModifiers(second),
- x+length-secondLen+xOff/2f, y+yOff/2f,
- new Color(0, 0, 0, 200/Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB(), false);
- }
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- fontRendererObj.drawString(second, x+length-secondLen, y, 4210752, false);
- }
- }*/
+
+
private static final HashMap<String, Pattern> STAT_PATTERN_MAP_BONUS = new HashMap<String, Pattern>() {{
String STAT_PATTERN_BONUS_END = ": (?:\\+|-)[0-9]+(?:\\.[0-9]+)?\\%? \\(((?:\\+|-)[0-9]+)%?";
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java
index e13934e1..e8653d53 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java
@@ -23,9 +23,11 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent;
import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -97,6 +99,21 @@ public class TrophyRewardOverlay {
return line.get(1);
}
+ @SubscribeEvent
+ public void onButtonExclusionZones(ButtonExclusionZoneEvent event) {
+ if (inTrophyFishingInventory()) {
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight(),
+ event.getGuiBaseRect().getTop(),
+ 168 /*width*/ + 4 /*space*/,
+ 128
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_RIGHT
+ );
+ }
+ }
+
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
if (!inTrophyFishingInventory()) return;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java
index 1a625794..93a39ec0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/render/MinionHelperOverlay.java
@@ -24,6 +24,7 @@ import com.google.common.collect.Lists;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.ArrowPagesUtils;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.miscgui.TrophyRewardOverlay;
import io.github.moulberry.notenoughupdates.miscgui.minionhelper.Minion;
import io.github.moulberry.notenoughupdates.miscgui.minionhelper.MinionHelperManager;
@@ -34,6 +35,7 @@ import io.github.moulberry.notenoughupdates.miscgui.minionhelper.sources.NpcSour
import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.ItemUtils;
import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -94,6 +96,20 @@ public class MinionHelperOverlay {
}
@SubscribeEvent
+ public void onButtonExclusionZones(ButtonExclusionZoneEvent event) {
+ if (manager.inCraftedMinionsInventory() && NotEnoughUpdates.INSTANCE.config.minionHelper.gui) {
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight(),
+ event.getGuiBaseRect().getTop(),
+ 168 /*width*/ + 4 /*space*/, 128
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_RIGHT
+ );
+ }
+ }
+
+ @SubscribeEvent
public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
if (!manager.inCraftedMinionsInventory()) return;
if (!NotEnoughUpdates.INSTANCE.config.minionHelper.gui) return;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
index 2173a3c8..633a82a2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 NotEnoughUpdates contributors
+ * Copyright (C) 2022-2023 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
@@ -148,51 +148,6 @@ public abstract class MixinRenderItem {
@Shadow
abstract void renderModel(IBakedModel model, int color);
- /*@Redirect(method="renderEffect",
- at=@At(
- value = "INVOKE",
- target = "Lnet/minecraft/client/renderer/entity/RenderItem;renderModel(Lnet/minecraft/client/resources/model/IBakedModel;I)V"
- )
- )
- public void renderEffect_renderModel(RenderItem renderItem, IBakedModel model, int colour) {
- if(customEnchGlint != null) {
- renderModel(model, ChromaColour.specialToChromaRGB(customEnchGlint));
- } else {
- renderModel(model, colour);
- }
- }
-
- @Redirect(method="renderEffect",
- at=@At(
- value = "INVOKE",
- target = "Lnet/minecraft/client/renderer/texture/TextureManager;bindTexture(Lnet/minecraft/util/ResourceLocation;)V"
- )
- )
- public void renderEffect_bindTexture(TextureManager textureManager, ResourceLocation location) {
- if(customEnchGlint != null) {
- textureManager.bindTexture(GlintManager.getCustomGlintTexture());
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
- GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
- } else {
- textureManager.bindTexture(location);
- }
- }
-
- @Redirect(method="renderEffect",
- at=@At(
- value = "INVOKE",
- target = "Lnet/minecraft/client/renderer/GlStateManager;blendFunc(II)V"
- )
- )
- public void renderEffect_blendFunc(int src, int dst) {
- if(dst != 1) {
- GlStateManager.blendFunc(src, dst);
- } else if(customEnchGlint != null) {
- GlintManager.setCustomBlendFunc(customEnchGlint);
- } else {
- GlStateManager.blendFunc(GL11.GL_SRC_COLOR, 1);
- }
- }*/
@Inject(method = "renderItemIntoGUI", at = @At("HEAD"))
public void renderItemHead(ItemStack stack, int x, int y, CallbackInfo ci) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
index 498b3b0d..53906cd8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
@@ -250,8 +250,8 @@ public class NEUConfig extends Config {
@Expose
@Category(
- name = "Todo Overlay",
- desc = "Todo Overlay"
+ name = "Todo Overlays",
+ desc = "Todo Overlays"
)
public MiscOverlays miscOverlays = new MiscOverlays();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
index affaa68a..02630df9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
@@ -319,5 +319,4 @@ public class Misc {
)
@ConfigEditorBoolean
public boolean oldSkyBlockMenu = false;
-
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java
index c476fc3b..6f03c2bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java
@@ -22,6 +22,7 @@ package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
public class Museum {
@@ -42,4 +43,22 @@ public class Museum {
@ConfigEditorColour
public String museumItemColor = "0:255:0:255:0";
+ @Expose
+ @ConfigOption(
+ name = "Show Items to donate",
+ desc = "Show the cheapest items you have not yet donated to the Museum"
+ )
+ @ConfigEditorBoolean
+ public boolean museumCheapestItemOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Value calculation",
+ desc = "Choose the source for the value calculation"
+ )
+ @ConfigEditorDropdown(
+ values = {"Lowest BIN", "Craft cost"}
+ )
+ public int museumCheapestItemOverlayValueSource = 0;
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java
index a812ff52..4d14e47f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java
@@ -25,12 +25,14 @@ import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe;
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent;
import io.github.moulberry.notenoughupdates.events.GuiInventoryBackgroundDrawnEvent;
import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
import io.github.moulberry.notenoughupdates.miscgui.GuiInvButtonEditor;
import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.Rectangle;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
@@ -149,6 +151,29 @@ public class EquipmentOverlay {
public ItemStack petStack;
//<editor-fold desc="events">
+ @SubscribeEvent
+ public void onButtonExclusionZones(ButtonExclusionZoneEvent event) {
+ if (isRenderingArmorHud()) {
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight() - 200,
+ event.getGuiBaseRect().getTop(),
+ 50, 84
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_LEFT
+ );
+ }
+ if (isRenderingPetHud()) {
+ event.blockArea(
+ new Rectangle(
+ event.getGuiBaseRect().getRight() - 200,
+ event.getGuiBaseRect().getTop() + 60,
+ 50, 60
+ ),
+ ButtonExclusionZoneEvent.PushDirection.TOWARDS_LEFT
+ );
+ }
+ }
@SubscribeEvent
public void onGuiTick(TickEvent.ClientTickEvent event) {
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/events/ButtonExclusionZoneEvent.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/events/ButtonExclusionZoneEvent.kt
new file mode 100644
index 00000000..3c8ce418
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/events/ButtonExclusionZoneEvent.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 Linnea Gräf
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events
+
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent.PushDirection.*
+import io.github.moulberry.notenoughupdates.util.Rectangle
+import net.minecraft.client.gui.GuiScreen
+import java.util.*
+
+class ButtonExclusionZoneEvent(
+ val gui: GuiScreen,
+ val guiBaseRect: Rectangle,
+) : NEUEvent() {
+ enum class PushDirection {
+ TOWARDS_RIGHT,
+ TOWARDS_LEFT,
+ TOWARDS_TOP,
+ TOWARDS_BOTTOM,
+ }
+
+ data class ExclusionZone(
+ val area: Rectangle,
+ val pushDirection: PushDirection,
+ )
+
+ val occupiedRects = mutableListOf<ExclusionZone>()
+ fun blockArea(area: Rectangle, direction: PushDirection) {
+ occupiedRects.add(ExclusionZone(area, direction))
+ }
+
+ @JvmOverloads
+ fun findButtonPosition(button: Rectangle, margin: Int = 0): Rectangle {
+ val processedAreas = IdentityHashMap<ExclusionZone, Unit>()
+
+ var buttonPosition = button
+ while (true) {
+ val overlappingExclusionZone =
+ occupiedRects.find { it !in processedAreas && it.area.intersects(buttonPosition) } ?: break
+ buttonPosition = when (overlappingExclusionZone.pushDirection) {
+ TOWARDS_RIGHT -> buttonPosition.copy(x = overlappingExclusionZone.area.right + margin)
+ TOWARDS_LEFT -> buttonPosition.copy(x = overlappingExclusionZone.area.left - buttonPosition.width - margin)
+ TOWARDS_TOP -> buttonPosition.copy(y = overlappingExclusionZone.area.top - buttonPosition.height - margin)
+ TOWARDS_BOTTOM -> buttonPosition.copy(y = overlappingExclusionZone.area.bottom + margin)
+ }
+ processedAreas[overlappingExclusionZone] = Unit
+ }
+
+ return buttonPosition
+ }
+
+
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt
new file mode 100644
index 00000000..8a711230
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.inventory
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import io.github.moulberry.notenoughupdates.core.util.ArrowPagesUtils
+import io.github.moulberry.notenoughupdates.core.util.render.TextRenderUtils
+import io.github.moulberry.notenoughupdates.events.ButtonExclusionZoneEvent
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer
+import io.github.moulberry.notenoughupdates.options.seperateSections.Museum
+import io.github.moulberry.notenoughupdates.util.*
+import io.github.moulberry.notenoughupdates.util.MuseumUtil.DonationState.MISSING
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.GuiScreen
+import net.minecraft.client.gui.ScaledResolution
+import net.minecraft.client.gui.inventory.GuiChest
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.client.renderer.RenderHelper
+import net.minecraft.init.Blocks
+import net.minecraft.init.Items
+import net.minecraft.inventory.Slot
+import net.minecraft.item.ItemStack
+import net.minecraft.util.EnumChatFormatting
+import net.minecraft.util.ResourceLocation
+import net.minecraftforge.client.event.GuiScreenEvent
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import org.lwjgl.input.Mouse
+import org.lwjgl.opengl.GL11
+import kotlin.math.ceil
+
+
+object MuseumCheapestItemOverlay {
+
+ enum class Category {
+ WEAPONS,
+ ARMOUR_SETS,
+ RARITIES,
+ NOT_APPLICABLE; // Either not a valid category or inside the "Special Items" category, which is not useful;
+
+ /**
+ * Convert to readable String to be displayed to the user
+ */
+ override fun toString(): String {
+ return when (this) {
+ WEAPONS -> "Weapons"
+ ARMOUR_SETS -> "Armour Sets"
+ RARITIES -> "Rarities"
+ NOT_APPLICABLE -> "Everything"
+ }
+ }
+ }
+
+ data class MuseumItem(
+ var name: String,
+ var internalNames: List<String>,
+ var value: Double,
+ var priceRefreshedAt: Long,
+ var category: Category
+ )
+
+ private const val ITEMS_PER_PAGE = 10
+
+ private val backgroundResource: ResourceLocation = ResourceLocation("notenoughupdates:minion_overlay.png")
+
+ val config: Museum get() = NotEnoughUpdates.INSTANCE.config.museum
+
+ /**
+ * The top left position of the arrows to be drawn, used by [ArrowPagesUtils]
+ */
+ private var topLeft = intArrayOf(237, 110)
+ private var currentPage: Int = 0
+ private var previousSlots: List<Slot> = emptyList()
+ private var itemsToDonate: MutableList<MuseumItem> = emptyList<MuseumItem>().toMutableList()
+ private var leftButtonRect = Rectangle(0, 0, 0, 0)
+ private var rightButtonRect = Rectangle(0, 0, 0, 0)
+ private var selectedCategory = Category.NOT_APPLICABLE
+ private var totalPages = 0
+
+ /**
+ *category -> was the highest page visited?
+ */
+ private var checkedPages: HashMap<Category, Boolean> = hashMapOf(
+ //this page only shows items when you have already donated them -> there is no useful information to gather
+ Category.WEAPONS to false,
+ Category.ARMOUR_SETS to false,
+ Category.RARITIES to false
+ )
+
+ /**
+ * Draw the overlay and parse items, if applicable
+ */
+ @SubscribeEvent
+ fun onDrawBackground(event: GuiScreenEvent.BackgroundDrawnEvent) {
+ if (!shouldRender(event.gui)) return
+ val chest = event.gui as GuiChest
+
+ val slots = chest.inventorySlots.inventorySlots
+ //check if there is any info to gather only when a category is currently open
+ if (!slots.equals(previousSlots) && Utils.getOpenChestName().startsWith("Museum ➜")) {
+ checkIfHighestPageWasVisited(slots)
+ parseItems(slots)
+ updateOutdatedValues()
+ }
+ previousSlots = slots
+
+ val xSize = (event.gui as AccessorGuiContainer).xSize
+ val guiLeft = (event.gui as AccessorGuiContainer).guiLeft
+ val guiTop = (event.gui as AccessorGuiContainer).guiTop
+
+ drawBackground(guiLeft, xSize, guiTop)
+ drawLines(guiLeft, guiTop)
+ drawButtons(guiLeft, xSize, guiTop)
+ }
+
+ /**
+ * Pass on mouse clicks to [ArrowPagesUtils], if applicable
+ */
+ @SubscribeEvent
+ fun onMouseClick(event: GuiScreenEvent.MouseInputEvent.Pre) {
+ if (!shouldRender(event.gui)) return
+ if (!Mouse.getEventButtonState()) return
+ val guiLeft = (event.gui as AccessorGuiContainer).guiLeft
+ val guiTop = (event.gui as AccessorGuiContainer).guiTop
+ ArrowPagesUtils.onPageSwitchMouse(
+ guiLeft, guiTop, topLeft, currentPage, totalPages
+ ) { pageChange: Int -> currentPage = pageChange }
+ }
+
+ @SubscribeEvent
+ fun onButtonExclusionZones(event: ButtonExclusionZoneEvent) {
+ if (shouldRender(event.gui)) {
+ event.blockArea(
+ Rectangle(
+ event.guiBaseRect.right,
+ event.guiBaseRect.top,
+ 175, 130
+ ), ButtonExclusionZoneEvent.PushDirection.TOWARDS_RIGHT
+ )
+ }
+ }
+
+ @SubscribeEvent
+ fun onMouseInput(event: GuiScreenEvent.MouseInputEvent.Pre) {
+ if (!shouldRender(event.gui)) return
+ val mouseX = Utils.getMouseX()
+ val mouseY = Utils.getMouseY()
+ if (Mouse.getEventButtonState() && leftButtonRect.contains(mouseX, mouseY)) {
+ config.museumCheapestItemOverlayValueSource = 1 - config.museumCheapestItemOverlayValueSource
+ updateAllValues()
+ } else if (Mouse.getEventButtonState() && rightButtonRect.contains(mouseX, mouseY)) {
+ advanceSelectedCategory()
+ }
+ }
+
+ /**
+ * Move the selected category one index forward, or back to the start when already at the end
+ */
+ private fun advanceSelectedCategory() {
+ val nextValueIndex = (selectedCategory.ordinal + 1) % 4
+ selectedCategory = enumValues<Category>()[nextValueIndex]
+ }
+
+ /**
+ * Draw the two clickable buttons on the bottom right and display a tooltip if needed
+ */
+ private fun drawButtons(guiLeft: Int, xSize: Int, guiTop: Int) {
+ RenderHelper.enableGUIStandardItemLighting()
+ val useBIN = config.museumCheapestItemOverlayValueSource == 0
+ val mouseX = Utils.getMouseX()
+ val mouseY = Utils.getMouseY()
+ val scaledResolution = ScaledResolution(Minecraft.getMinecraft())
+ val width = scaledResolution.scaledWidth
+ val height = scaledResolution.scaledHeight
+
+ // Left button
+ val leftItemStack = if (useBIN) {
+ ItemUtils.getCoinItemStack(100000.0)
+ } else {
+ ItemStack(Blocks.crafting_table)
+ }
+ leftButtonRect = Rectangle(
+ guiLeft + xSize + 131,
+ guiTop + 106,
+ 16,
+ 16
+ )
+ Minecraft.getMinecraft().renderItem.renderItemIntoGUI(
+ leftItemStack,
+ leftButtonRect.x,
+ leftButtonRect.y
+ )
+
+ if (leftButtonRect.contains(mouseX, mouseY)) {
+ val tooltip = if (useBIN) {
+ listOf(
+ "${EnumChatFormatting.GREEN}Using ${EnumChatFormatting.BLUE}lowest BIN ${EnumChatFormatting.GREEN}as price source!",
+ "",
+ "${EnumChatFormatting.YELLOW}Click to switch to craft cost!"
+ )
+ } else {
+ listOf(
+ "${EnumChatFormatting.GREEN}Using ${EnumChatFormatting.AQUA}craft cost ${EnumChatFormatting.GREEN}as price source!",
+ "",
+ "${EnumChatFormatting.YELLOW}Click to switch to lowest BIN!"
+ )
+ }
+ Utils.drawHoveringText(
+ tooltip,
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ )
+ }
+
+ // Right button
+ val rightItemStack = when (selectedCategory) {
+ Category.WEAPONS -> ItemStack(Items.diamond_sword)
+ Category.ARMOUR_SETS -> ItemStack(Items.diamond_chestplate)
+ Category.RARITIES -> ItemStack(Items.emerald)
+ Category.NOT_APPLICABLE -> ItemStack(Items.filled_map)
+ }
+ rightButtonRect = Rectangle(
+ guiLeft + xSize + 150,
+ guiTop + 106,
+ 16,
+ 16
+ )
+ Minecraft.getMinecraft().renderItem.renderItemIntoGUI(
+ rightItemStack,
+ rightButtonRect.x,
+ rightButtonRect.y
+ )
+ if (rightButtonRect.contains(mouseX, mouseY)) {
+ val tooltip = mutableListOf(
+ "${EnumChatFormatting.GREEN}Category Filter",
+ "",
+ )
+ for (category in Category.values()) {
+ tooltip.add(
+ if (category == selectedCategory) {
+ "${EnumChatFormatting.BLUE}>$category"
+ } else {
+ category.toString()
+ }
+ )
+ }
+
+ tooltip.add("")
+ tooltip.add("${EnumChatFormatting.YELLOW}Click to advance!")
+ Utils.drawHoveringText(
+ tooltip,
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ )
+ }
+ RenderHelper.disableStandardItemLighting()
+ }
+
+ /**
+ * Sort the collected items by their calculated value
+ */
+ private fun sortByValue() {
+ itemsToDonate.sortBy { it.value }
+ }
+
+ /**
+ * Update all values that have not been updated for the last minute
+ */
+ private fun updateOutdatedValues() {
+ val time = System.currentTimeMillis()
+ itemsToDonate.filter { time - it.priceRefreshedAt >= 60000 }
+ .forEach {
+ it.value = calculateValue(it.internalNames)
+ it.priceRefreshedAt = time
+ }
+ }
+
+ /**
+ * Update all values regardless of the time of the last update
+ */
+ private fun updateAllValues() {
+ val time = System.currentTimeMillis()
+ itemsToDonate.forEach {
+ it.value = calculateValue(it.internalNames)
+ it.priceRefreshedAt = time
+ }
+ sortByValue()
+ }
+
+ /**
+ * Calculate the value of an item as displayed in the museum, which may consist of multiple pieces
+ */
+ private fun calculateValue(internalNames: List<String>): Double {
+ var totalValue = 0.0
+ internalNames.forEach {
+ val itemValue: Double =
+ when (config.museumCheapestItemOverlayValueSource) {
+ 0 -> NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarOrBin(it, false)
+ 1 -> NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(it)?.craftCost ?: return@forEach
+ else -> -1.0 //unreachable
+ }
+ if (itemValue == -1.0 || itemValue == 0.0) {
+ totalValue = Double.MAX_VALUE
+ return@forEach
+ } else {
+ totalValue += itemValue
+ }
+ }
+ if (totalValue == 0.0) {
+ totalValue = Double.MAX_VALUE
+ }
+
+ return totalValue
+ }
+
+ /**
+ * Draw the lines containing the displayname and value over the background
+ */
+ private fun drawLines(guiLeft: Int, guiTop: Int) {
+ val mouseX = Utils.getMouseX()
+ val mouseY = Utils.getMouseY()
+ val scaledResolution = ScaledResolution(Minecraft.getMinecraft())
+ val width = scaledResolution.scaledWidth
+ val height = scaledResolution.scaledHeight
+
+ val applicableItems = if (selectedCategory == Category.NOT_APPLICABLE) {
+ itemsToDonate
+ } else {
+ itemsToDonate.toList().filter { it.category == selectedCategory }
+ }
+ val lines = buildLines(applicableItems)
+ totalPages = ceil(applicableItems.size.toFloat() / ITEMS_PER_PAGE.toFloat()).toInt()
+
+ lines.forEachIndexed { index, line ->
+ if (!visitedAllPages() && (index == ITEMS_PER_PAGE || index == lines.size - 1)) {
+ TextRenderUtils.drawStringScaledMaxWidth(
+ "${EnumChatFormatting.RED}Visit all pages for accurate info!",
+ Minecraft.getMinecraft().fontRendererObj,
+ (guiLeft + 185).toFloat(),
+ (guiTop + 95).toFloat(),
+ true,
+ 155,
+ 0
+ )
+ return@forEachIndexed
+ } else {
+ val x = (guiLeft + 187).toFloat()
+ val y = (guiTop + 5 + (index * 10)).toFloat()
+ Utils.renderAlignedString(
+ line.name,
+ if (line.value == Double.MAX_VALUE) "${EnumChatFormatting.RED}Unknown ${if (config.museumCheapestItemOverlayValueSource == 0) "BIN" else "Craft Cost"}" else "${EnumChatFormatting.AQUA}${
+ Utils.shortNumberFormat(
+ line.value,
+ 0
+ )
+ }",
+ x,
+ y,
+ 156
+ )
+
+ if (Utils.isWithinRect(mouseX, mouseY, x.toInt(), y.toInt(), 170, 10)) {
+ val tooltip = mutableListOf(line.name, "")
+ //armor set
+ if (line.internalNames.size > 1) {
+ tooltip.add("${EnumChatFormatting.AQUA}Consists of:")
+ line.internalNames.forEach {
+ val displayname =
+ NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery().withKnownInternalName(it)
+ .resolveToItemListJson()
+ ?.get("displayname")?.asString ?: "ERROR"
+ val value = calculateValue(listOf(it))
+
+ // Creates:" - displayname (price)" OR " - displayname (No BIN found!)"
+ tooltip.add(
+ " ${EnumChatFormatting.DARK_GRAY}-${EnumChatFormatting.RESET} $displayname${EnumChatFormatting.DARK_GRAY} (${EnumChatFormatting.GOLD}${
+ if (value == Double.MAX_VALUE) {
+ "${EnumChatFormatting.RED}No BIN found!"
+ } else {
+ Utils.shortNumberFormat(
+ value,
+ 0
+ )
+ }
+ }${EnumChatFormatting.DARK_GRAY})"
+ )
+ }
+ tooltip.add("")
+ }
+
+ if (NotEnoughUpdates.INSTANCE.manager.getRecipesFor(line.internalNames[0]).isNotEmpty()) {
+ tooltip.add("${EnumChatFormatting.YELLOW}${EnumChatFormatting.BOLD}Click to open recipe!")
+ } else {
+ tooltip.add("${EnumChatFormatting.RED}${EnumChatFormatting.BOLD}No recipe available!")
+ }
+
+ if (Mouse.getEventButtonState()) {
+ //TODO? this only opens the recipe for one of the armor pieces
+ NotEnoughUpdates.INSTANCE.manager.showRecipe(line.internalNames[0])
+ }
+
+ Utils.drawHoveringText(
+ tooltip,
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ )
+ }
+ }
+ }
+
+ //no page has been visited yet
+ if (lines.isEmpty()) {
+ TextRenderUtils.drawStringScaledMaxWidth(
+ "${EnumChatFormatting.RED}No items matching filter!",
+ Minecraft.getMinecraft().fontRendererObj,
+ (guiLeft + 200).toFloat(),
+ (guiTop + 128 / 2).toFloat(),
+ true,
+ 155,
+ 0
+ )
+ }
+
+ ArrowPagesUtils.onDraw(guiLeft, guiTop, topLeft, currentPage, totalPages)
+ return
+ }
+
+ /**
+ * Create the list of [MuseumItem]s that should be displayed on the current page
+ */
+ private fun buildLines(applicableItems: List<MuseumItem>): List<MuseumItem> {
+ val list = emptyList<MuseumItem>().toMutableList()
+
+ for (i in (ITEMS_PER_PAGE * currentPage) until ((ITEMS_PER_PAGE * currentPage) + ITEMS_PER_PAGE)) {
+ if (i >= applicableItems.size) {
+ break
+ }
+
+ list.add(applicableItems[i])
+ }
+ return list
+ }
+
+ /**
+ * Parse the not already donated items present in the currently open Museum page
+ */
+ private fun parseItems(slots: List<Slot>) {
+ Thread {
+ val time = System.currentTimeMillis()
+ val category = getCategory()
+ if (category == Category.NOT_APPLICABLE) {
+ return@Thread
+ }
+ val armor = category == Category.ARMOUR_SETS
+ for (i in 0..53) {
+ val stack = slots[i].stack ?: continue
+ val parsedItems = MuseumUtil.findMuseumItem(stack, armor) ?: continue
+ when (parsedItems.state) {
+ MISSING -> {
+ val displayName = if (armor) {
+ // Use the provided displayname for armor sets but change the color to blue (from red)
+ "${EnumChatFormatting.BLUE}${stack.displayName.stripControlCodes()}"
+ } else {
+ // Find out the real displayname and use it for normal items, if possible
+ NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery()
+ .withKnownInternalName(parsedItems.skyblockItemIds.first())
+ .resolveToItemListJson()
+ ?.get("displayname")?.asString ?: "${EnumChatFormatting.RED}ERROR"
+ }
+
+ //if the list does not already contain it, insert this MuseumItem
+ if (itemsToDonate.none { it.internalNames == parsedItems.skyblockItemIds }) {
+ itemsToDonate.add(
+ MuseumItem(
+ displayName,
+ parsedItems.skyblockItemIds,
+ calculateValue(parsedItems.skyblockItemIds),
+ time,
+ category
+ )
+ )
+ }
+ }
+
+ else -> itemsToDonate.retainAll { it.internalNames != parsedItems.skyblockItemIds }
+ }
+ }
+ sortByValue()
+ }.start()
+ }
+
+ /**
+ * Check if the highest page for the current category is currently open and update [checkedPages] accordingly
+ */
+ private fun checkIfHighestPageWasVisited(slots: List<Slot>) {
+ val category = getCategory()
+ val nextPageSlot = slots[53]
+ // If the "Next Page" arrow is missing, we are at the highest page
+ if ((nextPageSlot.stack ?: return).item != Items.arrow) {
+ checkedPages[category] = true
+ }
+ }
+
+ /**
+ * Draw the background texture to the right side of the open Museum Page
+ */
+ private fun drawBackground(guiLeft: Int, xSize: Int, guiTop: Int) {
+ Minecraft.getMinecraft().textureManager.bindTexture(backgroundResource)
+ GL11.glColor4f(1F, 1F, 1F, 1F)
+ GlStateManager.disableLighting()
+ Utils.drawTexturedRect(
+ (guiLeft + xSize + 4).toFloat(),
+ guiTop.toFloat(),
+ 168f,
+ 128f,
+ 0f,
+ 1f,
+ 0f,
+ 1f,
+ GL11.GL_NEAREST
+ )
+ }
+
+ /**
+ * Determine if the overlay should be active based on the config option and the currently open GuiChest, if applicable
+ */
+ private fun shouldRender(gui: GuiScreen): Boolean =
+ config.museumCheapestItemOverlay && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && (gui is GuiChest && Utils.getOpenChestName()
+ .startsWith("Museum ➜") || Utils.getOpenChestName() == "Your Museum")
+
+ /**
+ * Determine the currently open Museum Category
+ */
+ private fun getCategory(): Category =
+ when (Utils.getOpenChestName().substring(9, Utils.getOpenChestName().length)) {
+ "Weapons" -> Category.WEAPONS
+ "Armor Sets" -> Category.ARMOUR_SETS
+ "Rarities" -> Category.RARITIES
+ else -> Category.NOT_APPLICABLE
+ }
+
+ /**
+ * Determine if all useful pages have been visited
+ */
+ private fun visitedAllPages(): Boolean = !checkedPages.containsValue(false)
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt
new file mode 100644
index 00000000..d44b7721
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/Rectangle.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+/**
+ * An axis aligned rectangle in the following coordinate space:
+ *
+ * * The top direction is towards y=-INF
+ * * The bottom direction is towards y=+INF
+ * * The right direction is towards x=+INF
+ * * The left direction is towards x=-INF
+ */
+data class Rectangle(
+ val x: Int, val y: Int,
+ val width: Int, val height: Int,
+) {
+ /**
+ * The left edge of this rectangle (Low X)
+ */
+ val left get() = x
+
+ /**
+ * The right edge of this rectangle (High X)
+ */
+ val right get() = x + width
+
+ /**
+ * The top edge of this rectangle (Low X)
+ */
+ val top get() = y
+
+ /**
+ * The bottom edge of this rectangle (High X)
+ */
+ val bottom get() = y + height
+
+ init {
+ require(width >= 0)
+ require(height >= 0)
+ }
+
+ /**
+ * Check for intersections between two rectangles. Two rectangles with perfectly aligned edges do *not* count as
+ * intersecting.
+ */
+ fun intersects(other: Rectangle): Boolean {
+ val intersectsX = !(right <= other.left || left >= other.right)
+ val intersectsY = !(top >= other.bottom || bottom <= other.top)
+ return intersectsX && intersectsY
+ }
+
+ /**
+ * Check if this rectangle contains the given coordinate
+ */
+ fun contains(x1: Int, y1: Int) :Boolean{
+ return left <= x1 && x1 < left + width && top <= y1 && y1 < top + height
+ }
+}
diff --git a/src/test/kotlin/io/github/moulberry/notenoughupdates/util/RectangleTest.kt b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/RectangleTest.kt
new file mode 100644
index 00000000..6d4270dd
--- /dev/null
+++ b/src/test/kotlin/io/github/moulberry/notenoughupdates/util/RectangleTest.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertThrows
+
+class RectangleTest {
+
+ @Test
+ fun testNoNegativeSizes() {
+ assertThrows<IllegalArgumentException> {
+ Rectangle(0, 0, -1, 0)
+ }
+ assertThrows<IllegalArgumentException> {
+ Rectangle(0, 0, 0, -1)
+ }
+ }
+
+ @Test
+ fun testOverlaps() {
+ val topLeft = Rectangle(0, 0, 10, 10)
+ assertTrue(topLeft.intersects(topLeft))
+ assertTrue(topLeft.intersects(Rectangle(9, 2, 1, 1)))
+ assertTrue(topLeft.intersects(Rectangle(-2, -2, 4, 4)))
+ assertTrue(topLeft.intersects(Rectangle(4, 4, 1, 1)))
+ assertFalse(topLeft.intersects(Rectangle(-2,-2, 1,1)))
+ assertFalse(topLeft.intersects(Rectangle(-2,-2, 2,2)))
+ }
+}