aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/GuiContainerBackgroundDrawnEvent.java29
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneFavourites.java6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java3
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java46
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java11
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java3
-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/java/io/github/moulberry/notenoughupdates/util/LRUCache.java11
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt291
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt121
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinStringUtils.kt24
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/MuseumUtil.kt113
15 files changed, 735 insertions, 89 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index 5c3083a3..ce386b86 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -103,7 +103,7 @@ public class NEUManager {
private final TreeMap<String, JsonObject> itemMap = new TreeMap<>();
private boolean hasBeenLoadedBefore = false;
- private final TreeMap<String, HashMap<String, List<Integer>>> titleWordMap = new TreeMap<>();
+ public final TreeMap<String, HashMap<String, List<Integer>>> titleWordMap = new TreeMap<>();
private final TreeMap<String, HashMap<String, List<Integer>>> loreWordMap = new TreeMap<>();
public final KeyBinding keybindGive =
@@ -323,7 +323,7 @@ public class NEUManager {
synchronized (titleWordMap) {
int wordIndex = 0;
for (String str : json.get("displayname").getAsString().split(" ")) {
- str = clean(str);
+ str = cleanForTitleMapSearch(str);
if (!titleWordMap.containsKey(str)) {
titleWordMap.put(str, new HashMap<>());
}
@@ -341,7 +341,7 @@ public class NEUManager {
int wordIndex = 0;
for (JsonElement element : json.get("lore").getAsJsonArray()) {
for (String str : element.getAsString().split(" ")) {
- str = clean(str);
+ str = cleanForTitleMapSearch(str);
if (!loreWordMap.containsKey(str)) {
loreWordMap.put(str, new HashMap<>());
}
@@ -469,8 +469,8 @@ public class NEUManager {
int lastStringMatch = -1;
ArrayList<DebugMatch> debugMatches = new ArrayList<>();
- toSearch = clean(toSearch).toLowerCase();
- query = clean(query).toLowerCase();
+ toSearch = cleanForTitleMapSearch(toSearch).toLowerCase();
+ query = cleanForTitleMapSearch(query).toLowerCase();
String[] splitToSearch = toSearch.split(" ");
String[] queryArray = query.split(" ");
@@ -687,7 +687,7 @@ public class NEUManager {
public Set<String> search(String query, TreeMap<String, HashMap<String, List<Integer>>> wordMap) {
HashMap<String, List<Integer>> matches = null;
- query = clean(query).toLowerCase();
+ query = cleanForTitleMapSearch(query).toLowerCase();
for (String queryWord : query.split(" ")) {
HashMap<String, List<Integer>> matchesToKeep = new HashMap<>();
for (HashMap<String, List<Integer>> wordMatches : subMapWithKeysThatAreSuffixes(queryWord, wordMap).values()) {
@@ -862,7 +862,7 @@ public class NEUManager {
return item;
}
- private String clean(String str) {
+ public static String cleanForTitleMapSearch(String str) {
return str.replaceAll("(\u00a7.)|[^0-9a-zA-Z ]", "").toLowerCase().trim();
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index a4643eb5..94c7cc2b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -169,6 +169,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;
}
@@ -181,13 +188,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.
*/
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/GuiContainerBackgroundDrawnEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/events/GuiContainerBackgroundDrawnEvent.java
new file mode 100644
index 00000000..bdb6d1a1
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/GuiContainerBackgroundDrawnEvent.java
@@ -0,0 +1,29 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events;
+
+import lombok.Value;
+import net.minecraft.client.gui.inventory.GuiContainer;
+
+@Value
+public class GuiContainerBackgroundDrawnEvent extends NEUEvent {
+ public GuiContainer container;
+ public float partialTicks;
+}
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/mixins/MixinGuiContainer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
index a5bb99b8..8aca73d1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
@@ -21,6 +21,7 @@ package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NEUOverlay;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.GuiContainerBackgroundDrawnEvent;
import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
import io.github.moulberry.notenoughupdates.listener.RenderListener;
import io.github.moulberry.notenoughupdates.miscfeatures.AbiphoneFavourites;
@@ -330,6 +331,6 @@ public abstract class MixinGuiContainer extends GuiScreen {
@Inject(method = "drawScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;color(FFFF)V", ordinal = 1))
private void drawBackground(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) {
- AbiphoneFavourites.getInstance().onDrawBackground(this);
+ new GuiContainerBackgroundDrawnEvent(((GuiContainer) (Object) this), partialTicks).post();
}
}
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 7c2cfcbf..b6e0e45a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
@@ -25,6 +25,7 @@ import io.github.moulberry.notenoughupdates.core.ChromaColour;
import io.github.moulberry.notenoughupdates.listener.RenderListener;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
+import io.github.moulberry.notenoughupdates.miscfeatures.inventory.MuseumItemHighlighter;
import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -148,51 +149,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 371d657e..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"
)
@@ -246,8 +253,8 @@ public class NEUConfig extends Config {
@Expose
@Category(
- name = "Todo Overlay",
- desc = "Todo Overlay"
+ name = "Misc Overlays",
+ desc = "Miscellaneous Overlays"
)
public MiscOverlays miscOverlays = new MiscOverlays();
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..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
@@ -24,7 +24,7 @@ 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.ConfigEditorColour;
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 +431,5 @@ public class MiscOverlays {
@ConfigEditorBoolean
@ConfigAccordionId(id = 0)
public boolean todoIcons = true;
+
}
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 ea5e13ab..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;
- }
-
- private 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/java/io/github/moulberry/notenoughupdates/util/LRUCache.java b/src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java
index f107d522..6adbc30d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java
@@ -32,13 +32,15 @@ public interface LRUCache<K, V> extends Function<K, V> {
}
static <K, V> LRUCache<K, V> memoize(Function<K, V> mapper, IntSupplier maxCacheSize) {
- Map<K, V> cache = new LinkedHashMap<K, V>(10, 0.75F, true) {
+ Map<K, Object> cache = new LinkedHashMap<K, Object>(10, 0.75F, true) {
@Override
- protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<K, Object> eldest) {
return this.size() > maxCacheSize.getAsInt();
}
};
- Map<K, V> synchronizedCache = Collections.synchronizedMap(cache);
+ Object SENTINEL_CACHE_RESULT_NULL = new Object();
+ Function<K, Object> sentinelAwareMapper = mapper.andThen(it -> it == null ? SENTINEL_CACHE_RESULT_NULL : it);
+ Map<K, Object> synchronizedCache = Collections.synchronizedMap(cache);
return new LRUCache<K, V>() {
@Override
public void clearCache() {
@@ -52,7 +54,8 @@ public interface LRUCache<K, V> extends Function<K, V> {
@Override
public V apply(K k) {
- return synchronizedCache.computeIfAbsent(k, mapper);
+ Object value = synchronizedCache.computeIfAbsent(k, sentinelAwareMapper);
+ return value == SENTINEL_CACHE_RESULT_NULL ? null : (V) value;
}
};
}
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..ccaf5ad8
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumCheapestItemOverlay.kt
@@ -0,0 +1,291 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.inventory
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe
+import io.github.moulberry.notenoughupdates.core.util.ArrowPagesUtils
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer
+import io.github.moulberry.notenoughupdates.util.MuseumUtil
+import io.github.moulberry.notenoughupdates.util.MuseumUtil.DonationState.MISSING
+import io.github.moulberry.notenoughupdates.util.Utils
+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.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
+
+@NEUAutoSubscribe
+object MuseumCheapestItemOverlay {
+ data class MuseumItem(
+ var name: String,
+ var internalNames: List<String>,
+ var value: Double,
+ var priceRefreshedAt: Long
+ )
+
+ private const val ITEMS_PER_PAGE = 8
+
+ 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]
+ */
+ 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()
+
+ /**
+ *category -> was the highest page visited?
+ */
+ private var checkedPages: HashMap<String, Boolean> = 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
+ )
+
+ /**
+ * Draw the overlay and parse items, if applicable
+ */
+ @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)) {
+ checkIfHighestPageWasVisited(slots)
+ parseItems(slots)
+ updateOutdatedValues()
+ sortByValue()
+ }
+ 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)
+ }
+
+ /**
+ * 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 }
+ }
+
+ /**
+ * 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
+ }
+ }
+
+ /**
+ * 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 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.RESET}${line.name}",
+ 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
+ }
+
+ /**
+ * Create the list of [MuseumItem]s that should be displayed on the current page
+ */
+ private fun buildLines(): List<MuseumItem> {
+ val list = emptyList<MuseumItem>().toMutableList()
+ for (i in (if (currentPage == 0) ITEMS_PER_PAGE else ITEMS_PER_PAGE + 1) * (currentPage)..(if (currentPage == 0) ITEMS_PER_PAGE else ITEMS_PER_PAGE + 1) * currentPage + ITEMS_PER_PAGE) {
+ if (i >= itemsToDonate.size) {
+ break
+ }
+ list.add(itemsToDonate[i])
+ }
+ return list
+ }
+
+ /**
+ * 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
+ val time = System.currentTimeMillis()
+ val armor = Utils.getOpenChestName().endsWith("Armor Sets")
+ for (i in 0..53) {
+ val stack = slots[i].stack ?: continue
+ 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
+ )
+ )
+
+ else -> itemsToDonate.retainAll { it.internalNames != parsedItems.skyblockItemIds }
+ }
+ }
+ }
+
+ /**
+ * 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.toFloat() + xSize + 4,
+ guiTop.toFloat(),
+ 180F,
+ 101F,
+ 0F,
+ 180 / 256F,
+ 0F,
+ 101 / 256F,
+ 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 && gui is GuiChest && Utils.getOpenChestName()
+ .startsWith("Museum ➜")
+
+ /**
+ * Determine the name of the currently open Museum Category
+ */
+ private fun getCategory(): String = Utils.getOpenChestName().substring(9, Utils.getOpenChestName().length)
+
+ /**
+ * Determine if all useful pages have been visited
+ */
+ private fun visitedAllPages(): Boolean = !checkedPages.containsValue(false)
+
+ /**
+ * Calculate the total amount of pages the overlay should have
+ */
+ private fun totalPages(): Int = when (itemsToDonate.size % ITEMS_PER_PAGE) {
+ 0 -> itemsToDonate.size / ITEMS_PER_PAGE
+ else -> (itemsToDonate.size / ITEMS_PER_PAGE) + 1
+ }
+}
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
new file mode 100644
index 00000000..945449ba
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/inventory/MuseumItemHighlighter.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 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.miscfeatures.inventory
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates
+import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe
+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.item.EnumDyeColor
+import net.minecraft.item.ItemStack
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+
+@NEUAutoSubscribe
+object MuseumItemHighlighter {
+
+ private val manager get() = NotEnoughUpdates.INSTANCE.manager
+ private val config get() = NotEnoughUpdates.INSTANCE.config.museum
+
+ private fun getHighlightColor() = ChromaColour.specialToChromaRGB(config.museumItemColor)
+
+
+ private val findRawItemForName = LRUCache.memoize(::findRawItemForName0, 4 * 7 * 2)
+
+ @SubscribeEvent
+ fun onRepositoryReload(event: RepositoryReloadEvent) {
+ findRawItemForName.clearCache()
+ }
+
+ private fun findRawItemForName0(arg: Pair<String, Boolean>): ItemStack? {
+ val (name, armor) = arg
+ return MuseumUtil.findItemsByName(name, armor).firstOrNull()?.let { manager.createItem(it) }
+ }
+
+
+ @SubscribeEvent
+ fun onItemOverride(event: ReplaceItemEvent) {
+ if (!config.museumItemShow) return
+ if (!isMuseumInventory(event.inventory)) return
+ val original = event.original ?: return
+ if (!isCompletedRetrievedItem(original)) 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)
+ }
+
+ fun isCompletedRetrievedItem(itemStack: ItemStack): Boolean {
+ return itemStack.hasDisplayName() && itemStack.item == Items.dye && EnumDyeColor.byDyeDamage(itemStack.itemDamage) == EnumDyeColor.LIME
+ }
+
+ fun isMuseumInventory(inventory: IInventory): Boolean {
+ return StringUtils.cleanColour(inventory.displayName.unformattedText).startsWith("Museum ➜")
+ }
+
+ @SubscribeEvent
+ fun onBackgroundDrawn(event: GuiContainerBackgroundDrawnEvent) {
+ val egui = event.container ?: return
+ val chest = egui.inventorySlots as? ContainerChest ?: return
+ if (!config.museumItemShow) return
+ if (!isMuseumInventory(chest.lowerChestInventory)) return
+ val fixedHighlightColor = getHighlightColor()
+ for (slot in chest.inventorySlots) {
+ if (slot == null || slot.stack == null) continue
+ if (isHydratedMuseumItem(slot.stack) || isCompletedRetrievedItem(slot.stack)) {
+ val left = slot.xDisplayPosition
+ val top = slot.yDisplayPosition
+ Gui.drawRect(
+ left, top,
+ left + 16, top + 16,
+ fixedHighlightColor
+ )
+ }
+ }
+ }
+
+ fun hydrateMuseumItem(rawItem: ItemStack, original: ItemStack) = rawItem.copy().apply {
+ setStackDisplayName(original.displayName)
+ val originalLore = ItemUtils.getLore(original).toMutableList()
+ ItemUtils.setLore(this, originalLore)
+ val data = ItemUtils.getOrCreateTag(this)
+ val extraAttributes = data.getCompoundTag("ExtraAttributes")
+ extraAttributes.setByte("donated_museum", 1)
+ data.setTag("ExtraAttributes", extraAttributes)
+ data.setBoolean(MUSEUM_HYDRATED_ITEM_TAG, true)
+ }
+
+ fun isHydratedMuseumItem(stack: ItemStack): Boolean {
+ return ItemUtils.getOrCreateTag(stack).getBoolean(MUSEUM_HYDRATED_ITEM_TAG)
+ }
+
+ const val MUSEUM_HYDRATED_ITEM_TAG = "NEU_HYDRATED_MUSEUM_ITEM"
+
+}
diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinStringUtils.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinStringUtils.kt
new file mode 100644
index 00000000..dc1e800c
--- /dev/null
+++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/KotlinStringUtils.kt
@@ -0,0 +1,24 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util
+
+import net.minecraft.util.StringUtils
+
+fun String.stripControlCodes(): String = StringUtils.stripControlCodes(this)
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 }
+ }
+ }
+
+
+}