aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java1
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java4
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java24
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java5
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java83
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Location.java116
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/Utils.java80
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json2
10 files changed, 287 insertions, 48 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
index 033a919d..5bc98894 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/Kuudra.java
@@ -10,7 +10,6 @@ import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
public class Kuudra {
- public static final String LOCATION = "kuudra";
static KuudraPhase phase = KuudraPhase.OTHER;
public static void init() {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java
index 32f0b7e3..a207ddc7 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java
@@ -563,7 +563,9 @@ public class DungeonManager {
if (room != null && currentRoom != room) {
if (currentRoom != null && room.getType() == Room.Type.FAIRY) {
currentRoom.nextRoom = room;
- room.keyFound = currentRoom.keyFound;
+ if (currentRoom.keyFound) {
+ room.keyFound = true;
+ }
}
currentRoom = room;
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
index b12bba62..8e0073f7 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java
@@ -3,12 +3,12 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets;
import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
-import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.MapColor;
import net.minecraft.item.map.MapIcon;
import net.minecraft.item.map.MapState;
import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
@@ -286,14 +286,13 @@ public class DungeonMapUtils {
}
private static boolean hasWitherOrBloodDoor(World world, Vector2ic pos, BlockPos.Mutable doorPos) {
- return isWitherOrBloodDoor(world, doorPos.set(pos.x() - 2, 69, pos.y() + 14)) ||
- isWitherOrBloodDoor(world, doorPos.set(pos.x() + 14, 69, pos.y() - 2)) ||
- isWitherOrBloodDoor(world, doorPos.set(pos.x() + 14, 69, pos.y() + 30)) ||
- isWitherOrBloodDoor(world, doorPos.set(pos.x() + 30, 69, pos.y() + 14));
+ return isWitherOrBloodDoor(world, doorPos.set(pos.x() + 1, 72, pos.y() + 17)) ||
+ isWitherOrBloodDoor(world, doorPos.set(pos.x() + 17, 72, pos.y() + 1)) ||
+ isWitherOrBloodDoor(world, doorPos.set(pos.x() + 17, 72, pos.y() + 33)) ||
+ isWitherOrBloodDoor(world, doorPos.set(pos.x() + 33, 72, pos.y() + 17));
}
- private static boolean isWitherOrBloodDoor(World world, BlockPos pos) {
- BlockState state = world.getBlockState(pos);
- return state.isOf(Blocks.COAL_BLOCK) || state.isOf(Blocks.RED_TERRACOTTA);
+ private static boolean isWitherOrBloodDoor(World world, BlockPos.Mutable pos) {
+ return world.getStatesInBox(Box.enclosing(pos, pos.move(-3, -3, -3))).allMatch(state -> state.isOf(Blocks.COAL_BLOCK) || state.isOf(Blocks.RED_TERRACOTTA));
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
index 19f2e6fd..d5be7eee 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/ItemTooltip.java
@@ -140,15 +140,37 @@ public class ItemTooltip {
}
}
+ final Map<Integer, String> itemTierFloors = new HashMap<>() {{
+ put(1, "F1");
+ put(2, "F2");
+ put(3, "F3");
+ put(4, "F4/M1");
+ put(5, "F5/M2");
+ put(6, "F6/M3");
+ put(7, "F7/M4");
+ put(8, "M5");
+ put(9, "M6");
+ put(10, "M7");
+ }};
+
if (SkyblockerConfigManager.get().general.dungeonQuality) {
NbtCompound ea = ItemUtils.getExtraAttributes(stack);
if (ea != null && ea.contains("baseStatBoostPercentage")) {
int baseStatBoostPercentage = ea.getInt("baseStatBoostPercentage");
- if (baseStatBoostPercentage == 50) {
+ boolean maxQuality = baseStatBoostPercentage == 50;
+ if (maxQuality) {
lines.add(Text.literal(String.format("%-17s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.RED).formatted(Formatting.BOLD));
} else {
lines.add(Text.literal(String.format("%-21s", "Item Quality:") + baseStatBoostPercentage + "/50").formatted(Formatting.BLUE));
}
+ if (ea.contains("item_tier")) { // sometimes it just isn't here?
+ int itemTier = ea.getInt("item_tier");
+ if (maxQuality) {
+ lines.add(Text.literal(String.format("%-17s", "Floor Tier:") + itemTier + " (" + itemTierFloors.get(itemTier) + ")").formatted(Formatting.RED).formatted(Formatting.BOLD));
+ } else {
+ lines.add(Text.literal(String.format("%-21s", "Floor Tier:") + itemTier + " (" + itemTierFloors.get(itemTier) + ")").formatted(Formatting.BLUE));
+ }
+ }
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java
index 02b694b6..7413e06f 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/TheRift.java
@@ -8,11 +8,6 @@ import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
public class TheRift {
- /**
- * @see de.hysky.skyblocker.utils.Utils#isInTheRift() Utils#isInTheRift().
- */
- public static final String LOCATION = "rift";
-
public static void init() {
WorldRenderEvents.AFTER_TRANSLUCENT.register(MirrorverseWaypoints::render);
WorldRenderEvents.AFTER_TRANSLUCENT.register(EffigyWaypoints::render);
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java
index 5f0d2c3c..e37da755 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/Widget.java
@@ -67,6 +67,11 @@ public abstract class Widget {
this.addComponent(new IcoTextComponent(ico, txt));
}
+ public final void addSimpleIcoText(ItemStack ico, String string, Formatting fmt, String content) {
+ Text txt = Widget.simpleEntryText(content, string, fmt);
+ this.addComponent(new IcoTextComponent(ico, txt));
+ }
+
/**
* Calculate the size of this widget.
* <b>Must be called before returning from the widget constructor and after all
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java
index 1d11c2a6..fe23f19a 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/hud/HudPowderWidget.java
@@ -1,17 +1,47 @@
package de.hysky.skyblocker.skyblock.tabhud.widget.hud;
+import de.hysky.skyblocker.skyblock.dwarven.DwarvenHud;
import de.hysky.skyblocker.skyblock.tabhud.util.Ico;
import de.hysky.skyblocker.skyblock.tabhud.widget.Widget;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
// this widget shows the status of the king's commissions.
// (dwarven mines and crystal hollows)
// USE ONLY WITH THE DWARVEN HUD!
public class HudPowderWidget extends Widget {
+ /**
+ * American number format instance
+ */
+ private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);
+ /**
+ * current value of Mithril Powder
+ */
+ private static int mithrilPowder = 0;
+ /**
+ * current value of Gemstone Powder
+ */
+ private static int gemstonePowder = 0;
+ /**
+ * the difference between the previous and current value of Mithril Powder
+ */
+ private static int mithrilPowderDiff = 0;
+ /**
+ * the difference between the previous and current value of Gemstone Powder
+ */
+ private static int gemstonePowderDiff = 0;
+ /**
+ * The initial value of the timer for the difference update delay countdown.
+ */
+ private static long startTime = System.currentTimeMillis();
+
private static final MutableText TITLE = Text.literal("Powders").formatted(Formatting.DARK_AQUA,
Formatting.BOLD);
@@ -30,11 +60,60 @@ public class HudPowderWidget extends Widget {
super(TITLE, Formatting.DARK_AQUA.getColorValue());
}
+ /**
+ * Converts a string with a number and commas between digits to an integer value.
+ *
+ * @param str a string with a number and commas between digits
+ * @return integer value
+ */
+ private static int parsePowder(String str) {
+ try {
+ return NUMBER_FORMAT.parse(str).intValue();
+ } catch (ParseException e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Converts Powder and difference values to a string and adds commas to the digits of the numbers.
+ *
+ * @param powder the value of Mithril or Gemstone Powder
+ * @param diff the difference between the previous and current value of Mithril or Gemstone Powder
+ * @return formatted string
+ */
+ private static String formatPowderString(int powder, int diff) {
+ if (diff == 0) return NUMBER_FORMAT.format(powder);
+ return NUMBER_FORMAT.format(powder) + (diff > 0 ? " (+" : " (") + NUMBER_FORMAT.format(diff) + ")";
+ }
+
+ /**
+ * Updates Powders and difference values when Powder values change or every 2 seconds.
+ */
+ private static void updatePowders() {
+ long elapsedTime = System.currentTimeMillis() - startTime;
+
+ int newMithrilPowder = parsePowder(DwarvenHud.mithrilPowder);
+ int newGemstonePowder = parsePowder(DwarvenHud.gemStonePowder);
+
+ if (newMithrilPowder != mithrilPowder || newGemstonePowder != gemstonePowder || elapsedTime > 2000) {
+ startTime = System.currentTimeMillis();
+
+ mithrilPowderDiff = newMithrilPowder - mithrilPowder;
+ gemstonePowderDiff = newGemstonePowder - gemstonePowder;
+
+ mithrilPowder = newMithrilPowder;
+ gemstonePowder = newGemstonePowder;
+ }
+ }
@Override
public void updateContent() {
- this.addSimpleIcoText(Ico.MITHRIL, "Mithril:", Formatting.AQUA, 46);
- this.addSimpleIcoText(Ico.AMETHYST_SHARD, "Gemstone:", Formatting.DARK_PURPLE, 47);
+ updatePowders();
+ String mithrilPowderString = formatPowderString(mithrilPowder, mithrilPowderDiff);
+ String gemstonePowderString = formatPowderString(gemstonePowder, gemstonePowderDiff);
+
+ this.addSimpleIcoText(Ico.MITHRIL, "Mithril: ", Formatting.AQUA, mithrilPowderString);
+ this.addSimpleIcoText(Ico.AMETHYST_SHARD, "Gemstone: ", Formatting.DARK_PURPLE, gemstonePowderString);
}
}
diff --git a/src/main/java/de/hysky/skyblocker/utils/Location.java b/src/main/java/de/hysky/skyblocker/utils/Location.java
new file mode 100644
index 00000000..bd2773fd
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/Location.java
@@ -0,0 +1,116 @@
+package de.hysky.skyblocker.utils;
+
+import java.util.Arrays;
+
+/**
+ * All Skyblock locations
+ */
+public enum Location {
+ /**
+ * mode: dynamic
+ */
+ PRIVATE_ISLAND("dynamic"),
+ /**
+ * mode: garden
+ */
+ GARDEN("garden"),
+ /**
+ * mode: hub
+ */
+ HUB("hub"),
+ /**
+ * mode: farming_1
+ */
+ THE_FARMING_ISLAND("farming_1"),
+ /**
+ * mode: foraging_1
+ */
+ THE_PARK("foraging_1"),
+ /**
+ * mode: combat_1
+ */
+ SPIDERS_DEN("combat_1"),
+ /**
+ * mode: combat_2
+ */
+ BLAZING_FORTRESS("combat_2"),
+ /**
+ * mode: combat_3
+ */
+ THE_END("combat_3"),
+ /**
+ * mode: crimson_isle
+ */
+ CRIMSON_ISLE("crimson_isle"),
+ /**
+ * mode: mining_1
+ */
+ GOLD_MINE("mining_1"),
+ /**
+ * mode: mining_2
+ */
+ DEEP_CAVERNS("mining_2"),
+ /**
+ * mode: mining_3
+ */
+ DWARVEN_MINES("mining_3"),
+ /**
+ * mode: dungeon_hub
+ */
+ DUNGEON_HUB("dungeon_hub"),
+ /**
+ * mode: winter
+ */
+ WINTER_ISLAND("winter"),
+ /**
+ * mode: rift
+ */
+ THE_RIFT("rift"),
+ /**
+ * mode: dark_auction
+ */
+ DARK_AUCTION("dark_auction"),
+ /**
+ * mode: crystal_hollows
+ */
+ CRYSTAL_HOLLOWS("crystal_hollows"),
+ /**
+ * mode: dungeon
+ */
+ DUNGEON("dungeon"),
+ /**
+ * mode: kuudra
+ */
+ KUUDRAS_HOLLOW("kuudra"),
+ /**
+ * Unknown Skyblock location
+ */
+ UNKNOWN("unknown");
+
+ /**
+ * location id from <a href="https://api.hypixel.net/v2/resources/games">Hypixel API</a>
+ */
+ private final String id;
+
+ /**
+ * @param id location id from <a href="https://api.hypixel.net/v2/resources/games">Hypixel API</a>
+ */
+ Location(String id) {
+ this.id = id;
+ }
+
+ /**
+ * @return location id
+ */
+ public String id() {
+ return this.id;
+ }
+
+ /**
+ * @param id location id from <a href="https://api.hypixel.net/v2/resources/games">Hypixel API</a>
+ * @return location object
+ */
+ public static Location from(String id) {
+ return Arrays.stream(Location.values()).filter(loc -> id.equals(loc.id())).findFirst().orElse(UNKNOWN);
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java
index cd739a0c..08d0b167 100644
--- a/src/main/java/de/hysky/skyblocker/utils/Utils.java
+++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java
@@ -3,10 +3,8 @@ package de.hysky.skyblocker.utils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import de.hysky.skyblocker.events.SkyblockEvents;
-import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra;
import de.hysky.skyblocker.skyblock.item.MuseumItemCache;
import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip;
-import de.hysky.skyblocker.skyblock.rift.TheRift;
import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
import de.hysky.skyblocker.utils.scheduler.Scheduler;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
@@ -37,15 +35,17 @@ import java.util.concurrent.CompletableFuture;
public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
private static final String ALTERNATE_HYPIXEL_ADDRESS = System.getProperty("skyblocker.alternateHypixelAddress", "");
- private static final String DUNGEONS_LOCATION = "dungeon";
- private static final String CRYSTAL_HOLLOWS_LOCATION = "crystal_hollows";
- private static final String DWARVEN_MINES_LOCATION = "mining_3";
private static final String PROFILE_PREFIX = "Profile: ";
private static boolean isOnHypixel = false;
private static boolean isOnSkyblock = false;
private static boolean isInjected = false;
/**
+ * Current Skyblock location (from /locraw)
+ */
+ @NotNull
+ private static Location location = Location.UNKNOWN;
+ /**
* The profile name parsed from the player list.
*/
@NotNull
@@ -88,31 +88,30 @@ public class Utils {
}
public static boolean isInDungeons() {
- return getLocationRaw().equals(DUNGEONS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment();
+ return location == Location.DUNGEON || FabricLoader.getInstance().isDevelopmentEnvironment();
}
public static boolean isInCrystalHollows() {
- return getLocationRaw().equals(CRYSTAL_HOLLOWS_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment();
+ return location == Location.CRYSTAL_HOLLOWS || FabricLoader.getInstance().isDevelopmentEnvironment();
}
public static boolean isInDwarvenMines() {
- return getLocationRaw().equals(DWARVEN_MINES_LOCATION) || FabricLoader.getInstance().isDevelopmentEnvironment();
+ return location == Location.DWARVEN_MINES || FabricLoader.getInstance().isDevelopmentEnvironment();
}
public static boolean isInTheRift() {
- return getLocationRaw().equals(TheRift.LOCATION);
+ return location == Location.THE_RIFT;
}
/**
* @return if the player is in the end island
*/
public static boolean isInTheEnd() {
- // /locraw returns "combat_3" when in The End
- return getLocationRaw().equals("combat_3");
+ return location == Location.THE_END;
}
public static boolean isInKuudra() {
- return getLocationRaw().equals(Kuudra.LOCATION);
+ return location == Location.KUUDRAS_HOLLOW;
}
public static boolean isInjected() {
@@ -133,6 +132,14 @@ public class Utils {
}
/**
+ * @return the location parsed from /locraw.
+ */
+ @NotNull
+ public static Location getLocation() {
+ return location;
+ }
+
+ /**
* @return the server parsed from /locraw.
*/
@NotNull
@@ -376,31 +383,45 @@ public class Utils {
}
/**
+ * Parses /locraw chat message and updates {@link #server}, {@link #gameType}, {@link #locationRaw}, {@link #map}
+ * and {@link #location}
+ *
+ * @param message json message from chat
+ */
+ private static void parseLocRaw(String message) {
+ JsonObject locRaw = JsonParser.parseString(message).getAsJsonObject();
+
+ if (locRaw.has("server")) {
+ server = locRaw.get("server").getAsString();
+ }
+ if (locRaw.has("gameType")) {
+ gameType = locRaw.get("gameType").getAsString();
+ }
+ if (locRaw.has("mode")) {
+ locationRaw = locRaw.get("mode").getAsString();
+ location = Location.from(locationRaw);
+ } else {
+ location = Location.UNKNOWN;
+ }
+ if (locRaw.has("map")) {
+ map = locRaw.get("map").getAsString();
+ }
+ }
+
+ /**
* Parses the /locraw reply from the server and updates the player's profile id
*
* @return not display the message in chat if the command is sent by the mod
*/
public static boolean onChatMessage(Text text, boolean overlay) {
String message = text.getString();
- if (message.startsWith("{\"server\":") && message.endsWith("}")) {
- JsonObject locRaw = JsonParser.parseString(message).getAsJsonObject();
- if (locRaw.has("server")) {
- server = locRaw.get("server").getAsString();
- if (locRaw.has("gameType")) {
- gameType = locRaw.get("gameType").getAsString();
- }
- if (locRaw.has("mode")) {
- locationRaw = locRaw.get("mode").getAsString();
- }
- if (locRaw.has("map")) {
- map = locRaw.get("map").getAsString();
- }
- boolean shouldFilter = !sentLocRaw;
- sentLocRaw = false;
+ if (message.startsWith("{\"server\":") && message.endsWith("}")) {
+ parseLocRaw(message);
+ boolean shouldFilter = !sentLocRaw;
+ sentLocRaw = false;
- return shouldFilter;
- }
+ return shouldFilter;
}
if (isOnSkyblock && message.startsWith("Profile ID: ")) {
@@ -419,6 +440,7 @@ public class Utils {
gameType = "";
locationRaw = "";
map = "";
+ location = Location.UNKNOWN;
}
private static void tickMayorCache(boolean refresh) {
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index be5921ce..3c6c6349 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -89,7 +89,7 @@
"text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip": "Enable Exotic Tooltip",
"text.autoconfig.skyblocker.option.general.itemTooltip.enableExoticTooltip.@Tooltip": "Displays the type of exotic below the item's name if an armor piece is exotic.",
"text.autoconfig.skyblocker.option.general.dungeonQuality": "Dungeon Quality",
- "text.autoconfig.skyblocker.option.general.dungeonQuality.@Tooltip": "Displays quality of dungeon drops from mobs",
+ "text.autoconfig.skyblocker.option.general.dungeonQuality.@Tooltip": "Displays quality and tier of dungeon drops from mobs.\n\n\nReminder:\nTier 1-3 dropped from F1-F3\nTier 4-7 dropped from F4-F7 or M1-M4\nTier 8-10 are dropped only from M5-M7",
"text.autoconfig.skyblocker.option.general.itemInfoDisplay": "Item Info Display",
"text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo": "Attribute Shard Info",
"text.autoconfig.skyblocker.option.general.itemInfoDisplay.attributeShardInfo.@Tooltip": "Displays the attribute's level as the stack count and the initials of the attribute's name.",