From a321287e85fb577745647d12049fc1d24997717c Mon Sep 17 00:00:00 2001 From: nea Date: Sat, 14 Jan 2023 22:59:19 +0100 Subject: Use common utility methods for all museum features --- .../inventory/MuseumCheapestItemOverlay.kt | 100 +++++------------- .../inventory/MuseumItemHighlighter.kt | 37 +++---- .../moulberry/notenoughupdates/util/MuseumUtil.kt | 113 +++++++++++++++++++++ 3 files changed, 148 insertions(+), 102 deletions(-) create mode 100644 src/main/kotlin/io/github/moulberry/notenoughupdates/util/MuseumUtil.kt (limited to 'src/main/kotlin') 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 index fe2dd1e1..7485f14d 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt @@ -19,20 +19,18 @@ package io.github.moulberry.notenoughupdates.miscfeatures.inventory -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.ItemResolutionQuery +import io.github.moulberry.notenoughupdates.util.MuseumUtil +import io.github.moulberry.notenoughupdates.util.MuseumUtil.DonationState.MISSING 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 @@ -52,9 +50,9 @@ object MuseumCheapestItemOverlay { private const val ITEMS_PER_PAGE = 8 - private val backgroundResource: ResourceLocation by lazy { - ResourceLocation("notenoughupdates:dungeon_chest_worth.png") - } + private val backgroundResource: ResourceLocation = ResourceLocation("notenoughupdates:dungeon_chest_worth.png") + + val config get() = NotEnoughUpdates.INSTANCE.config.museum /** * The top left position of the arrows to be drawn, used by [ArrowPagesUtils] @@ -140,7 +138,7 @@ object MuseumCheapestItemOverlay { var totalValue = 0.0 internalNames.forEach { val itemValue: Double = - when (NotEnoughUpdates.INSTANCE.config.miscOverlays.museumCheapestItemOverlayValueSource) { + 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 @@ -210,42 +208,25 @@ object MuseumCheapestItemOverlay { * Parse the not already donated items present in the currently open Museum page */ private fun parseItems(slots: List) { - //iterate upper chest with 56 slots + // Iterate upper chest with 56 slots val time = System.currentTimeMillis() + val armor = Utils.getOpenChestName().endsWith("Armor Sets") 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 armor = Utils.getOpenChestName().endsWith("Armor Sets") - val internalNames = guessInternalNames(name, armor) - val value = calculateValue(internalNames) - - val displayName = if (armor) { - "${EnumChatFormatting.BLUE}$name" - } else { - NotEnoughUpdates.INSTANCE.manager.getDisplayName(internalNames[0]) ?: "ERROR" - } + val parsedItems = MuseumUtil.findMuseumItem(stack, armor) ?: continue + when (parsedItems.state) { + MISSING -> + if (itemsToDonate.none { it.internalNames == parsedItems.skyblockItemIds }) + itemsToDonate.add( + MuseumItem( + stack.displayName, + parsedItems.skyblockItemIds, + calculateValue(parsedItems.skyblockItemIds), + time + ) + ) - //make sure this item does not already exist - if (itemsToDonate.none { it.internalNames == internalNames }) { - itemsToDonate.add(MuseumItem(displayName, internalNames, value, time)) - } - } else if (stack.item is ItemDye && stack.itemDamage == 10) { //also check donated items - val name = stack.displayName.stripControlCodes() - val armor = Utils.getOpenChestName().endsWith("Armor Sets") - val internalNames = guessInternalNames(name, armor) - //remove items that have these internalnames - itemsToDonate.retainAll { it.internalNames != internalNames } - } else { - var name = listOf( - NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery().withItemStack(stack) - .resolveInternalName() - ) - if (name[0] == null) { - name = guessInternalNames(stack.displayName, true) - } - itemsToDonate.retainAll { it.internalNames != name } + else -> itemsToDonate.retainAll { it.internalNames != parsedItems.skyblockItemIds } } } } @@ -256,47 +237,12 @@ object MuseumCheapestItemOverlay { 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 the "Next Page" arrow is missing, we are at the highest page if ((nextPageSlot.stack ?: return).item != Items.arrow) { checkedPages[category] = true } } - /** - * Try to guess the internal names for a given item from the Museum. Due to Hypixels naming inconsistencies this does not work on every armor set - */ - private fun guessInternalNames(itemName: String, armor: Boolean): List { - return if (armor) { - val mustHaves = arrayOf( - "HELMET", - "LEGGINGS", - "CHESTPLATE", - "BOOTS" - ) - val monochromeName = NEUManager.cleanForTitleMapSearch(itemName) - val candidates = monochromeName.split(" ") - .asSequence() - .mapNotNull { NotEnoughUpdates.INSTANCE.manager.titleWordMap[it]?.keys } - .flatten() - .filter { - val item = NotEnoughUpdates.INSTANCE.manager.createItem(it) - val name = NEUManager.cleanForTitleMapSearch(item.displayName) - monochromeName.replace("armor", "") in name - }.filter { item -> - mustHaves.any { - item.contains(it) - } - } - //filter out duplicates - .toSet() - .toList() - - return candidates - } else { - listOf(ItemResolutionQuery.getInternalNameByDisplayName(itemName)) - } - } - /** * Draw the background texture to the right side of the open Museum Page */ @@ -321,7 +267,7 @@ object MuseumCheapestItemOverlay { * 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 = - NotEnoughUpdates.INSTANCE.config.miscOverlays.museumCheapestItemOverlay && gui is GuiChest && Utils.getOpenChestName() + config.museumCheapestItemOverlay && gui is GuiChest && Utils.getOpenChestName() .startsWith("Museum ➜") /** diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt index 63b88094..b809ee9f 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022 Linnea Gräf * * This file is part of NotEnoughUpdates. * @@ -19,51 +19,42 @@ package io.github.moulberry.notenoughupdates.miscfeatures.inventory -import io.github.moulberry.notenoughupdates.NEUManager import io.github.moulberry.notenoughupdates.NotEnoughUpdates import io.github.moulberry.notenoughupdates.core.ChromaColour import io.github.moulberry.notenoughupdates.core.util.StringUtils import io.github.moulberry.notenoughupdates.events.GuiContainerBackgroundDrawnEvent import io.github.moulberry.notenoughupdates.events.ReplaceItemEvent import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent +import io.github.moulberry.notenoughupdates.util.ItemResolutionQuery import io.github.moulberry.notenoughupdates.util.ItemUtils import io.github.moulberry.notenoughupdates.util.LRUCache +import io.github.moulberry.notenoughupdates.util.MuseumUtil import net.minecraft.client.gui.Gui import net.minecraft.init.Items import net.minecraft.inventory.ContainerChest import net.minecraft.inventory.IInventory -import net.minecraft.inventory.Slot import net.minecraft.item.EnumDyeColor import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object MuseumItemHighlighter { - val manager get() = NotEnoughUpdates.INSTANCE.manager - val config get() = NotEnoughUpdates.INSTANCE.config.miscOverlays + private val manager get() = NotEnoughUpdates.INSTANCE.manager + private val config get() = NotEnoughUpdates.INSTANCE.config.museum - fun getHighlightColor() = ChromaColour.specialToChromaRGB(config.museumItemColor) + private fun getHighlightColor() = ChromaColour.specialToChromaRGB(config.museumItemColor) - val findRawItemForName = LRUCache.memoize(::findRawItemForName0, 4 * 7 * 2) + private val findRawItemForName = LRUCache.memoize(::findRawItemForName0, 4 * 7 * 2) @SubscribeEvent fun onRepositoryReload(event: RepositoryReloadEvent) { findRawItemForName.clearCache() } - fun findRawItemForName0(name: String): ItemStack? { - val monochromeName = NEUManager.cleanForTitleMapSearch(name) - return monochromeName.split(" ") - .mapNotNull { manager.titleWordMap[it]?.keys } - .flatten() - .toSet() - .asSequence() - .map { manager.createItem(it) } - .filter { - it.displayName != null && it.displayName.isNotEmpty() && NEUManager.cleanForTitleMapSearch(it.displayName) in monochromeName - } - .maxByOrNull { it.displayName.length } + private fun findRawItemForName0(arg: Pair): ItemStack? { + val (name, armor) = arg + return MuseumUtil.findItemsByName(name, armor).firstOrNull()?.let { manager.createItem(it) } } @@ -73,7 +64,8 @@ object MuseumItemHighlighter { if (!isMuseumInventory(event.inventory)) return val original = event.original ?: return if (!isCompletedRetrievedItem(original)) return - val rawItem = findRawItemForName.apply(original.displayName) ?: return + val armor = StringUtils.cleanColour(event.inventory.displayName.unformattedText).endsWith("Armor Sets") + val rawItem = findRawItemForName.apply(original.displayName to armor) ?: return val hydratedItem = hydrateMuseumItem(rawItem, original) event.replaceWith(hydratedItem) } @@ -122,11 +114,6 @@ object MuseumItemHighlighter { return ItemUtils.getOrCreateTag(stack).getBoolean(MUSEUM_HYDRATED_ITEM_TAG) } - @JvmStatic - fun onDrawSlot(slotIn: Slot) { - - } - const val MUSEUM_HYDRATED_ITEM_TAG = "NEU_HYDRATED_MUSEUM_ITEM" } diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/MuseumUtil.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/MuseumUtil.kt new file mode 100644 index 00000000..dd52d175 --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/MuseumUtil.kt @@ -0,0 +1,113 @@ +/* + * 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 . + */ + +package io.github.moulberry.notenoughupdates.util + +import io.github.moulberry.notenoughupdates.NEUManager +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import net.minecraft.item.EnumDyeColor +import net.minecraft.item.ItemDye +import net.minecraft.item.ItemStack + +object MuseumUtil { + + data class MuseumItem( + /** + * A potentially non-exhaustive list of item ids that are required for this museum donation. + */ + val skyblockItemIds: List, + val state: DonationState, + ) + + enum class DonationState { + /** + * Donated armor only shows one piece, so we use that for id resolution, which might result in incomplete + * results (hence the separate state). This still means that the entire set is donated, but it is guaranteed to + * be only a partial result. Other values of this enum do not guarantee a full result, but at least they do not + * guarantee a partial one. + */ + DONATED_PRESENT_PARTIAL, + DONATED_PRESENT, + DONATED_VACANT, + MISSING, + } + + fun findMuseumItem(stack: ItemStack, isOnArmorPage: Boolean): MuseumItem? { + val item = stack.item ?: return null + val items by lazy { findItemsByName(stack.displayName, isOnArmorPage)} + if (item is ItemDye) { + val dyeColor = EnumDyeColor.byDyeDamage(stack.itemDamage) + if (dyeColor == EnumDyeColor.LIME) { + // Item is donated, but not present in the museum + return MuseumItem(items, DonationState.DONATED_VACANT) + } else if (dyeColor == EnumDyeColor.GRAY) { + // Item is not donated + return MuseumItem(items, DonationState.MISSING) + } + // Otherwise unknown item, try to analyze as normal item. + } + val skyblockId = NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery().withItemStack(stack) + .resolveInternalName() + if (skyblockId != null) { + return MuseumItem( + listOf(skyblockId), + if (isOnArmorPage) DonationState.DONATED_PRESENT_PARTIAL else DonationState.DONATED_PRESENT + ) + } + return MuseumItem( + items, + DonationState.DONATED_PRESENT + ) + } + + fun findItemsByName(displayName: String, armor: Boolean): List { + return (if (armor) + findMuseumArmorSetByName(displayName) + else + listOf(findMuseumItemByName(displayName))).filterNotNull() + + } + + fun findMuseumItemByName(displayName: String): String? = + ItemResolutionQuery.findInternalNameByDisplayName(displayName, true) + + + fun findMuseumArmorSetByName(displayName: String): List { + val armorSlots = arrayOf( + "HELMET", + "LEGGINGS", + "CHESTPLATE", + "BOOTS" + ) + val monochromeName = NEUManager.cleanForTitleMapSearch(displayName) + val results = ItemResolutionQuery.findInternalNameCandidatesForDisplayName(displayName) + .asSequence() + .filter { + val item = NotEnoughUpdates.INSTANCE.manager.createItem(it) + val name = NEUManager.cleanForTitleMapSearch(item.displayName) + monochromeName.replace("armor", "") in name + } + .toSet() + return armorSlots.map { armorSlot -> + results.singleOrNull { armorSlot in it } + } + } + + +} -- cgit