diff options
Diffstat (limited to 'src/main/java/de')
12 files changed, 265 insertions, 381 deletions
diff --git a/src/main/java/de/hysky/skyblocker/config/categories/OtherLocationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/OtherLocationsCategory.java index 259e91d9..c7fa6cb2 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/OtherLocationsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/OtherLocationsCategory.java @@ -134,11 +134,7 @@ public class OtherLocationsCategory { .option(ButtonOption.createBuilder() .name(Text.translatable("skyblocker.config.otherLocations.end.resetName")) .text(Text.translatable("skyblocker.config.otherLocations.end.resetText")) - .action((screen, opt) -> { - TheEnd.zealotsKilled = 0; - TheEnd.zealotsSinceLastEye = 0; - TheEnd.eyes = 0; - }) + .action((screen, opt) -> TheEnd.PROFILES_STATS.put(TheEnd.EndStats.EMPTY)) .build()) .option(Option.<Boolean>createBuilder() .name(Text.translatable("skyblocker.config.otherLocations.end.muteEndermanSounds")) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java b/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java index 35fea3fa..603f1017 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/PetCache.java @@ -1,41 +1,27 @@ package de.hysky.skyblocker.skyblock; -import com.google.gson.JsonParser; -import com.mojang.logging.LogUtils; -import com.mojang.serialization.Codec; -import com.mojang.serialization.JsonOps; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.skyblock.item.PetInfo; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import de.hysky.skyblocker.utils.profile.ProfiledData; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.minecraft.client.gui.screen.ingame.GenericContainerScreen; import net.minecraft.item.ItemStack; import net.minecraft.screen.slot.Slot; import org.jetbrains.annotations.Nullable; -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.concurrent.CompletableFuture; /** - * Doesn't work with auto pet right now because thats complicated. + * Doesn't work with auto pet right now because that's complicated. * <p> * Want support? Ask the Admins for a Mod API event or open your pets menu. */ public class PetCache { - private static final Logger LOGGER = LogUtils.getLogger(); private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("pet_cache.json"); - private static final Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>> CACHED_PETS = new Object2ObjectOpenHashMap<>(); - public static final Codec<Object2ObjectOpenHashMap<String, Object2ObjectOpenHashMap<String, PetInfo>>> SERIALIZATION_CODEC = Codec.unboundedMap(Codec.STRING, - Codec.unboundedMap(Codec.STRING, PetInfo.CODEC).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new) - ).xmap(Object2ObjectOpenHashMap::new, Object2ObjectOpenHashMap::new); + private static final ProfiledData<PetInfo> CACHED_PETS = new ProfiledData<>(FILE, PetInfo.CODEC, true, true); /** * Used in case the server lags to prevent the screen tick check from overwriting the clicked pet logic @@ -44,7 +30,7 @@ public class PetCache { @Init public static void init() { - load(); + CACHED_PETS.load(); ScreenEvents.BEFORE_INIT.register((_client, screen, _scaledWidth, _scaledHeight) -> { if (Utils.isOnSkyblock() && screen instanceof GenericContainerScreen genericContainerScreen) { @@ -70,27 +56,6 @@ public class PetCache { }); } - private static void load() { - CompletableFuture.runAsync(() -> { - try (BufferedReader reader = Files.newBufferedReader(FILE)) { - CACHED_PETS.putAll(SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow()); - } catch (NoSuchFileException ignored) { - } catch (Exception e) { - LOGGER.error("[Skyblocker Pet Cache] Failed to load saved pet!", e); - } - }); - } - - private static void save() { - CompletableFuture.runAsync(() -> { - try (BufferedWriter writer = Files.newBufferedWriter(FILE)) { - SkyblockerMod.GSON.toJson(SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, CACHED_PETS).getOrThrow(), writer); - } catch (Exception e) { - LOGGER.error("[Skyblocker Pet Cache] Failed to save pet data to the cache!", e); - } - }); - } - public static void handlePetEquip(Slot slot, int slotId) { //Ignore inventory clicks if (slotId >= 0 && slotId <= 53) { @@ -112,24 +77,19 @@ public class PetCache { shouldLook4Pets = false; - Object2ObjectOpenHashMap<String, PetInfo> playerData = CACHED_PETS.computeIfAbsent(Utils.getUndashedUuid(), _uuid -> new Object2ObjectOpenHashMap<>()); - //Handle deselecting pets if (clicked && getCurrentPet() != null && getCurrentPet().uuid().orElse("").equals(petInfo.uuid().orElse(""))) { - playerData.remove(profileId); + CACHED_PETS.remove(); } else { - playerData.put(profileId, petInfo); + CACHED_PETS.put(petInfo); } - save(); + CACHED_PETS.save(); } } @Nullable public static PetInfo getCurrentPet() { - String uuid = Utils.getUndashedUuid(); - String profileId = Utils.getProfileId(); - - return CACHED_PETS.containsKey(uuid) && CACHED_PETS.get(uuid).containsKey(profileId) ? CACHED_PETS.get(uuid).get(profileId) : null; + return CACHED_PETS.get(); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/PowderMiningTracker.java b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/PowderMiningTracker.java index 5459d955..121422d5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dwarven/PowderMiningTracker.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dwarven/PowderMiningTracker.java @@ -1,9 +1,6 @@ package de.hysky.skyblocker.skyblock.dwarven; -import com.google.gson.JsonElement; import com.mojang.serialization.Codec; -import com.mojang.serialization.JsonOps; -import com.mojang.serialization.codecs.UnboundedMapCodec; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; @@ -16,10 +13,10 @@ import de.hysky.skyblocker.utils.CodecUtils; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Location; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.profile.ProfiledData; import it.unimi.dsi.fastutil.doubles.DoubleBooleanPair; import it.unimi.dsi.fastutil.objects.*; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.ChatHud; @@ -33,9 +30,9 @@ import org.jetbrains.annotations.Unmodifiable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.nio.file.Files; import java.nio.file.Path; import java.text.NumberFormat; +import java.util.Comparator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -47,27 +44,16 @@ public class PowderMiningTracker { private static final Pattern GEMSTONE_SYMBOLS = Pattern.compile("[α☘☠✎✧❁❂❈❤⸕] "); private static final Pattern REWARD_PATTERN = Pattern.compile(" {4}(.*?) ?x?([\\d,]*)"); private static final Codec<Object2IntMap<String>> REWARDS_CODEC = CodecUtils.object2IntMapCodec(Codec.STRING); - // Doesn't matter if the codec outputs a java map instead of a fastutils map, it's only used in #putAll anyway so the contents are copied over - private static final UnboundedMapCodec<String, Object2IntMap<String>> ALL_REWARDS_CODEC = Codec.unboundedMap(Codec.STRING, REWARDS_CODEC); private static final Object2ObjectArrayMap<String, String> NAME2ID_MAP = new Object2ObjectArrayMap<>(50); // This constructor takes in a comparator that is triggered to decide where to add the element in the tree map // This causes it to be sorted at all times. This is for rendering them in a sort of easy-to-read manner. - private static final Object2IntAVLTreeMap<Text> SHOWN_REWARDS = new Object2IntAVLTreeMap<>((o1, o2) -> { - String o1String = o1.getString(); - String o2String = o2.getString(); - int priority1 = comparePriority(o1String); - int priority2 = comparePriority(o2String); - if (priority1 != priority2) return Integer.compare(priority1, priority2); - return o1String.compareTo(o2String); - }); + private static final Object2IntAVLTreeMap<Text> SHOWN_REWARDS = new Object2IntAVLTreeMap<>(Comparator.<Text>comparingInt(text -> comparePriority(text.getString())).thenComparing(Text::getString)); /** * Holds the total reward maps for all accounts and profiles. {@link #currentProfileRewards} is a subset of this map, updated on profile change. - * - * @implNote This is a map from (account uuid + "+" + profile uuid) to itemId/amount map. */ - private static final Object2ObjectArrayMap<String, Object2IntMap<String>> ALL_REWARDS = new Object2ObjectArrayMap<>(); + private static final ProfiledData<Object2IntMap<String>> ALL_REWARDS = new ProfiledData<>(getRewardFilePath(), REWARDS_CODEC); /** * <p> @@ -98,8 +84,7 @@ public class PowderMiningTracker { if (isEnabled()) recalculatePrices(); }); - ClientLifecycleEvents.CLIENT_STARTED.register(PowderMiningTracker::loadRewards); - ClientLifecycleEvents.CLIENT_STOPPING.register(PowderMiningTracker::saveRewards); + ALL_REWARDS.init(); SkyblockEvents.PROFILE_CHANGE.register(PowderMiningTracker::onProfileChange); SkyblockEvents.PROFILE_INIT.register(PowderMiningTracker::onProfileInit); @@ -163,7 +148,7 @@ public class PowderMiningTracker { private static void onProfileInit(String profileId) { if (!isEnabled()) return; - currentProfileRewards = ALL_REWARDS.computeIfAbsent(getCombinedId(profileId), k -> new Object2IntArrayMap<>()); + currentProfileRewards = ALL_REWARDS.computeIfAbsent(Object2IntArrayMap::new); recalculateAll(); } @@ -247,33 +232,6 @@ public class PowderMiningTracker { return Object2ObjectMaps.unmodifiable(NAME2ID_MAP); } - private static void loadRewards(MinecraftClient client) { - if (Files.notExists(getRewardFilePath())) return; - try { - String jsonString = Files.readString(getRewardFilePath()); - JsonElement json = SkyblockerMod.GSON.fromJson(jsonString, JsonElement.class); - ALL_REWARDS.clear(); - ALL_REWARDS.putAll(ALL_REWARDS_CODEC.decode(JsonOps.INSTANCE, json).getOrThrow().getFirst()); - LOGGER.info("Loaded powder mining rewards from file."); - } catch (Exception e) { - LOGGER.error("Failed to load powder mining rewards from file!", e); - } - } - - private static void saveRewards(MinecraftClient client) { - try { - String jsonString = ALL_REWARDS_CODEC.encodeStart(JsonOps.INSTANCE, ALL_REWARDS).getOrThrow().toString(); - if (Files.notExists(getRewardFilePath())) { - Files.createDirectories(getRewardFilePath().getParent()); // Create all parent directories if they don't exist - Files.createFile(getRewardFilePath()); - } - Files.writeString(getRewardFilePath(), jsonString); - LOGGER.info("Saved powder mining rewards to file."); - } catch (Exception e) { - LOGGER.error("Failed to save powder mining rewards to file!", e); - } - } - static { NAME2ID_MAP.put("Gemstone Powder", "GEMSTONE_POWDER"); // Not an actual item, but since we're using IDs for mapping to colored text we need to have this here @@ -347,10 +305,6 @@ public class PowderMiningTracker { return SkyblockerMod.CONFIG_DIR.resolve("reward-trackers/powder-mining.json"); } - private static String getCombinedId(String profileUuid) { - return Utils.getUndashedUuid() + "+" + profileUuid; - } - private static void render(DrawContext context, RenderTickCounter tickCounter) { if (Utils.getLocation() != Location.CRYSTAL_HOLLOWS || !isEnabled()) return; int y = MinecraftClient.getInstance().getWindow().getScaledHeight() / 2 - 100; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java index a4b183f7..ddfc892f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/end/EndHudWidget.java @@ -68,10 +68,11 @@ public class EndHudWidget extends ComponentBasedWidget { public void updateContent() { // Zealots if (SkyblockerConfigManager.get().otherLocations.end.zealotKillsEnabled) { + TheEnd.EndStats endStats = TheEnd.PROFILES_STATS.putIfAbsent(TheEnd.EndStats.EMPTY); addComponent(new IcoTextComponent(ENDERMAN_HEAD, Text.literal("Zealots").formatted(Formatting.BOLD))); - addComponent(new PlainTextComponent(Text.translatable("skyblocker.end.hud.zealotsSinceLastEye", TheEnd.zealotsSinceLastEye))); - addComponent(new PlainTextComponent(Text.translatable("skyblocker.end.hud.zealotsTotalKills", TheEnd.zealotsKilled))); - String avg = TheEnd.eyes == 0 ? "???" : DECIMAL_FORMAT.format((float) TheEnd.zealotsKilled / TheEnd.eyes); + addComponent(new PlainTextComponent(Text.translatable("skyblocker.end.hud.zealotsSinceLastEye", endStats.zealotsSinceLastEye()))); + addComponent(new PlainTextComponent(Text.translatable("skyblocker.end.hud.zealotsTotalKills", endStats.totalZealotKills()))); + String avg = endStats.eyes() == 0 ? "???" : DECIMAL_FORMAT.format((float) endStats.totalZealotKills() / endStats.eyes()); addComponent(new PlainTextComponent(Text.translatable("skyblocker.end.hud.avgKillsPerEye", avg))); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java b/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java index bbbc29e4..a87ac6d9 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/end/TheEnd.java @@ -1,16 +1,16 @@ package de.hysky.skyblocker.skyblock.end; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.utils.ColorUtils; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.profile.ProfiledData; import de.hysky.skyblocker.utils.waypoint.Waypoint; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; @@ -30,29 +30,16 @@ import net.minecraft.util.math.ChunkPos; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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.*; -import java.util.concurrent.CompletableFuture; public class TheEnd { protected static final Logger LOGGER = LoggerFactory.getLogger(TheEnd.class); + private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("end.json"); public static Set<UUID> hitZealots = new HashSet<>(); - public static int zealotsSinceLastEye = 0; - public static int zealotsKilled = 0; - public static int eyes = 0; - /** - * needs to be saved? - */ - private static boolean dirty = false; - private static String currentProfile = ""; - private static JsonObject PROFILES_STATS; + public static ProfiledData<EndStats> PROFILES_STATS = new ProfiledData<>(FILE, EndStats.CODEC); - private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("end.json"); public static List<ProtectorLocation> protectorLocations = List.of( new ProtectorLocation(-649, -219, Text.translatable("skyblocker.end.hud.protectorLocations.left")), new ProtectorLocation(-644, -269, Text.translatable("skyblocker.end.hud.protectorLocations.front")), @@ -86,20 +73,12 @@ public class TheEnd { if (isProtectorHere(world, protectorLocation)) break; } } - if (currentProfile.isEmpty()) load(); // Wacky fix for when you join skyblock, and you are directly in the end (profile id isn't parsed yet most of the time) } - - }); + // Fix for when you join skyblock, and you are directly in the end + SkyblockEvents.PROFILE_CHANGE.register((prev, profile) -> EndHudWidget.getInstance().update()); // Reset when changing island - SkyblockEvents.LOCATION_CHANGE.register(location -> { - resetLocation(); - save(); - load(); - EndHudWidget.getInstance().update(); - }); - // Save when leaving as well - ClientLifecycleEvents.CLIENT_STOPPING.register((client) -> save()); + SkyblockEvents.LOCATION_CHANGE.register(location -> resetLocation()); ClientReceiveMessageEvents.GAME.register((message, overlay) -> { if (!Utils.isInTheEnd() || overlay) return; @@ -115,7 +94,7 @@ public class TheEnd { }); WorldRenderEvents.AFTER_TRANSLUCENT.register(TheEnd::renderWaypoint); - ClientLifecycleEvents.CLIENT_STARTED.register((client -> loadFile())); + PROFILES_STATS.init(); } private static void checkAllProtectorLocations() { @@ -153,15 +132,13 @@ public class TheEnd { public static void onEntityDeath(Entity entity) { if (!(entity instanceof EndermanEntity enderman) || !isZealot(enderman)) return; if (hitZealots.contains(enderman.getUuid())) { - //MinecraftClient.getInstance().player.sendMessage(Text.literal("You killed a zealot!!!")); + EndStats stats = PROFILES_STATS.putIfAbsent(EndStats.EMPTY); if (isSpecialZealot(enderman)) { - zealotsSinceLastEye = 0; - eyes++; - } - else zealotsSinceLastEye++; - zealotsKilled++; - dirty = true; - hitZealots.remove(enderman.getUuid()); + PROFILES_STATS.put(new EndStats(stats.totalZealotKills() + 1, 0, stats.eyes() + 1)); + } else { + PROFILES_STATS.put(new EndStats(stats.totalZealotKills() + 1, stats.zealotsSinceLastEye() + 1, stats.eyes())); + } + hitZealots.remove(enderman.getUuid()); EndHudWidget.getInstance().update(); } } @@ -183,82 +160,21 @@ public class TheEnd { return isZealot(enderman) && enderman.getCarriedBlock() != null && enderman.getCarriedBlock().isOf(Blocks.END_PORTAL_FRAME); } - /** - * Loads if needed - */ - public static void load() { - if (!Utils.isOnSkyblock() || Utils.getProfileId().isEmpty()) return; - String id = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", ""); - String profile = Utils.getProfileId(); - if (!profile.equals(currentProfile) && PROFILES_STATS != null) { - currentProfile = profile; - JsonElement jsonElement = PROFILES_STATS.get(id); - if (jsonElement == null) return; - JsonElement jsonElement1 = jsonElement.getAsJsonObject().get(profile); - if (jsonElement1 == null) return; - zealotsKilled = jsonElement1.getAsJsonObject().get("totalZealotKills").getAsInt(); - zealotsSinceLastEye = jsonElement1.getAsJsonObject().get("zealotsSinceLastEye").getAsInt(); - eyes = jsonElement1.getAsJsonObject().get("eyes").getAsInt(); - EndHudWidget.getInstance().update(); - } - } - - private static void loadFile() { - CompletableFuture.runAsync(() -> { - try (BufferedReader reader = Files.newBufferedReader(FILE)) { - PROFILES_STATS = SkyblockerMod.GSON.fromJson(reader, JsonObject.class); - LOGGER.debug("[Skyblocker End] Loaded end stats"); - } catch (NoSuchFileException ignored) { - PROFILES_STATS = new JsonObject(); - } catch (Exception e) { - LOGGER.error("[Skyblocker End] Failed to load end stats", e); - } - }); - } - - /** - * Saves if dirty - */ - public static void save() { - if (dirty && PROFILES_STATS != null) { - String uuid = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", ""); - JsonObject jsonObject = PROFILES_STATS.getAsJsonObject(uuid); - if (jsonObject == null) { - PROFILES_STATS.add(uuid, new JsonObject()); - jsonObject = PROFILES_STATS.getAsJsonObject(uuid); - } - - jsonObject.add(currentProfile, new JsonObject()); - JsonElement jsonElement1 = jsonObject.get(currentProfile); - - jsonElement1.getAsJsonObject().addProperty("totalZealotKills", zealotsKilled); - jsonElement1.getAsJsonObject().addProperty("zealotsSinceLastEye", zealotsSinceLastEye); - jsonElement1.getAsJsonObject().addProperty("eyes", eyes); - - if (Utils.isOnSkyblock()) { - CompletableFuture.runAsync(TheEnd::performSave); - } else { - performSave(); - } - } - } - - private static void performSave() { - try (BufferedWriter writer = Files.newBufferedWriter(FILE)) { - SkyblockerMod.GSON.toJson(PROFILES_STATS, writer); - LOGGER.info("[Skyblocker End] Saved end stats"); - dirty = false; - } catch (Exception e) { - LOGGER.error("[Skyblocker End] Failed to save end stats", e); - } - } - - private static void renderWaypoint(WorldRenderContext context) { + private static void renderWaypoint(WorldRenderContext context) { if (!SkyblockerConfigManager.get().otherLocations.end.waypoint) return; if (currentProtectorLocation == null || stage != 5) return; currentProtectorLocation.waypoint().render(context); } + public record EndStats(int totalZealotKills, int zealotsSinceLastEye, int eyes) { + private static final Codec<EndStats> CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("totalZealotKills").forGetter(EndStats::totalZealotKills), + Codec.INT.fieldOf("zealotsSinceLastEye").forGetter(EndStats::zealotsSinceLastEye), + Codec.INT.fieldOf("eyes").forGetter(EndStats::eyes) + ).apply(instance, EndStats::new)); + public static final EndStats EMPTY = new EndStats(0, 0, 0); + } + public record ProtectorLocation(int x, int z, Text name, Waypoint waypoint) { public ProtectorLocation(int x, int z, Text name) { this(x, z, name, new Waypoint(new BlockPos(x, 0, z), Waypoint.Type.WAYPOINT, ColorUtils.getFloatComponents(DyeColor.MAGENTA))); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java index cf0356bc..f9dd1705 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/ItemCooldowns.java @@ -58,7 +58,7 @@ public class ItemCooldowns { public static void updateCooldown() { PetInfo pet = PetCache.getCurrentPet(); - if (pet != null && pet.tier().equals("LEGENDARY")) { + if (pet != null && pet.tier().equals(SkyblockItemRarity.LEGENDARY)) { monkeyExp = pet.exp(); monkeyLevel = 0; @@ -172,4 +172,4 @@ public class ItemCooldowns { return this.isOnCooldown() ? (float) this.getRemainingCooldown() / cooldown : 0.0f; } } -}
\ No newline at end of file +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java index 7adda957..84ceb82c 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/item/MuseumItemCache.java @@ -6,22 +6,22 @@ import com.google.gson.JsonParser; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; 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.annotations.Init; +import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Http; import de.hysky.skyblocker.utils.Http.ApiResponse; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import de.hysky.skyblocker.utils.profile.ProfiledData; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; -import net.minecraft.client.MinecraftClient; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.item.ItemStack; import net.minecraft.nbt.*; @@ -31,15 +31,11 @@ import net.minecraft.util.collection.DefaultedList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Base64; import java.util.Map; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -48,7 +44,7 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit public class MuseumItemCache { private static final Logger LOGGER = LoggerFactory.getLogger(MuseumItemCache.class); private static final Path CACHE_FILE = SkyblockerMod.CONFIG_DIR.resolve("museum_item_cache.json"); - private static final Map<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> MUSEUM_ITEM_CACHE = new Object2ObjectOpenHashMap<>(); + private static final ProfiledData<ProfileMuseumData> MUSEUM_ITEM_CACHE = new ProfiledData<>(CACHE_FILE, ProfileMuseumData.CODEC, true, true); private static final String ERROR_LOG_TEMPLATE = "[Skyblocker] Failed to refresh museum item data for profile {}"; public static final String DONATION_CONFIRMATION_SCREEN_TITLE = "Confirm Donation"; private static final int CONFIRM_DONATION_BUTTON_SLOT = 20; @@ -57,8 +53,9 @@ public class MuseumItemCache { @Init public static void init() { - ClientLifecycleEvents.CLIENT_STARTED.register(MuseumItemCache::load); + ClientLifecycleEvents.CLIENT_STARTED.register(client -> loaded = MUSEUM_ITEM_CACHE.load()); ClientCommandRegistrationCallback.EVENT.register(MuseumItemCache::registerCommands); + SkyblockEvents.PROFILE_CHANGE.register((prev, profile) -> tick()); } private static void registerCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess registryAccess) { @@ -76,30 +73,6 @@ public class MuseumItemCache { })))); } - private static void load(MinecraftClient client) { - loaded = CompletableFuture.runAsync(() -> { - try (BufferedReader reader = Files.newBufferedReader(CACHE_FILE)) { - Map<String, Object2ObjectOpenHashMap<String, ProfileMuseumData>> cachedData = ProfileMuseumData.SERIALIZATION_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).getOrThrow(); - - MUSEUM_ITEM_CACHE.putAll(cachedData); - LOGGER.info("[Skyblocker] Loaded museum items cache"); - } catch (NoSuchFileException ignored) { - } catch (IOException e) { - LOGGER.error("[Skyblocker] Failed to load cached museum items", e); - } - }); - } - - private static void save() { - CompletableFuture.runAsync(() -> { - try (BufferedWriter writer = Files.newBufferedWriter(CACHE_FILE)) { - SkyblockerMod.GSON.toJson(ProfileMuseumData.SERIALIZATION_CODEC.encodeStart(JsonOps.INSTANCE, MUSEUM_ITEM_CACHE).getOrThrow(), writer); - } catch (IOException e) { - LOGGER.error("[Skyblocker] Failed to save cached museum items!", e); - } - }); - } - public static void handleClick(Slot slot, int slotId, DefaultedList<Slot> slots) { if (slotId == CONFIRM_DONATION_BUTTON_SLOT) { //Slots 0 to 17 can have items, well not all but thats the general range @@ -111,24 +84,19 @@ public class MuseumItemCache { String profileId = Utils.getProfileId(); if (!itemId.isEmpty() && !profileId.isEmpty()) { - String uuid = Utils.getUndashedUuid(); - //Be safe about access to avoid NPEs - Map<String, ProfileMuseumData> playerData = MUSEUM_ITEM_CACHE.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()); - playerData.putIfAbsent(profileId, ProfileMuseumData.EMPTY.get()); - - playerData.get(profileId).collectedItemIds().add(itemId); - save(); + MUSEUM_ITEM_CACHE.putIfAbsent(ProfileMuseumData.EMPTY.get()).collectedItemIds().add(itemId); + MUSEUM_ITEM_CACHE.save(); } } } } } - private static void updateData4ProfileMember(String uuid, String profileId) { + private static void updateData4ProfileMember(UUID uuid, String profileId) { updateData4ProfileMember(uuid, profileId, null); } - private static void updateData4ProfileMember(String uuid, String profileId, FabricClientCommandSource source) { + private static void updateData4ProfileMember(UUID uuid, String profileId, FabricClientCommandSource source) { CompletableFuture.runAsync(() -> { try (ApiResponse response = Http.sendHypixelRequest("skyblock/museum", "?profile=" + profileId)) { //The request was successful @@ -136,8 +104,9 @@ public class MuseumItemCache { JsonObject profileData = JsonParser.parseString(response.content()).getAsJsonObject(); JsonObject members = profileData.getAsJsonObject("members"); - if (members.has(uuid)) { - JsonObject memberData = members.get(uuid).getAsJsonObject(); + String uuidString = UndashedUuid.toString(uuid); + if (members.has(uuidString)) { + JsonObject memberData = members.get(uuidString).getAsJsonObject(); //We call them sets because it could either be a singular item or an entire armour set Map<String, JsonElement> donatedSets = memberData.get("items").getAsJsonObject().asMap(); @@ -161,8 +130,8 @@ public class MuseumItemCache { } } - MUSEUM_ITEM_CACHE.get(uuid).put(profileId, new ProfileMuseumData(System.currentTimeMillis(), itemIds)); - save(); + MUSEUM_ITEM_CACHE.put(uuid, profileId, new ProfileMuseumData(System.currentTimeMillis(), itemIds)); + MUSEUM_ITEM_CACHE.save(); if (source != null) source.sendFeedback(Constants.PREFIX.get().append(Text.translatable("skyblocker.museum.resyncSuccess"))); @@ -194,21 +163,18 @@ public class MuseumItemCache { }); } - private static void putEmpty(String uuid, String profileId) { + private static void putEmpty(UUID uuid, String profileId) { //Only put new data if they didn't have any before - if (!MUSEUM_ITEM_CACHE.get(uuid).containsKey(profileId)) { - MUSEUM_ITEM_CACHE.get(uuid).put(profileId, new ProfileMuseumData(System.currentTimeMillis(), ObjectOpenHashSet.of())); - } - - save(); + MUSEUM_ITEM_CACHE.computeIfAbsent(uuid, profileId, () -> new ProfileMuseumData(System.currentTimeMillis(), ObjectOpenHashSet.of())); + MUSEUM_ITEM_CACHE.save(); } private static boolean tryResync(FabricClientCommandSource source) { - String uuid = Utils.getUndashedUuid(); + UUID uuid = Utils.getUuid(); String profileId = Utils.getProfileId(); //Only allow resyncing if the data is actually present yet, otherwise the player needs to swap servers for the tick method to be called - if (loaded.isDone() && !profileId.isEmpty() && MUSEUM_ITEM_CACHE.containsKey(uuid) && MUSEUM_ITEM_CACHE.get(uuid).containsKey(profileId) && MUSEUM_ITEM_CACHE.get(uuid).get(profileId).canResync()) { + if (loaded.isDone() && !profileId.isEmpty() && MUSEUM_ITEM_CACHE.containsKey() && MUSEUM_ITEM_CACHE.get().canResync()) { updateData4ProfileMember(uuid, profileId, source); return true; @@ -220,22 +186,18 @@ public class MuseumItemCache { /** * The cache is ticked upon switching Skyblock servers. Only loads from the API if the profile wasn't cached yet. */ - public static void tick(String profileId) { - String uuid = Utils.getUndashedUuid(); + public static void tick() { + UUID uuid = Utils.getUuid(); - if (loaded.isDone() && (!MUSEUM_ITEM_CACHE.containsKey(uuid) || !MUSEUM_ITEM_CACHE.getOrDefault(uuid, new Object2ObjectOpenHashMap<>()).containsKey(profileId))) { - Map<String, ProfileMuseumData> playerData = MUSEUM_ITEM_CACHE.computeIfAbsent(uuid, _uuid -> new Object2ObjectOpenHashMap<>()); - playerData.putIfAbsent(profileId, ProfileMuseumData.EMPTY.get()); + if (loaded.isDone() && !MUSEUM_ITEM_CACHE.containsKey()) { + MUSEUM_ITEM_CACHE.putIfAbsent(ProfileMuseumData.EMPTY.get()); - updateData4ProfileMember(uuid, profileId); + updateData4ProfileMember(uuid, Utils.getProfileId()); } } public static boolean hasItemInMuseum(String id) { - String uuid = Utils.getUndashedUuid(); - ObjectOpenHashSet<String> collectedItemIds = (!MUSEUM_ITEM_CACHE.containsKey(uuid) || Utils.getProfileId().isBlank() || !MUSEUM_ITEM_CACHE.get(uuid).containsKey(Utils.getProfileId())) ? null : MUSEUM_ITEM_CACHE.get(uuid).get(Utils.getProfileId()).collectedItemIds(); - - return collectedItemIds != null && collectedItemIds.contains(id); + return MUSEUM_ITEM_CACHE.containsKey() && MUSEUM_ITEM_CACHE.get().collectedItemIds().contains(id); } private record ProfileMuseumData(long lastResync, ObjectOpenHashSet<String> collectedItemIds) { @@ -246,12 +208,8 @@ public class MuseumItemCache { Codec.STRING.listOf() .xmap(ObjectOpenHashSet::new, ObjectArrayList::new) .fieldOf("collectedItemIds") - .forGetter(i -> new ObjectOpenHashSet<>(i.collectedItemIds())) + .forGetter(ProfileMuseumData::collectedItemIds) ).apply(instance, ProfileMuseumData::new)); - //Mojang's internal Codec impleme |
