From 1d3303178635566b14a6f24b5741bbf331113f84 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sun, 24 Mar 2024 02:27:13 -0400 Subject: Accessories Helper --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 2 + .../hysky/skyblocker/config/SkyblockerConfig.java | 3 + .../config/categories/GeneralCategory.java | 10 + .../skyblock/item/tooltip/AccessoriesHelper.java | 230 +++++++++++++++++++++ .../skyblock/item/tooltip/ItemTooltip.java | 23 +++ .../skyblock/item/tooltip/TooltipInfoType.java | 31 ++- 6 files changed, 292 insertions(+), 7 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index e334ef86..ee82209d 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -25,6 +25,7 @@ import de.hysky.skyblocker.skyblock.end.TheEnd; import de.hysky.skyblocker.skyblock.garden.FarmingHud; import de.hysky.skyblocker.skyblock.garden.VisitorHelper; import de.hysky.skyblocker.skyblock.item.*; +import de.hysky.skyblocker.skyblock.item.tooltip.AccessoriesHelper; import de.hysky.skyblocker.skyblock.item.tooltip.BackpackPreview; import de.hysky.skyblocker.skyblock.item.tooltip.ItemTooltip; import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; @@ -102,6 +103,7 @@ public class SkyblockerMod implements ClientModInitializer { PlayerHeadHashCache.init(); HotbarSlotLock.init(); ItemTooltip.init(); + AccessoriesHelper.init(); WikiLookup.init(); FairySouls.init(); Relics.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index a3e710c1..8d65806f 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -555,6 +555,9 @@ public class SkyblockerConfig { @SerialEntry public boolean enableExoticTooltip = true; + + @SerialEntry + public boolean enableAccessoriesHelper = true; } public static class ItemInfoDisplay { diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index 23ce7bb6..abe20e18 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -434,6 +434,16 @@ public class GeneralCategory { newValue -> config.general.itemTooltip.enableExoticTooltip = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper")) + .description(OptionDescription.of(Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper.@Tooltip[0]"), Text.literal("\n\n✔ Collected").formatted(Formatting.GREEN), Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper.@Tooltip[1]"), + Text.literal("\n✦ Upgrade").withColor(0x218bff), Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper.@Tooltip[2]"), Text.literal("\n↑ Upgradable").withColor(0xf8d048), Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper.@Tooltip[3]"), + Text.literal("\n↓ Downgrade").formatted(Formatting.GRAY), Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper.@Tooltip[4]"), Text.literal("\n✖ Missing").formatted(Formatting.RED), Text.translatable("text.autoconfig.skyblocker.option.general.itemTooltip.enableAccessoriesHelper.@Tooltip[5]"))) + .binding(defaults.general.itemTooltip.enableAccessoriesHelper, + () -> config.general.itemTooltip.enableAccessoriesHelper, + newValue -> config.general.itemTooltip.enableAccessoriesHelper = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .build()) //Item Info Display diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java new file mode 100644 index 00000000..b5291af6 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -0,0 +1,230 @@ +package de.hysky.skyblocker.skyblock.item.tooltip; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; +import java.util.function.ToIntFunction; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.slf4j.Logger; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.util.UndashedUuid; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.slot.Slot; + +public class AccessoriesHelper { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("collected_accessories.json"); + private static final Pattern ACCESSORY_BAG_TITLE = Pattern.compile("Accessory Bag \\(\\d+\\/\\d+\\)"); + //UUID -> Profile Id & Data + private static final Map> COLLECTED_ACCESSORIES = new Object2ObjectOpenHashMap<>(); + private static final Predicate NON_EMPTY = s -> !s.isEmpty(); + private static final Predicate HAS_FAMILY = Accessory::hasFamily; + private static final ToIntFunction ACCESSORY_TIER = Accessory::tier; + + private static Map ACCESSORY_DATA = new Object2ObjectOpenHashMap<>(); + //remove?? + private static CompletableFuture loaded; + + public static void init() { + ClientLifecycleEvents.CLIENT_STARTED.register((_client) -> load()); + ClientLifecycleEvents.CLIENT_STOPPING.register((_client) -> save()); + ScreenEvents.BEFORE_INIT.register((_client, screen, _scaledWidth, _scaledHeight) -> { + if (Utils.isOnSkyblock() && TooltipInfoType.ACCESSORIES.isTooltipEnabled() && !Utils.getProfileId().isEmpty() && screen instanceof GenericContainerScreen genericContainerScreen) { + if (ACCESSORY_BAG_TITLE.matcher(genericContainerScreen.getTitle().getString()).matches()) { + ScreenEvents.afterRender(screen).register((_screen, _context, _mouseX, _mouseY, _delta) -> { + GenericContainerScreenHandler handler = genericContainerScreen.getScreenHandler(); + + collectAccessories(handler.slots.subList(0, handler.getRows() * 9)); + }); + } + } + }); + } + + private static void load() { + loaded = CompletableFuture.runAsync(() -> { + try (BufferedReader reader = Files.newBufferedReader(FILE)) { + COLLECTED_ACCESSORIES.putAll(ProfileAccessoryData.SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow()); + } catch (NoSuchFileException ignored) { + } catch (Exception e) { + LOGGER.error("[Skyblocker Accessory Helper] Failed to load accessory file!", e); + } + }); + } + + private static void save() { + try (BufferedWriter writer = Files.newBufferedWriter(FILE)) { + SkyblockerMod.GSON.toJson(ProfileAccessoryData.SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, COLLECTED_ACCESSORIES).result().orElseThrow(), writer); + } catch (Exception e) { + LOGGER.error("[Skyblocker Accessory Helper] Failed to save accessory file!", e); + } + } + + private static void collectAccessories(List slots) { + //Is this even needed? + if (!loaded.isDone()) return; + + List accessoryIds = slots.stream() + .map(Slot::getStack) + .map(ItemUtils::getItemId) + .filter(NON_EMPTY) + .collect(Collectors.toUnmodifiableList()); + + String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); + + Map playerData = COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()); + playerData.putIfAbsent(Utils.getProfileId(), ProfileAccessoryData.createDefault()); + + ProfileAccessoryData profileData = playerData.get(Utils.getProfileId()); + + profileData.accessoryIds().addAll(accessoryIds); + } + + static AccessoryReport calculateReport4Accessory(String accessoryId) { + if (!ACCESSORY_DATA.containsKey(accessoryId) || Utils.getProfileId().isEmpty()) return AccessoryReport.INELIGIBLE; + + Accessory accessory = ACCESSORY_DATA.get(accessoryId); + String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); + Set collectedAccessories = COLLECTED_ACCESSORIES.get(uuid).get(Utils.getProfileId()).accessoryIds().stream() + .filter(ACCESSORY_DATA::containsKey) + .map(ACCESSORY_DATA::get) + .collect(Collectors.toSet()); + + //If the player has this accessory and it doesn't belong to a family + if (collectedAccessories.contains(accessory) && accessory.family().isEmpty()) return AccessoryReport.HAS_HIGHEST_TIER; + + Predicate HAS_SAME_FAMILY = accessory::hasSameFamily; + Set collectedAccessoriesInTheSameFamily = collectedAccessories.stream() + .filter(HAS_FAMILY) + .filter(HAS_SAME_FAMILY) + .collect(Collectors.toSet()); + + //If the player doesn't have any collected accessories with same family + if (collectedAccessoriesInTheSameFamily.isEmpty()) return AccessoryReport.MISSING; + + Set accessoriesInTheSameFamily = ACCESSORY_DATA.values().stream() + .filter(HAS_FAMILY) + .filter(HAS_SAME_FAMILY) + .collect(Collectors.toSet()); + + ///If the player has the highest tier accessory in this family + //Take the the accessories in the same family as {@code accessory}, then get the one with the highest tier + Optional highestTierOfFamily = accessoriesInTheSameFamily.stream() + .max(Comparator.comparingInt(ACCESSORY_TIER)); + + if (highestTierOfFamily.isPresent()) { + Accessory highestTier = highestTierOfFamily.orElseThrow(); + + if (collectedAccessoriesInTheSameFamily.contains(highestTier)) return AccessoryReport.HAS_HIGHEST_TIER; + + //For when the highest tier is tied + if (highestTier.hasSameFamily(accessory) && collectedAccessoriesInTheSameFamily.stream().allMatch(ca -> ca.tier() == highestTier.tier())) return AccessoryReport.HAS_HIGHEST_TIER; + } + + //If this accessory is a higher tier than all of other collected accessories in the same family + OptionalInt highestTierOfAllCollectedInFamily = collectedAccessoriesInTheSameFamily.stream() + .mapToInt(ACCESSORY_TIER) + .max(); + + if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() > highestTierOfAllCollectedInFamily.orElseThrow()) return AccessoryReport.IS_GREATER_TIER; + + //If this accessory is a lower tier than one already obtained from same family + if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() < highestTierOfAllCollectedInFamily.orElseThrow()) return AccessoryReport.OWNS_BETTER_TIER; + + //If there is an accessory in the same family that has a higher tier + //Take the accessories in the same family, then check if there is an accessory whose tier is greater than {@code accessory} + boolean hasGreaterTierInFamily = accessoriesInTheSameFamily.stream() + .anyMatch(ca -> ca.tier() > accessory.tier()); + + if (hasGreaterTierInFamily) return AccessoryReport.HAS_GREATER_TIER; + + return AccessoryReport.MISSING; + } + + static void refreshData(JsonObject data) { + try { + Map accessoryData = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).result().orElseThrow(); + + ACCESSORY_DATA = accessoryData; + } catch (Exception e) { + LOGGER.error("[Skyblocker Accessory Helper] Failed to parse data!", e); + } + } + + private record ProfileAccessoryData(Set accessoryIds) { + private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.listOf() + .xmap(ObjectOpenHashSet::new, ObjectArrayList::new) + .fieldOf("accessoryIds") + .forGetter(i -> new ObjectOpenHashSet(i.accessoryIds()))) + .apply(instance, ProfileAccessoryData::new)); + //Mojang's internal Codec implementation uses ImmutableMaps so we'll just xmap those away and type safety while we're at it :') + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static final Codec>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, Codec.unboundedMap(Codec.STRING, CODEC) + .xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new)) + .xmap(Object2ObjectOpenHashMap::new, m -> (Map) new Object2ObjectOpenHashMap(m)); + + private static ProfileAccessoryData createDefault() { + return new ProfileAccessoryData(new ObjectOpenHashSet<>()); + } + } + + /** + * @author AzureAaron + * @implSpec Aaron's Mod + */ + private record Accessory(String id, Optional family, int tier) { + private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.fieldOf("id").forGetter(Accessory::id), + Codec.STRING.optionalFieldOf("family").forGetter(Accessory::family), + Codec.INT.optionalFieldOf("tier", 0).forGetter(Accessory::tier)) + .apply(instance, Accessory::new)); + private static final Codec> MAP_CODEC = Codec.unboundedMap(Codec.STRING, CODEC); + + private boolean hasFamily() { + return family.isPresent(); + } + + private boolean hasSameFamily(Accessory other) { + return other.family().equals(this.family); + } + } + + enum AccessoryReport { + HAS_HIGHEST_TIER, //You've collected the highest tier - Collected + IS_GREATER_TIER, //This accessory is an upgrade from the one in the same family that you already have - Upgrade + HAS_GREATER_TIER, //This accessory has a higher tier upgrade - Upgradable + OWNS_BETTER_TIER, //You've collected an accessory in this family with a higher tier - Downgrade + MISSING, //You don't have any accessories in this family - Missing + INELIGIBLE; + } +} 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 1b3f402d..8a11b9bd 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 @@ -5,6 +5,7 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.item.MuseumItemCache; +import de.hysky.skyblocker.skyblock.item.tooltip.AccessoriesHelper.AccessoryReport; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; @@ -238,6 +239,27 @@ public class ItemTooltip { } } } + + if (TooltipInfoType.ACCESSORIES.isTooltipEnabledAndHasOrNullWarning(internalID)) { + AccessoryReport report = AccessoriesHelper.calculateReport4Accessory(internalID); + + if (report != AccessoryReport.INELIGIBLE) { + MutableText title = Text.literal(String.format("%-19s", "Accessory: ")).withColor(0xf57542); + + Text stateText = switch (report) { + case HAS_HIGHEST_TIER -> Text.literal("✔ Collected").formatted(Formatting.GREEN); + case IS_GREATER_TIER -> Text.literal("✦ Upgrade").withColor(0x218bff); + case HAS_GREATER_TIER -> Text.literal("↑ Upgradable").withColor(0xf8d048); + case OWNS_BETTER_TIER -> Text.literal("↓ Downgrade").formatted(Formatting.GRAY); + case MISSING -> Text.literal("✖ Missing").formatted(Formatting.RED); + + //Should never be the case + default -> Text.literal("? Unknown").formatted(Formatting.GRAY); + }; + + lines.add(title.append(stateText)); + } + } } private static void addExoticTooltip(List lines, String internalID, NbtCompound nbt, String colorHex, String expectedHex, String existingTooltip) { @@ -390,6 +412,7 @@ public class ItemTooltip { TooltipInfoType.MOTES.downloadIfEnabled(futureList); TooltipInfoType.MUSEUM.downloadIfEnabled(futureList); TooltipInfoType.COLOR.downloadIfEnabled(futureList); + TooltipInfoType.ACCESSORIES.downloadIfEnabled(futureList); CompletableFuture.allOf(futureList.toArray(CompletableFuture[]::new)).exceptionally(e -> { LOGGER.error("Encountered unknown error while downloading tooltip data", e); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java index 4aba040d..d0cf91b8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java @@ -6,13 +6,15 @@ import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Http; import de.hysky.skyblocker.utils.Utils; -import org.jetbrains.annotations.Nullable; import java.net.http.HttpHeaders; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; import java.util.function.Predicate; +import org.jetbrains.annotations.Nullable; + public enum TooltipInfoType implements Runnable { NPC("https://hysky.de/api/npcprice", itemTooltip -> itemTooltip.enableNPCPrice, true), BAZAAR("https://hysky.de/api/bazaar", itemTooltip -> itemTooltip.enableBazaarPrice || SkyblockerConfigManager.get().locations.dungeons.dungeonChestProfit.enableProfitCalculator || SkyblockerConfigManager.get().locations.dungeons.dungeonChestProfit.croesusProfit || SkyblockerConfigManager.get().general.chestValue.enableChestValue, itemTooltip -> itemTooltip.enableBazaarPrice, false), @@ -22,7 +24,8 @@ public enum TooltipInfoType implements Runnable { MOTES("https://hysky.de/api/motesprice", itemTooltip -> itemTooltip.enableMotesPrice, itemTooltip -> itemTooltip.enableMotesPrice && Utils.isInTheRift(), true), OBTAINED(itemTooltip -> itemTooltip.enableObtainedDate), MUSEUM("https://hysky.de/api/museum", itemTooltip -> itemTooltip.enableMuseumInfo, true), - COLOR("https://hysky.de/api/color", itemTooltip -> itemTooltip.enableExoticTooltip, true); + COLOR("https://hysky.de/api/color", itemTooltip -> itemTooltip.enableExoticTooltip, true), + ACCESSORIES("https://api.azureaaron.net/skyblock/accessories", itemTooltip -> itemTooltip.enableAccessoriesHelper, true, AccessoriesHelper::refreshData); private final String address; private final Predicate dataEnabled; @@ -30,12 +33,23 @@ public enum TooltipInfoType implements Runnable { private JsonObject data; private final boolean cacheable; private long hash; + private final Consumer callback; /** * Use this for when you're adding tooltip info that has no data associated with it */ TooltipInfoType(Predicate enabled) { - this(null, itemTooltip -> false, enabled, null, false); + this(null, itemTooltip -> false, enabled, false, 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 enabled, boolean cacheable, Consumer callback) { + this(address, enabled, enabled, cacheable, callback); } /** @@ -44,7 +58,7 @@ public enum TooltipInfoType implements Runnable { * @param cacheable whether the data should be cached */ TooltipInfoType(String address, Predicate enabled, boolean cacheable) { - this(address, enabled, enabled, null, cacheable); + this(address, enabled, enabled, cacheable, null); } /** @@ -54,7 +68,7 @@ public enum TooltipInfoType implements Runnable { * @param cacheable whether the data should be cached */ TooltipInfoType(String address, Predicate dataEnabled, Predicate tooltipEnabled, boolean cacheable) { - this(address, dataEnabled, tooltipEnabled, null, cacheable); + this(address, dataEnabled, tooltipEnabled, cacheable, null); } /** @@ -64,12 +78,13 @@ public enum TooltipInfoType implements Runnable { * @param data the data * @param cacheable whether the data should be cached */ - TooltipInfoType(String address, Predicate dataEnabled, Predicate tooltipEnabled, @Nullable JsonObject data, boolean cacheable) { + TooltipInfoType(String address, Predicate dataEnabled, Predicate tooltipEnabled, boolean cacheable, @Nullable Consumer callback) { this.address = address; this.dataEnabled = dataEnabled; this.tooltipEnabled = tooltipEnabled; - this.data = data; + this.data = null; this.cacheable = cacheable; + this.callback = callback; } /** @@ -146,6 +161,8 @@ public enum TooltipInfoType implements Runnable { else this.hash = hash; } data = SkyblockerMod.GSON.fromJson(Http.sendGetRequest(address), JsonObject.class); + + if (callback != null) callback.accept(data); } catch (Exception e) { ItemTooltip.LOGGER.warn("[Skyblocker] Failed to download " + this + " prices!", e); } -- cgit From b21515cfdcd6a4a14cc256131d5ae6bb6666792d Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sun, 24 Mar 2024 16:05:09 -0400 Subject: Use hysky redirect --- .../java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java index d0cf91b8..6edee8d6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/TooltipInfoType.java @@ -25,7 +25,7 @@ public enum TooltipInfoType implements Runnable { OBTAINED(itemTooltip -> itemTooltip.enableObtainedDate), MUSEUM("https://hysky.de/api/museum", itemTooltip -> itemTooltip.enableMuseumInfo, true), COLOR("https://hysky.de/api/color", itemTooltip -> itemTooltip.enableExoticTooltip, true), - ACCESSORIES("https://api.azureaaron.net/skyblock/accessories", itemTooltip -> itemTooltip.enableAccessoriesHelper, true, AccessoriesHelper::refreshData); + ACCESSORIES("https://hysky.de/api/accessories", itemTooltip -> itemTooltip.enableAccessoriesHelper, true, AccessoriesHelper::refreshData); private final String address; private final Predicate dataEnabled; -- cgit From fad85d138db8761ca2a3edfe08520b32e08ae3dc Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Fri, 29 Mar 2024 21:44:37 -0400 Subject: Enhance the accessories helper --- .../skyblock/item/tooltip/AccessoriesHelper.java | 36 ++++++++++++---------- .../skyblock/item/tooltip/ItemTooltip.java | 13 ++++---- 2 files changed, 27 insertions(+), 22 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java index b5291af6..a3fc40d5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -30,6 +30,7 @@ import com.mojang.util.UndashedUuid; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -60,7 +61,7 @@ public class AccessoriesHelper { ScreenEvents.BEFORE_INIT.register((_client, screen, _scaledWidth, _scaledHeight) -> { if (Utils.isOnSkyblock() && TooltipInfoType.ACCESSORIES.isTooltipEnabled() && !Utils.getProfileId().isEmpty() && screen instanceof GenericContainerScreen genericContainerScreen) { if (ACCESSORY_BAG_TITLE.matcher(genericContainerScreen.getTitle().getString()).matches()) { - ScreenEvents.afterRender(screen).register((_screen, _context, _mouseX, _mouseY, _delta) -> { + ScreenEvents.afterTick(screen).register(_screen -> { GenericContainerScreenHandler handler = genericContainerScreen.getScreenHandler(); collectAccessories(handler.slots.subList(0, handler.getRows() * 9)); @@ -109,8 +110,8 @@ public class AccessoriesHelper { profileData.accessoryIds().addAll(accessoryIds); } - static AccessoryReport calculateReport4Accessory(String accessoryId) { - if (!ACCESSORY_DATA.containsKey(accessoryId) || Utils.getProfileId().isEmpty()) return AccessoryReport.INELIGIBLE; + static Pair calculateReport4Accessory(String accessoryId) { + if (!ACCESSORY_DATA.containsKey(accessoryId) || Utils.getProfileId().isEmpty()) return Pair.of(AccessoryReport.INELIGIBLE, null); Accessory accessory = ACCESSORY_DATA.get(accessoryId); String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); @@ -120,7 +121,7 @@ public class AccessoriesHelper { .collect(Collectors.toSet()); //If the player has this accessory and it doesn't belong to a family - if (collectedAccessories.contains(accessory) && accessory.family().isEmpty()) return AccessoryReport.HAS_HIGHEST_TIER; + if (collectedAccessories.contains(accessory) && accessory.family().isEmpty()) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); Predicate HAS_SAME_FAMILY = accessory::hasSameFamily; Set collectedAccessoriesInTheSameFamily = collectedAccessories.stream() @@ -129,7 +130,7 @@ public class AccessoriesHelper { .collect(Collectors.toSet()); //If the player doesn't have any collected accessories with same family - if (collectedAccessoriesInTheSameFamily.isEmpty()) return AccessoryReport.MISSING; + if (collectedAccessoriesInTheSameFamily.isEmpty()) return Pair.of(AccessoryReport.MISSING, null); Set accessoriesInTheSameFamily = ACCESSORY_DATA.values().stream() .filter(HAS_FAMILY) @@ -142,12 +143,12 @@ public class AccessoriesHelper { .max(Comparator.comparingInt(ACCESSORY_TIER)); if (highestTierOfFamily.isPresent()) { - Accessory highestTier = highestTierOfFamily.orElseThrow(); + Accessory highestTier = highestTierOfFamily.get(); - if (collectedAccessoriesInTheSameFamily.contains(highestTier)) return AccessoryReport.HAS_HIGHEST_TIER; + if (collectedAccessoriesInTheSameFamily.contains(highestTier)) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); //For when the highest tier is tied - if (highestTier.hasSameFamily(accessory) && collectedAccessoriesInTheSameFamily.stream().allMatch(ca -> ca.tier() == highestTier.tier())) return AccessoryReport.HAS_HIGHEST_TIER; + if (highestTier.hasSameFamily(accessory) && collectedAccessoriesInTheSameFamily.stream().allMatch(ca -> ca.tier() == highestTier.tier())) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); } //If this accessory is a higher tier than all of other collected accessories in the same family @@ -155,19 +156,21 @@ public class AccessoriesHelper { .mapToInt(ACCESSORY_TIER) .max(); - if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() > highestTierOfAllCollectedInFamily.orElseThrow()) return AccessoryReport.IS_GREATER_TIER; + int maxTierInFamily = highestTierOfFamily.orElse(Accessory.EMPTY).tier(); + + if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() > highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.IS_GREATER_TIER, String.format("(%d/%d)", accessory.tier(), maxTierInFamily)); //If this accessory is a lower tier than one already obtained from same family - if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() < highestTierOfAllCollectedInFamily.orElseThrow()) return AccessoryReport.OWNS_BETTER_TIER; + if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() < highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.OWNS_BETTER_TIER, String.format("(%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), maxTierInFamily)); //If there is an accessory in the same family that has a higher tier //Take the accessories in the same family, then check if there is an accessory whose tier is greater than {@code accessory} boolean hasGreaterTierInFamily = accessoriesInTheSameFamily.stream() .anyMatch(ca -> ca.tier() > accessory.tier()); - if (hasGreaterTierInFamily) return AccessoryReport.HAS_GREATER_TIER; + if (hasGreaterTierInFamily) return Pair.of(AccessoryReport.HAS_GREATER_TIER, String.format("(%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), maxTierInFamily)); - return AccessoryReport.MISSING; + return Pair.of(AccessoryReport.MISSING, null); } static void refreshData(JsonObject data) { @@ -200,7 +203,7 @@ public class AccessoriesHelper { /** * @author AzureAaron - * @implSpec Aaron's Mod + * @implSpec Aaron's Mod */ private record Accessory(String id, Optional family, int tier) { private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -209,6 +212,7 @@ public class AccessoriesHelper { Codec.INT.optionalFieldOf("tier", 0).forGetter(Accessory::tier)) .apply(instance, Accessory::new)); private static final Codec> MAP_CODEC = Codec.unboundedMap(Codec.STRING, CODEC); + private static final Accessory EMPTY = new Accessory("", Optional.empty(), 0); private boolean hasFamily() { return family.isPresent(); @@ -221,9 +225,9 @@ public class AccessoriesHelper { enum AccessoryReport { HAS_HIGHEST_TIER, //You've collected the highest tier - Collected - IS_GREATER_TIER, //This accessory is an upgrade from the one in the same family that you already have - Upgrade - HAS_GREATER_TIER, //This accessory has a higher tier upgrade - Upgradable - OWNS_BETTER_TIER, //You've collected an accessory in this family with a higher tier - Downgrade + IS_GREATER_TIER, //This accessory is an upgrade from the one in the same family that you already have - Upgrade -- Shows you what tier this accessory is in it's family + HAS_GREATER_TIER, //This accessory has a higher tier upgrade - Upgradable -- Shows you the highest tier accessory you've collected in that family + OWNS_BETTER_TIER, //You've collected an accessory in this family with a higher tier - Downgrade -- Shows you the highest tier accessory you've collected in that family MISSING, //You don't have any accessories in this family - Missing INELIGIBLE; } 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 8a11b9bd..637aea22 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 @@ -10,6 +10,7 @@ import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.Pair; import net.minecraft.client.MinecraftClient; import net.minecraft.client.item.TooltipContext; import net.minecraft.item.DyeableItem; @@ -241,16 +242,16 @@ public class ItemTooltip { } if (TooltipInfoType.ACCESSORIES.isTooltipEnabledAndHasOrNullWarning(internalID)) { - AccessoryReport report = AccessoriesHelper.calculateReport4Accessory(internalID); + Pair report = AccessoriesHelper.calculateReport4Accessory(internalID); - if (report != AccessoryReport.INELIGIBLE) { + if (report.left() != AccessoryReport.INELIGIBLE) { MutableText title = Text.literal(String.format("%-19s", "Accessory: ")).withColor(0xf57542); - Text stateText = switch (report) { + Text stateText = switch (report.left()) { case HAS_HIGHEST_TIER -> Text.literal("✔ Collected").formatted(Formatting.GREEN); - case IS_GREATER_TIER -> Text.literal("✦ Upgrade").withColor(0x218bff); - case HAS_GREATER_TIER -> Text.literal("↑ Upgradable").withColor(0xf8d048); - case OWNS_BETTER_TIER -> Text.literal("↓ Downgrade").formatted(Formatting.GRAY); + case IS_GREATER_TIER -> Text.literal("✦ Upgrade ").withColor(0x218bff).append(Text.literal(report.right()).withColor(0xf8f8ff)); + case HAS_GREATER_TIER -> Text.literal("↑ Upgradable ").withColor(0xf8d048).append(Text.literal(report.right()).withColor(0xf8f8ff)); + case OWNS_BETTER_TIER -> Text.literal("↓ Downgrade ").formatted(Formatting.GRAY).append(Text.literal(report.right()).withColor(0xf8f8ff)); case MISSING -> Text.literal("✖ Missing").formatted(Formatting.RED); //Should never be the case -- cgit From bbea21ac0a8419f1cf5c133747416152bb70ccb5 Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sun, 31 Mar 2024 22:20:55 -0400 Subject: Page based data storage --- .../skyblock/item/tooltip/AccessoriesHelper.java | 44 ++++++++++++---------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java index a3fc40d5..951d8d5f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -14,6 +14,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import java.util.function.ToIntFunction; +import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -31,9 +32,11 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.MinecraftClient; @@ -44,9 +47,9 @@ import net.minecraft.screen.slot.Slot; public class AccessoriesHelper { private static final Logger LOGGER = LogUtils.getLogger(); private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("collected_accessories.json"); - private static final Pattern ACCESSORY_BAG_TITLE = Pattern.compile("Accessory Bag \\(\\d+\\/\\d+\\)"); + private static final Pattern ACCESSORY_BAG_TITLE = Pattern.compile("Accessory Bag \\((?\\d+)\\/\\d+\\)"); //UUID -> Profile Id & Data - private static final Map> COLLECTED_ACCESSORIES = new Object2ObjectOpenHashMap<>(); + private static final Object2ObjectOpenHashMap> COLLECTED_ACCESSORIES = new Object2ObjectOpenHashMap<>(); private static final Predicate NON_EMPTY = s -> !s.isEmpty(); private static final Predicate HAS_FAMILY = Accessory::hasFamily; private static final ToIntFunction ACCESSORY_TIER = Accessory::tier; @@ -60,21 +63,24 @@ public class AccessoriesHelper { ClientLifecycleEvents.CLIENT_STOPPING.register((_client) -> save()); ScreenEvents.BEFORE_INIT.register((_client, screen, _scaledWidth, _scaledHeight) -> { if (Utils.isOnSkyblock() && TooltipInfoType.ACCESSORIES.isTooltipEnabled() && !Utils.getProfileId().isEmpty() && screen instanceof GenericContainerScreen genericContainerScreen) { - if (ACCESSORY_BAG_TITLE.matcher(genericContainerScreen.getTitle().getString()).matches()) { + Matcher matcher = ACCESSORY_BAG_TITLE.matcher(genericContainerScreen.getTitle().getString()); + + if (matcher.matches()) { ScreenEvents.afterTick(screen).register(_screen -> { GenericContainerScreenHandler handler = genericContainerScreen.getScreenHandler(); - collectAccessories(handler.slots.subList(0, handler.getRows() * 9)); + collectAccessories(handler.slots.subList(0, handler.getRows() * 9), Integer.parseInt(matcher.group("page"))); }); } } }); } + //Note: JsonOps.COMPRESSED must be used if you're using maps with non-string keys private static void load() { loaded = CompletableFuture.runAsync(() -> { try (BufferedReader reader = Files.newBufferedReader(FILE)) { - COLLECTED_ACCESSORIES.putAll(ProfileAccessoryData.SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result().orElseThrow()); + COLLECTED_ACCESSORIES.putAll(ProfileAccessoryData.SERIALIZATION_CODEC.parse(JsonOps.COMPRESSED, JsonParser.parseReader(reader)).result().orElseThrow()); } catch (NoSuchFileException ignored) { } catch (Exception e) { LOGGER.error("[Skyblocker Accessory Helper] Failed to load accessory file!", e); @@ -84,13 +90,13 @@ public class AccessoriesHelper { private static void save() { try (BufferedWriter writer = Files.newBufferedWriter(FILE)) { - SkyblockerMod.GSON.toJson(ProfileAccessoryData.SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, COLLECTED_ACCESSORIES).result().orElseThrow(), writer); + SkyblockerMod.GSON.toJson(ProfileAccessoryData.SERIALIZATION_CODEC.encodeStart(JsonOps.COMPRESSED, COLLECTED_ACCESSORIES).result().orElseThrow(), writer); } catch (Exception e) { LOGGER.error("[Skyblocker Accessory Helper] Failed to save accessory file!", e); } } - private static void collectAccessories(List slots) { + private static void collectAccessories(List slots, int page) { //Is this even needed? if (!loaded.isDone()) return; @@ -107,7 +113,7 @@ public class AccessoriesHelper { ProfileAccessoryData profileData = playerData.get(Utils.getProfileId()); - profileData.accessoryIds().addAll(accessoryIds); + profileData.pages().put(page, new ObjectOpenHashSet<>(accessoryIds)); } static Pair calculateReport4Accessory(String accessoryId) { @@ -115,7 +121,9 @@ public class AccessoriesHelper { Accessory accessory = ACCESSORY_DATA.get(accessoryId); String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); - Set collectedAccessories = COLLECTED_ACCESSORIES.get(uuid).get(Utils.getProfileId()).accessoryIds().stream() + Set collectedAccessories = COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()).computeIfAbsent(Utils.getProfileId(), profileId -> ProfileAccessoryData.createDefault()).pages().int2ObjectEntrySet().stream() + .map(Entry::getValue) + .flatMap(ObjectOpenHashSet::stream) .filter(ACCESSORY_DATA::containsKey) .map(ACCESSORY_DATA::get) .collect(Collectors.toSet()); @@ -183,21 +191,17 @@ public class AccessoriesHelper { } } - private record ProfileAccessoryData(Set accessoryIds) { + private record ProfileAccessoryData(Int2ObjectOpenHashMap> pages) { private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Codec.STRING.listOf() - .xmap(ObjectOpenHashSet::new, ObjectArrayList::new) - .fieldOf("accessoryIds") - .forGetter(i -> new ObjectOpenHashSet(i.accessoryIds()))) + Codec.unboundedMap(Codec.INT, Codec.STRING.listOf().xmap(ObjectOpenHashSet::new, ObjectArrayList::new)) + .xmap(Int2ObjectOpenHashMap::new, Int2ObjectOpenHashMap::new).fieldOf("pages").forGetter(ProfileAccessoryData::pages)) .apply(instance, ProfileAccessoryData::new)); - //Mojang's internal Codec implementation uses ImmutableMaps so we'll just xmap those away and type safety while we're at it :') - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static final Codec>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, Codec.unboundedMap(Codec.STRING, CODEC) + private static final Codec>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, Codec.unboundedMap(Codec.STRING, CODEC) .xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new)) - .xmap(Object2ObjectOpenHashMap::new, m -> (Map) new Object2ObjectOpenHashMap(m)); + .xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new); private static ProfileAccessoryData createDefault() { - return new ProfileAccessoryData(new ObjectOpenHashSet<>()); + return new ProfileAccessoryData(new Int2ObjectOpenHashMap<>()); } } -- cgit From 0a2fa0a57c817cabb64b0890a7271acb491b6e98 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:38:36 -0400 Subject: Refactor AccessoriesHelper --- .../skyblock/item/tooltip/AccessoriesHelper.java | 46 +++++++--------------- 1 file changed, 15 insertions(+), 31 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java index 951d8d5f..358f3d85 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -32,7 +32,6 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.Pair; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -47,7 +46,7 @@ import net.minecraft.screen.slot.Slot; public class AccessoriesHelper { private static final Logger LOGGER = LogUtils.getLogger(); private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("collected_accessories.json"); - private static final Pattern ACCESSORY_BAG_TITLE = Pattern.compile("Accessory Bag \\((?\\d+)\\/\\d+\\)"); + private static final Pattern ACCESSORY_BAG_TITLE = Pattern.compile("Accessory Bag \\((?\\d+)/\\d+\\)"); //UUID -> Profile Id & Data private static final Object2ObjectOpenHashMap> COLLECTED_ACCESSORIES = new Object2ObjectOpenHashMap<>(); private static final Predicate NON_EMPTY = s -> !s.isEmpty(); @@ -104,16 +103,12 @@ public class AccessoriesHelper { .map(Slot::getStack) .map(ItemUtils::getItemId) .filter(NON_EMPTY) - .collect(Collectors.toUnmodifiableList()); + .toList(); String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); - Map playerData = COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()); - playerData.putIfAbsent(Utils.getProfileId(), ProfileAccessoryData.createDefault()); - - ProfileAccessoryData profileData = playerData.get(Utils.getProfileId()); - - profileData.pages().put(page, new ObjectOpenHashSet<>(accessoryIds)); + COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()).computeIfAbsent(Utils.getProfileId(), profileId -> ProfileAccessoryData.createDefault()).pages() + .put(page, new ObjectOpenHashSet<>(accessoryIds)); } static Pair calculateReport4Accessory(String accessoryId) { @@ -121,14 +116,13 @@ public class AccessoriesHelper { Accessory accessory = ACCESSORY_DATA.get(accessoryId); String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull()); - Set collectedAccessories = COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()).computeIfAbsent(Utils.getProfileId(), profileId -> ProfileAccessoryData.createDefault()).pages().int2ObjectEntrySet().stream() - .map(Entry::getValue) + Set collectedAccessories = COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()).computeIfAbsent(Utils.getProfileId(), profileId -> ProfileAccessoryData.createDefault()).pages().values().stream() .flatMap(ObjectOpenHashSet::stream) .filter(ACCESSORY_DATA::containsKey) .map(ACCESSORY_DATA::get) .collect(Collectors.toSet()); - //If the player has this accessory and it doesn't belong to a family + //If the player has this accessory, and it doesn't belong to a family if (collectedAccessories.contains(accessory) && accessory.family().isEmpty()) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); Predicate HAS_SAME_FAMILY = accessory::hasSameFamily; @@ -146,30 +140,22 @@ public class AccessoriesHelper { .collect(Collectors.toSet()); ///If the player has the highest tier accessory in this family - //Take the the accessories in the same family as {@code accessory}, then get the one with the highest tier + //Take the accessories in the same family as {@code accessory}, then get the one with the highest tier Optional highestTierOfFamily = accessoriesInTheSameFamily.stream() .max(Comparator.comparingInt(ACCESSORY_TIER)); + int maxTierInFamily = highestTierOfFamily.orElse(Accessory.EMPTY).tier(); - if (highestTierOfFamily.isPresent()) { - Accessory highestTier = highestTierOfFamily.get(); - - if (collectedAccessoriesInTheSameFamily.contains(highestTier)) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); + if (collectedAccessoriesInTheSameFamily.stream().anyMatch(ca -> ca.tier() == maxTierInFamily)) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); - //For when the highest tier is tied - if (highestTier.hasSameFamily(accessory) && collectedAccessoriesInTheSameFamily.stream().allMatch(ca -> ca.tier() == highestTier.tier())) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null); - } - - //If this accessory is a higher tier than all of other collected accessories in the same family + //If this accessory is a higher tier than all the other collected accessories in the same family OptionalInt highestTierOfAllCollectedInFamily = collectedAccessoriesInTheSameFamily.stream() .mapToInt(ACCESSORY_TIER) .max(); - int maxTierInFamily = highestTierOfFamily.orElse(Accessory.EMPTY).tier(); - - if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() > highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.IS_GREATER_TIER, String.format("(%d/%d)", accessory.tier(), maxTierInFamily)); + if (accessory.tier() > highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.IS_GREATER_TIER, String.format("(%d/%d)", accessory.tier(), maxTierInFamily)); //If this accessory is a lower tier than one already obtained from same family - if (highestTierOfAllCollectedInFamily.isPresent() && accessory.tier() < highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.OWNS_BETTER_TIER, String.format("(%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), maxTierInFamily)); + if (accessory.tier() < highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.OWNS_BETTER_TIER, String.format("(%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), maxTierInFamily)); //If there is an accessory in the same family that has a higher tier //Take the accessories in the same family, then check if there is an accessory whose tier is greater than {@code accessory} @@ -183,9 +169,7 @@ public class AccessoriesHelper { static void refreshData(JsonObject data) { try { - Map accessoryData = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).result().orElseThrow(); - - ACCESSORY_DATA = accessoryData; + ACCESSORY_DATA = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).result().orElseThrow(); } catch (Exception e) { LOGGER.error("[Skyblocker Accessory Helper] Failed to parse data!", e); } @@ -229,10 +213,10 @@ public class AccessoriesHelper { enum AccessoryReport { HAS_HIGHEST_TIER, //You've collected the highest tier - Collected - IS_GREATER_TIER, //This accessory is an upgrade from the one in the same family that you already have - Upgrade -- Shows you what tier this accessory is in it's family + IS_GREATER_TIER, //This accessory is an upgrade from the one in the same family that you already have - Upgrade -- Shows you what tier this accessory is in its family HAS_GREATER_TIER, //This accessory has a higher tier upgrade - Upgradable -- Shows you the highest tier accessory you've collected in that family OWNS_BETTER_TIER, //You've collected an accessory in this family with a higher tier - Downgrade -- Shows you the highest tier accessory you've collected in that family MISSING, //You don't have any accessories in this family - Missing - INELIGIBLE; + INELIGIBLE } } -- cgit From 69d925788dcb7ef23157acdd97e184b66f08e622 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:56:24 -0400 Subject: Show accessory tier change --- .../de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java index 358f3d85..69bc6f1c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/tooltip/AccessoriesHelper.java @@ -152,10 +152,10 @@ public class AccessoriesHelper { .mapToInt(ACCESSORY_TIER) .max(); - if (accessory.tier() > highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.IS_GREATER_TIER, String.format("(%d/%d)", accessory.tier(), maxTierInFamily)); + if (accessory.tier() > highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.IS_GREATER_TIER, String.format("(%d→%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), accessory.tier(), maxTierInFamily)); //If this accessory is a lower tier than one already obtained from same family - if (accessory.tier() < highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.OWNS_BETTER_TIER, String.format("(%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), maxTierInFamily)); + if (accessory.tier() < highestTierOfAllCollectedInFamily.getAsInt()) return Pair.of(AccessoryReport.OWNS_BETTER_TIER, String.format("(%d→%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), accessory.tier(), maxTierInFamily)); //If there is an accessory in the same family that has a higher tier //Take the accessories in the same family, then check if there is an accessory whose tier is greater than {@code accessory} -- cgit