From 9e19c3a95ff88319ab509d77c93cca3a2f9de970 Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Mon, 21 Jul 2025 21:27:03 +0200 Subject: save warps to file in case api takes a nap (#1313) --- .../skyblocker/skyblock/WarpAutocomplete.java | 104 +++++++++++++++------ 1 file changed, 75 insertions(+), 29 deletions(-) (limited to 'src/main/java/de') diff --git a/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java index 4d191558..71b1e137 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/WarpAutocomplete.java @@ -1,8 +1,11 @@ package de.hysky.skyblocker.skyblock; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.tree.LiteralCommandNode; +import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; @@ -20,6 +23,13 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; @@ -30,38 +40,74 @@ import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.lit * the mixin {@link de.hysky.skyblocker.mixins.CommandTreeS2CPacketMixin} */ public class WarpAutocomplete { - private static final Logger LOGGER = LoggerFactory.getLogger(WarpAutocomplete.class); - private static final Codec> MAP_CODEC = CodecUtils.object2BooleanMapCodec(Codec.STRING); + private static final Path FILE = SkyblockerMod.CONFIG_DIR.resolve("warp_autocomplete.json"); + private static final Logger LOGGER = LoggerFactory.getLogger(WarpAutocomplete.class); + private static final Codec> MAP_CODEC = CodecUtils.object2BooleanMapCodec(Codec.STRING); - @Nullable - public static LiteralCommandNode commandNode; + @Nullable + public static LiteralCommandNode commandNode; - @Init - public static void init() { - CompletableFuture.supplyAsync(() -> { - try { - String warps = Http.sendGetRequest("https://hysky.de/api/locations"); + @Init + public static void init() { + CompletableFuture.supplyAsync(() -> { + try { + String warps = Http.sendGetRequest("https://hysky.de/api/locations"); - return MAP_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(warps)).getOrThrow(); - } catch (Exception e) { - LOGGER.error("[Skyblocker] Failed to download warps list", e); - } - return Object2BooleanMaps.emptyMap(); - }).thenAccept(warps -> commandNode = literal("warp") - .requires(fabricClientCommandSource -> Utils.isOnSkyblock()) - .then(argument("destination", StringArgumentType.string()) - .suggests((context, builder) -> CommandSource.suggestMatching(getEligibleWarps(warps), builder)) - ).build() - ); - } + return MAP_CODEC.parse(JsonOps.INSTANCE, JsonParser.parseString(warps)).getOrThrow(); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to download warps list", e); + } + return Object2BooleanMaps.emptyMap(); + }).thenAccept(warps -> { + if (warps.isEmpty()) { + getWarpsFromFile(); + } else { + CompletableFuture.runAsync(() -> { + Optional result = MAP_CODEC.encodeStart(JsonOps.INSTANCE, warps).result(); + if (result.isEmpty()) return; + JsonElement warpsJson = result.get(); + try (BufferedWriter writer = Files.newBufferedWriter(FILE, StandardCharsets.UTF_8)) { + SkyblockerMod.GSON.toJson(warpsJson, writer); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to save warps auto complete", e); + } + }); + createCommandNode(warps); + } + } + ); + } - private static Stream getEligibleWarps(Object2BooleanMap warps) { - return warps.object2BooleanEntrySet().stream() - .filter(WarpAutocomplete::shouldShowWarp) - .map(Object2BooleanMap.Entry::getKey); - } + private static void getWarpsFromFile() { + CompletableFuture.supplyAsync(() -> { + JsonObject object; + try (BufferedReader reader = Files.newBufferedReader(FILE)) { + object = SkyblockerMod.GSON.fromJson(reader, JsonObject.class); + } catch (NoSuchFileException e) { + return Object2BooleanMaps.emptyMap(); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Failed to read warp autocomplete file", e); + return Object2BooleanMaps.emptyMap(); + } + return MAP_CODEC.parse(JsonOps.INSTANCE, object).result().orElse(Object2BooleanMaps.emptyMap()); + }).thenAccept(WarpAutocomplete::createCommandNode); + } - private static boolean shouldShowWarp(Object2BooleanMap.Entry entry) { - return !entry.getBooleanValue() || Utils.isOnBingo() || RankType.compare(Utils.getRank(), PackageRank.MVP_PLUS) >= 0; - } + private static void createCommandNode(Object2BooleanMap warps) { + commandNode = literal("warp") + .requires(fabricClientCommandSource -> Utils.isOnSkyblock()) + .then(argument("destination", StringArgumentType.string()) + .suggests((context, builder) -> CommandSource.suggestMatching(getEligibleWarps(warps), builder)) + ).build(); + } + + private static Stream getEligibleWarps(Object2BooleanMap warps) { + return warps.object2BooleanEntrySet().stream() + .filter(WarpAutocomplete::shouldShowWarp) + .map(Object2BooleanMap.Entry::getKey); + } + + private static boolean shouldShowWarp(Object2BooleanMap.Entry entry) { + return !entry.getBooleanValue() || Utils.isOnBingo() || RankType.compare(Utils.getRank(), PackageRank.MVP_PLUS) >= 0; + } } -- cgit