aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-04-10 12:37:49 +0200
committerGitHub <noreply@github.com>2024-04-10 12:37:49 +0200
commitc09c456d72ef95aeddf9c3b93639af8c64552fd1 (patch)
tree319d83484ffd6b92f83b65843d0fcdae680adc2a
parentb04290ede8420e8ef9b56f2c8a9252224b8f1d2d (diff)
downloadNotEnoughUpdates-c09c456d72ef95aeddf9c3b93639af8c64552fd1.tar.gz
NotEnoughUpdates-c09c456d72ef95aeddf9c3b93639af8c64552fd1.tar.bz2
NotEnoughUpdates-c09c456d72ef95aeddf9c3b93639af8c64552fd1.zip
Add tab list tutorial (#1014)
Co-authored-by: Lulonaut <lulonaut@lulonaut.tech>
-rw-r--r--build.gradle.kts2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java7
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/minionhelper/loaders/MinionHelperInventoryLoader.java8
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorBooleanState.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGlStateManager.java30
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java81
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java72
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/commands/dev/NEUStatsCommand.kt7
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistAPI.kt146
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTaskQueue.kt62
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/miscfeatures/tablisttutorial/TablistTutorial.kt268
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/StateManagerUtils.kt36
-rw-r--r--src/main/kotlin/io/github/moulberry/notenoughupdates/util/TabSkillInfoParser.kt16
-rw-r--r--src/main/resources/META-INF/accesstransformer.cfg2
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/tablisttutorial/arrow.pngbin0 -> 560 bytes
-rw-r--r--src/main/resources/mixins.notenoughupdates.json2
18 files changed, 693 insertions, 97 deletions
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 <https://www.gnu.org/licenses/>.
+ */
+
+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 <https://www.gnu.org/licenses/>.
+ */
+
+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<String> 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<String> 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<String> 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<String> 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<String> commissionsStrings = new ArrayList<>();
for (Map.Entry<String, Float> 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<String> getTabLinesOrAddWarning(int configIndex, TablistAPI.WidgetNames widgetName) {
+ List<String> 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<String> 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<String> 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<String> 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<String> 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 <https://www.gnu.org/licenses/>.
+ */
+
+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<String> {
+ val regex = widget.widgetName.regex ?: Regex.fromLiteral("${widget.widgetName}:")
+ val list = mutableListOf<String>()
+ // 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<String> {
+ 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<String> {
+ 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<String> {
+ 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 <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.tablisttutorial
+
+import io.github.moulberry.notenoughupdates.util.NotificationHandler
+
+object TablistTaskQueue {
+ private val queue = mutableListOf<TablistTutorial.TabListWidget>()
+
+ 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 <https://www.gnu.org/licenses/>.
+ */
+
+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<WidgetStatus> {
+ 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 (?<area>[\\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 <https://www.gnu.org/licenses/>.
+ */
+
+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(?<type>\\w+) (?<level>\\d+): §r§3(?<progress>.+)%§r\$")
+ Pattern.compile("^§r (?<type>\\w+) (?<level>\\d+): §r§a(?<progress>.+)%§r\$")
private val maxSkillTabPattern: Pattern =
- Pattern.compile("^§r§e§lSkills: §r§a(?<type>\\w+) (?<level>\\d+): §r§c§lMAX§r\$")
+ Pattern.compile("^§r (?<type>\\w+) (?<level>\\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
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/tablisttutorial/arrow.png
Binary files 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",