From 65e5ee4b431cc7513e53d61827249148b06de79a Mon Sep 17 00:00:00 2001 From: Cow Date: Tue, 6 Jul 2021 20:24:21 +0200 Subject: Added 'lowest BINs' support to Chest Tracker & Analyzer --- .../cowlection/chesttracker/ChestTracker.java | 118 +++++++++++++++++++-- 1 file changed, 110 insertions(+), 8 deletions(-) (limited to 'src/main/java/de/cowtipper/cowlection/chesttracker/ChestTracker.java') diff --git a/src/main/java/de/cowtipper/cowlection/chesttracker/ChestTracker.java b/src/main/java/de/cowtipper/cowlection/chesttracker/ChestTracker.java index 64e4067..4ff6fe2 100644 --- a/src/main/java/de/cowtipper/cowlection/chesttracker/ChestTracker.java +++ b/src/main/java/de/cowtipper/cowlection/chesttracker/ChestTracker.java @@ -1,29 +1,39 @@ package de.cowtipper.cowlection.chesttracker; import de.cowtipper.cowlection.Cowlection; +import de.cowtipper.cowlection.data.DataHelper; +import de.cowtipper.cowlection.data.HySkyBlockStats; import de.cowtipper.cowlection.util.ApiUtils; +import de.cowtipper.cowlection.util.GsonUtils; import de.cowtipper.cowlection.util.MooChatComponent; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.EnumFacing; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.Constants; import java.util.*; public class ChestTracker { + public static long lastBazaarUpdate; + public static long lastLowestBinsUpdate; private final Map> chestCache = new HashMap<>(); private final Map doubleChestCache = new HashMap<>(); private Map analysisResult = new HashMap<>(); private ChestInteractionListener chestInteractionListener; private HyBazaarData bazaarCache; - private long lastBazaarUpdate; + private LowestBinsCache lowestBinsCache; private final Cowlection main; public ChestTracker(Cowlection main) { this.main = main; - refreshBazaarCache(); + refreshPriceCache(); chestInteractionListener = new ChestInteractionListener(main); MinecraftForge.EVENT_BUS.register(chestInteractionListener); } @@ -34,12 +44,30 @@ public class ChestTracker { for (ItemStack item : chestContents) { String key = item.hasDisplayName() ? item.getDisplayName() : item.getUnlocalizedName(); + boolean isAmbiguousItem = false; if (item.hasTagCompound()) { key = item.getTagCompound().getCompoundTag("ExtraAttributes").getString("id"); } + if ("PET".equals(key)) { + HySkyBlockStats.Profile.Pet petInfo = GsonUtils.fromJson(item.getTagCompound().getCompoundTag("ExtraAttributes").getString("petInfo"), HySkyBlockStats.Profile.Pet.class); + key = petInfo.getType() + ";" + petInfo.getRarity().ordinal(); + // remove pet lvl from name, as lowest BINs also disregard it + String petName = item.getDisplayName(); + int endOfPetLevel = petName.indexOf(']'); + if (petName.startsWith(EnumChatFormatting.GRAY + "[Lvl ") && endOfPetLevel > 0) { + item.setStackDisplayName(EnumChatFormatting.GRAY + "[Lvl " + EnumChatFormatting.DARK_GRAY + "?" + EnumChatFormatting.GRAY + petName.substring(endOfPetLevel)); + } + } else if (DataHelper.AMBIGUOUS_ITEM_IDS.contains(key)) { + isAmbiguousItem = true; + key += "_ambiguous"; + } ItemData itemData = itemCounts.get(key); if (itemData == null) { + // item hasn't been cached yet + if (isAmbiguousItem) { + convertToDummyItem(item, key); + } itemData = new ItemData(key, item.copy()); } itemCounts.put(key, itemData.addAmount(item.stackSize)); @@ -48,6 +76,46 @@ public class ChestTracker { this.analysisResult = itemCounts; } + private void convertToDummyItem(ItemStack item, String key) { + NBTTagCompound itemNbtDisplay = item.getSubCompound("display", true); + NBTTagList loreList = new NBTTagList(); + loreList.appendTag(new NBTTagString("" + EnumChatFormatting.RED + EnumChatFormatting.ITALIC + "This ambiguous item type")); + loreList.appendTag(new NBTTagString("" + EnumChatFormatting.RED + EnumChatFormatting.ITALIC + "is not listed separately.")); + itemNbtDisplay.setTag("Lore", loreList); + String itemName = null; + switch (key) { + case "ENCHANTED_BOOK_ambiguous": + itemName = "Enchanted Book"; + break; + case "POTION_ambiguous": + itemName = "Potion"; + break; + case "RUNE_ambiguous": + itemName = "Rune"; + NBTTagCompound skullNbtTextureData = item.getSubCompound("SkullOwner", false); + if (skullNbtTextureData != null) { + skullNbtTextureData.setString("Id", UUID.randomUUID().toString()); + NBTTagCompound nbtSkin = new NBTTagCompound(); + // set texture to Empty Rune + nbtSkin.setString("Value", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJiODIwN2E1ZmUxOTJjZDQ3N2U5MjE0NjYxOTdjOGFmNzQ5YWYxOGRkMWVmMzg5ZTI3MzNhMmY3NGQwOTI4YiJ9fX0="); + skullNbtTextureData.getCompoundTag("Properties").getTagList("textures", Constants.NBT.TAG_COMPOUND).set(0, nbtSkin); + } + break; + case "NEW_YEAR_CAKE_ambiguous": + itemName = "New Year Cake"; + break; + case "SPOOKY_PIE_ambiguous": + itemName = "Spooky Pie"; + break; + case "CAKE_SOUL_ambiguous": + itemName = "Cake Soul"; + break; + } + if (itemName != null) { + item.setStackDisplayName(EnumChatFormatting.GRAY + itemName); + } + } + /** * Returns ordered analysis result with prices */ @@ -55,6 +123,7 @@ public class ChestTracker { List orderedAnalysisResult = new ArrayList<>(); // sort by bazaar value (most value first) for (Map.Entry itemEntry : analysisResult.entrySet()) { + boolean foundPriceForItem = false; if (bazaarCache != null && bazaarCache.isSuccess()) { String productKey = itemEntry.getKey(); HyBazaarData.Product product = bazaarCache.getProduct(productKey); @@ -62,6 +131,15 @@ public class ChestTracker { // item is sold on bazaar! itemEntry.getValue().setBazaarInstantSellPrice(product.getInstantSellPrice()); itemEntry.getValue().setBazaarSellOfferPrice(product.getSellOfferPrice()); + foundPriceForItem = true; + } + } + if (!foundPriceForItem && lowestBinsCache != null && lowestBinsCache.size() > 0) { + String productKey = itemEntry.getKey().replace(':', '-'); + Integer lowestBin = lowestBinsCache.get(productKey); + if (lowestBin != null) { + // item is sold via BIN + itemEntry.getValue().setLowestBin(lowestBin); } } orderedAnalysisResult.add(itemEntry.getValue()); @@ -75,10 +153,10 @@ public class ChestTracker { comparator = Comparator.comparing(ItemData::getAmount); break; case PRICE_EACH: - comparator = useInstantSellPrices ? Comparator.comparing(ItemData::getBazaarInstantSellPrice) : Comparator.comparing(ItemData::getBazaarSellOfferPrice); + comparator = Comparator.comparing(itemData -> itemData.getPrice(useInstantSellPrices)); break; default: // case PRICE_SUM: - comparator = useInstantSellPrices ? Comparator.comparing(ItemData::getBazaarInstantSellValue) : Comparator.comparing(ItemData::getBazaarSellOfferValue); + comparator = Comparator.comparing(itemData -> itemData.getPriceSum(useInstantSellPrices)); break; } orderedAnalysisResult.sort((orderDesc ? comparator.reversed() : comparator).thenComparing(ItemData::getName)); @@ -93,6 +171,7 @@ public class ChestTracker { MinecraftForge.EVENT_BUS.unregister(chestInteractionListener); chestInteractionListener = null; bazaarCache = null; + lowestBinsCache = null; chestCache.clear(); doubleChestCache.clear(); analysisResult.clear(); @@ -148,23 +227,46 @@ public class ChestTracker { return doubleChestCache.getOrDefault(pos, EnumFacing.UP); } - public void refreshBazaarCache() { + public EnumSet refreshPriceCache() { + EnumSet updating = EnumSet.of(Updating.UNDEFINED); if (allowUpdateBazaar()) { + updating.add(Updating.BAZAAR); ApiUtils.fetchBazaarData(bazaarData -> { if (bazaarData == null || !bazaarData.isSuccess()) { main.getChatHelper().sendMessage(new MooChatComponent("Error: Couldn't get Bazaar data from Hypixel API! API might be down: check status.hypixel.net").red().setUrl("https://status.hypixel.net/")); } this.bazaarCache = bazaarData; - this.lastBazaarUpdate = System.currentTimeMillis(); + lastBazaarUpdate = System.currentTimeMillis(); + }); + } + if (allowUpdateLowestBins()) { + updating.add(Updating.LOWEST_BINS); + ApiUtils.fetchLowestBins(lowestBins -> { + if (!lowestBins.hasData()) { + main.getChatHelper().sendMessage(new MooChatComponent("Error: Couldn't get lowest BINs from Moulberry's API! API might be down: check if " + ApiUtils.LOWEST_BINS + " is reachable.").red().setUrl(ApiUtils.LOWEST_BINS)); + } + this.lowestBinsCache = lowestBins; + lastLowestBinsUpdate = System.currentTimeMillis(); }); } + return updating; } + /** + * Allow bazaar update once per minute + */ public boolean allowUpdateBazaar() { return bazaarCache == null || bazaarCache.allowRefreshData(); } - public long getLastBazaarUpdate() { - return this.lastBazaarUpdate; + /** + * Allow lowest bins update once every 5 minutes + */ + public boolean allowUpdateLowestBins() { + return lowestBinsCache == null || (System.currentTimeMillis() - lastLowestBinsUpdate) > 300000; + } + + public enum Updating { + UNDEFINED, BAZAAR, LOWEST_BINS } } -- cgit