aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon
diff options
context:
space:
mode:
authorAaron <51387595+AzureAaron@users.noreply.github.com>2023-09-11 02:24:37 -0400
committerAaron <51387595+AzureAaron@users.noreply.github.com>2023-09-11 02:25:19 -0400
commit42c7732864cd28873dceaab27a7a65a71ed109f0 (patch)
tree6012959fa1c2e9ee14d972a89cbddba1232b0925 /src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon
parentcddd32a81916bffa67a3de0e5754c8068fc2d56e (diff)
downloadSkyblocker-42c7732864cd28873dceaab27a7a65a71ed109f0.tar.gz
Skyblocker-42c7732864cd28873dceaab27a7a65a71ed109f0.tar.bz2
Skyblocker-42c7732864cd28873dceaab27a7a65a71ed109f0.zip
Dungeon Chest Profit Calculator!
Diffstat (limited to 'src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon')
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonChestProfit.java171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonChestProfit.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonChestProfit.java
new file mode 100644
index 00000000..33521ae2
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonChestProfit.java
@@ -0,0 +1,171 @@
+package me.xmrvizzy.skyblocker.skyblock.dungeon;
+
+import java.text.DecimalFormat;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.JsonObject;
+
+import it.unimi.dsi.fastutil.ints.IntBooleanPair;
+import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
+import me.xmrvizzy.skyblocker.skyblock.item.PriceInfoTooltip;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.item.TooltipContext;
+import net.minecraft.item.ItemStack;
+import net.minecraft.screen.GenericContainerScreenHandler;
+import net.minecraft.screen.slot.Slot;
+import net.minecraft.text.MutableText;
+import net.minecraft.text.Style;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+
+public class DungeonChestProfit {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DungeonChestProfit.class);
+ private static final Pattern ESSENCE_PATTERN = Pattern.compile("(?<type>[A-Za-z]+) Essence x(?<amount>[0-9]+)");
+ private static final DecimalFormat FORMATTER = new DecimalFormat("#,###");
+ private static final Style GRAY = Style.EMPTY.withColor(Formatting.GRAY);
+ private static final Style GOLD = Style.EMPTY.withColor(0xd4a72c);
+ private static final Style DARK_GREEN = Style.EMPTY.withColor(Formatting.DARK_GREEN);
+ private static final Style DARK_RED = Style.EMPTY.withColor(Formatting.DARK_RED);
+
+ public static Text getChestProfit(GenericContainerScreenHandler handler, Text title, MinecraftClient client) {
+ try {
+ if (SkyblockerConfig.get().locations.dungeons.dungeonChestProfit.enableProfitCalculator && isDungeonChest(title.getString())) {
+ int profit = 0;
+ boolean hasIncompleteData = false, usedKismet = false;
+ List<Slot> slots = handler.slots.subList(0, handler.getRows() * 9);
+
+ //If the item stack for the "Open Reward Chest" button or the kismet button hasn't been sent to the client yet
+ if (slots.get(31).getStack().isEmpty() || slots.get(50).getStack().isEmpty()) return title;
+
+ for (Slot slot : slots) {
+ ItemStack stack = slot.getStack();
+
+ if (!stack.isEmpty()) {
+ String name = stack.getName().getString();
+ String id = PriceInfoTooltip.getInternalNameFromNBT(stack, false);
+
+ //Regular item price
+ if (id != null) {
+ IntBooleanPair priceData = getItemPrice(id);
+
+ if (priceData.rightBoolean() == false) hasIncompleteData = true;
+
+ //Add the item price to the profit
+ profit += priceData.leftInt();
+
+ continue;
+ }
+
+ //Essence price
+ if (name.contains("Essence")) {
+ Matcher matcher = ESSENCE_PATTERN.matcher(name);
+
+ if (matcher.matches()) {
+ String type = matcher.group("type");
+ int amount = Integer.parseInt(matcher.group("amount"));
+
+ IntBooleanPair priceData = getItemPrice(("ESSENCE_" + type).toUpperCase());
+
+ if (priceData.rightBoolean() == false) hasIncompleteData = true;
+
+ //Add the price of the essence to the profit
+ profit += priceData.leftInt() * amount;
+
+ continue;
+ }
+ }
+
+ //Determine the cost of the chest
+ if (name.contains("Open Reward Chest")) {
+ String foundString = searchLoreFor(stack, client, "Coins");
+
+ //Incase we're searching the free chest
+ if (!StringUtils.isBlank(foundString)) {
+ profit -= Integer.parseInt(foundString.replaceAll("[^0-9]", ""));
+ }
+
+ continue;
+ }
+
+ //Determine if a kismet was used or not
+ if (name.contains("Reroll Chest")) {
+ usedKismet = !StringUtils.isBlank(searchLoreFor(stack, client, "You already rerolled a chest!"));
+
+ continue;
+ }
+ }
+ }
+
+ if (SkyblockerConfig.get().locations.dungeons.dungeonChestProfit.includeKismet && usedKismet) {
+ IntBooleanPair kismetPriceData = getItemPrice("KISMET_FEATHER");
+
+ if (kismetPriceData.rightBoolean() == false) hasIncompleteData = true;
+
+ profit -= kismetPriceData.leftInt();
+ }
+
+ return ((MutableText) Text.literal(title.getString())).append(getProfitText(profit, hasIncompleteData));
+ }
+ } catch (Exception e) {
+ LOGGER.error("[Skyblocker Profit Calculator] Failed to calculate dungeon chest profit! ", e);
+ }
+
+ return title;
+ }
+
+ /**
+ *
+ * @return An {@link IntBooleanPair} with the {@code left int} representing the item's price, and the {@code right boolean} indicating if the price
+ * was based on complete data.
+ */
+ private static IntBooleanPair getItemPrice(String id) {
+ JsonObject bazaarPrices = PriceInfoTooltip.getBazaarPrices();
+ JsonObject lbinPrices = PriceInfoTooltip.getLBINPrices();
+
+ if (bazaarPrices == null || lbinPrices == null) return IntBooleanPair.of(0, false);
+
+ if (bazaarPrices.has(id)) {
+ JsonObject item = bazaarPrices.get(id).getAsJsonObject();
+ boolean isPriceNull = item.get("sellPrice").isJsonNull();
+
+ return IntBooleanPair.of(isPriceNull ? 0 : (int) item.get("sellPrice").getAsDouble(), !isPriceNull);
+ }
+
+ if (lbinPrices.has(id)) {
+ return IntBooleanPair.of((int) lbinPrices.get(id).getAsDouble(), true);
+ }
+
+ return IntBooleanPair.of(0, false);
+ }
+
+ /**
+ * Searches for a specific string of characters in the name and lore of an item
+ */
+ private static String searchLoreFor(ItemStack stack, MinecraftClient client, String searchString) {
+ List<Text> lore = stack.getTooltip(client.player, TooltipContext.BASIC);
+
+ for (int i = 0; i < lore.size(); i++) {
+ String line = lore.get(i).getString();
+
+ if (line.contains(searchString)) {
+ return line;
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isDungeonChest(String name) {
+ return name.equals("Wood Chest") || name.equals("Gold Chest") || name.equals("Diamond Chest") || name.equals("Emerald Chest") || name.equals("Obsidian Chest") || name.equals("Bedrock Chest");
+ }
+
+ private static Text getProfitText(int profit, boolean hasIncompleteData) {
+ return (profit == 0) ? Text.literal(" " + FORMATTER.format(profit)).setStyle(hasIncompleteData ? GOLD : GRAY) : (profit > 0) ? Text.literal(" +" + FORMATTER.format(profit)).setStyle(hasIncompleteData ? GOLD : DARK_GREEN) : Text.literal(" " + FORMATTER.format(profit)).setStyle(hasIncompleteData ? GOLD : DARK_RED);
+ }
+}