aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java23
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/QuiverWarning.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonBlaze.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/LividColor.java6
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java11
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java3
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java40
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/quicknav/QuickNavButton.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TheRift.java10
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TwinClawsIndicator.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/Http.java89
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/render/title/TitleContainer.java3
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/MessageScheduler.java7
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/Scheduler.java85
-rw-r--r--src/test/java/me/xmrvizzy/skyblocker/utils/scheduler/SchedulerTest.java88
18 files changed, 298 insertions, 93 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
index bb08b99a..b630e5f5 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
@@ -38,14 +38,11 @@ import java.nio.file.Path;
* this class.
*/
public class SkyblockerMod implements ClientModInitializer {
+ public static final String VERSION = FabricLoader.getInstance().getModContainer("skyblocker").get().getMetadata().getVersion().getFriendlyString();
public static final String NAMESPACE = "skyblocker";
public static final Path CONFIG_DIR = FabricLoader.getInstance().getConfigDir().resolve(NAMESPACE);
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static SkyblockerMod INSTANCE;
-
- @SuppressWarnings("deprecation")
- public final Scheduler scheduler = new Scheduler();
- public final MessageScheduler messageScheduler = new MessageScheduler();
public final ContainerSolverManager containerSolverManager = new ContainerSolverManager();
public final StatusBarTracker statusBarTracker = new StatusBarTracker();
@@ -103,13 +100,13 @@ public class SkyblockerMod implements ClientModInitializer {
SpecialEffects.init();
containerSolverManager.init();
statusBarTracker.init();
- scheduler.scheduleCyclic(Utils::update, 20);
- scheduler.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 100);
- scheduler.scheduleCyclic(TicTacToe::tick, 4);
- scheduler.scheduleCyclic(LividColor::update, 10);
- scheduler.scheduleCyclic(BackpackPreview::tick, 50);
- scheduler.scheduleCyclic(DwarvenHud::update, 40);
- scheduler.scheduleCyclic(PlayerListMgr::updateList, 20);
+ Scheduler.INSTANCE.scheduleCyclic(Utils::update, 20);
+ Scheduler.INSTANCE.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 100);
+ Scheduler.INSTANCE.scheduleCyclic(TicTacToe::tick, 4);
+ Scheduler.INSTANCE.scheduleCyclic(LividColor::update, 10);
+ Scheduler.INSTANCE.scheduleCyclic(BackpackPreview::tick, 50);
+ Scheduler.INSTANCE.scheduleCyclic(DwarvenHud::update, 40);
+ Scheduler.INSTANCE.scheduleCyclic(PlayerListMgr::updateList, 20);
}
/**
@@ -119,7 +116,7 @@ public class SkyblockerMod implements ClientModInitializer {
* @param client the Minecraft client.
*/
public void tick(MinecraftClient client) {
- scheduler.tick();
- messageScheduler.tick();
+ Scheduler.INSTANCE.tick();
+ MessageScheduler.INSTANCE.tick();
}
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
index 5107833c..ca3b221a 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
@@ -67,7 +67,7 @@ public class SkyblockerConfig implements ConfigData {
@ConfigEntry.Category("button3")
@ConfigEntry.Gui.CollapsibleObject()
- public QuickNavItem button3 = new QuickNavItem(true, new ItemData("bone"), "\\(\\d+/\\d+\\) Pets", "/pets");
+ public QuickNavItem button3 = new QuickNavItem(true, new ItemData("bone"), "\\Pets \\(\\d+/\\d+\\)", "/pets");
@ConfigEntry.Category("button4")
@ConfigEntry.Gui.CollapsibleObject()
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/QuiverWarning.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/QuiverWarning.java
index cf793461..381bf94c 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/QuiverWarning.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/QuiverWarning.java
@@ -1,8 +1,8 @@
package me.xmrvizzy.skyblocker.skyblock;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.Utils;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.hud.InGameHud;
@@ -16,7 +16,7 @@ public class QuiverWarning {
public static void init() {
ClientReceiveMessageEvents.ALLOW_GAME.register(QuiverWarning::onChatMessage);
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(QuiverWarning::update, 10);
+ Scheduler.INSTANCE.scheduleCyclic(QuiverWarning::update, 10);
}
public static boolean onChatMessage(Text text, boolean overlay) {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonBlaze.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonBlaze.java
index 6e354ddc..8d676d0b 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonBlaze.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/DungeonBlaze.java
@@ -1,10 +1,10 @@
package me.xmrvizzy.skyblocker.skyblock.dungeon;
import it.unimi.dsi.fastutil.objects.ObjectIntPair;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.Utils;
import me.xmrvizzy.skyblocker.utils.render.RenderHelper;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.minecraft.client.MinecraftClient;
@@ -35,7 +35,7 @@ public class DungeonBlaze {
private static ArmorStandEntity nextLowestBlaze = null;
public static void init() {
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(DungeonBlaze::update, 4);
+ Scheduler.INSTANCE.scheduleCyclic(DungeonBlaze::update, 4);
WorldRenderEvents.BEFORE_DEBUG_RENDER.register(DungeonBlaze::blazeRenderer);
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/LividColor.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/LividColor.java
index 4701c485..e5d8a720 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/LividColor.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/LividColor.java
@@ -1,8 +1,8 @@
package me.xmrvizzy.skyblocker.skyblock.dungeon;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.Utils;
+import me.xmrvizzy.skyblocker.utils.scheduler.MessageScheduler;
import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.math.BlockPos;
@@ -23,13 +23,13 @@ public class LividColor {
if (tenTicks != 0) {
if (SkyblockerConfig.get().locations.dungeons.lividColor.enableLividColor && Utils.isInDungeons() && client.world != null) {
if (tenTicks == 1) {
- SkyblockerMod.getInstance().messageScheduler.sendMessageAfterCooldown(SkyblockerConfig.get().locations.dungeons.lividColor.lividColorText.replace("[color]", "red"));
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(SkyblockerConfig.get().locations.dungeons.lividColor.lividColorText.replace("[color]", "red"));
tenTicks = 0;
return;
}
String key = client.world.getBlockState(new BlockPos(5, 110, 42)).getBlock().getTranslationKey();
if (key.startsWith("block.minecraft.") && key.endsWith("wool") && !key.endsWith("red_wool")) {
- SkyblockerMod.getInstance().messageScheduler.sendMessageAfterCooldown(SkyblockerConfig.get().locations.dungeons.lividColor.lividColorText.replace("[color]", key.substring(16, key.length() - 5)));
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(SkyblockerConfig.get().locations.dungeons.lividColor.lividColorText.replace("[color]", key.substring(16, key.length() - 5)));
tenTicks = 0;
return;
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java
index e1194632..8d8a840a 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java
@@ -1,10 +1,11 @@
package me.xmrvizzy.skyblocker.skyblock.dungeon;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.Utils;
import me.xmrvizzy.skyblocker.utils.chat.ChatFilterResult;
import me.xmrvizzy.skyblocker.utils.chat.ChatPatternListener;
+import me.xmrvizzy.skyblocker.utils.scheduler.MessageScheduler;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.minecraft.client.MinecraftClient;
@@ -35,7 +36,7 @@ public class Reparty extends ChatPatternListener {
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("rp").executes(context -> {
if (!Utils.isOnSkyblock() || this.repartying || client.player == null) return 0;
this.repartying = true;
- SkyblockerMod.getInstance().messageScheduler.sendMessageAfterCooldown("/p list");
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown("/p list");
return 0;
})));
}
@@ -57,7 +58,7 @@ public class Reparty extends ChatPatternListener {
}
} else if (matcher.group("disband") != null && !matcher.group("disband").equals(client.getSession().getUsername())) {
partyLeader = matcher.group("disband");
- SkyblockerMod.getInstance().scheduler.schedule(() -> partyLeader = null, 61);
+ Scheduler.INSTANCE.schedule(() -> partyLeader = null, 61);
return false;
} else if (matcher.group("invite") != null && matcher.group("invite").equals(partyLeader)) {
String command = "/party accept " + partyLeader;
@@ -84,10 +85,10 @@ public class Reparty extends ChatPatternListener {
String command = "/p invite " + this.players[i];
sendCommand(command, i + 2);
}
- SkyblockerMod.getInstance().scheduler.schedule(() -> this.repartying = false, this.players.length + 2);
+ Scheduler.INSTANCE.schedule(() -> this.repartying = false, this.players.length + 2);
}
private void sendCommand(String command, int delay) {
- SkyblockerMod.getInstance().messageScheduler.queueMessage(command, delay * BASE_DELAY);
+ MessageScheduler.INSTANCE.queueMessage(command, delay * BASE_DELAY);
}
} \ No newline at end of file
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
index a7420bf5..18b63793 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/DungeonSecrets.java
@@ -13,6 +13,7 @@ import it.unimi.dsi.fastutil.objects.ObjectIntPair;
import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.Utils;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
@@ -140,7 +141,7 @@ public class DungeonSecrets {
LOGGER.error("[Skyblocker] Failed to load dungeon secrets", e);
return null;
});
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(DungeonSecrets::update, 10);
+ Scheduler.INSTANCE.scheduleCyclic(DungeonSecrets::update, 10);
WorldRenderEvents.AFTER_TRANSLUCENT.register(DungeonSecrets::render);
ClientReceiveMessageEvents.GAME.register(DungeonSecrets::onChatMessage);
ClientReceiveMessageEvents.GAME_CANCELED.register(DungeonSecrets::onChatMessage);
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
index 6825d779..ae5afaa3 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/secrets/Room.java
@@ -8,7 +8,7 @@ import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import it.unimi.dsi.fastutil.ints.IntSortedSets;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.block.BlockState;
@@ -249,7 +249,7 @@ public class Room {
// If no rooms match, reset the fields and scan again after 50 ticks.
matched = TriState.FALSE;
DungeonSecrets.LOGGER.warn("[Skyblocker] No dungeon room matches after checking {} block(s)", checkedBlocks.size());
- SkyblockerMod.getInstance().scheduler.schedule(() -> matched = TriState.DEFAULT, 50);
+ Scheduler.INSTANCE.schedule(() -> matched = TriState.DEFAULT, 50);
reset();
return true;
} else if (matchingRoomsSize == 1 && ++doubleCheckBlocks >= 10) {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java
index 44ce7339..d20aa0e3 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java
@@ -2,9 +2,10 @@ package me.xmrvizzy.skyblocker.skyblock.item;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
+import me.xmrvizzy.skyblocker.utils.Http;
import me.xmrvizzy.skyblocker.utils.Utils;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.item.ItemStack;
@@ -15,10 +16,7 @@ import net.minecraft.util.Formatting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
+import java.net.http.HttpHeaders;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -29,11 +27,9 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
-import java.util.zip.GZIPInputStream;
public class PriceInfoTooltip {
private static final Logger LOGGER = LoggerFactory.getLogger(PriceInfoTooltip.class.getName());
- private static final SkyblockerMod skyblocker = SkyblockerMod.getInstance();
private static final MinecraftClient client = MinecraftClient.getInstance();
private static JsonObject npcPricesJson;
private static JsonObject bazaarPricesJson;
@@ -45,6 +41,9 @@ public class PriceInfoTooltip {
private static boolean nullMsgSend = false;
private final static Gson gson = new Gson();
private static final Map<String, String> apiAddresses;
+ private static long npcHash = 0;
+ private static long museumHash = 0;
+ private static long motesHash = 0;
public static void onInjectTooltip(ItemStack stack, TooltipContext context, List<Text> lines) {
if (!Utils.isOnSkyblock() || client.player == null) return;
@@ -355,7 +354,7 @@ public class PriceInfoTooltip {
public static int minute = -1;
public static void init() {
- skyblocker.scheduler.scheduleCyclic(() -> {
+ Scheduler.INSTANCE.scheduleCyclic(() -> {
if (!Utils.isOnSkyblock() && 0 < minute++) {
nullMsgSend = false;
return;
@@ -400,11 +399,22 @@ public class PriceInfoTooltip {
private static JsonObject downloadPrices(String type) {
try {
String url = apiAddresses.get(type);
- URL apiAddress = new URL(url);
- InputStream src = apiAddress.openStream();
- InputStreamReader reader = new InputStreamReader(url.contains(".gz") ? new GZIPInputStream(src) : src);
- return new Gson().fromJson(reader, JsonObject.class);
- } catch (IOException e) {
+
+ if (type.equals("npc") || type.equals("museum") || type.equals("motes")) {
+ HttpHeaders headers = Http.sendHeadRequest(url);
+ long combinedHash = Http.getEtag(headers).hashCode() + Http.getLastModified(headers).hashCode();
+
+ switch (type) {
+ case "npc": if (npcHash == combinedHash) return npcPricesJson; else npcHash = combinedHash;
+ case "museum": if (museumHash == combinedHash) return isMuseumJson; else museumHash = combinedHash;
+ case "motes": if (motesHash == combinedHash) return motesPricesJson; else motesHash = combinedHash;
+ }
+ }
+
+ String apiResponse = Http.sendGetRequest(url);
+
+ return new Gson().fromJson(apiResponse, JsonObject.class);
+ } catch (Exception e) {
LOGGER.warn("[Skyblocker] Failed to download " + type + " prices!", e);
return null;
}
@@ -420,8 +430,8 @@ public class PriceInfoTooltip {
static {
apiAddresses = new HashMap<>();
- apiAddresses.put("1 day avg", "https://moulberry.codes/auction_averages_lbin/1day.json.gz");
- apiAddresses.put("3 day avg", "https://moulberry.codes/auction_averages_lbin/3day.json.gz");
+ apiAddresses.put("1 day avg", "https://moulberry.codes/auction_averages_lbin/1day.json");
+ apiAddresses.put("3 day avg", "https://moulberry.codes/auction_averages_lbin/3day.json");
apiAddresses.put("bazaar", "https://hysky.de/api/bazaar");
apiAddresses.put("lowest bins", "https://hysky.de/api/auctions/lowestbins");
apiAddresses.put("npc", "https://hysky.de/api/npcprice");
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/quicknav/QuickNavButton.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/quicknav/QuickNavButton.java
index fe229a44..e41ea768 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/quicknav/QuickNavButton.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/quicknav/QuickNavButton.java
@@ -2,8 +2,8 @@ package me.xmrvizzy.skyblocker.skyblock.quicknav;
import com.mojang.blaze3d.systems.RenderSystem;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.mixin.accessor.HandledScreenAccessor;
+import me.xmrvizzy.skyblocker.utils.scheduler.MessageScheduler;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
@@ -54,7 +54,7 @@ public class QuickNavButton extends ClickableWidget {
public void onClick(double mouseX, double mouseY) {
if (!this.toggled) {
this.toggled = true;
- SkyblockerMod.getInstance().messageScheduler.sendMessageAfterCooldown(command);
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(command);
// TODO : add null check with log error
}
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TheRift.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TheRift.java
index 5ca89dcf..4b11fcb0 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TheRift.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TheRift.java
@@ -1,7 +1,7 @@
package me.xmrvizzy.skyblocker.skyblock.rift;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
public class TheRift {
@@ -13,9 +13,9 @@ public class TheRift {
public static void init() {
WorldRenderEvents.AFTER_TRANSLUCENT.register(MirrorverseWaypoints::render);
WorldRenderEvents.AFTER_TRANSLUCENT.register(EffigyWaypoints::render);
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(EffigyWaypoints::updateEffigies, SkyblockerConfig.get().slayer.vampireSlayer.effigyUpdateFrequency);
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(TwinClawsIndicator::updateIce, SkyblockerConfig.get().slayer.vampireSlayer.holyIceUpdateFrequency);
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(ManiaIndicator::updateMania, SkyblockerConfig.get().slayer.vampireSlayer.maniaUpdateFrequency);
- SkyblockerMod.getInstance().scheduler.scheduleCyclic(StakeIndicator::updateStake, SkyblockerConfig.get().slayer.vampireSlayer.steakStakeUpdateFrequency);
+ Scheduler.INSTANCE.scheduleCyclic(EffigyWaypoints::updateEffigies, SkyblockerConfig.get().slayer.vampireSlayer.effigyUpdateFrequency);
+ Scheduler.INSTANCE.scheduleCyclic(TwinClawsIndicator::updateIce, SkyblockerConfig.get().slayer.vampireSlayer.holyIceUpdateFrequency);
+ Scheduler.INSTANCE.scheduleCyclic(ManiaIndicator::updateMania, SkyblockerConfig.get().slayer.vampireSlayer.maniaUpdateFrequency);
+ Scheduler.INSTANCE.scheduleCyclic(StakeIndicator::updateStake, SkyblockerConfig.get().slayer.vampireSlayer.steakStakeUpdateFrequency);
}
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TwinClawsIndicator.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TwinClawsIndicator.java
index e141b6a8..6e6fad2d 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TwinClawsIndicator.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/rift/TwinClawsIndicator.java
@@ -1,12 +1,12 @@
package me.xmrvizzy.skyblocker.skyblock.rift;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.SlayerUtils;
import me.xmrvizzy.skyblocker.utils.Utils;
import me.xmrvizzy.skyblocker.utils.render.RenderHelper;
import me.xmrvizzy.skyblocker.utils.render.title.Title;
import me.xmrvizzy.skyblocker.utils.render.title.TitleContainer;
+import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.minecraft.entity.Entity;
import net.minecraft.util.Formatting;
@@ -29,7 +29,7 @@ public class TwinClawsIndicator {
anyClaws = true;
if (!TitleContainer.containsTitle(title) && !scheduled) {
scheduled = true;
- SkyblockerMod.getInstance().scheduler.schedule(() -> {
+ Scheduler.INSTANCE.schedule(() -> {
RenderHelper.displayInTitleContainerAndPlaySound(title);
scheduled = false;
}, SkyblockerConfig.get().slayer.vampireSlayer.holyIceIndicatorTickDelay);
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/Http.java b/src/main/java/me/xmrvizzy/skyblocker/utils/Http.java
new file mode 100644
index 00000000..3461189c
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/Http.java
@@ -0,0 +1,89 @@
+package me.xmrvizzy.skyblocker.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpClient.Version;
+import java.net.http.HttpHeaders;
+import java.net.http.HttpRequest;
+import java.net.http.HttpRequest.BodyPublishers;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.time.Duration;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
+
+import me.xmrvizzy.skyblocker.SkyblockerMod;
+import net.minecraft.SharedConstants;
+
+/**
+ * @implNote All http requests are sent using HTTP 2
+ */
+public class Http {
+ private static final String USER_AGENT = "Skyblocker/" + SkyblockerMod.VERSION + " (" + SharedConstants.getGameVersion().getName() + ")";
+ private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
+ .connectTimeout(Duration.ofSeconds(10))
+ .build();
+
+ public static String sendGetRequest(String url) throws IOException, InterruptedException {
+ HttpRequest request = HttpRequest.newBuilder()
+ .GET()
+ .header("Accept", "application/json")
+ .header("Accept-Encoding", "gzip, deflate")
+ .header("User-Agent", USER_AGENT)
+ .version(Version.HTTP_2)
+ .uri(URI.create(url))
+ .build();
+
+ HttpResponse<InputStream> response = HTTP_CLIENT.send(request, BodyHandlers.ofInputStream());
+ InputStream decodedInputStream = getDecodedInputStream(response);
+ String body = new String(decodedInputStream.readAllBytes());
+
+ return body;
+ }
+
+ public static HttpHeaders sendHeadRequest(String url) throws IOException, InterruptedException {
+ HttpRequest request = HttpRequest.newBuilder()
+ .method("HEAD", BodyPublishers.noBody())
+ .header("User-Agent", USER_AGENT)
+ .version(Version.HTTP_2)
+ .uri(URI.create(url))
+ .build();
+
+ HttpResponse<Void> response = HTTP_CLIENT.send(request, BodyHandlers.discarding());
+ return response.headers();
+ }
+
+ private static InputStream getDecodedInputStream(HttpResponse<InputStream> response) {
+ String encoding = getContentEncoding(response);
+
+ try {
+ switch (encoding) {
+ case "":
+ return response.body();
+ case "gzip":
+ return new GZIPInputStream(response.body());
+ case "deflate":
+ return new InflaterInputStream(response.body());
+ default:
+ throw new UnsupportedOperationException("The server sent content in an unexpected encoding: " + encoding);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private static String getContentEncoding(HttpResponse<InputStream> response) {
+ return response.headers().firstValue("Content-Encoding").orElse("");
+ }
+
+ public static String getEtag(HttpHeaders headers) {
+ return headers.firstValue("Etag").orElse("");
+ }
+
+ public static String getLastModified(HttpHeaders headers) {
+ return headers.firstValue("Last-Modified").orElse("");
+ }
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java b/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java
index 1e8e7ffa..149004c4 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java
@@ -2,9 +2,9 @@ package me.xmrvizzy.skyblocker.utils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.skyblock.item.PriceInfoTooltip;
import me.xmrvizzy.skyblocker.skyblock.rift.TheRift;
+import me.xmrvizzy.skyblocker.utils.scheduler.MessageScheduler;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.fabricmc.fabric.api.client.message.v1.ClientReceiveMessageEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
@@ -294,7 +294,7 @@ public class Utils {
if (isOnSkyblock) {
long currentTime = System.currentTimeMillis();
if (!sentLocRaw && currentTime > clientWorldJoinTime + 1000 && currentTime > lastLocRaw + 15000) {
- SkyblockerMod.getInstance().messageScheduler.sendMessageAfterCooldown("/locraw");
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown("/locraw");
sentLocRaw = true;
lastLocRaw = currentTime;
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/render/title/TitleContainer.java b/src/main/java/me/xmrvizzy/skyblocker/utils/render/title/TitleContainer.java
index 6e15c871..2555572c 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/render/title/TitleContainer.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/render/title/TitleContainer.java
@@ -1,6 +1,5 @@
package me.xmrvizzy.skyblocker.utils.render.title;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.utils.scheduler.Scheduler;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
@@ -66,7 +65,7 @@ public class TitleContainer {
*/
public static boolean addTitle(Title title, int ticks) {
if (addTitle(title)) {
- SkyblockerMod.getInstance().scheduler.schedule(() -> TitleContainer.removeTitle(title), ticks);
+ Scheduler.INSTANCE.schedule(() -> TitleContainer.removeTitle(title), ticks);
return true;
}
return false;
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/MessageScheduler.java b/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/MessageScheduler.java
index bde29c13..b8ffa548 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/MessageScheduler.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/MessageScheduler.java
@@ -3,19 +3,22 @@ package me.xmrvizzy.skyblocker.utils.scheduler;
import net.minecraft.client.MinecraftClient;
/**
- * A scheduler for sending chat messages or commands. Use the instance in {@link me.xmrvizzy.skyblocker.SkyblockerMod#messageScheduler SkyblockerMod.messageScheduler}. Do not instantiate this class.
+ * A scheduler for sending chat messages or commands. Use the instance in {@link #INSTANCE}. Do not instantiate this class.
*/
-@SuppressWarnings("deprecation")
public class MessageScheduler extends Scheduler {
/**
* The minimum delay that the server will accept between chat messages.
*/
private static final int MIN_DELAY = 200;
+ public static final MessageScheduler INSTANCE = new MessageScheduler();
/**
* The timestamp of the last message send,
*/
private long lastMessage = 0;
+ protected MessageScheduler() {
+ }
+
/**
* Sends a chat message or command after the minimum cooldown. Prefer this method to send messages or commands to the server.
*
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/Scheduler.java b/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/Scheduler.java
index 76112e0d..700bdce3 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/Scheduler.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/Scheduler.java
@@ -1,30 +1,28 @@
package me.xmrvizzy.skyblocker.utils.scheduler;
import com.mojang.brigadier.Command;
-import me.xmrvizzy.skyblocker.SkyblockerMod;
+import it.unimi.dsi.fastutil.ints.AbstractInt2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.PriorityQueue;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Supplier;
/**
- * A scheduler for running tasks at a later time. Tasks will be run synchronously on the main client thread. Use the instance stored in {@link SkyblockerMod#scheduler}. Do not instantiate this class.
+ * A scheduler for running tasks at a later time. Tasks will be run synchronously on the main client thread. Use the instance stored in {@link #INSTANCE}. Do not instantiate this class.
*/
public class Scheduler {
private static final Logger LOGGER = LoggerFactory.getLogger(Scheduler.class);
+ public static final Scheduler INSTANCE = new Scheduler();
private int currentTick = 0;
- private final PriorityQueue<ScheduledTask> tasks = new PriorityQueue<>();
+ private final AbstractInt2ObjectMap<List<ScheduledTask>> tasks = new Int2ObjectOpenHashMap<>();
- /**
- * Do not instantiate this class. Use {@link SkyblockerMod#scheduler} instead.
- */
- @SuppressWarnings("DeprecatedIsStillUsed")
- @Deprecated
- public Scheduler() {
+ protected Scheduler() {
}
/**
@@ -34,11 +32,11 @@ public class Scheduler {
* @param delay the delay in ticks
*/
public void schedule(Runnable task, int delay) {
- if (delay < 0) {
+ if (delay >= 0) {
+ addTask(new ScheduledTask(task), currentTick + delay);
+ } else {
LOGGER.warn("Scheduled a task with negative delay");
}
- ScheduledTask tmp = new ScheduledTask(task, currentTick + delay);
- tasks.add(tmp);
}
/**
@@ -48,15 +46,15 @@ public class Scheduler {
* @param period the period in ticks
*/
public void scheduleCyclic(Runnable task, int period) {
- if (period <= 0) {
- LOGGER.error("Attempted to schedule a cyclic task with period lower than 1");
+ if (period > 0) {
+ addTask(new CyclicTask(task, period), currentTick);
} else {
- new CyclicTask(task, period).run();
+ LOGGER.error("Attempted to schedule a cyclic task with period lower than 1");
}
}
public static Command<FabricClientCommandSource> queueOpenScreenCommand(Supplier<Screen> screenSupplier) {
- return context -> SkyblockerMod.getInstance().scheduler.queueOpenScreen(screenSupplier);
+ return context -> INSTANCE.queueOpenScreen(screenSupplier);
}
/**
@@ -71,11 +69,18 @@ public class Scheduler {
}
public void tick() {
- currentTick += 1;
- ScheduledTask task;
- while ((task = tasks.peek()) != null && task.schedule <= currentTick && runTask(task)) {
- tasks.poll();
+ if (tasks.containsKey(currentTick)) {
+ List<ScheduledTask> currentTickTasks = tasks.get(currentTick);
+ //noinspection ForLoopReplaceableByForEach (or else we get a ConcurrentModificationException)
+ for (int i = 0; i < currentTickTasks.size(); i++) {
+ ScheduledTask task = currentTickTasks.get(i);
+ if (!runTask(task)) {
+ tasks.computeIfAbsent(currentTick + 1, key -> new ArrayList<>()).add(task);
+ }
+ }
+ tasks.remove(currentTick);
}
+ currentTick += 1;
}
/**
@@ -89,30 +94,42 @@ public class Scheduler {
return true;
}
+ private void addTask(ScheduledTask scheduledTask, int schedule) {
+ if (tasks.containsKey(schedule)) {
+ tasks.get(schedule).add(scheduledTask);
+ } else {
+ List<ScheduledTask> list = new ArrayList<>();
+ list.add(scheduledTask);
+ tasks.put(schedule, list);
+ }
+ }
+
/**
* A task that runs every period ticks. More specifically, this task reschedules itself to run again after period ticks every time it runs.
- *
- * @param inner the task to run
- * @param period the period in ticks
*/
- protected record CyclicTask(Runnable inner, int period) implements Runnable {
+ protected class CyclicTask extends ScheduledTask {
+ private final int period;
+
+ CyclicTask(Runnable inner, int period) {
+ super(inner);
+ this.period = period;
+ }
+
@Override
public void run() {
- SkyblockerMod.getInstance().scheduler.schedule(this, period);
- inner.run();
+ super.run();
+ addTask(this, currentTick + period);
}
}
/**
* A task that runs at a specific tick, relative to {@link #currentTick}.
- *
- * @param inner the task to run
- * @param schedule the tick to run at
*/
- protected record ScheduledTask(Runnable inner, int schedule) implements Comparable<ScheduledTask>, Runnable {
- @Override
- public int compareTo(ScheduledTask o) {
- return schedule - o.schedule;
+ protected static class ScheduledTask implements Runnable {
+ private final Runnable inner;
+
+ public ScheduledTask(Runnable inner) {
+ this.inner = inner;
}
@Override
diff --git a/src/test/java/me/xmrvizzy/skyblocker/utils/scheduler/SchedulerTest.java b/src/test/java/me/xmrvizzy/skyblocker/utils/scheduler/SchedulerTest.java
new file mode 100644
index 00000000..3ec63df1
--- /dev/null
+++ b/src/test/java/me/xmrvizzy/skyblocker/utils/scheduler/SchedulerTest.java
@@ -0,0 +1,88 @@
+package me.xmrvizzy.skyblocker.utils.scheduler;
+
+import org.apache.commons.lang3.mutable.MutableInt;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class SchedulerTest {
+ private final MutableInt currentTick = new MutableInt(0);
+ private final MutableInt cycleCount1 = new MutableInt(0);
+ private final MutableInt cycleCount2 = new MutableInt(0);
+ private final MutableInt cycleCount3 = new MutableInt(0);
+ private final MutableInt cycleCount4 = new MutableInt(0);
+ private final MutableInt cycleCount5 = new MutableInt(0);
+ private final MutableInt cycleCount6 = new MutableInt(0);
+ private final MutableInt cycleCount7 = new MutableInt(0);
+ private final MutableInt cycleCount8 = new MutableInt(0);
+
+ @Test
+ public void testSchedule() {
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(0, currentTick.intValue()), 0);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(1, currentTick.intValue()), 1);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(2, currentTick.intValue()), 2);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(10, currentTick.intValue()), 10);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(20, currentTick.intValue()), 20);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(50, currentTick.intValue()), 50);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(100, currentTick.intValue()), 100);
+ Scheduler.INSTANCE.schedule(() -> Assertions.assertEquals(123, currentTick.intValue()), 123);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {}, 1);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {}, 1);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {}, 1);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {}, 1);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {
+ Assertions.assertEquals(cycleCount1.intValue(), currentTick.intValue());
+ cycleCount1.increment();
+ }, 1);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {
+ Assertions.assertEquals(0, currentTick.intValue() % 10);
+ Assertions.assertEquals(cycleCount2.intValue(), currentTick.intValue() / 10);
+ cycleCount2.increment();
+ }, 10);
+ Scheduler.INSTANCE.scheduleCyclic(() -> {
+ Assertions.assertEquals(0, currentTick.intValue() % 55);
+ Assertions.assertEquals(cycleCount3.intValue(), currentTick.intValue() / 55);
+ cycleCount3.increment();
+ }, 55);
+ Scheduler.INSTANCE.schedule(() -> Scheduler.INSTANCE.scheduleCyclic(() -> {
+ Assertions.assertEquals(7, currentTick.intValue() % 10);
+ Assertions.assertEquals(cycleCount4.intValue(), currentTick.intValue() / 10);
+ cycleCount4.increment();
+ }, 10), 7);
+ Scheduler.INSTANCE.schedule(() -> Scheduler.INSTANCE.scheduleCyclic(() -> {
+ Assertions.assertEquals(0, currentTick.intValue() % 75);
+ Assertions.assertEquals(cycleCount5.intValue(), currentTick.intValue() / 75);
+ cycleCount5.increment();
+ }, 75), 0);
+ Scheduler.INSTANCE.schedule(() -> Scheduler.INSTANCE.scheduleCyclic(() -> {
+ Assertions.assertEquals(1, currentTick.intValue() % 99);
+ Assertions.assertEquals(cycleCount6.intValue(), currentTick.intValue() / 99);
+ cycleCount6.increment();
+ }, 99), 1);
+ Scheduler.INSTANCE.scheduleCyclic(() -> Scheduler.INSTANCE.schedule(() -> {
+ Assertions.assertEquals(5, currentTick.intValue() % 10);
+ Assertions.assertEquals(cycleCount7.intValue(), currentTick.intValue() / 10);
+ cycleCount7.increment();
+ }, 5), 10);
+ Scheduler.INSTANCE.scheduleCyclic(() -> Scheduler.INSTANCE.schedule(() -> {
+ Assertions.assertEquals(10, currentTick.intValue() % 55);
+ Assertions.assertEquals(cycleCount8.intValue(), currentTick.intValue() / 55);
+ cycleCount8.increment();
+ }, 10), 55);
+ while (currentTick.intValue() < 10_000_000) {
+ tick();
+ }
+ Assertions.assertEquals(10000000, cycleCount1.intValue());
+ Assertions.assertEquals(1000000, cycleCount2.intValue());
+ Assertions.assertEquals(181819, cycleCount3.intValue());
+ Assertions.assertEquals(1000000, cycleCount4.intValue());
+ Assertions.assertEquals(133334, cycleCount5.intValue());
+ Assertions.assertEquals(101011, cycleCount6.intValue());
+ Assertions.assertEquals(1000000, cycleCount7.intValue());
+ Assertions.assertEquals(181818, cycleCount8.intValue());
+ }
+
+ private void tick() {
+ Scheduler.INSTANCE.tick();
+ currentTick.increment();
+ }
+}