aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle.kts6
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java300
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantMatcher.java128
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantStyleCustomizer.java113
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java63
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/LateBindingChroma.java103
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java7
9 files changed, 422 insertions, 302 deletions
diff --git a/build.gradle.kts b/build.gradle.kts
index a661d6be..a93fccfc 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -30,6 +30,7 @@ plugins {
id("com.github.johnrengelman.shadow") version "7.1.2"
id("io.github.juuxel.loom-quiltflower") version "1.7.3"
`maven-publish`
+ id("io.freefair.lombok") version "6.5.1"
kotlin("jvm") version "1.7.20"
}
@@ -76,6 +77,11 @@ repositories {
maven("https://jitpack.io")
}
+lombok {
+ version.set("1.18.24")
+}
+
+
val shadowImplementation by configurations.creating {
configurations.implementation.get().extendsFrom(this)
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index 37b493e2..32c8aa31 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -67,6 +67,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.WitherCloakChanger;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBlockSounds;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures;
+import io.github.moulberry.notenoughupdates.miscfeatures.item.enchants.EnchantStyleCustomizer;
import io.github.moulberry.notenoughupdates.miscfeatures.updater.AutoUpdater;
import io.github.moulberry.notenoughupdates.miscfeatures.world.EnderNodeHighlighter;
import io.github.moulberry.notenoughupdates.miscfeatures.world.GlowingMushroomHighlighter;
@@ -340,6 +341,7 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(navigation);
MinecraftForge.EVENT_BUS.register(new GlowingMushroomHighlighter());
MinecraftForge.EVENT_BUS.register(new WorldListener(this));
+ MinecraftForge.EVENT_BUS.register(EnchantStyleCustomizer.INSTANCE);
MinecraftForge.EVENT_BUS.register(TitleUtil.getInstance());
MinecraftForge.EVENT_BUS.register(EnderNodeHighlighter.getInstance());
MinecraftForge.EVENT_BUS.register(AbiphoneFavourites.getInstance());
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java
index dd3f5efd..d9a00370 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java
@@ -29,9 +29,7 @@ import io.github.moulberry.notenoughupdates.ItemPriceInformation;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.MiscUtils;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
-import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
-import io.github.moulberry.notenoughupdates.miscgui.GuiEnchantColour;
import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.Utils;
@@ -45,7 +43,6 @@ import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
-import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.text.WordUtils;
@@ -61,7 +58,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
@@ -79,81 +75,6 @@ public class ItemTooltipListener {
private boolean showReforgeStoneStats = true;
private boolean pressedArrowLast = false;
private boolean pressedShiftLast = false;
- private int sbaloaded = -1;
-
- //region Enchant optimisation
- private String lastItemUuid;
-
- public static class EnchantString {
- final String preEnchantText;
- final String enchantName;
-
- final String mod;
- final String colourCode;
- final boolean isChroma;
-
- public EnchantString(String enchant, String preEnchantText, String modifier, String colourCode) {
- this.preEnchantText = preEnchantText;
- this.enchantName = enchant;
- this.mod = modifier;
- this.colourCode = colourCode;
- this.isChroma = colourCode.equals("z");
- }
-
- private boolean matches(String line) {
- return line.matches(".*" + preEnchantText + enchantName + ".*");
- }
-
- public String applyMods(String line, int lineIndex) {
- if (!matches(line)) return null;
-
- if (!isChroma) {
- return line.replace(preEnchantText + enchantName,
- "\u00A7" + colourCode + mod + enchantName
- );
- } else {
- //if you couldn't tell, this is for chroma.
- int newOffset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(preEnchantText + enchantName);
- return line.replace(
- preEnchantText + enchantName,
- Utils.chromaString(enchantName, newOffset / 12f + lineIndex, preEnchantText.matches(".*\\u00A7d.*"))
- );
- }
- }
-}
-
-public static class EnchantLine {
- final String originalLine;
- final ArrayList<EnchantString> enchants;
-
- public EnchantLine(String line, ArrayList<EnchantString> enchants) {
- this.enchants = enchants;
- this.originalLine = line;
- }
-
- public boolean isSameAsBefore(String line) {
- return line.equals(originalLine);
- }
-
- public String replaceLine(String line, int index) {
- if (line.equals(originalLine)) {
- for (EnchantString enchant: enchants) {
- String modifiedLine = enchant.applyMods(line, index);
- if (modifiedLine != null) {
- line = modifiedLine;
- }
- }
- }
-
- return line;
- }
-}
-
- private final ArrayList<EnchantLine> enchantList = new ArrayList<>();
- private int firstEnchantIndex = -1;
- private int lastEnchantIndex = -1;
-
- //endregion
public ItemTooltipListener(NotEnoughUpdates neu) {
this.neu = neu;
@@ -164,17 +85,6 @@ public static class EnchantLine {
percentStats.add("ability_damage");
}
- private boolean isSkyblockAddonsLoaded() {
- if (sbaloaded == -1) {
- if (Loader.isModLoaded("skyblockaddons")) {
- sbaloaded = 1;
- } else {
- sbaloaded = 0;
- }
- }
- return sbaloaded == 1;
- }
-
@SubscribeEvent(priority = EventPriority.LOW)
public void onItemTooltipLow(ItemTooltipEvent event) {
if (!NotEnoughUpdates.INSTANCE.isOnSkyblock()) return;
@@ -194,10 +104,6 @@ public static class EnchantLine {
"enchantments",
10
);
- boolean hasAttributes = event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").hasKey(
- "attributes",
- 10
- );
Set<String> enchantIds = new HashSet<>();
if (hasEnchantments) enchantIds = event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").getCompoundTag(
"enchantments").getKeySet();
@@ -251,22 +157,10 @@ public static class EnchantLine {
boolean gotToEnchants = false;
boolean passedEnchants = false;
- boolean foundEnchants = false;
boolean dungeonProfit = false;
List<String> newTooltip = new ArrayList<>();
- String currentUuid = ItemCustomizeManager.getUuidForItem(event.itemStack);
-
- boolean resetEnchantCache = false;
- //reset data if cache is off
- if (!NotEnoughUpdates.INSTANCE.config.misc.cacheItemEnchant) {
- lastItemUuid = null;
- firstEnchantIndex = -1;
- lastEnchantIndex = -1;
- enchantList.clear();
- }
-
for (int k = 0; k < event.toolTip.size(); k++) {
String line = event.toolTip.get(k);
boolean thisLineHasEnchants = false;
@@ -470,187 +364,6 @@ public static class EnchantLine {
}
}
}
- if (hasEnchantments || hasAttributes) {
- Pattern findEnchantPattern = Pattern.compile(".*(?<enchant>[\\w ]+) (?<level>[0-9]+|[IVXLCDM]+)$");
- Matcher findEnchantMatcher = findEnchantPattern.matcher(line);
- if (findEnchantMatcher.matches()) {
- if (NotEnoughUpdates.INSTANCE.config.misc.cacheItemEnchant && !foundEnchants) {
- foundEnchants = true;
- if ((
- lastItemUuid == null || currentUuid == null ||
- (currentUuid != null &&
- !Objects.equals(lastItemUuid, currentUuid)))) {
- firstEnchantIndex = k;//k being the line index
- lastEnchantIndex = k;
- enchantList.clear();
- }
- }
- thisLineHasEnchants = true;
- }
-
- ArrayList<String> addedEnchants = new ArrayList<>();
- //if cacheItemEnchant option is disabled it will always be length of 0
- if (enchantList.size() == 0 || enchantList.size() <= k - firstEnchantIndex) {
- ArrayList<EnchantString> enchants = new ArrayList<>();
- final String oLine = line;
-
- for (String op : NotEnoughUpdates.INSTANCE.config.hidden.enchantColours) {
- List<String> colourOps = GuiEnchantColour.splitter.splitToList(op);
- String enchantName = GuiEnchantColour.getColourOpIndex(colourOps, 0);
- String comparator = GuiEnchantColour.getColourOpIndex(colourOps, 1);
- String comparison = GuiEnchantColour.getColourOpIndex(colourOps, 2);
- String colourCode = GuiEnchantColour.getColourOpIndex(colourOps, 3);
- String modifier = GuiEnchantColour.getColourOpIndex(colourOps, 4);
-
- int modifierI = GuiEnchantColour.getIntModifier(modifier);
-
- assert enchantName != null;
- if (enchantName.length() == 0) continue;
- assert comparator != null;
- if (comparator.length() == 0) continue;
- assert comparison != null;
- if (comparison.length() == 0) continue;
- assert colourCode != null;
- if (colourCode.length() == 0) continue;
-
- int comparatorI = ">=<".indexOf(comparator.charAt(0));
-
- int levelToFind;
- try {
- levelToFind = Integer.parseInt(comparison);
- } catch (Exception e) {
- continue;
- }
-
- if (comparatorI < 0) continue;
- String regexText = "0123456789abcdefz";
- if (isSkyblockAddonsLoaded()) {
- regexText = regexText + "Z";
- }
-
- if (regexText.indexOf(colourCode.charAt(0)) < 0) continue;
-
- //item_lore = item_lore.replaceAll("\\u00A79("+lvl4Max+" IV)", EnumChatFormatting.DARK_PURPLE+"$1");
- //9([a-zA-Z ]+?) ([0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X))(,|$)
- Pattern pattern;
- try {
- pattern = Pattern.compile(
- "(\\u00A7b|\\u00A79|\\u00A7(b|9|l)\\u00A7d\\u00A7l)(?<enchantName>" + enchantName + ") " +
- "(?<level>[0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX))((\\u00A79)?,|( \\u00A78(?:,?[0-9]+)*)?$)");
- } catch (Exception e) {
- continue;
- }
- Matcher matcher = pattern.matcher(oLine);
- int matchCount = 0;
- while (matcher.find() && matchCount < 5) {
- if (Utils.cleanColour(matcher.group("enchantName")).startsWith(" ")) continue;
-
- matchCount++;
- int level = -1;
- String levelStr = matcher.group("level");
- if (levelStr == null || levelStr.isEmpty()) continue;
- level = Utils.parseIntOrRomanNumeral(levelStr);
- boolean matches = false;
- if (level > 0) {
- switch (comparator) {
- case ">":
- matches = level > levelToFind;
- break;
- case "=":
- matches = level == levelToFind;
- break;
- case "<":
- matches = level < levelToFind;
- break;
- }
- }
- if (matches) {
- String enchantText = matcher.group("enchantName");
- StringBuilder extraModifiersBuilder = new StringBuilder();
-
- if ((modifierI & GuiEnchantColour.BOLD_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.BOLD);
- }
- if ((modifierI & GuiEnchantColour.ITALIC_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.ITALIC);
- }
- if ((modifierI & GuiEnchantColour.UNDERLINE_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.UNDERLINE);
- }
- if ((modifierI & GuiEnchantColour.OBFUSCATED_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.OBFUSCATED);
- }
- if ((modifierI & GuiEnchantColour.STRIKETHROUGH_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.STRIKETHROUGH);
- }
-
- String extraMods = extraModifiersBuilder.toString();
- if (!colourCode.equals("z")) {
- if (!addedEnchants.contains(enchantText)) {
- int startMatch = matcher.start();
- int endMatch = matcher.end();
- String subString = oLine.substring(startMatch, endMatch);
- String preEnchantText = subString.split(String.valueOf(enchantText.charAt(0)))[0];
-
- line = line.replace(preEnchantText + enchantText,
- "\u00A7" + colourCode + extraMods + enchantText
- );
-
- enchants.add(new EnchantString(
- enchantText,
- preEnchantText,
- extraMods,
- colourCode
- ));
- }
- } else {
- //Chroma
- int startMatch = matcher.start();
- int endMatch = matcher.end();
- String subString = line.substring(startMatch, endMatch);
- int newOffset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(subString);
-
- //split the substring with the first letter found in enchant text allowing to only get the color codes.
- String preEnchantText = subString.split(String.valueOf(enchantText.charAt(0)))[0];
-
- line = line.replace(
- preEnchantText + enchantText,
- Utils.chromaString(enchantText, newOffset / 12f + k, preEnchantText.matches(".*\\u00A7d.*"))
- );
- enchants.add(new EnchantString(
- enchantText,
- preEnchantText,
- extraMods,
- colourCode
- ));
- }
- addedEnchants.add(enchantText);
- }
- }
- }
- if (NotEnoughUpdates.INSTANCE.config.misc.cacheItemEnchant) {
- if (lastItemUuid == null || !Objects.equals(lastItemUuid, currentUuid)) {
- EnchantLine enchantLine = new EnchantLine(oLine, enchants);
- enchantList.add(enchantLine);
- }
- }
- }
-
- if (NotEnoughUpdates.INSTANCE.config.misc.cacheItemEnchant && foundEnchants) {
- //found enchants in the past
- if (k <= lastEnchantIndex) {
- if (Objects.equals(lastItemUuid, currentUuid) && (firstEnchantIndex != -1 && enchantList.size() > k - firstEnchantIndex) && (k - firstEnchantIndex) > 0) {
- //if it has the line, replaces it with the cached line
- EnchantLine enchantLine = enchantList.get(k - firstEnchantIndex);
- if (!enchantLine.isSameAsBefore(line)) {
- resetEnchantCache = true;
- }
-
- line = enchantLine.replaceLine(line, k);
- }
- }
- }
- }
newTooltip.add(line);
@@ -816,7 +529,6 @@ public static class EnchantLine {
}
}
}
- if (thisLineHasEnchants) lastEnchantIndex+=1;
}
pressedShiftLast = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
@@ -833,18 +545,6 @@ public static class EnchantLine {
NotEnoughUpdates.INSTANCE.config.petOverlay.hidePetTooltip) {
event.toolTip.clear();
}
-
-
- if (foundEnchants && currentUuid != null && lastItemUuid != currentUuid) {
- lastItemUuid = currentUuid;//cache is set;
- }
-
- if (resetEnchantCache) {
- lastItemUuid = null;
- enchantList.clear();
- firstEnchantIndex = -1;
- lastEnchantIndex = -1;
- }
}
private void petToolTipXPExtendPetMenu(ItemTooltipEvent event) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantMatcher.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantMatcher.java
new file mode 100644
index 00000000..e8ded18c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantMatcher.java
@@ -0,0 +1,128 @@
+/*
+ * 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.item.enchants;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.miscgui.GuiEnchantColour;
+import io.github.moulberry.notenoughupdates.util.LRUCache;
+import lombok.Value;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.fml.common.Loader;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+@Value
+public class EnchantMatcher {
+ public static final String GROUP_ENCHANT_NAME = "enchantName";
+ public static final String GROUP_LEVEL = "level";
+
+ private final static String romanNumerals =
+ "(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX)";
+ private final static Supplier<String> validColors = Suppliers.memoize(() ->
+ "0123456789abcdefz" + (Loader.isModLoaded("skyblockaddons") ? "Z" : ""));
+
+ public static LRUCache<String, Optional<EnchantMatcher>> fromSaveFormatMemoized =
+ LRUCache.memoize(
+ EnchantMatcher::fromSaveFormat,
+ () -> NotEnoughUpdates.INSTANCE.config.hidden.enchantColours.size() + 1
+ );
+
+ Pattern patternWithLevels;
+ int compareWith;
+ String formatting;
+ char compareUsing;
+
+ /**
+ * Use {@link #fromSaveFormatMemoized} instead.
+ */
+ @Deprecated
+ public static Optional<EnchantMatcher> fromSaveFormat(String saveFormat) {
+ List<String> colourOps = GuiEnchantColour.splitter.splitToList(saveFormat);
+ String enchantName = GuiEnchantColour.getColourOpIndex(colourOps, 0);
+ String comparator = GuiEnchantColour.getColourOpIndex(colourOps, 1);
+ String comparison = GuiEnchantColour.getColourOpIndex(colourOps, 2);
+ String colourCode = GuiEnchantColour.getColourOpIndex(colourOps, 3);
+ String modifier = GuiEnchantColour.getColourOpIndex(colourOps, 4);
+
+ int intModifier = GuiEnchantColour.getIntModifier(modifier);
+
+ if (comparator.length() != 1
+ || colourCode.length() != 1
+ || comparison.isEmpty()
+ || enchantName.isEmpty()) return Optional.empty();
+
+ if (!">=<".contains(comparator)) return Optional.empty();
+ int compareWith;
+ try {
+ compareWith = Integer.parseInt(comparison);
+ } catch (NumberFormatException e) {
+ return Optional.empty();
+ }
+
+ if (!validColors.get().contains(colourCode)) return Optional.empty();
+ Pattern patternWithLevels;
+ try {
+ patternWithLevels = Pattern.compile(
+ "(§b|§9|§([b9l])§d§l)(?<" + GROUP_ENCHANT_NAME + ">" + enchantName + ") " +
+ "(?<" + GROUP_LEVEL + ">\\d+|" + romanNumerals + ")(?:(?:§9)?,|(?: §8(?:,?[0-9]+)*)?$)");
+ } catch (PatternSyntaxException e) {
+ NotEnoughUpdates.LOGGER.warn("Invalid pattern constructed for enchant matching", e);
+ return Optional.empty();
+ }
+
+ String formatting = "§" + colourCode;
+
+ if ((intModifier & GuiEnchantColour.BOLD_MODIFIER) != 0) {
+ formatting += EnumChatFormatting.BOLD;
+ }
+ if ((intModifier & GuiEnchantColour.ITALIC_MODIFIER) != 0) {
+ formatting += EnumChatFormatting.ITALIC;
+ }
+ if ((intModifier & GuiEnchantColour.UNDERLINE_MODIFIER) != 0) {
+ formatting += EnumChatFormatting.UNDERLINE;
+ }
+ if ((intModifier & GuiEnchantColour.OBFUSCATED_MODIFIER) != 0) {
+ formatting += EnumChatFormatting.OBFUSCATED;
+ }
+ if ((intModifier & GuiEnchantColour.STRIKETHROUGH_MODIFIER) != 0) {
+ formatting += EnumChatFormatting.STRIKETHROUGH;
+ }
+
+ return Optional.of(new EnchantMatcher(patternWithLevels, compareWith, formatting, comparator.charAt(0)));
+ }
+
+ public boolean doesLevelMatch(int level) {
+ switch (compareUsing) {
+ case '>':
+ return level > compareWith;
+ case '=':
+ return level == compareWith;
+ case '<':
+ return level < compareWith;
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantStyleCustomizer.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantStyleCustomizer.java
new file mode 100644
index 00000000..47acfa60
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/item/enchants/EnchantStyleCustomizer.java
@@ -0,0 +1,113 @@
+/*
+ * 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.item.enchants;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.LRUCache;
+import io.github.moulberry.notenoughupdates.util.LateBindingChroma;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import lombok.var;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+public class EnchantStyleCustomizer {
+
+ public static EnchantStyleCustomizer INSTANCE = new EnchantStyleCustomizer();
+
+ LRUCache<String, LateBindingChroma> enchantLineCache = LRUCache.memoize(this::replaceEnchantLine, 1000);
+ List<String> lastEnchant = new ArrayList<>();
+
+ public LateBindingChroma replaceEnchantLine(String originalLine) {
+ var line = originalLine;
+ Set<String> alreadyReplacedEnchants = new HashSet<>();
+ for (String enchantMatcherStr : NotEnoughUpdates.INSTANCE.config.hidden.enchantColours) {
+ var enchantMatcherP = EnchantMatcher.fromSaveFormatMemoized.apply(enchantMatcherStr);
+ if (!enchantMatcherP.isPresent()) continue;
+ var enchantMatcher = enchantMatcherP.get();
+ Matcher matcher;
+ var matchIterations = 0;
+ var last = 0;
+ while ((matcher = enchantMatcher.getPatternWithLevels().matcher(line)).find(last) && matchIterations++ < 5) {
+ var enchantName = matcher.group(EnchantMatcher.GROUP_ENCHANT_NAME);
+ var levelText = matcher.group(EnchantMatcher.GROUP_LEVEL);
+ if (enchantName == null || levelText == null
+ || levelText.isEmpty() || enchantName.isEmpty()) continue;
+ String cleanEnchantName = Utils.cleanColour(enchantName);
+ if (cleanEnchantName.startsWith(" ")) {
+ last = matcher.end();
+ continue;
+ }
+
+ var level = Utils.parseIntOrRomanNumeral(levelText);
+ if (!enchantMatcher.doesLevelMatch(level)) {
+ last = matcher.end();
+ continue;
+ }
+
+ if (alreadyReplacedEnchants.contains(cleanEnchantName)) continue;
+ alreadyReplacedEnchants.add(cleanEnchantName);
+
+ var startMatch = matcher.start();
+ var endLevel = matcher.end(EnchantMatcher.GROUP_LEVEL);
+
+ var parsed = line.substring(0, startMatch)
+ + enchantMatcher.getFormatting() + enchantName + " " + levelText;
+ line = parsed + (endLevel >= line.length() ? "" : line.substring(endLevel));
+ last = parsed.length();
+ }
+ }
+ return LateBindingChroma.of(line);
+ }
+
+ public void cacheInvalidate() {
+ enchantLineCache.clearCache();
+ }
+
+ @SubscribeEvent
+ public void onItemTooltip(ItemTooltipEvent event) {
+ var nbt = event.itemStack.getTagCompound();
+ if (nbt == null) return;
+ var extraAttributes = nbt.getCompoundTag("ExtraAttributes");
+ var enchantments = extraAttributes.getCompoundTag("enchantments");
+ var attributes = extraAttributes.getCompoundTag("attributes");
+ enchantments.merge(attributes);
+ if (enchantments.getKeySet().isEmpty()) return;
+ if (!lastEnchant.equals(NotEnoughUpdates.INSTANCE.config.hidden.enchantColours)
+ || !NotEnoughUpdates.INSTANCE.config.misc.cacheItemEnchant) {
+ cacheInvalidate();
+ lastEnchant = new ArrayList<>(NotEnoughUpdates.INSTANCE.config.hidden.enchantColours);
+ }
+ var lineIndex = 0;
+ for (var iterator = event.toolTip.listIterator(); iterator.hasNext(); ) {
+ var nextLine = iterator.next();
+ var replacedLine = enchantLineCache.apply(nextLine).render(lineIndex++);
+ if (!nextLine.equals(replacedLine)) {
+ iterator.set(replacedLine);
+ }
+ }
+ }
+
+}
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 ce8325bb..11ace314 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
@@ -186,7 +186,7 @@ public class Misc {
@Expose
@ConfigOption(
name = "Cache Tooltip Enchants",
- desc = "Caches item enchants in tooltip to only use the neuec config once per item lookup.\nNOTE: It doesn't work on items without a uuid"
+ desc = "Caches item enchants in tooltip to only use the neuec config once per item lookup."
)
@ConfigEditorBoolean
@ConfigAccordionId(id = 1)
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java b/src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java
new file mode 100644
index 00000000..f107d522
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/LRUCache.java
@@ -0,0 +1,63 @@
+/*
+ * 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 java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.IntSupplier;
+
+public interface LRUCache<K, V> extends Function<K, V> {
+
+ static <K, V> LRUCache<K, V> memoize(Function<K, V> mapper, int maxCacheSize) {
+ return memoize(mapper, () -> maxCacheSize);
+ }
+
+ 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) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return this.size() > maxCacheSize.getAsInt();
+ }
+ };
+ Map<K, V> synchronizedCache = Collections.synchronizedMap(cache);
+ return new LRUCache<K, V>() {
+ @Override
+ public void clearCache() {
+ synchronizedCache.clear();
+ }
+
+ @Override
+ public int size() {
+ return synchronizedCache.size();
+ }
+
+ @Override
+ public V apply(K k) {
+ return synchronizedCache.computeIfAbsent(k, mapper);
+ }
+ };
+ }
+
+ int size();
+
+ void clearCache();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/LateBindingChroma.java b/src/main/java/io/github/moulberry/notenoughupdates/util/LateBindingChroma.java
new file mode 100644
index 00000000..ace3afff
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/LateBindingChroma.java
@@ -0,0 +1,103 @@
+/*
+ * 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 lombok.EqualsAndHashCode;
+import lombok.Value;
+import lombok.var;
+import net.minecraft.client.Minecraft;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public abstract class LateBindingChroma {
+ private static final Pattern FORMATTING_CODE = Pattern.compile("§(.)");
+
+ public static LateBindingChroma of(String raw) {
+ if (!raw.contains("§z"))
+ return new LateBindingChroma.WithoutChroma(raw);
+ var matcher = FORMATTING_CODE.matcher(raw);
+ var chunks = new ArrayList<Chunk>();
+ var sb = new StringBuffer();
+ var color = "";
+ var extraFormatting = "";
+ while (matcher.find()) {
+ sb.setLength(0);
+ matcher.appendReplacement(sb, "");
+ chunks.add(new Chunk(color, extraFormatting, sb.toString()));
+ var c = matcher.group(1);
+ if ("lnomk".contains(c)) {
+ extraFormatting += "§" + c;
+ } else {
+ color = c;
+ extraFormatting = "";
+ }
+ }
+ sb.setLength(0);
+ matcher.appendTail(sb);
+ chunks.add(new Chunk(color, extraFormatting, sb.toString()));
+ chunks.removeIf(it -> it.text.isEmpty());
+ return new LateBindingChroma.WithChroma(chunks);
+ }
+
+ public abstract String render(float chromaOffset);
+
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ static class WithoutChroma extends LateBindingChroma {
+ String content;
+
+ @Override
+ public String render(float chromaOffset) {
+ return content;
+ }
+ }
+
+ @Value
+ @EqualsAndHashCode(callSuper = false)
+ static class WithChroma extends LateBindingChroma {
+ List<Chunk> chunks;
+
+ @Override
+ public String render(float offset) {
+ var sb = new StringBuilder();
+ for (Chunk chunk : chunks) {
+ String text;
+ if (chunk.color.equals("z")) {
+ text = Utils.chromaString(chunk.text, offset, chunk.extraFormatting);
+ } else {
+ text = (chunk.color.isEmpty() ? "" : ("§" + chunk.color)) + chunk.extraFormatting + chunk.text;
+ }
+ sb.append(text);
+ offset += Minecraft.getMinecraft().fontRendererObj.getStringWidth(text);
+ }
+ return sb.toString();
+ }
+ }
+
+ @Value
+ public static class Chunk {
+ String color;
+ String extraFormatting;
+ String text;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
index cac6990f..ecc03caf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -301,7 +301,12 @@ public class Utils {
}
public static String chromaString(String str, float offset, boolean bold) {
+ return chromaString(str, offset, bold ? "§l" : "");
+ }
+
+ public static String chromaString(String str, float offset, String extraFormatting) {
str = cleanColour(str);
+ boolean bold = extraFormatting.contains("§l");
long currentTimeMillis = System.currentTimeMillis();
if (startTime == 0) startTime = currentTimeMillis;
@@ -320,7 +325,7 @@ public class Utils {
if (index < 0) index += rainbow.length;
rainbowText.append(rainbow[index]);
- if (bold) rainbowText.append(EnumChatFormatting.BOLD);
+ rainbowText.append(extraFormatting);
rainbowText.append(c);
}
return rainbowText.toString();