From c09c456d72ef95aeddf9c3b93639af8c64552fd1 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Wed, 10 Apr 2024 12:37:49 +0200 Subject: Add tab list tutorial (#1014) Co-authored-by: Lulonaut --- build.gradle.kts | 2 + .../notenoughupdates/listener/ChatListener.java | 7 +- .../loaders/MinionHelperInventoryLoader.java | 8 +- .../mixins/AccessorBooleanState.java | 31 +++ .../mixins/AccessorGlStateManager.java | 30 +++ .../overlays/EquipmentOverlay.java | 5 +- .../notenoughupdates/overlays/MiningOverlay.java | 81 +++---- .../moulberry/notenoughupdates/util/ItemUtils.java | 15 +- .../moulberry/notenoughupdates/util/SBInfo.java | 72 +++--- .../commands/dev/NEUStatsCommand.kt | 7 +- .../miscfeatures/tablisttutorial/TablistAPI.kt | 146 +++++++++++ .../tablisttutorial/TablistTaskQueue.kt | 62 +++++ .../tablisttutorial/TablistTutorial.kt | 268 +++++++++++++++++++++ .../notenoughupdates/util/StateManagerUtils.kt | 36 +++ .../notenoughupdates/util/TabSkillInfoParser.kt | 16 +- src/main/resources/META-INF/accesstransformer.cfg | 2 + .../textures/gui/tablisttutorial/arrow.png | Bin 0 -> 560 bytes src/main/resources/mixins.notenoughupdates.json | 2 + 18 files changed, 693 insertions(+), 97 deletions(-) create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorBooleanState.java create mode 100644 src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGlStateManager.java create mode 100644 src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistAPI.kt create mode 100644 src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTaskQueue.kt create mode 100644 src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTutorial.kt create mode 100644 src/main/kotlin/io/github/moulberry/notenoughupdates/util/StateManagerUtils.kt create mode 100644 src/main/resources/META-INF/accesstransformer.cfg create mode 100644 src/main/resources/assets/notenoughupdates/textures/gui/tablisttutorial/arrow.png diff --git a/build.gradle.kts b/build.gradle.kts index c465df33..5ff7c7ce 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -68,6 +68,7 @@ loom { } } forge { + accessTransformer(file("src/main/resources/META-INF/accesstransformer.cfg")) pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter()) mixinConfig("mixins.notenoughupdates.json") } @@ -215,6 +216,7 @@ tasks.withType(Jar::class) { this["FMLCorePluginContainsFMLMod"] = "true" this["ForceLoadAsMod"] = "true" this["Manifest-Version"] = "1.0" + this["FMLAT"] = "accesstransformer.cfg" } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java index 22d360e5..e68c54c8 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -212,11 +212,8 @@ public class ChatListener { SBInfo.getInstance().setCurrentProfile(unformatted .substring("Your profile was changed to: ".length()) .split(" ")[0].trim()); - } else if (unformatted.startsWith("Player List Info is now disabled!")) { - SBInfo.getInstance().hasNewTab = false; - } else if (unformatted.startsWith("Player List Info is now enabled!")) { - SBInfo.getInstance().hasNewTab = true; } + if (e.message.getFormattedText().equals( EnumChatFormatting.RESET.toString() + EnumChatFormatting.RED + "You haven't unlocked this recipe!" + EnumChatFormatting.RESET)) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperInventoryLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperInventoryLoader.java index c97ddbea..62f291c0 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperInventoryLoader.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperInventoryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 NotEnoughUpdates contributors + * Copyright (C) 2022-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -21,10 +21,10 @@ package io.github.moulberry.notenoughupdates.miscgui.minionhelper.loaders; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.core.util.StringUtils; +import io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial.TablistAPI; import io.github.moulberry.notenoughupdates.miscgui.minionhelper.Minion; import io.github.moulberry.notenoughupdates.miscgui.minionhelper.MinionHelperManager; import io.github.moulberry.notenoughupdates.util.ItemUtils; -import io.github.moulberry.notenoughupdates.util.TabListUtils; import net.minecraft.client.Minecraft; import net.minecraft.inventory.Container; import net.minecraft.inventory.ContainerChest; @@ -95,8 +95,8 @@ public class MinionHelperInventoryLoader { private void checkLocalPelts() { int pelts = -1; - for (String name : TabListUtils.getTabList()) { - Matcher matcher = PATTERN_PELTS.matcher(name); + for (String line : TablistAPI.getOptionalWidgetLines(TablistAPI.WidgetNames.TRAPPER)) { + Matcher matcher = PATTERN_PELTS.matcher(line); if (matcher.matches()) { pelts = Integer.parseInt(matcher.group(1)); break; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorBooleanState.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorBooleanState.java new file mode 100644 index 00000000..a2102487 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorBooleanState.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see . + */ + +package io.github.moulberry.notenoughupdates.mixins; + +import net.minecraft.client.renderer.GlStateManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GlStateManager.BooleanState.class) +public interface AccessorBooleanState { + @Accessor("currentState") + boolean getCurrentState(); + +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGlStateManager.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGlStateManager.java new file mode 100644 index 00000000..2b543c00 --- /dev/null +++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGlStateManager.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see . + */ + +package io.github.moulberry.notenoughupdates.mixins; + +import net.minecraft.client.renderer.GlStateManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(GlStateManager.class) +public interface AccessorGlStateManager { + @Accessor("lightingState") + static GlStateManager.BooleanState getLightingState() {throw new AssertionError();} +} diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java index 3bfb2f47..0d94cd1b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -390,6 +390,9 @@ public class EquipmentOverlay { ItemStack heldItem = Minecraft.getMinecraft().thePlayer.getHeldItem(); List heldItemLore = ItemUtils.getLore(heldItem); + if (heldItemLore.isEmpty()) { + return; + } String itemType = Objects.requireNonNull(StringUtils.substringAfterLast(heldItemLore.get(heldItemLore.size() - 1), " "), "null"); if (!Arrays.asList("NECKLACE", "CLOAK", "BELT", "GLOVES", "BRACELET").contains(itemType)) return; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java index f8019b85..f2d2886d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 NotEnoughUpdates contributors + * Copyright (C) 2022-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -26,11 +26,11 @@ import io.github.moulberry.notenoughupdates.core.util.StringUtils; import io.github.moulberry.notenoughupdates.core.util.lerp.LerpUtils; import io.github.moulberry.notenoughupdates.guifeatures.SkyMallDisplay; import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns; +import io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial.TablistAPI; import io.github.moulberry.notenoughupdates.options.NEUConfig; import io.github.moulberry.notenoughupdates.util.ItemResolutionQuery; import io.github.moulberry.notenoughupdates.util.SBInfo; import io.github.moulberry.notenoughupdates.util.StarCultCalculator; -import io.github.moulberry.notenoughupdates.util.TabListUtils; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiChest; @@ -51,13 +51,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import static io.github.moulberry.notenoughupdates.util.Utils.showOutdatedRepoNotification; -import static net.minecraft.util.EnumChatFormatting.BLUE; -import static net.minecraft.util.EnumChatFormatting.BOLD; import static net.minecraft.util.EnumChatFormatting.DARK_AQUA; import static net.minecraft.util.EnumChatFormatting.GOLD; import static net.minecraft.util.EnumChatFormatting.GREEN; import static net.minecraft.util.EnumChatFormatting.RED; -import static net.minecraft.util.EnumChatFormatting.RESET; import static net.minecraft.util.EnumChatFormatting.YELLOW; public class MiningOverlay extends TextTabOverlay { @@ -239,7 +236,7 @@ public class MiningOverlay extends TextTabOverlay { @Override public void update() { - overlayStrings = null; + overlayStrings = new ArrayList<>(); NEUConfig.HiddenProfileSpecific profileConfig = NotEnoughUpdates.INSTANCE.config.getProfileSpecific(); if (!NotEnoughUpdates.INSTANCE.config.mining.dwarvenOverlay && @@ -257,43 +254,31 @@ public class MiningOverlay extends TextTabOverlay { commissionProgress.clear(); // These strings will be displayed one after the other when the player list is disabled - String mithrilPowder = RED + "[NEU] Failed to get data from your tablist"; - String gemstonePowder = RED + "Please enable player list info in your SkyBlock settings"; + String mithrilPowder = ""; + String gemstonePowder = ""; int forgeInt = 0; - boolean commissions = false; - boolean forges = false; - for (String name : TabListUtils.getTabList()) { - if (name.contains("Mithril Powder:")) { - mithrilPowder = DARK_AQUA + Utils.trimWhitespaceAndFormatCodes(name).replaceAll("\u00a7[f|F|r]", ""); - continue; - } + List powderLines = getTabLinesOrAddWarning(1, TablistAPI.WidgetNames.POWDER); + getTabLinesOrAddWarning(2, TablistAPI.WidgetNames.POWDER); - if (name.contains("Gemstone Powder:")) { - gemstonePowder = DARK_AQUA + Utils.trimWhitespaceAndFormatCodes(name).replaceAll("\u00a7[f|F|r]", ""); - continue; + for (String line : powderLines) { + if (line.contains("Mithril:")) { + mithrilPowder = DARK_AQUA + Utils.trimWhitespaceAndFormatCodes(line).replaceAll("\u00a7[f|F|r]", ""); } - - Matcher forgesMatcher = forgesHeaderPattern.matcher(name); - if (forgesMatcher.matches() && profileConfig != null) { - commissions = false; - forges = true; - continue; + if (line.contains("Gemstone:")) { + gemstonePowder = DARK_AQUA + Utils.trimWhitespaceAndFormatCodes(line).replaceAll("\u00a7[f|F|r]", ""); } + } - // Commissions appear after Forges, start enumerating Commissions instead of Forges - if (name.equals(RESET.toString() + BLUE + BOLD + "Commissions" + RESET) && profileConfig != null) { - commissions = true; - forges = false; - continue; - } + List tabForgeLines = getTabLinesOrAddWarning(3, TablistAPI.WidgetNames.FORGE); + for (String name : tabForgeLines) { String cleanName = StringUtils.cleanColour(name); - if (forges && cleanName.startsWith(" ") && profileConfig != null) { + if (cleanName.startsWith(" ") && profileConfig != null) { char firstChar = cleanName.trim().charAt(0); if (firstChar < '0' || firstChar > '9') { - forges = false; + break; } else { if (name.contains("LOCKED")) { @@ -344,7 +329,13 @@ public class MiningOverlay extends TextTabOverlay { } forgeInt++; } - } else if (commissions && cleanName.startsWith(" ") && profileConfig != null) { + } + } + List tabCommissionLines = getTabLinesOrAddWarning(0, TablistAPI.WidgetNames.COMMISSIONS); + + for (String name : tabCommissionLines) { + String cleanName = StringUtils.cleanColour(name); + if (cleanName.startsWith(" ") && profileConfig != null) { String[] split = cleanName.trim().split(": "); if (split.length == 2) { if (split[1].endsWith("%")) { @@ -358,16 +349,9 @@ public class MiningOverlay extends TextTabOverlay { commissionProgress.put(split[0], 1.0f); } } - } else { - commissions = false; - forges = false; } } - if (!NotEnoughUpdates.INSTANCE.config.mining.dwarvenOverlay) { - return; - } - List commissionsStrings = new ArrayList<>(); for (Map.Entry entry : commissionProgress.entrySet()) { if (entry.getValue() >= 1) { @@ -421,7 +405,6 @@ public class MiningOverlay extends TextTabOverlay { DARK_AQUA + "Pickaxe CD: \u00a7a" + (ItemCooldowns.pickaxeUseCooldownMillisRemaining / 1000) + "s"; } - overlayStrings = new ArrayList<>(); for (int index : NotEnoughUpdates.INSTANCE.config.mining.dwarvenText2) { switch (index) { case 0: @@ -523,6 +506,22 @@ public class MiningOverlay extends TextTabOverlay { if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null; } + private List getTabLinesOrAddWarning(int configIndex, TablistAPI.WidgetNames widgetName) { + List lines; + if (NotEnoughUpdates.INSTANCE.config.mining.dwarvenText2.contains(configIndex) && + NotEnoughUpdates.INSTANCE.config.mining.dwarvenOverlay) { + lines = TablistAPI.getWidgetLinesWithoutNotification(widgetName); + if (lines.isEmpty() && !overlayStrings.contains("§l§4One or more tab widgets missing!")) { + overlayStrings.add("§l§4One or more tab widgets missing!"); + overlayStrings.add("§l§4Enable it in §b/tab§4!"); + } + } else { + lines = TablistAPI.getOptionalWidgetLines(widgetName); + } + + return lines; + } + private String getTipPart(String name) { int settings = NotEnoughUpdates.INSTANCE.config.mining.commissionTaskTips; if (settings == 0) return ""; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java index 3d7f6d40..eb6a5696 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -39,6 +39,7 @@ import net.minecraft.nbt.NBTTagString; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.MathHelper; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; @@ -139,12 +140,12 @@ public class ItemUtils { is.setTagCompound(tagCompound); } - public static List getLore(ItemStack is) { + public static @NotNull List<@NotNull String> getLore(@Nullable ItemStack is) { if (is == null) return new ArrayList<>(); return getLore(is.getTagCompound()); } - public static List getLore(NBTTagCompound tagCompound) { + public static @NotNull List<@NotNull String> getLore(@Nullable NBTTagCompound tagCompound) { if (tagCompound == null) { return Collections.emptyList(); } @@ -156,7 +157,13 @@ public class ItemUtils { return list; } - public static String getDisplayName(NBTTagCompound compound) { + public static @Nullable String getDisplayName(@Nullable ItemStack itemStack) { + if (itemStack == null) + return null; + return getDisplayName(itemStack.getTagCompound()); + } + + public static @Nullable String getDisplayName(@Nullable NBTTagCompound compound) { if (compound == null) return null; String string = compound.getCompoundTag("display").getString("Name"); if (string == null || string.isEmpty()) diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java index ad2a0542..86799147 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 NotEnoughUpdates contributors + * Copyright (C) 2022-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -27,12 +27,12 @@ import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe; import io.github.moulberry.notenoughupdates.events.SidebarChangeEvent; import io.github.moulberry.notenoughupdates.miscfeatures.CookieWarning; import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent; +import io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial.TablistAPI; import io.github.moulberry.notenoughupdates.miscgui.minionhelper.MinionHelperManager; import io.github.moulberry.notenoughupdates.overlays.OverlayManager; import io.github.moulberry.notenoughupdates.overlays.SlayerOverlay; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiChest; -import net.minecraft.client.network.NetworkPlayerInfo; import net.minecraft.init.Blocks; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.Slot; @@ -108,7 +108,6 @@ public class SBInfo { public long unloadedWorld = -1; private JsonObject locraw = null; public boolean isInDungeon = false; - public boolean hasNewTab = false; public enum Gamemode { NORMAL("", ""), IRONMAN("Ironman", "♲"), STRANDED("Stranded", "☀"); @@ -242,7 +241,6 @@ public class SBInfo { joinedWorld = System.currentTimeMillis(); currentlyOpenChestName = ""; lastOpenChestName = ""; - hasNewTab = false; } @SubscribeEvent @@ -307,7 +305,6 @@ public class SBInfo { return lastLocation; } - private static final String profilePrefix = "\u00a7r\u00a7e\u00a7lProfile: \u00a7r\u00a7a"; private static final String skillsPrefix = "\u00a7r\u00a7e\u00a7lSkills: \u00a7r\u00a7a"; private static final String completedFactionQuests = "\u00a7r \u00a7r\u00a7a(?!(Paul|Finnegan|Aatrox|Cole|Diana|Diaz|Foxy|Marina)).*"; @@ -332,40 +329,40 @@ public class SBInfo { updateMayor(); lastMayorUpdate = currentTime; } - try { - for (NetworkPlayerInfo info : Minecraft.getMinecraft().thePlayer.sendQueue.getPlayerInfoMap()) { - String name = Minecraft.getMinecraft().ingameGUI.getTabList().getPlayerName(info); - if (name.startsWith(profilePrefix)) { - String newProfile = Utils.cleanColour(name.substring(profilePrefix.length())); - setCurrentProfile(newProfile); - if (!Objects.equals(currentProfile, newProfile)) { - currentProfile = newProfile; - if (NotEnoughUpdates.INSTANCE.config != null) - if (NotEnoughUpdates.INSTANCE.config.mining.powderGrindingTrackerResetMode == 2) - OverlayManager.powderGrindingOverlay.load(); - } - hasNewTab = true; - } else if (name.startsWith(skillsPrefix)) { - String levelInfo = name.substring(skillsPrefix.length()).trim(); - Matcher matcher = SKILL_LEVEL_PATTERN.matcher(Utils.cleanColour(levelInfo).split(":")[0]); - if (matcher.find()) { - try { - int level = Integer.parseInt(matcher.group(2).trim()); - XPInformation.getInstance().updateLevel(matcher.group(1).toLowerCase().trim(), level); - } catch (Exception ignored) { - } - } - } else if (name.matches(completedFactionQuests) && "crimson_isle".equals(mode)) { - if (completedQuests.isEmpty()) { - completedQuests.add(name); - } else if (!completedQuests.contains(name)) { - completedQuests.add(name); - } + List profileData = TablistAPI.getWidgetLines(TablistAPI.WidgetNames.PROFILE); + if (!profileData.isEmpty()) { + String newProfile = Utils.cleanColour(profileData.get(0)).split(" ")[1]; + if (Character.isLowerCase(newProfile.charAt(0))) + newProfile = new StringBuilder(newProfile).reverse().toString(); + setCurrentProfile(newProfile); + } + // todo convert to api + for (String s : TabListUtils.getTabList()) { + if (s.matches(completedFactionQuests) && "crimson_isle".equals(mode)) { + if (completedQuests.isEmpty()) { + completedQuests.add(s); + } else if (!completedQuests.contains(s)) { + completedQuests.add(s); } } - } catch (Exception e) { - e.printStackTrace(); +// else if (s.startsWith(skillsPrefix)) { +// String levelInfo = s.substring(skillsPrefix.length()).trim(); +// Matcher matcher = SKILL_LEVEL_PATTERN.matcher(Utils.cleanColour(levelInfo).split(":")[0]); +// if (matcher.find()) { +// try { +// int level = Integer.parseInt(matcher.group(2).trim()); +// XPInformation.getInstance().updateLevel(matcher.group(1).toLowerCase().trim(), level); +// } catch (Exception ignored) { +// } +// } +// } } +// for (String line : TablistAPI.getWidgetLines(new TablistTutorial.TabListWidget( +// "ALL", +// TablistAPI.WidgetNames.SKILLS +// ))) { +// +// } try { List lines = SidebarUtil.readSidebarLines(true, false); @@ -481,6 +478,9 @@ public class SBInfo { currentProfile = newProfile; MinionHelperManager.getInstance().onProfileSwitch(); CookieWarning.onProfileSwitch(); + if (NotEnoughUpdates.INSTANCE.config != null) + if (NotEnoughUpdates.INSTANCE.config.mining.powderGrindingTrackerResetMode == 2) + OverlayManager.powderGrindingOverlay.load(); } } } diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/dev/NEUStatsCommand.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/dev/NEUStatsCommand.kt index d5b91b9d..9e9cca14 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/dev/NEUStatsCommand.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/dev/NEUStatsCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 NotEnoughUpdates contributors + * Copyright (C) 2023-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -27,6 +27,7 @@ import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe import io.github.moulberry.notenoughupdates.events.RegisterBrigadierCommandEvent import io.github.moulberry.notenoughupdates.util.DiscordMarkdownBuilder import io.github.moulberry.notenoughupdates.util.SBInfo +import io.github.moulberry.notenoughupdates.util.TabListUtils import io.github.moulberry.notenoughupdates.util.brigadier.reply import io.github.moulberry.notenoughupdates.util.brigadier.thenExecute import io.github.moulberry.notenoughupdates.util.brigadier.thenLiteralExecute @@ -61,6 +62,9 @@ class NEUStatsCommand { .toString() ) }.withHelp("Copy the mod list to your clipboard") + thenLiteralExecute("tablist") { + clipboardAndSendMessage("```\n${TabListUtils.getTabList()}\n```") + }.withHelp("Copy the current tab list to your clipboard") thenLiteralExecute("repo") { clipboardAndSendMessage( DiscordMarkdownBuilder() @@ -173,7 +177,6 @@ class NEUStatsCommand { Loader.instance().indexedModList[NotEnoughUpdates.MODID]!!.displayVersion ) builder.append("SB Profile", SBInfo.getInstance().currentProfile) - builder.append("Has Advanced Tab", if (SBInfo.getInstance().hasNewTab) "TRUE" else "FALSE") .also(::appendRepoStats) } diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistAPI.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistAPI.kt new file mode 100644 index 00000000..5c493108 --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistAPI.kt @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see . + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial + +import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe +import io.github.moulberry.notenoughupdates.util.TabListUtils +import io.github.moulberry.notenoughupdates.util.stripControlCodes +import net.minecraft.client.Minecraft +import net.minecraftforge.event.entity.EntityJoinWorldEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.* + +@NEUAutoSubscribe +object TablistAPI { + + private var lastWorldSwitch = 0L + var lastWidgetEnabled: WidgetNames? = null + + @SubscribeEvent + fun onWorldSwitch(event: EntityJoinWorldEvent) { + if (event.entity == Minecraft.getMinecraft().thePlayer) { + lastWorldSwitch = System.nanoTime() + } + } + + @JvmStatic + fun getWidgetLinesInRegion( + widget: TablistTutorial.TabListWidget, + addToQueue: Boolean, + showNotification: Boolean + ): List { + val regex = widget.widgetName.regex ?: Regex.fromLiteral("${widget.widgetName}:") + val list = mutableListOf() + // If not a single reset is present, the tab list hasn't been initialized yet + var sawReset = false + + for (entry in TabListUtils.getTabList()) { + if (entry.contains("§r")) { + sawReset = true + } + + if (list.isNotEmpty()) { + // New tab section, or empty line indicate a new section + if (entry == "§r §r§3§lInfo§r" || entry == "§r") { + break + } + list.add(entry) + } else if (entry.stripControlCodes().matches(regex)) { + list.add(entry) + } + } + if (addToQueue && + list.isEmpty() && + sawReset && + (System.nanoTime() - lastWorldSwitch > 10_000_000L) && + widget.widgetName != lastWidgetEnabled + ) { + TablistTaskQueue.addToQueue(widget, showNotification) + } + return list + } + + /** + * Attempt to get the lines for this widget. + * Otherwise, add the widget to the tablist queue and show a notification to the user + */ + @JvmStatic + fun getWidgetLines(widgetName: WidgetNames): List { + return getWidgetLinesInRegion( + TablistTutorial.TabListWidget("CURRENT_REGION", widgetName), + addToQueue = true, + showNotification = true + ) + } + + /** + * Attempt to get the lines for this widget. + * Otherwise, add the widget to the tablist queue without showing a notification to the user. + * + * Consider using this if there is a more optimal way of informing the user. + */ + @JvmStatic + fun getWidgetLinesWithoutNotification(widgetName: WidgetNames): List { + return getWidgetLinesInRegion( + TablistTutorial.TabListWidget("CURRENT_REGION", widgetName), + addToQueue = true, + showNotification = false + ) + } + + /** + * Attempt to get the lines for this widget. + * Otherwise, do nothing. + * + * Consider using this if the result is not important, but simply a nice to have. + */ + @JvmStatic + fun getOptionalWidgetLines(widgetName: WidgetNames): List { + return getWidgetLinesInRegion( + TablistTutorial.TabListWidget("CURRENT_REGION", widgetName), + addToQueue = false, + showNotification = false + ) + } + + enum class WidgetNames(val regex: Regex?) { + COMMISSIONS(null), + SKILLS(null), + TRAPPER(null), + FORGE(Regex.fromLiteral("Forges:")), + POWDER(Regex.fromLiteral("Powders:")), + PROFILE(Regex("Profile: ([A-Za-z]+)( .*)?")) + ; + + override fun toString(): String { + return this.name.lowercase().split(" ").joinToString(" ") { str -> + str.replaceFirstChar { + if (it.isLowerCase()) { + it.titlecase( + Locale.ROOT + ) + } else { + it.toString() + } + } + } + } + } +} diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTaskQueue.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTaskQueue.kt new file mode 100644 index 00000000..8cbd27a0 --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTaskQueue.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see . + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial + +import io.github.moulberry.notenoughupdates.util.NotificationHandler + +object TablistTaskQueue { + private val queue = mutableListOf() + + fun addToQueue(task: TablistTutorial.TabListWidget, showNotification: Boolean) { + if (showNotification && !queueContainsElements()) { + NotificationHandler.displayNotification( + listOf( + "§l§4Widget missing", + "§cOne or more tab list widgets, which are required for NEU to function properly, are missing", + "§cOpen the Tablist Widgets settings using", + "§b/tab", + "§cto get some assistance in fixing this problem." + ), + false + ) + } + if (task !in queue) { + // see todo in MiningOverlay.java:377 +// Utils.addChatMessage("Adding $task") + queue.add(task) + } + } + + fun removeFromQueue(task: TablistTutorial.TabListWidget) { + queue.remove(task) + } + + fun queueContainsElements(): Boolean { + return queue.isNotEmpty() + } + + fun getNextQueueItem(): TablistTutorial.TabListWidget? { + return if (!queueContainsElements()) { + null + } else { + queue.removeLast() + } + } +} diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTutorial.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTutorial.kt new file mode 100644 index 00000000..e7299e12 --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTutorial.kt @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see . + */ + +package io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial + +import com.mojang.brigadier.arguments.StringArgumentType.string +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import io.github.moulberry.notenoughupdates.autosubscribe.NEUAutoSubscribe +import io.github.moulberry.notenoughupdates.core.util.StringUtils +import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils +import io.github.moulberry.notenoughupdates.events.RegisterBrigadierCommandEvent +import io.github.moulberry.notenoughupdates.mixins.AccessorGlStateManager +import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer +import io.github.moulberry.notenoughupdates.util.ItemUtils +import io.github.moulberry.notenoughupdates.util.StateManagerUtils +import io.github.moulberry.notenoughupdates.util.brigadier.thenArgument +import io.github.moulberry.notenoughupdates.util.brigadier.thenExecute +import io.github.moulberry.notenoughupdates.util.brigadier.withHelp +import io.github.moulberry.notenoughupdates.util.stripControlCodes +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiChest +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.inventory.ContainerChest +import net.minecraft.inventory.Slot +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.event.GuiScreenEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@NEUAutoSubscribe +object TablistTutorial { + data class TabListWidget( + var regionName: String, + val widgetName: TablistAPI.WidgetNames, + ) + + private object Arrow { + val imageLocation = ResourceLocation("notenoughupdates:textures/gui/tablisttutorial/arrow.png") + val tipXOffset = 16 + val tipYOffset = 64 + val labelXOffset = 58 + val labelYOffset = 19 + val textureSize = 64 + val textScale = 2f + + fun drawBigRedArrow(x: Int, y: Int, label: String) { + val imgX = x - Arrow.tipXOffset + val imgY = y - Arrow.tipYOffset + val textX = imgX + Arrow.labelXOffset + val textY = imgY + Arrow.labelYOffset + + GlStateManager.pushMatrix() + GlStateManager.translate(0f, 0f, 300f) + GlStateManager.color(1f, 1f, 1f, 1f) + Minecraft.getMinecraft().textureManager.bindTexture(imageLocation) + RenderUtils.drawTexturedRect(imgX.toFloat(), imgY.toFloat(), textureSize.toFloat(), textureSize.toFloat()) + GlStateManager.translate(textX.toFloat(), textY.toFloat(), 0F) + GlStateManager.scale(textScale, textScale, 1F) + val fr = Minecraft.getMinecraft().fontRendererObj + fr.drawString(label, 0, -fr.FONT_HEIGHT / 2, -1) + GlStateManager.popMatrix() + } + + fun drawBigRedArrow(gui: GuiContainer, slot: Slot, label: String) { + gui as AccessorGuiContainer + drawBigRedArrow(gui.guiLeft + slot.xDisplayPosition + 9, gui.guiTop + slot.yDisplayPosition, label) + } + } + + var activeTask: TabListWidget? = null + + @SubscribeEvent + fun onGuiPostRender(event: GuiScreenEvent.DrawScreenEvent.Post) { + if (activeTask == null) { + activeTask = TablistTaskQueue.getNextQueueItem() + } + val task = activeTask ?: return + + val gui = event.gui as? GuiChest ?: return + val chestInventory = gui.inventorySlots as ContainerChest + + val name = chestInventory.lowerChestInventory.displayName.unformattedText + + StateManagerUtils.withSavedState(AccessorGlStateManager.getLightingState()) { + GlStateManager.disableLighting() + if (name == "Tablist Widgets") { + drawSelectAreaArrow(gui, chestInventory, task) + } + val regionName = getRegionName(name) + + // Assume the user is capable of clicking on the current region + if (task.regionName == "CURRENT_REGION") { + activeTask!!.regionName = regionName ?: return + } + if (regionName == task.regionName) { + drawEnableEffect(gui, chestInventory, task) + } else if (regionName != null) { + val backSlot = chestInventory.inventorySlots.getOrNull(5 * 9 + 3) + if (backSlot != null) { + Arrow.drawBigRedArrow(gui, backSlot, "Go back!") + } + } + } + } + + data class WidgetStatus( + val widgetName: String, + val enabled: Boolean, + val slot: Slot, + ) + + fun findWidgets(chestInventory: ContainerChest): List { + return chestInventory.inventorySlots.mapNotNull { + val name = ItemUtils.getDisplayName(it.stack)?.let(StringUtils::cleanColour) ?: return@mapNotNull null + if (!name.endsWith(" Widget")) { + return@mapNotNull null + } + val disabled = name.startsWith("✖") + val enabled = name.startsWith("✔") + if (!(enabled || disabled)) { + return@mapNotNull null + } + return@mapNotNull WidgetStatus(name.drop(1).removeSuffix(" Widget").trim(), enabled, it) + } + } + + private fun drawEnableEffect(gui: GuiChest, chestInventory: ContainerChest, task: TabListWidget) { + val widgets = findWidgets(chestInventory) + val widget = widgets.find { it.widgetName == task.widgetName.toString() } + if (widget == null) return + if (widget.enabled) { + drawPriorityClick(gui, chestInventory, widget) + return + } + Arrow.drawBigRedArrow(gui, widget.slot, "Click here!") + } + + /*{ + id: "minecraft:skull", + Count: 1b, + tag: { + overrideMeta: 1b, + HideFlags: 254, + SkullOwner: { + Id: "474a0574-24e5-4949-bf61-f8d06120815e", + hypixelPopulated: 1b, + Properties: { + textures: [{ + Value: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzljODg4MWU0MjkxNWE5ZDI5YmI2MWExNmZiMjZkMDU5OTEzMjA0ZDI2NWRmNWI0MzliM2Q3OTJhY2Q1NiJ9fX0=" + }] + }, + Name: "§474a0574-24e5-4949-bf61-f8d06120815e" + }, + display: { + Lore: ["§7§3⬛ §3§lInfo", "§7§8⬛§f§b§lArea: §7Private Island", "§7§8⬛§f Server: §8mini4C", "§7§8⬛§f Gems: §a0", "§7§8⬛§f Crystals: §d3", "§7§8⬛§f", "§7§8⬛§f§b§lMinions§f: 27§7/§r28", "§7§8⬛§f 7x Ice VII §7[§aACTIVE§7]", "§7§8⬛§f 1x Acacia XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Cave Spider XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Cow XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Creeper X §7[§aACTIVE§7]", "§7§8⬛§f 1x Fishing X §7[§aACTIVE§7]", "§7§8⬛§f 1x Ice XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Iron XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Jungle XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Melon XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Obsidian XI §7[§aACTIVE§7]", "§7§8⬛§f 1x Pig XI §7[§aACTIVE§7]", "§7§8⬛§f ... and 10 more."], + Name: "§aPrivate Island Widgets Preview" + }, + AttributeModifiers: [] + }, + Damage: 3s + }*/ + fun drawPriorityClick(gui: GuiChest, chestInventory: ContainerChest, widget: WidgetStatus) { + val prioritySlot = chestInventory.inventorySlots.getOrNull(13) ?: return + val leftSide = chestInventory.inventory.getOrNull(3).let(ItemUtils::getLore) + val middle = chestInventory.inventory.getOrNull(4).let(ItemUtils::getLore) + val rightSide = chestInventory.inventory.getOrNull(5).let(ItemUtils::getLore) + + val priorityList = chestInventory.inventory.getOrNull(13).let(ItemUtils::getLore) + val allTabListEntries = leftSide + middle + rightSide + val regex = activeTask?.widgetName?.regex ?: Regex.fromLiteral("${widget.widgetName}:") + if (allTabListEntries.any { it.replace("⬛", "").stripControlCodes().matches(regex) }) { + TablistAPI.lastWidgetEnabled = activeTask!!.widgetName + activeTask = TablistTaskQueue.getNextQueueItem() +// Utils.addChatMessage("Success! You enabled ${widget.widgetName}!") + return + } + val editingIndex = priorityList.indexOfFirst { it.contains("EDITING") } + val widgetPriorityIndex = priorityList.indexOfFirst { it.contains("${widget.widgetName} Widget") } + if (editingIndex < 0 || widgetPriorityIndex < 0) { + return + } + if (editingIndex == widgetPriorityIndex) { + Arrow.drawBigRedArrow(gui, prioritySlot, "Shift Right Click") + } else if (editingIndex < widgetPriorityIndex) { + Arrow.drawBigRedArrow(gui, prioritySlot, "Left Click") + } else { + Arrow.drawBigRedArrow(gui, prioritySlot, "Right Click") + } + } + + fun getRegionName(label: String): String? { + if (!label.startsWith("Widgets")) return null + if (label == "Private Islands") return "Private Island" + return label.removePrefix("Widgets ").removePrefix("in ").removePrefix("on ") + .removePrefix("the ") + } + + private fun drawSelectAreaArrow(gui: GuiChest, inventory: ContainerChest, task: TabListWidget) { + var regionName = task.regionName + if (regionName == "CURRENT_REGION") { + val infoSlot = inventory.inventory.getOrNull(4).let(ItemUtils::getLore) + if (infoSlot.isEmpty()) { + return + } + val lastLine = infoSlot.last().stripControlCodes() + val pattern = Regex("Click to edit (?[\\w\\s]+) settings!") + + val result = pattern.matchEntire(lastLine) ?: return + regionName = result.groups["area"]?.value!! + activeTask!!.regionName = regionName + } + + val regionSlot = inventory.inventorySlots.find { + val name = ItemUtils.getDisplayName(it.stack)?.let(StringUtils::cleanColour) ?: "" + getRegionName(name) == regionName + } ?: return + Arrow.drawBigRedArrow(gui, regionSlot, "§cClick here!") + } + + @SubscribeEvent + fun onCommands(event: RegisterBrigadierCommandEvent) { + event.command("neutesttablisttutorial") { + thenArgument("region", string()) { region -> + thenArgument("widget", string()) { widget -> + thenExecute { + TablistTaskQueue.addToQueue( + TabListWidget( + "Dwarven Mines", + TablistAPI.WidgetNames.COMMISSIONS, + ), + true + ) + NotEnoughUpdates.INSTANCE.sendChatMessage("/tab") + } + }.withHelp("Test command for showing a tab list tutorial") + } + } + + event.command("neutesttablistapi") { + thenExecute { + TablistAPI.getWidgetLinesInRegion(TabListWidget("CURRENT_REGION", TablistAPI.WidgetNames.SKILLS), + addToQueue = true, + showNotification = true + ) + .forEach { println(it) } +// println("SEP") +// TablistAPI.getWidgetLines(TabListWidget("Dwarven Mines", TablistAPI.WidgetNames.FORGE)) +// .forEach { println(it) } + } + } + } +} diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/StateManagerUtils.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/StateManagerUtils.kt new file mode 100644 index 00000000..a7e50fda --- /dev/null +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/StateManagerUtils.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 NotEnoughUpdates contributors + * + * This file is part of NotEnoughUpdates. + * + * NotEnoughUpdates is free software: you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * NotEnoughUpdates is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with NotEnoughUpdates. If not, see . + */ + +package io.github.moulberry.notenoughupdates.util + +import io.github.moulberry.notenoughupdates.mixins.AccessorBooleanState +import net.minecraft.client.renderer.GlStateManager + +object StateManagerUtils { + fun readState(state: GlStateManager.BooleanState): Boolean { + state as AccessorBooleanState + return state.currentState + } + + inline fun withSavedState(state: GlStateManager.BooleanState, block: () -> Unit) { + val savedState = readState(state) + block() + state.setState(savedState) + } +} diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt index b4bfdf28..0c3e1901 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 NotEnoughUpdates contributors + * Copyright (C) 2023-2024 NotEnoughUpdates contributors * * This file is part of NotEnoughUpdates. * @@ -20,15 +20,17 @@ package io.github.moulberry.notenoughupdates.util import com.google.gson.JsonArray +import io.github.moulberry.notenoughupdates.NotEnoughUpdates +import io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial.TablistAPI import net.minecraft.util.EnumChatFormatting import java.util.regex.Pattern import kotlin.math.abs object TabSkillInfoParser { private val skillTabPattern: Pattern = - Pattern.compile("^§r§e§lSkills: §r§a(?\\w+) (?\\d+): §r§3(?.+)%§r\$") + Pattern.compile("^§r (?\\w+) (?\\d+): §r§a(?.+)%§r\$") private val maxSkillTabPattern: Pattern = - Pattern.compile("^§r§e§lSkills: §r§a(?\\w+) (?\\d+): §r§c§lMAX§r\$") + Pattern.compile("^§r (?\\w+) (?\\d+): §r§c§lMAX§r\$") private var sentErrorOnce = false private fun calculateLevelXp(levelingArray: JsonArray, level: Int): Double { @@ -58,12 +60,18 @@ object TabSkillInfoParser { @JvmStatic fun parseSkillInfo() { + if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) { + return + } + if (Constants.LEVELING == null) { sendError("${EnumChatFormatting.RED}[NEU] There is an error with your repo, please report this in the discord at ${EnumChatFormatting.AQUA}discord.gg/moulberry") return } - for (s in TabListUtils.getTabList()) { + for (s in TablistAPI.getOptionalWidgetLines( + TablistAPI.WidgetNames.SKILLS + )) { val matcher = skillTabPattern.matcher(s) val maxLevelMatcher = maxSkillTabPattern.matcher(s) if (matcher.matches()) { diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..9b2d5dd9 --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,2 @@ + +public net.minecraft.client.renderer.GlStateManager$BooleanState diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/tablisttutorial/arrow.png b/src/main/resources/assets/notenoughupdates/textures/gui/tablisttutorial/arrow.png new file mode 100644 index 00000000..c93b8be0 Binary files /dev/null and b/src/main/resources/assets/notenoughupdates/textures/gui/tablisttutorial/arrow.png differ diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json index b72c1ba4..fab5374d 100644 --- a/src/main/resources/mixins.notenoughupdates.json +++ b/src/main/resources/mixins.notenoughupdates.json @@ -5,9 +5,11 @@ "plugin": "io.github.moulberry.notenoughupdates.envcheck.NEUMixinConfigPlugin", "compatibilityLevel": "JAVA_8", "mixins": [ + "AccessorBooleanState", "AccessorCommandHandler", "AccessorEntityAgeable", "AccessorEntityArmorStand", + "AccessorGlStateManager", "AccessorGuiPlayerTabOverlay", "MixinAbstractClientPlayer", "MixinContainer", -- cgit