From 86faab993dc7be7223feb5d5eb4a36e76df53610 Mon Sep 17 00:00:00 2001 From: Lulonaut Date: Mon, 26 Dec 2022 14:56:29 +0100 Subject: working version --- .../notenoughupdates/NotEnoughUpdates.java | 3 +- .../options/seperateSections/Misc.java | 11 +- .../options/seperateSections/MiscOverlays.java | 8 +- .../miscfeatures/MuseumCheapestItemOverlay.kt | 281 +++++++++++++++++++++ 4 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/MuseumCheapestItemOverlay.kt diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java index 8e50c109..c24d69f9 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java @@ -55,6 +55,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper; import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns; import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager; import io.github.moulberry.notenoughupdates.miscfeatures.MiningStuff; +import io.github.moulberry.notenoughupdates.miscfeatures.MuseumCheapestItemOverlay; import io.github.moulberry.notenoughupdates.miscfeatures.NPCRetexturing; import io.github.moulberry.notenoughupdates.miscfeatures.Navigation; import io.github.moulberry.notenoughupdates.miscfeatures.NullzeeSphere; @@ -84,7 +85,6 @@ import io.github.moulberry.notenoughupdates.overlays.EquipmentOverlay; import io.github.moulberry.notenoughupdates.overlays.FuelBar; import io.github.moulberry.notenoughupdates.overlays.OverlayManager; import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer; -import io.github.moulberry.notenoughupdates.recipes.KatRecipe; import io.github.moulberry.notenoughupdates.recipes.RecipeGenerator; import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.SBInfo; @@ -351,6 +351,7 @@ public class NotEnoughUpdates { MinecraftForge.EVENT_BUS.register(AbiphoneFavourites.getInstance()); MinecraftForge.EVENT_BUS.register(AbiphoneContactHelper.getInstance()); 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/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java index 7266b570..29edb314 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 @@ -298,7 +298,7 @@ public class Misc { @ConfigOption( name = "Museum Overlay", - desc = "Display items you've taken out of the museum" + desc = "" ) @ConfigEditorAccordion(id = 2) public boolean museumAccordion = false; @@ -321,4 +321,13 @@ public class Misc { @Expose public String museumItemColor = "0:255:0:255:0"; + @Expose + @ConfigOption( + name = "Enable Overlay", + desc = "Show the cheapest items you have not yet donated to the Museum" + ) + @ConfigEditorBoolean + @ConfigAccordionId(id = 2) + public boolean museumCheapestItemOverlay = true; + } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java index 714dd7b7..bb713041 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java @@ -24,7 +24,6 @@ import io.github.moulberry.notenoughupdates.core.config.Position; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean; -import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown; import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption; @@ -431,4 +430,11 @@ public class MiscOverlays { @ConfigEditorBoolean @ConfigAccordionId(id = 0) public boolean todoIcons = true; + + @ConfigOption( + name = "Museum Overlay", + desc = "" + ) + @ConfigEditorAccordion(id = 1) + public boolean museumOverlay = true; } diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/MuseumCheapestItemOverlay.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/MuseumCheapestItemOverlay.kt new file mode 100644 index 00000000..1526513e --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/MuseumCheapestItemOverlay.kt @@ -0,0 +1,281 @@ +/* + * 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.NEUManager +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import io.github.moulberry.notenoughupdates.core.util.ArrowPagesUtils +import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer +import io.github.moulberry.notenoughupdates.util.Utils +import io.github.moulberry.notenoughupdates.util.stripControlCodes +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiScreen +import net.minecraft.client.gui.inventory.GuiChest +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.init.Items +import net.minecraft.inventory.Slot +import net.minecraft.item.ItemDye +import net.minecraft.util.EnumChatFormatting +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.client.event.GuiScreenEvent.BackgroundDrawnEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import org.lwjgl.input.Mouse +import org.lwjgl.opengl.GL11 + + +object MuseumCheapestItemOverlay { + data class MuseumItem(var name: String, var value: Double, var priceRefreshedAt: Long) + + private val backgroundResource: ResourceLocation by lazy { + ResourceLocation("notenoughupdates:dungeon_chest_worth.png") + } + + private const val ITEMS_PER_PAGE = 8 + private var topLeft = intArrayOf(237, 110) + private var currentPage: Int = 0 + private var previousSlots: List = emptyList() + private var itemsToDonate: MutableList = emptyList().toMutableList() + + //category -> was the highest page visited? + private var checkedPages: HashMap = hashMapOf( + //this page only shows items when you have already donated them -> there is no useful information to gather + "Special Items" to true, + "Weapons" to false, + "Armor Sets" to false, + "Rarities" to false + ) + + @SubscribeEvent + fun onDrawBackground(event: BackgroundDrawnEvent) { + if (!shouldRender(event.gui)) return + val chest = event.gui as GuiChest + + val slots = chest.inventorySlots.inventorySlots + if (!slots.equals(previousSlots)) { + parseItems(slots) + checkIfHighestPageWasVisited(slots) + sortByPrice() + } + 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, xSize, guiTop) + } + + @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 } + } + + + private fun sortByPrice() { + itemsToDonate.sortBy { it.value } + } + + + private fun drawLines(guiLeft: Int, xSize: Int, guiTop: Int) { + //render + val lines = buildLines() + lines.forEachIndexed { index, line -> + if (index == ITEMS_PER_PAGE && !visitedAllPages()) { + Minecraft.getMinecraft().fontRendererObj.drawStringWithShadow( + "${EnumChatFormatting.RED}Visit all pages for accurate info!", + (guiLeft + 185).toFloat(), + (guiTop + 85).toFloat(), + 0 + ) + } else { + Utils.renderAlignedString( + "${EnumChatFormatting.BLUE}${line.name}", + "${EnumChatFormatting.BLUE}${ + if (line.value == Double.MAX_VALUE) "${EnumChatFormatting.RED}Unknown" else "${EnumChatFormatting.AQUA}${ + Utils.shortNumberFormat( + line.value, + 0 + ) + }" + }", + (guiLeft + 187).toFloat(), + (guiTop + 5 + (index * 10)).toFloat(), + 160 + ) + } + } + + ArrowPagesUtils.onDraw(guiLeft, guiTop, topLeft, currentPage, totalPages()) + return + } + + private fun buildLines(): List { + val list = emptyList().toMutableList() + for (i in ITEMS_PER_PAGE * currentPage..ITEMS_PER_PAGE * currentPage + ITEMS_PER_PAGE) { + if (i >= itemsToDonate.size) { + break + } + list.add(itemsToDonate[i]) + } + return list + } + + private fun parseItems(slots: List) { + //iterate upper chest with 56 slots + val time = System.currentTimeMillis() + for (i in 0..53) { + val stack = slots[i].stack ?: continue + //check for gray dye which indicates that the item has not been donated + if (stack.item is ItemDye && stack.itemDamage == 8) { + val name = stack.displayName.stripControlCodes() + val internalNames = guessInternalNames(name, Utils.getOpenChestName().endsWith("Armor Sets")) +// println("$name resolves to ${internalNames.toString()}") + var totalValue = 0.0 + internalNames.forEach { + val itemValue = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarOrBin(it, false) + if (itemValue == -1.0 || itemValue == 0.0) { + totalValue = Double.MAX_VALUE + return@forEach + } else { + totalValue += itemValue + } + } + if (totalValue == 0.0) { + totalValue = Double.MAX_VALUE + } + itemsToDonate.add(MuseumItem(name, totalValue, time)) + } + } + } + + private fun checkIfHighestPageWasVisited(slots: List) { + 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 + } + } + + private fun guessInternalNames(itemName: String, armor: Boolean): List { + return if (armor) { + //TODO: convert this to use titlewordmap as well + val suffixes = listOf( + "HELMET", + "CHESTPLATE", + "LEGGINGS", + "BOOTS", + "ARMOR_HELMET", + "ARMOR_CHESTPLATE", + "ARMOR_LEGGINGS", + "ARMOR_BOOTS" + ) + + val prefixes = listOf( + "HELMET", + "LEGGINGS", + "CHESTPLATE", + "BOOTS" + ) + val validNames = mutableListOf() + val name = itemName + .replace(" Armor", "") + .replace("Armor ", "") + .replace("'s", "") + .replace(" ", "_") + .uppercase() + + for (suffix in suffixes) { + val possibleName = name + "_" + suffix + if (NotEnoughUpdates.INSTANCE.manager.isValidInternalName(possibleName)) { + validNames.add(possibleName) + } else { + //catch for example: ARMOR_OF_YOG_LEGGINGS, where "Armor" does not need to be replaced to get a valid internalname + val unchangedName = itemName.replace(" ", "_").uppercase() + "_" + suffix + if (NotEnoughUpdates.INSTANCE.manager.isValidInternalName(unchangedName)) { + validNames.add(unchangedName) + } + } + } + + for (prefix in prefixes) { + val possibleName = prefix + "_" + name + if (NotEnoughUpdates.INSTANCE.manager.isValidInternalName(possibleName)) { + validNames.add(possibleName) + } + + } + + validNames + } else { + val monochromeName = NEUManager.cleanForTitleMapSearch(itemName) + val internalName = monochromeName.split(" ") + .asSequence() + .mapNotNull { NotEnoughUpdates.INSTANCE.manager.titleWordMap[it]?.keys } + .flatten() + .filter { + val item = NotEnoughUpdates.INSTANCE.manager.createItem(it) ?: return@filter false + item.displayName != null && item.displayName.isNotEmpty() && NEUManager.cleanForTitleMapSearch(item.displayName) in monochromeName + } + .firstOrNull() ?: return emptyList() + + listOf(internalName) + } + } + + + 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.toFloat() + xSize + 4, + guiTop.toFloat(), + 180F, + 101F, + 0F, + 180 / 256F, + 0F, + 101 / 256F, + GL11.GL_NEAREST + ) + } + + private fun shouldRender(gui: GuiScreen): Boolean = + NotEnoughUpdates.INSTANCE.config.misc.museumCheapestItemOverlay && gui is GuiChest && Utils.getOpenChestName() + .startsWith("Museum ➜") + + private fun getCategory(): String = Utils.getOpenChestName().substring(9, Utils.getOpenChestName().length) + + private fun visitedAllPages(): Boolean = !checkedPages.containsValue(false) + + private fun totalPages(): Int = when (itemsToDonate.size % ITEMS_PER_PAGE) { + 0 -> itemsToDonate.size / ITEMS_PER_PAGE + else -> (itemsToDonate.size / ITEMS_PER_PAGE) + 1 + } +} -- cgit