aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authornea <nea@nea.moe>2023-01-14 22:59:19 +0100
committernea <nea@nea.moe>2023-01-14 22:59:19 +0100
commita321287e85fb577745647d12049fc1d24997717c (patch)
treec217b43663f3160bae41f5510b7ed48677a6f80e /src/main
parent14f2c9d48a31327a13791dc734813bb2fdb0926e (diff)
downloadNotEnoughUpdates-a321287e85fb577745647d12049fc1d24997717c.tar.gz
NotEnoughUpdates-a321287e85fb577745647d12049fc1d24997717c.tar.bz2
NotEnoughUpdates-a321287e85fb577745647d12049fc1d24997717c.zip
Use common utility methods for all museum features
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java44
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java64
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java74
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt100
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt37
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/MuseumUtil.kt113
7 files changed, 273 insertions, 166 deletions
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 6822ab75..4f524c26 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
@@ -54,6 +54,7 @@ import io.github.moulberry.notenoughupdates.options.seperateSections.Mining;
import io.github.moulberry.notenoughupdates.options.seperateSections.MinionHelper;
import io.github.moulberry.notenoughupdates.options.seperateSections.Misc;
import io.github.moulberry.notenoughupdates.options.seperateSections.MiscOverlays;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Museum;
import io.github.moulberry.notenoughupdates.options.seperateSections.NeuAuctionHouse;
import io.github.moulberry.notenoughupdates.options.seperateSections.Notifications;
import io.github.moulberry.notenoughupdates.options.seperateSections.PetOverlay;
@@ -183,6 +184,12 @@ public class NEUConfig extends Config {
@Expose
@Category(
+ name = "Museum",desc = "Musem overlays"
+ )
+ public Museum museum = new Museum();
+
+ @Expose
+ @Category(
name = "GUI Locations",
desc = "Edit the GUI locations of everything here"
)
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 f6710514..064a9304 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
@@ -432,48 +432,4 @@ public class MiscOverlays {
@ConfigAccordionId(id = 0)
public boolean todoIcons = true;
- @ConfigOption(
- name = "Museum Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- public boolean museumAccordion = true;
-
- @Expose
- @ConfigOption(
- name = "Show Museum Items",
- desc = "Show real items instead of green dye in the museum"
- )
- @ConfigAccordionId(id = 1)
- @ConfigEditorBoolean
- public boolean museumItemShow = true;
-
- @Expose
- @ConfigOption(
- name = "Highlight virtual museum items",
- desc = "Highlight virtual museum items with a background color"
- )
- @ConfigAccordionId(id = 1)
- @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
- @ConfigAccordionId(id = 1)
- public boolean museumCheapestItemOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Value calculation",
- desc = "Choose the source for the value calculation"
- )
- @ConfigEditorDropdown(
- values = {"Lowest BIN", "Craft cost"}
- )
- @ConfigAccordionId(id = 1)
- public int museumCheapestItemOverlayValueSource = 0;
}
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
new file mode 100644
index 00000000..6f03c2bb
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Museum.java
@@ -0,0 +1,64 @@
+/*
+ * 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.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 {
+
+ @Expose
+ @ConfigOption(
+ name = "Show Museum Items",
+ desc = "Show real items instead of green dye in the museum"
+ )
+ @ConfigEditorBoolean
+ public boolean museumItemShow = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Highlight virtual museum items",
+ desc = "Highlight virtual museum items with a background color"
+ )
+ @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/util/ItemResolutionQuery.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java
index e5c1b9ad..280a0d3d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java
@@ -24,6 +24,7 @@ import com.google.gson.JsonParseException;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import lombok.var;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.inventory.GuiChest;
@@ -36,9 +37,10 @@ import net.minecraft.nbt.NBTTagCompound;
import javax.annotation.Nullable;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -188,31 +190,63 @@ public class ItemResolutionQuery {
return null;
}
+ /**
+ * Search for an item by the display name
+ *
+ * @param displayName The display name of the item we are searching
+ * @param mayBeMangled Whether the item name may be mangled (for example: reforges, stars)
+ * @return the internal neu item id of that item, or null
+ */
+ public static String findInternalNameByDisplayName(String displayName, boolean mayBeMangled) {
+ var cleanDisplayName = StringUtils.cleanColour(displayName);
+ var manager = NotEnoughUpdates.INSTANCE.manager;
+ String bestMatch = null;
+ int bestMatchLength = -1;
+ for (String internalName : findInternalNameCandidatesForDisplayName(cleanDisplayName)) {
+ var item = manager.createItem(internalName);
+ if (item.getDisplayName() == null) continue;
+ var cleanItemDisplayName = StringUtils.cleanColour(item.getDisplayName());
+ if (cleanItemDisplayName.length() == 0) continue;
+ if (mayBeMangled
+ ? !cleanDisplayName.contains(cleanItemDisplayName)
+ : !cleanItemDisplayName.equals(cleanDisplayName)) {
+ continue;
+ }
+ if (cleanItemDisplayName.length() > bestMatchLength) {
+ bestMatchLength = cleanItemDisplayName.length();
+ bestMatch = internalName;
+ }
+ }
+ return bestMatch;
+ }
+
+ /**
+ * Find potential item ids for a given display name. This function is over eager to give results,
+ * and may give invalid results, but if there is a matching item in the repository it will return <em>at least</em>
+ * that item. This should be used as a first filtering pass. Use {@link #findInternalNameByDisplayName} for a more
+ * user-friendly API.
+ *
+ * @param displayName The display name of the item we are searching
+ * @return a list of internal neu item ids some of which may have a matching display name
+ */
+ public static Set<String> findInternalNameCandidatesForDisplayName(String displayName) {
+ var cleanDisplayName = NEUManager.cleanForTitleMapSearch(displayName);
+ var titleWordMap = NotEnoughUpdates.INSTANCE.manager.titleWordMap;
+ var candidates = new HashSet<String>();
+ for (var partialDisplayName : cleanDisplayName.split(" ")) {
+ if (!titleWordMap.containsKey(partialDisplayName)) continue;
+ candidates.addAll(titleWordMap.get(partialDisplayName).keySet());
+ }
+ return candidates;
+ }
+
private String resolveItemInCatacombsRngMeter() {
List<String> lore = ItemUtils.getLore(compound);
if (lore.size() > 16) {
String s = lore.get(15);
if (s.equals("§7Selected Drop")) {
String displayName = lore.get(16);
- return getInternalNameByDisplayName(displayName);
- }
- }
-
- return null;
- }
-
- public static String getInternalNameByDisplayName(String displayName) {
- String cleanDisplayName = StringUtils.cleanColour(displayName);
- for (Map.Entry<String, JsonObject> entry : NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .entrySet()) {
-
- JsonObject object = entry.getValue();
- if (object.has("displayname")) {
- String name = object.get("displayname").getAsString();
- if (StringUtils.cleanColour(name).equals(cleanDisplayName)) {
- return entry.getKey();
- }
+ return findInternalNameByDisplayName(displayName, false);
}
}
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<Slot>) {
- //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,48 +237,13 @@ object MuseumCheapestItemOverlay {
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 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<String> {
- 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
*/
private fun drawBackground(guiLeft: Int, xSize: Int, guiTop: Int) {
@@ -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<String, Boolean>): 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 <https://www.gnu.org/licenses/>.
+ */
+
+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<String>,
+ 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<String> {
+ return (if (armor)
+ findMuseumArmorSetByName(displayName)
+ else
+ listOf(findMuseumItemByName(displayName))).filterNotNull()
+
+ }
+
+ fun findMuseumItemByName(displayName: String): String? =
+ ItemResolutionQuery.findInternalNameByDisplayName(displayName, true)
+
+
+ fun findMuseumArmorSetByName(displayName: String): List<String?> {
+ 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 }
+ }
+ }
+
+
+}