diff options
| author | Rime <81419447+Emirlol@users.noreply.github.com> | 2024-08-13 22:09:51 +0300 |
|---|---|---|
| committer | Rime <81419447+Emirlol@users.noreply.github.com> | 2024-08-13 22:09:51 +0300 |
| commit | 37136d199a74d2dff5c27632170c7a3a5a2944e4 (patch) | |
| tree | 1852d48bdb92d4878654fc89e9a0f1494d8b757a /src/main/java/de | |
| parent | 6e6b19356140a047d44d3135e78caf8566d1cd10 (diff) | |
| download | Skyblocker-37136d199a74d2dff5c27632170c7a3a5a2944e4.tar.gz Skyblocker-37136d199a74d2dff5c27632170c7a3a5a2944e4.tar.bz2 Skyblocker-37136d199a74d2dff5c27632170c7a3a5a2944e4.zip | |
Change mayor & minister parsing and storing
Diffstat (limited to 'src/main/java/de')
8 files changed, 150 insertions, 72 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 405827e0..ac84b5e1 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -58,6 +58,7 @@ import de.hysky.skyblocker.skyblock.waypoint.*; import de.hysky.skyblocker.utils.*; import de.hysky.skyblocker.utils.chat.ChatMessageListener; import de.hysky.skyblocker.utils.discord.DiscordRPCManager; +import de.hysky.skyblocker.utils.mayor.MayorUtils; import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; import de.hysky.skyblocker.utils.container.ContainerSolverManager; @@ -215,6 +216,7 @@ public class SkyblockerMod implements ClientModInitializer { SlotTextManager.init(); BazaarHelper.init(); MobGlow.init(); + MayorUtils.init(); SlayerEntitiesGlow.init(); Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java index eb214022..f470d5ad 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonScore.java @@ -9,6 +9,7 @@ import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListMgr; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.ProfileUtils; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.mayor.MayorUtils; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; @@ -19,7 +20,6 @@ import net.minecraft.entity.mob.ZombieEntity; import net.minecraft.item.ItemStack; import net.minecraft.sound.SoundEvents; import net.minecraft.util.collection.DefaultedList; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -151,7 +151,7 @@ public class DungeonScore { setCurrentFloor(); dungeonStarted = true; puzzleCount = getPuzzleCount(); - isMayorPaul = StringUtils.equalsAny("Paul", Utils.getMayor(), Utils.getMinister()); + isMayorPaul = MayorUtils.getMayor().perks().stream().anyMatch(perk -> perk.name().equals("EZPZ")) || MayorUtils.getMinister().perk().name().equals("EZPZ"); startingTime = System.currentTimeMillis(); floorRequirement = FloorRequirement.valueOf(currentFloor); floorHasMimics = MIMIC_FLOORS_PATTERN.matcher(currentFloor).matches(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/mayors/JerryTimer.java b/src/main/java/de/hysky/skyblocker/skyblock/mayors/JerryTimer.java index 7131a567..4945c0bc 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/mayors/JerryTimer.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/mayors/JerryTimer.java @@ -3,6 +3,7 @@ package de.hysky.skyblocker.skyblock.mayors; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.mayor.MayorUtils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents; import net.minecraft.client.MinecraftClient; @@ -20,7 +21,7 @@ public final class JerryTimer { //Example message: "§b ☺ §eThere is a §aGreen Jerry§e!" //There are various formats, all of which start with the "§b ☺ " prefix and contain the word "<color> Jerry" ClientReceiveMessageEvents.GAME.register((message, overlay) -> { - if (overlay || !Utils.getMayor().equals("Jerry") || !SkyblockerConfigManager.get().helpers.jerry.enableJerryTimer) return; + if (overlay || !MayorUtils.getMayor().name().equals("Jerry") || !SkyblockerConfigManager.get().helpers.jerry.enableJerryTimer) return; String text = message.getString(); //This part of hypixel still uses legacy text formatting, so we can't directly check for the actual text if (!text.startsWith("§b ☺ ") || !text.contains("Jerry")) return; diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java index 8336561f..73861f24 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -6,7 +6,6 @@ import com.mojang.util.UndashedUuid; import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.mixins.accessors.MessageHandlerAccessor; import de.hysky.skyblocker.skyblock.item.MuseumItemCache; -import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.azureaaron.hmapi.data.server.Environment; @@ -27,14 +26,12 @@ import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Util; -import org.apache.http.client.HttpResponseException; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Instant; import java.util.Collections; -import java.util.concurrent.CompletableFuture; /** * Utility variables and methods for retrieving Skyblock related information. @@ -77,10 +74,6 @@ public class Utils { private static String locationRaw = ""; @NotNull private static String map = ""; - private static boolean mayorTickScheduled = false; - private static int mayorTickRetryAttempts = 0; - private static String mayor = ""; - private static String minister = ""; /** * @implNote The parent text will always be empty, the actual text content is inside the text's siblings. @@ -193,30 +186,7 @@ public class Utils { return map; } - /** - * @return the current mayor as cached on skyblock join. - */ - @NotNull - public static String getMayor() { - return mayor; - } - - /** - * @return the current minister as cached on skyblock join. - */ - @NotNull - public static String getMinister() { - return minister; - } - public static void init() { - SkyblockEvents.JOIN.register(() -> { - if (!mayorTickScheduled) { - tickMayorCache(); - scheduleMayorTick(); - mayorTickScheduled = true; - } - }); ClientReceiveMessageEvents.ALLOW_GAME.register(Utils::onChatMessage); ClientReceiveMessageEvents.GAME_CANCELED.register(Utils::onChatMessage); // Somehow this works even though onChatMessage returns a boolean ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> onDisconnect()); @@ -505,45 +475,6 @@ public class Utils { return true; } - private static void scheduleMayorTick() { - long currentYearMillis = SkyblockTime.getSkyblockMillis() % 446400000L; //446400000ms is 1 year, 105600000ms is the amount of time from early spring 1st to late spring 27th - // If current time is past late spring 27th, the next mayor change is at next year's spring 27th, otherwise it's at this year's spring 27th - long millisUntilNextMayorChange = currentYearMillis > 105600000L ? 446400000L - currentYearMillis + 105600000L : 105600000L - currentYearMillis; - Scheduler.INSTANCE.schedule(Utils::tickMayorCache, (int) (millisUntilNextMayorChange / 50) + 5 * 60 * 20); // 5 extra minutes to allow the cache to expire. This is a simpler than checking age and subtracting from max age and rescheduling again. - } - - private static void tickMayorCache() { - CompletableFuture.supplyAsync(() -> { - try { - Http.ApiResponse response = Http.sendCacheableGetRequest("https://api.hypixel.net/v2/resources/skyblock/election", null); //Authentication is not required for this endpoint - if (!response.ok()) throw new HttpResponseException(response.statusCode(), response.content()); - JsonObject json = JsonParser.parseString(response.content()).getAsJsonObject(); - if (!json.get("success").getAsBoolean()) throw new RuntimeException("Request failed!"); //Can't find a more appropriate exception to throw here. - return json.get("mayor").getAsJsonObject(); - } catch (Exception e) { - throw new RuntimeException(e); //Wrap the exception to be handled by the exceptionally block - } - }).exceptionally(throwable -> { - LOGGER.error("[Skyblocker] Failed to get mayor status!", throwable.getCause()); - if (mayorTickRetryAttempts < 5) { - int minutes = 5 << mayorTickRetryAttempts; //5, 10, 20, 40, 80 minutes - mayorTickRetryAttempts++; - LOGGER.warn("[Skyblocker] Retrying in {} minutes.", minutes); - Scheduler.INSTANCE.schedule(Utils::tickMayorCache, minutes * 60 * 20); - } else { - LOGGER.warn("[Skyblocker] Failed to get mayor status after 5 retries! Stopping further retries until next reboot."); - } - return new JsonObject(); //Have to return a value for the thenAccept block. - }).thenAccept(result -> { - if (!result.isEmpty()) { - mayor = result.get("name").getAsString(); - minister = result.getAsJsonObject("minister").get("name").getAsString(); - LOGGER.info("[Skyblocker] Mayor set to {}, minister set to {}.", mayor, minister); - scheduleMayorTick(); //Ends up as a cyclic task with finer control over scheduled time - } - }); - } - /** * Used to avoid triggering things like chat rules or chat listeners infinitely, do not use otherwise. * <p> diff --git a/src/main/java/de/hysky/skyblocker/utils/mayor/Mayor.java b/src/main/java/de/hysky/skyblocker/utils/mayor/Mayor.java new file mode 100644 index 00000000..eeade3bf --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/mayor/Mayor.java @@ -0,0 +1,18 @@ +package de.hysky.skyblocker.utils.mayor; + +import it.unimi.dsi.fastutil.objects.ObjectLists; + +import java.util.List; + +/** + * Represents a mayor as retrieved from the API. + * @param key The key of the mayor. + * @param name The name of the mayor. + * @param perks The perks of the mayor. + */ +public record Mayor(String key, String name, List<Perk> perks) { + /** + * An empty mayor. Allows for better null safety. + */ + public static final Mayor EMPTY = new Mayor("", "", ObjectLists.emptyList()); +} diff --git a/src/main/java/de/hysky/skyblocker/utils/mayor/MayorUtils.java b/src/main/java/de/hysky/skyblocker/utils/mayor/MayorUtils.java new file mode 100644 index 00000000..0a8f6342 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/mayor/MayorUtils.java @@ -0,0 +1,99 @@ +package de.hysky.skyblocker.utils.mayor; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import de.hysky.skyblocker.events.SkyblockEvents; +import de.hysky.skyblocker.utils.Http; +import de.hysky.skyblocker.utils.SkyblockTime; +import de.hysky.skyblocker.utils.scheduler.Scheduler; +import org.apache.http.client.HttpResponseException; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; + +public class MayorUtils { + private static Mayor mayor = Mayor.EMPTY; + private static Minister minister = Minister.EMPTY; + private static boolean mayorTickScheduled = false; + private static int mayorTickRetryAttempts = 0; + private static final Logger LOGGER = LoggerFactory.getLogger(MayorUtils.class); + + private MayorUtils() {} + + @NotNull + public static Mayor getMayor() { + return mayor; + } + + @NotNull + public static Minister getMinister() { + return minister; + } + + public static void init() { + SkyblockEvents.JOIN.register(() -> { + if (!mayorTickScheduled) { + tickMayorCache(); + scheduleMayorTick(); + mayorTickScheduled = true; + } + }); + } + + private static void scheduleMayorTick() { + long currentYearMillis = SkyblockTime.getSkyblockMillis() % 446400000L; //446400000ms is 1 year, 105600000ms is the amount of time from early spring 1st to late spring 27th + // If current time is past late spring 27th, the next mayor change is at next year's spring 27th, otherwise it's at this year's spring 27th + long millisUntilNextMayorChange = currentYearMillis > 105600000L ? 446400000L - currentYearMillis + 105600000L : 105600000L - currentYearMillis; + Scheduler.INSTANCE.schedule(MayorUtils::tickMayorCache, (int) (millisUntilNextMayorChange / 50) + 5 * 60 * 20); // 5 extra minutes to allow the cache to expire. This is a simpler than checking age and subtracting from max age and rescheduling again. + } + + private static void tickMayorCache() { + CompletableFuture.supplyAsync(() -> { + try { + Http.ApiResponse response = Http.sendCacheableGetRequest("https://api.hypixel.net/v2/resources/skyblock/election", null); //Authentication is not required for this endpoint + if (!response.ok()) throw new HttpResponseException(response.statusCode(), response.content()); + JsonObject json = JsonParser.parseString(response.content()).getAsJsonObject(); + if (!json.get("success").getAsBoolean()) throw new RuntimeException("Request failed!"); //Can't find a more appropriate exception to throw here. + return json.get("mayor").getAsJsonObject(); + } catch (Exception e) { + throw new RuntimeException(e); //Wrap the exception to be handled by the exceptionally block + } + }).exceptionally(throwable -> { + LOGGER.error("[Skyblocker] Failed to get mayor status!", throwable.getCause()); + if (mayorTickRetryAttempts < 5) { + int minutes = 5 << mayorTickRetryAttempts; //5, 10, 20, 40, 80 minutes + mayorTickRetryAttempts++; + LOGGER.warn("[Skyblocker] Retrying in {} minutes.", minutes); + Scheduler.INSTANCE.schedule(MayorUtils::tickMayorCache, minutes * 60 * 20); + } else { + LOGGER.warn("[Skyblocker] Failed to get mayor status after 5 retries! Stopping further retries until next reboot."); + } + return new JsonObject(); //Have to return a value for the thenAccept block. + }).thenAccept(result -> { + if (!result.isEmpty()) { + mayor = new Mayor(result.get("key").getAsString(), + result.get("name").getAsString(), + result.getAsJsonArray("perks") + .asList() + .stream() + .map(JsonElement::getAsJsonObject) + .map(object -> new Perk(object.get("name").getAsString(), object.get("description").getAsString())) + .toList()); + JsonObject ministerObject = result.getAsJsonObject("minister"); + minister = new Minister(ministerObject.get("key").getAsString(), + ministerObject.get("name").getAsString(), + ministerObject.getAsJsonArray("perk") + .asList() + .stream() + .map(JsonElement::getAsJsonObject) + .map(object -> new Perk(object.get("name").getAsString(), object.get("description").getAsString())) + .findFirst().orElse(Perk.EMPTY)); + LOGGER.info("[Skyblocker] Mayor set to {}, minister set to {}.", mayor.name(), minister.name()); + scheduleMayorTick(); //Ends up as a cyclic task with finer control over scheduled time + } + }); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/mayor/Minister.java b/src/main/java/de/hysky/skyblocker/utils/mayor/Minister.java new file mode 100644 index 00000000..13638b39 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/mayor/Minister.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.utils.mayor; + +/** + * Represents a minister as retrieved from the API. + * @param key The key of the minister. + * @param name The name of the minister. + * @param perk The perk of the minister. + */ +public record Minister(String key, String name, Perk perk) { + /** + * An empty minister. Allows for better null safety. + */ + public static final Minister EMPTY = new Minister("", "", Perk.EMPTY); +} diff --git a/src/main/java/de/hysky/skyblocker/utils/mayor/Perk.java b/src/main/java/de/hysky/skyblocker/utils/mayor/Perk.java new file mode 100644 index 00000000..a2dc1700 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/mayor/Perk.java @@ -0,0 +1,13 @@ +package de.hysky.skyblocker.utils.mayor; + +/** + * Represents a mayor perk. + * @param name The name of the perk. + * @param description The description of the perk. This will include the formatting codes that are used in the game. + */ +public record Perk(String name, String description) { + /** + * An empty perk. Allows for better null safety. + */ + public static Perk EMPTY = new Perk("", ""); +} |
