Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EssenceShopPrice feature #737

Merged
merged 6 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/main/java/de/hysky/skyblocker/SkyblockerMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import de.hysky.skyblocker.skyblock.end.EnderNodes;
import de.hysky.skyblocker.skyblock.end.TheEnd;
import de.hysky.skyblocker.skyblock.entity.MobBoundingBoxes;
import de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars;
import de.hysky.skyblocker.skyblock.events.EventNotifications;
import de.hysky.skyblocker.skyblock.fancybars.FancyStatusBars;
import de.hysky.skyblocker.skyblock.garden.FarmingHud;
import de.hysky.skyblocker.skyblock.garden.LowerSensitivity;
import de.hysky.skyblocker.skyblock.garden.VisitorHelper;
Expand All @@ -48,11 +48,7 @@
import de.hysky.skyblocker.skyblock.tabhud.TabHud;
import de.hysky.skyblocker.skyblock.tabhud.screenbuilder.ScreenMaster;
import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import de.hysky.skyblocker.skyblock.waypoint.FairySouls;
import de.hysky.skyblocker.skyblock.waypoint.MythologicalRitual;
import de.hysky.skyblocker.skyblock.waypoint.OrderedWaypoints;
import de.hysky.skyblocker.skyblock.waypoint.Relics;
import de.hysky.skyblocker.skyblock.waypoint.Waypoints;
import de.hysky.skyblocker.skyblock.waypoint.*;
import de.hysky.skyblocker.utils.*;
import de.hysky.skyblocker.utils.chat.ChatMessageListener;
import de.hysky.skyblocker.utils.discord.DiscordRPCManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig
newValue -> config.general.itemTooltip.dungeonQuality = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.option(Option.<Boolean>createBuilder()
.name(Text.translatable("skyblocker.config.general.itemTooltip.showEssenceCost"))
.binding(defaults.general.itemTooltip.showEssenceCost,
() -> config.general.itemTooltip.showEssenceCost,
newValue -> config.general.itemTooltip.showEssenceCost = newValue)
.controller(ConfigUtils::createBooleanController)
.build())
.build())

//Item Info Display
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ public static class ItemTooltip {

@SerialEntry
public boolean dungeonQuality = true;

@SerialEntry
public boolean showEssenceCost = false;
}

public enum Average {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public ChocolateFactorySolver() {

private static void onTick(MinecraftClient client) {
if (ding != StraySound.NONE) {
dingTick = (++dingTick) % (ding == StraySound.NORMAL ? 5 : 3);
dingTick = (++dingTick) % (ding == StraySound.NORMAL ? 5 : 3);
if (dingTick == 0) {
client.getSoundManager().play(PositionedSoundInstance.master(ding == StraySound.NORMAL ? SoundEvents.BLOCK_NOTE_BLOCK_PLING.value() : SoundEvents.BLOCK_NOTE_BLOCK_HARP.value(), 1.f, 1.f));
}
Expand Down Expand Up @@ -150,14 +150,14 @@ private static void updateFactoryInfo(Int2ObjectMap<ItemStack> slots) {
RegexUtils.getLongFromMatcher(CHOCOLATE_PATTERN.matcher(slots.get(CHOCOLATE_SLOT).getName().getString())).ifPresent(l -> totalChocolate = l);

//Cps item (cocoa bean) is in slot 45
String cpsItemLore = getConcatenatedLore(slots.get(CPS_SLOT));
String cpsItemLore = ItemUtils.getConcatenatedLore(slots.get(CPS_SLOT));
Matcher cpsMatcher = CPS_PATTERN.matcher(cpsItemLore);
RegexUtils.getDoubleFromMatcher(cpsMatcher).ifPresent(d -> totalCps = d);
Matcher multiplierMatcher = TOTAL_MULTIPLIER_PATTERN.matcher(cpsItemLore);
RegexUtils.getDoubleFromMatcher(multiplierMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0).ifPresent(d -> totalCpsMultiplier = d);

//Prestige item is in slot 28
String prestigeLore = getConcatenatedLore(slots.get(PRESTIGE_SLOT));
String prestigeLore = ItemUtils.getConcatenatedLore(slots.get(PRESTIGE_SLOT));
Matcher prestigeMatcher = PRESTIGE_REQUIREMENT_PATTERN.matcher(prestigeLore);
OptionalLong currentChocolate = RegexUtils.getLongFromMatcher(prestigeMatcher);
if (currentChocolate.isPresent()) {
Expand All @@ -178,7 +178,7 @@ private static void updateFactoryInfo(Int2ObjectMap<ItemStack> slots) {

//Time Tower is in slot 39
isTimeTowerMaxed = StringUtils.substringAfterLast(slots.get(TIME_TOWER_SLOT).getName().getString(), ' ').equals("XV");
String timeTowerLore = getConcatenatedLore(slots.get(TIME_TOWER_SLOT));
String timeTowerLore = ItemUtils.getConcatenatedLore(slots.get(TIME_TOWER_SLOT));
Matcher timeTowerMultiplierMatcher = TIME_TOWER_MULTIPLIER_PATTERN.matcher(timeTowerLore);
RegexUtils.getDoubleFromMatcher(timeTowerMultiplierMatcher).ifPresent(d -> timeTowerMultiplier = d);
Matcher timeTowerStatusMatcher = TIME_TOWER_STATUS_PATTERN.matcher(timeTowerLore);
Expand All @@ -190,29 +190,9 @@ private static void updateFactoryInfo(Int2ObjectMap<ItemStack> slots) {
cpsIncreaseFactors.sort(Comparator.comparingDouble(rabbit -> rabbit.cost() / rabbit.cpsIncrease())); //Ascending order, lower = better
}

/**
* Utility method.
*/
private static String getConcatenatedLore(ItemStack item) {
return concatenateLore(ItemUtils.getLore(item));
}

/**
* Concatenates the lore of an item into one string.
* This is useful in case some pattern we're looking for is split into multiple lines, which would make it harder to regex.
*/
private static String concatenateLore(List<Text> lore) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < lore.size(); i++) {
stringBuilder.append(lore.get(i).getString());
if (i != lore.size() - 1) stringBuilder.append(" ");
}
return stringBuilder.toString();
}

private static Optional<Rabbit> getCoach(ItemStack coachItem) {
if (!coachItem.isOf(Items.PLAYER_HEAD)) return Optional.empty();
String coachLore = getConcatenatedLore(coachItem);
String coachLore = ItemUtils.getConcatenatedLore(coachItem);

if (totalCps < 0 || totalCpsMultiplier < 0) return Optional.empty(); //We need these 2 to calculate the increase in cps.

Expand All @@ -234,7 +214,7 @@ private static Optional<Rabbit> getCoach(ItemStack coachItem) {
}

private static Optional<Rabbit> getRabbit(ItemStack item, int slot) {
String lore = getConcatenatedLore(item);
String lore = ItemUtils.getConcatenatedLore(item);
Matcher cpsMatcher = CPS_INCREASE_PATTERN.matcher(lore);
OptionalInt currentCps = RegexUtils.getIntFromMatcher(cpsMatcher);
if (currentCps.isEmpty()) return Optional.empty();
Expand All @@ -247,7 +227,7 @@ private static Optional<Rabbit> getRabbit(ItemStack item, int slot) {
Matcher costMatcher = COST_PATTERN.matcher(lore);
OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher, cpsMatcher.hasMatch() ? cpsMatcher.end() : 0); //Cost comes after the cps line
if (cost.isEmpty()) return Optional.empty();
return Optional.of(new Rabbit((nextCps.getAsInt() - currentCps.getAsInt())*(totalCpsMultiplier < 0 ? 1 : totalCpsMultiplier), cost.getAsLong(), slot));
return Optional.of(new Rabbit((nextCps.getAsInt() - currentCps.getAsInt()) * (totalCpsMultiplier < 0 ? 1 : totalCpsMultiplier), cost.getAsLong(), slot));
}

private static Optional<ColorHighlight> getPrestigeHighlight() {
Expand All @@ -271,7 +251,7 @@ private static List<ColorHighlight> getStrayRabbitHighlight(Int2ObjectMap<ItemSt
return highlights;
}

private record Rabbit(double cpsIncrease, long cost, int slot) { }
private record Rabbit(double cpsIncrease, long cost, int slot) {}

private enum StraySound {
NONE,
Expand All @@ -293,7 +273,7 @@ public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text>
//It should be set to true if there's any information added, false otherwise.
boolean shouldAddLine = false;

String lore = concatenateLore(lines);
String lore = ItemUtils.concatenateLore(lines);
Matcher costMatcher = COST_PATTERN.matcher(lore);
OptionalLong cost = RegexUtils.getLongFromMatcher(costMatcher);
//Available on all items with a chocolate cost
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import de.hysky.skyblocker.SkyblockerMod;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.config.configs.GeneralConfig;
import de.hysky.skyblocker.skyblock.item.tooltip.adders.EssenceShopPrice;
import de.hysky.skyblocker.utils.Http;
import de.hysky.skyblocker.utils.Utils;
import org.jetbrains.annotations.Nullable;
Expand All @@ -16,7 +17,7 @@

public enum TooltipInfoType implements Runnable {
NPC("https://hysky.de/api/npcprice", itemTooltip -> itemTooltip.enableNPCPrice, true),
BAZAAR("https://hysky.de/api/bazaar", itemTooltip -> itemTooltip.enableBazaarPrice || itemTooltip.enableCraftingCost.getOrder() != null || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.croesusProfit || SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue, itemTooltip -> itemTooltip.enableBazaarPrice, false),
BAZAAR("https://hysky.de/api/bazaar", itemTooltip -> itemTooltip.enableBazaarPrice || itemTooltip.enableCraftingCost.getOrder() != null || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.croesusProfit || SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue || itemTooltip.showEssenceCost, itemTooltip -> itemTooltip.enableBazaarPrice, false, EssenceShopPrice::refreshEssencePrices),
LOWEST_BINS("https://hysky.de/api/auctions/lowestbins", itemTooltip -> itemTooltip.enableLowestBIN || itemTooltip.enableCraftingCost.getOrder() != null || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.enableProfitCalculator || SkyblockerConfigManager.get().dungeons.dungeonChestProfit.croesusProfit || SkyblockerConfigManager.get().uiAndVisuals.chestValue.enableChestValue, itemTooltip -> itemTooltip.enableLowestBIN, false),
ONE_DAY_AVERAGE("https://hysky.de/api/auctions/lowestbins/average/1day.json", itemTooltip -> itemTooltip.enableAvgBIN, false),
THREE_DAY_AVERAGE("https://hysky.de/api/auctions/lowestbins/average/3day.json", itemTooltip -> itemTooltip.enableAvgBIN || SkyblockerConfigManager.get().uiAndVisuals.searchOverlay.enableAuctionHouse, itemTooltip -> itemTooltip.enableAvgBIN, false),
Expand All @@ -29,10 +30,10 @@ public enum TooltipInfoType implements Runnable {
private final String address;
private final Predicate<GeneralConfig.ItemTooltip> dataEnabled;
private final Predicate<GeneralConfig.ItemTooltip> tooltipEnabled;
private JsonObject data;
private @Nullable JsonObject data;
private final boolean cacheable;
private long hash;
private final Consumer<JsonObject> callback;
private final @Nullable Consumer<JsonObject> callback;

/**
* Use this for when you're adding tooltip info that has no data associated with it
Expand All @@ -45,19 +46,19 @@ public enum TooltipInfoType implements Runnable {
* @param address the address to download the data from
* @param enabled the predicate to check if the data should be downloaded and the tooltip should be shown
* @param cacheable whether the data should be cached
* @param callback called when the {@code data} is refreshed
*/
TooltipInfoType(String address, Predicate<GeneralConfig.ItemTooltip> enabled, boolean cacheable, Consumer<JsonObject> callback) {
this(address, enabled, enabled, cacheable, callback);
TooltipInfoType(String address, Predicate<GeneralConfig.ItemTooltip> enabled, boolean cacheable) {
this(address, enabled, enabled, cacheable, null);
}

/**
* @param address the address to download the data from
* @param enabled the predicate to check if the data should be downloaded and the tooltip should be shown
* @param cacheable whether the data should be cached
* @param callback called when the {@code data} is refreshed
*/
TooltipInfoType(String address, Predicate<GeneralConfig.ItemTooltip> enabled, boolean cacheable) {
this(address, enabled, enabled, cacheable, null);
TooltipInfoType(String address, Predicate<GeneralConfig.ItemTooltip> enabled, boolean cacheable, Consumer<JsonObject> callback) {
this(address, enabled, enabled, cacheable, callback);
}

/**
Expand Down Expand Up @@ -99,7 +100,7 @@ public boolean isTooltipEnabled() {
return tooltipEnabled.test(ItemTooltip.config);
}

public JsonObject getData() {
public @Nullable JsonObject getData() {
return data;
}

Expand Down Expand Up @@ -160,14 +161,14 @@ public void run() {
}
String response = Http.sendGetRequest(address);
if (response.trim().startsWith("<!DOCTYPE") || response.trim().startsWith("<html")) {
ItemTooltip.LOGGER.warn("[Skyblocker] Received HTML content for " + this.name() + ". Expected JSON.");
ItemTooltip.LOGGER.warn("[Skyblocker] Received HTML content for {}. Expected JSON.", this);
return;
}
data = SkyblockerMod.GSON.fromJson(response, JsonObject.class);

if (callback != null) callback.accept(data);
} catch (Exception e) {
ItemTooltip.LOGGER.warn("[Skyblocker] Failed to download " + this + " prices!", e);
ItemTooltip.LOGGER.warn("[Skyblocker] Failed to download {} prices!", this, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ public class TooltipManager {
new BazaarPriceTooltip(2),
new LBinTooltip(3),
new AvgBinTooltip(4),
new CraftPriceTooltip(5),
new DungeonQualityTooltip(6),
new MotesTooltip(7),
new ObtainedDateTooltip(8),
new MuseumTooltip(9),
new ColorTooltip(10),
new AccessoryTooltip(11),
new EssenceShopPrice(5),
new CraftPriceTooltip(6),
new DungeonQualityTooltip(7),
new MotesTooltip(8),
new ObtainedDateTooltip(9),
new MuseumTooltip(10),
new ColorTooltip(11),
new AccessoryTooltip(12),
};
private static final ArrayList<TooltipAdder> currentScreenAdders = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package de.hysky.skyblocker.skyblock.item.tooltip.adders;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import de.hysky.skyblocker.config.SkyblockerConfigManager;
import de.hysky.skyblocker.skyblock.item.tooltip.TooltipAdder;
import de.hysky.skyblocker.utils.ItemUtils;
import de.hysky.skyblocker.utils.RegexUtils;
import it.unimi.dsi.fastutil.objects.Object2LongArrayMap;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.Nullable;

import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
import java.util.OptionalLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EssenceShopPrice extends TooltipAdder {
private static final Pattern ESSENCE_PATTERN = Pattern.compile("Cost (?<amount>[\\d,]+) (?<type>[A-Za-z]+) Essence");
private static final NumberFormat DECIMAL_FORMAT = NumberFormat.getInstance(Locale.US);
private static final String[] ESSENCE_TYPES = {"WITHER", "SPIDER", "UNDEAD", "DRAGON", "GOLD", "DIAMOND", "ICE", "CRIMSON"};
private static final Object2LongArrayMap<String> ESSENCE_PRICES = new Object2LongArrayMap<>(ESSENCE_TYPES, new long[8]);

public EssenceShopPrice(int priority) {
super("\\S+ Essence Shop", priority);
}

public static void refreshEssencePrices(JsonObject data) {
for (String essenceType : ESSENCE_TYPES) {
JsonElement price = data.get("ESSENCE_" + essenceType);
if (price == null || !price.isJsonObject()) continue;
JsonElement sellPrice = price.getAsJsonObject().get("sellPrice");
if (sellPrice == null) continue;
if (sellPrice.isJsonPrimitive()) {
ESSENCE_PRICES.put(essenceType, sellPrice.getAsLong());
}
}
}

//Todo: maybe move the price value right after the essence amount ex: "1,500 Wither Essence (645k coins)"
@Override
public void addToTooltip(@Nullable Slot focusedSlot, ItemStack stack, List<Text> lines) {
if (!SkyblockerConfigManager.get().general.itemTooltip.showEssenceCost) return;

String lore = ItemUtils.concatenateLore(lines);
Matcher essenceMatcher = ESSENCE_PATTERN.matcher(lore);
OptionalLong cost = RegexUtils.getLongFromMatcher(essenceMatcher);
if (cost.isEmpty()) return;

String type = essenceMatcher.group("type");
long priceData = ESSENCE_PRICES.getLong(type.toUpperCase(Locale.ROOT));
if (priceData == 0) return; //Default value for getLong is 0 if no value exists for that key

lines.add(Text.empty()
.append(Text.literal("Essence Cost: ").formatted(Formatting.AQUA))
.append(Text.literal(DECIMAL_FORMAT.format(priceData * cost.getAsLong()) + " coins").formatted(Formatting.DARK_AQUA))
.append(Text.literal(" (").formatted(Formatting.GRAY))
.append(Text.literal(DECIMAL_FORMAT.format(priceData) + " each").formatted(Formatting.GRAY))
.append(Text.literal(")").formatted(Formatting.GRAY))
);
}
}
20 changes: 20 additions & 0 deletions src/main/java/de/hysky/skyblocker/utils/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,24 @@ public static Matcher getLoreLineIfContainsMatch(ItemStack stack, Pattern patter
throw new RuntimeException(e);
}
}

/**
* Utility method.
*/
public static @NotNull String getConcatenatedLore(@NotNull ItemStack item) {
return concatenateLore(getLore(item));
}

/**
* Concatenates the lore of an item into one string.
* This is useful in case some pattern we're looking for is split into multiple lines, which would make it harder to regex.
*/
public static @NotNull String concatenateLore(@NotNull List<Text> lore) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < lore.size(); i++) {
stringBuilder.append(lore.get(i).getString());
if (i != lore.size() - 1) stringBuilder.append(" ");
}
return stringBuilder.toString();
}
}
2 changes: 1 addition & 1 deletion src/main/java/de/hysky/skyblocker/utils/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public static Location getLocation() {

/**
* Can be used to restrict features to being active only on the Alpha network.
*
*
* @return the current environment parsed from the Mod API.
*/
@NotNull
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/assets/skyblocker/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@
"skyblocker.config.general.itemTooltip.enableMuseumInfo.@Tooltip": "If this item is donatable to the museum, then the item's category in the musuem is displayed. It also displays a marker indicating whether you've donated that item to your musuem or not (freebies not yet supported).\n\nMake sure to enable your Museum API for accurate information!",
"skyblocker.config.general.itemTooltip.enableNPCPrice": "Enable NPC Price",
"skyblocker.config.general.itemTooltip.enableObtainedDate": "Enable Obtained Date",
"skyblocker.config.general.itemTooltip.showEssenceCost": "Show Essence Cost",
kevinthegreat1 marked this conversation as resolved.
Show resolved Hide resolved

"skyblocker.config.general.quiverWarning": "Quiver Warning",
"skyblocker.config.general.quiverWarning.enableQuiverWarning": "Enable Quiver Warning",
Expand Down