Skip to content

Commit

Permalink
Merge pull request #650 from kevinthegreat1/accessories-fix
Browse files Browse the repository at this point in the history
Fix has highest tier
  • Loading branch information
kevinthegreat1 authored Apr 19, 2024
2 parents 46121c8 + 411e687 commit 7fa4ac6
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -1,33 +1,12 @@
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.Matcher;
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;
Expand All @@ -42,6 +21,23 @@
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.slot.Slot;
import org.slf4j.Logger;

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.List;
import java.util.Map;
import java.util.Optional;
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;

public class AccessoriesHelper {
private static final Logger LOGGER = LogUtils.getLogger();
Expand Down Expand Up @@ -95,7 +91,7 @@ private static void save() {
}
}

private static void collectAccessories(List<Slot> slots, int page) {
private static void collectAccessories(List<Slot> slots, int page) {
//Is this even needed?
if (!loaded.isDone()) return;

Expand All @@ -107,69 +103,70 @@ private static void collectAccessories(List<Slot> slots, int page) {

String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull());

COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()).computeIfAbsent(Utils.getProfileId(), profileId -> ProfileAccessoryData.createDefault()).pages()
COLLECTED_ACCESSORIES.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()).computeIfAbsent(Utils.getProfileId(), profileId -> ProfileAccessoryData.createDefault()).pages()
.put(page, new ObjectOpenHashSet<>(accessoryIds));
}

static Pair<AccessoryReport, String> calculateReport4Accessory(String accessoryId) {
if (!ACCESSORY_DATA.containsKey(accessoryId) || Utils.getProfileId().isEmpty()) return Pair.of(AccessoryReport.INELIGIBLE, null);

Accessory accessory = ACCESSORY_DATA.get(accessoryId);
Accessory accessory = ACCESSORY_DATA.get(accessoryId);
String uuid = UndashedUuid.toString(MinecraftClient.getInstance().getSession().getUuidOrNull());
Set<Accessory> 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 (collectedAccessories.contains(accessory) && accessory.family().isEmpty()) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null);
// If the accessory doesn't belong to a family
if (accessory.family().isEmpty()) {
//If the player has this accessory or player doesn't have this accessory
return collectedAccessories.contains(accessory) ? Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null) : Pair.of(AccessoryReport.MISSING, "");
}

Predicate<Accessory> HAS_SAME_FAMILY = accessory::hasSameFamily;
Set<Accessory> 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 Pair.of(AccessoryReport.MISSING, null);

Set<Accessory> 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 accessories in the same family as {@code accessory}, then get the one with the highest tier
Optional<Accessory> highestTierOfFamily = accessoriesInTheSameFamily.stream()
.max(Comparator.comparingInt(ACCESSORY_TIER));
int maxTierInFamily = highestTierOfFamily.orElse(Accessory.EMPTY).tier();
int highestTierInFamily = accessoriesInTheSameFamily.stream()
.mapToInt(ACCESSORY_TIER)
.max()
.orElse(0);

if (collectedAccessoriesInTheSameFamily.stream().anyMatch(ca -> ca.tier() == maxTierInFamily)) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null);
//If the player hasn't collected any accessory in same family
if (collectedAccessoriesInTheSameFamily.isEmpty()) return Pair.of(AccessoryReport.MISSING, String.format("(%d/%d)", accessory.tier(), highestTierInFamily));

//If this accessory is a higher tier than all the other collected accessories in the same family
OptionalInt highestTierOfAllCollectedInFamily = collectedAccessoriesInTheSameFamily.stream()
int highestTierCollectedInFamily = collectedAccessoriesInTheSameFamily.stream()
.mapToInt(ACCESSORY_TIER)
.max();
.max()
.getAsInt();

//If this accessory is the highest tier, and the player has the highest tier accessory in this family
//This accounts for multiple accessories with the highest tier
if (accessory.tier() == highestTierInFamily && highestTierCollectedInFamily == highestTierInFamily) return Pair.of(AccessoryReport.HAS_HIGHEST_TIER, null);

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 higher tier than all the other collected accessories in the same family
if (accessory.tier() > highestTierCollectedInFamily) return Pair.of(AccessoryReport.IS_GREATER_TIER, String.format("(%d→%d/%d)", highestTierCollectedInFamily, accessory.tier(), highestTierInFamily));

//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/%d)", highestTierOfAllCollectedInFamily.orElse(0), accessory.tier(), maxTierInFamily));
if (accessory.tier() < highestTierCollectedInFamily) return Pair.of(AccessoryReport.OWNS_BETTER_TIER, String.format("(%d→%d/%d)", highestTierCollectedInFamily, accessory.tier(), highestTierInFamily));

//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 (accessory.tier() < highestTierInFamily) return Pair.of(AccessoryReport.HAS_GREATER_TIER, String.format("(%d/%d)", highestTierCollectedInFamily, highestTierInFamily));

if (hasGreaterTierInFamily) return Pair.of(AccessoryReport.HAS_GREATER_TIER, String.format("(%d/%d)", highestTierOfAllCollectedInFamily.orElse(0), maxTierInFamily));

return Pair.of(AccessoryReport.MISSING, null);
return Pair.of(AccessoryReport.MISSING, String.format("(%d/%d)", accessory.tier(), highestTierInFamily));
}

static void refreshData(JsonObject data) {
try {
ACCESSORY_DATA = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).result().orElseThrow();
ACCESSORY_DATA = Accessory.MAP_CODEC.parse(JsonOps.INSTANCE, data).result().orElseThrow();
} catch (Exception e) {
LOGGER.error("[Skyblocker Accessory Helper] Failed to parse data!", e);
}
Expand All @@ -178,11 +175,11 @@ static void refreshData(JsonObject data) {
private record ProfileAccessoryData(Int2ObjectOpenHashMap<ObjectOpenHashSet<String>> pages) {
private static final Codec<ProfileAccessoryData> CODEC = RecordCodecBuilder.create(instance -> instance.group(
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));
.xmap(Int2ObjectOpenHashMap::new, Int2ObjectOpenHashMap::new).fieldOf("pages").forGetter(ProfileAccessoryData::pages)
).apply(instance, ProfileAccessoryData::new));
private static final Codec<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, ProfileAccessoryData>>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, Codec.unboundedMap(Codec.STRING, CODEC)
.xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new))
.xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new);
.xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new)
).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new);

private static ProfileAccessoryData createDefault() {
return new ProfileAccessoryData(new Int2ObjectOpenHashMap<>());
Expand All @@ -197,11 +194,10 @@ private record Accessory(String id, Optional<String> family, int tier) {
private static final Codec<Accessory> 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));
Codec.INT.optionalFieldOf("tier", 0).forGetter(Accessory::tier)
).apply(instance, Accessory::new));
private static final Codec<Map<String, Accessory>> MAP_CODEC = Codec.unboundedMap(Codec.STRING, CODEC);
private static final Accessory EMPTY = new Accessory("", Optional.empty(), 0);


private boolean hasFamily() {
return family.isPresent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public static void getTooltip(ItemStack stack, TooltipContext context, List<Text
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);
case MISSING -> Text.literal("✖ Missing ").formatted(Formatting.RED).append(Text.literal(report.right()).withColor(0xf8f8ff));

//Should never be the case
default -> Text.literal("? Unknown").formatted(Formatting.GRAY);
Expand Down

0 comments on commit 7fa4ac6

Please sign in to comment.