diff options
| author | Yasin <a.piri@hotmail.de> | 2023-10-09 12:58:02 +0200 |
|---|---|---|
| committer | Yasin <a.piri@hotmail.de> | 2023-10-09 12:58:02 +0200 |
| commit | bd3f0329d0e391bd84b5f9e3ff207d9dd9815853 (patch) | |
| tree | 2fd1d1ef625f57acc2e4916c967d8d2393844798 /src/main/java/de/hysky/skyblocker/utils | |
| parent | 2315b90da8117f28f66348927afdb621ee4fc815 (diff) | |
| download | Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.tar.gz Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.tar.bz2 Skyblocker-bd3f0329d0e391bd84b5f9e3ff207d9dd9815853.zip | |
new pr because fixing merge conflict would take too long
Diffstat (limited to 'src/main/java/de/hysky/skyblocker/utils')
26 files changed, 2304 insertions, 0 deletions
diff --git a/src/main/java/de/hysky/skyblocker/utils/Boxes.java b/src/main/java/de/hysky/skyblocker/utils/Boxes.java new file mode 100644 index 00000000..cd944a46 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/Boxes.java @@ -0,0 +1,50 @@ +package de.hysky.skyblocker.utils; + +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Direction.Axis; +import net.minecraft.util.math.Vec3d; + +public class Boxes { + /** Returns the vector of the min pos of this box. **/ + public static Vec3d getMinVec(Box box) { + return new Vec3d(box.minX, box.minY, box.minZ); + } + + /** Returns the vector of the max pos of this box. **/ + public static Vec3d getMaxVec(Box box) { + return new Vec3d(box.maxX, box.maxY, box.maxZ); + } + + /** Returns the vector of the side lengths of this box. **/ + public static Vec3d getLengthVec(Box box) { + return new Vec3d(box.getLengthX(), box.getLengthY(), box.getLengthZ()); + } + + /** Offsets this box so that minX, minY and minZ are all zero. **/ + public static Box moveToZero(Box box) { + return box.offset(getMinVec(box).negate()); + } + + /** Returns the distance between to oppisite corners of the box. **/ + public static double getCornerLength(Box box) { + return getMinVec(box).distanceTo(getMaxVec(box)); + } + + /** Returns the length of an axis in the box. **/ + public static double getAxisLength(Box box, Axis axis) { + return box.getMax(axis) - box.getMin(axis); + } + + /** Returns a box with each axis multiplied by the amount specified. **/ + public static Box multiply(Box box, double amount) { + return multiply(box, amount, amount, amount); + } + + /** Returns a box with each axis multiplied by the amount specified. **/ + public static Box multiply(Box box, double x, double y, double z) { + return box.expand( + getAxisLength(box, Axis.X) * (x - 1) / 2d, + getAxisLength(box, Axis.Y) * (y - 1) / 2d, + getAxisLength(box, Axis.Z) * (z - 1) / 2d); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/Constants.java b/src/main/java/de/hysky/skyblocker/utils/Constants.java new file mode 100644 index 00000000..fbeb448c --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/Constants.java @@ -0,0 +1,8 @@ +package de.hysky.skyblocker.utils; + +/** + * Holds generic static constants + */ +public interface Constants { + String LEVEL_EMBLEMS = "\u2E15\u273F\u2741\u2E19\u03B1\u270E\u2615\u2616\u2663\u213B\u2694\u27B6\u26A1\u2604\u269A\u2693\u2620\u269B\u2666\u2660\u2764\u2727\u238A\u1360\u262C\u269D\u29C9\uA214\u32D6\u2E0E\u26A0\uA541\u3020\u30C4\u2948\u2622\u2623\u273E\u269C\u0BD0\u0A6D\u2742\u16C3\u3023\u10F6\u0444\u266A\u266B\u04C3\u26C1\u26C3\u16DD\uA03E\u1C6A\u03A3\u09EB\u2603\u2654\u26C2\u12DE"; +} diff --git a/src/main/java/de/hysky/skyblocker/utils/Http.java b/src/main/java/de/hysky/skyblocker/utils/Http.java new file mode 100644 index 00000000..ee500b5a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/Http.java @@ -0,0 +1,89 @@ +package de.hysky.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 de.hysky.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/de/hysky/skyblocker/utils/ItemUtils.java b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java new file mode 100644 index 00000000..6ae1b4d0 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/ItemUtils.java @@ -0,0 +1,111 @@ +package de.hysky.skyblocker.utils; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.StringNbtReader; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +public class ItemUtils { + private final static Pattern WHITESPACES = Pattern.compile("^\\s*$"); + + public static List<Text> getTooltip(ItemStack item) { + MinecraftClient client = MinecraftClient.getInstance(); + return client.player == null || item == null ? Collections.emptyList() : item.getTooltip(client.player, TooltipContext.Default.BASIC); + } + + public static List<String> getTooltipStrings(ItemStack item) { + List<Text> lines = getTooltip(item); + List<String> list = new ArrayList<>(); + + for (Text line : lines) { + String string = line.getString(); + if (!WHITESPACES.matcher(string).matches()) + list.add(string); + } + + return list; + } + + @Nullable + public static Durability getDurability(ItemStack stack) { + if (!Utils.isOnSkyblock() || !SkyblockerConfigManager.get().locations.dwarvenMines.enableDrillFuel || stack.isEmpty()) { + return null; + } + + NbtCompound tag = stack.getNbt(); + if (tag == null || !tag.contains("ExtraAttributes")) { + return null; + } + + NbtCompound extraAttributes = tag.getCompound("ExtraAttributes"); + if (!extraAttributes.contains("drill_fuel") && !extraAttributes.getString("id").equals("PICKONIMBUS")) { + return null; + } + + int current = 0; + int max = 0; + String clearFormatting; + + for (String line : ItemUtils.getTooltipStrings(stack)) { + clearFormatting = Formatting.strip(line); + if (line.contains("Fuel: ")) { + if (clearFormatting != null) { + String clear = Pattern.compile("[^0-9 /]").matcher(clearFormatting).replaceAll("").trim(); + String[] split = clear.split("/"); + current = Integer.parseInt(split[0]); + max = Integer.parseInt(split[1]) * 1000; + return new Durability(current, max); + } + } else if (line.contains("uses.")) { + if (clearFormatting != null) { + int startIndex = clearFormatting.lastIndexOf("after") + 6; + int endIndex = clearFormatting.indexOf("uses", startIndex); + if (startIndex >= 0 && endIndex > startIndex) { + String usesString = clearFormatting.substring(startIndex, endIndex).trim(); + current = Integer.parseInt(usesString); + max = 5000; + } + return new Durability(current, max); + } + } + } + + return null; + } + + public static ItemStack getSkyblockerStack() { + try { + return ItemStack.fromNbt(StringNbtReader.parse("{id:\"minecraft:player_head\",Count:1,tag:{SkullOwner:{Id:[I;-300151517,-631415889,-1193921967,-1821784279],Properties:{textures:[{Value:\"e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDdjYzY2ODc0MjNkMDU3MGQ1NTZhYzUzZTA2NzZjYjU2M2JiZGQ5NzE3Y2Q4MjY5YmRlYmVkNmY2ZDRlN2JmOCJ9fX0=\"}]}}}}")); + } catch (CommandSyntaxException e) { + throw new RuntimeException(e); + } + } + + public static String getItemId(ItemStack itemStack) { + if (itemStack == null) return null; + + NbtCompound nbt = itemStack.getNbt(); + if (nbt != null && nbt.contains("ExtraAttributes")) { + NbtCompound extraAttributes = nbt.getCompound("ExtraAttributes"); + if (extraAttributes.contains("id")) { + return extraAttributes.getString("id"); + } + } + + return null; + } + + public record Durability(int current, int max) { + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/NEURepo.java b/src/main/java/de/hysky/skyblocker/utils/NEURepo.java new file mode 100644 index 00000000..9bc6b245 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/NEURepo.java @@ -0,0 +1,101 @@ +package de.hysky.skyblocker.utils; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.itemlist.ItemRegistry; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.Text; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.TransportException; +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * Initializes the NEU repo, which contains item metadata and fairy souls location data. Clones the repo if it does not exist and checks for updates. Use {@link #runAsyncAfterLoad(Runnable)} to run code after the repo is initialized. + */ +public class NEURepo { + private static final Logger LOGGER = LoggerFactory.getLogger(NEURepo.class); + public static final String REMOTE_REPO_URL = "https://github.com/NotEnoughUpdates/NotEnoughUpdates-REPO.git"; + public static final Path LOCAL_REPO_DIR = SkyblockerMod.CONFIG_DIR.resolve("item-repo"); + private static final CompletableFuture<Void> REPO_INITIALIZED = initRepository(); + + /** + * Adds command to update repository manually from ingame. + * <p></p> + * TODO A button could be added to the settings menu that will trigger this command. + */ + public static void init() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> + dispatcher.register(ClientCommandManager.literal(SkyblockerMod.NAMESPACE) + .then(ClientCommandManager.literal("updaterepository").executes(context -> { + deleteAndDownloadRepository(); + return 1; + })))); + } + + private static CompletableFuture<Void> initRepository() { + return CompletableFuture.runAsync(() -> { + try { + if (Files.isDirectory(NEURepo.LOCAL_REPO_DIR)) { + try (Git localRepo = Git.open(NEURepo.LOCAL_REPO_DIR.toFile())) { + localRepo.pull().setRebase(true).call(); + LOGGER.info("[Skyblocker] NEU Repository Updated"); + } + } else { + Git.cloneRepository().setURI(REMOTE_REPO_URL).setDirectory(NEURepo.LOCAL_REPO_DIR.toFile()).setBranchesToClone(List.of("refs/heads/master")).setBranch("refs/heads/master").call().close(); + LOGGER.info("[Skyblocker] NEU Repository Downloaded"); + } + } catch (TransportException e){ + LOGGER.error("[Skyblocker] Transport operation failed. Most likely unable to connect to the remote NEU repo on github", e); + } catch (RepositoryNotFoundException e) { + LOGGER.warn("[Skyblocker] Local NEU Repository not found or corrupted, downloading new one", e); + deleteAndDownloadRepository(); + } catch (Exception e) { + LOGGER.error("[Skyblocker] Encountered unknown exception while initializing NEU Repository", e); + } + }); + } + + private static void deleteAndDownloadRepository() { + CompletableFuture.runAsync(() -> { + try { + ItemRegistry.filesImported = false; + File dir = NEURepo.LOCAL_REPO_DIR.toFile(); + recursiveDelete(dir); + } catch (Exception ex) { + if (MinecraftClient.getInstance().player != null) + MinecraftClient.getInstance().player.sendMessage(Text.translatable("skyblocker.updaterepository.failed"), false); + return; + } + initRepository(); + }); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + private static void recursiveDelete(File dir) { + File[] children; + if (dir.isDirectory() && !Files.isSymbolicLink(dir.toPath()) && (children = dir.listFiles()) != null) { + for (File child : children) { + recursiveDelete(child); + } + } + dir.delete(); + } + + /** + * Runs the given runnable after the NEU repo is initialized. + * @param runnable the runnable to run + * @return a completable future of the given runnable + */ + public static CompletableFuture<Void> runAsyncAfterLoad(Runnable runnable) { + return REPO_INITIALIZED.thenRunAsync(runnable); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/PosUtils.java b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java new file mode 100644 index 00000000..6a34b060 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/PosUtils.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.utils; + +import net.minecraft.util.math.BlockPos; + +public final class PosUtils { + public static BlockPos parsePosString(String posData) { + String[] posArray = posData.split(","); + return new BlockPos(Integer.parseInt(posArray[0]), Integer.parseInt(posArray[1]), Integer.parseInt(posArray[2])); + } + + public static String getPosString(BlockPos blockPos) { + return blockPos.getX() + "," + blockPos.getY() + "," + blockPos.getZ(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java new file mode 100644 index 00000000..0a42c6ae --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/SlayerUtils.java @@ -0,0 +1,54 @@ +package de.hysky.skyblocker.utils; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +//TODO Slayer Packet system that can provide information about the current slayer boss, abstract so that different bosses can have different info +public class SlayerUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(SlayerUtils.class); + + //TODO: Cache this, probably included in Packet system + public static List<Entity> getEntityArmorStands(Entity entity) { + return entity.getEntityWorld().getOtherEntities(entity, entity.getBoundingBox().expand(1F, 2.5F, 1F), x -> x instanceof ArmorStandEntity && x.hasCustomName()); + } + + //Eventually this should be modified so that if you hit a slayer boss all slayer features will work on that boss. + public static Entity getSlayerEntity() { + if (MinecraftClient.getInstance().world != null) { + for (Entity entity : MinecraftClient.getInstance().world.getEntities()) { + //Check if entity is Bloodfiend + if (entity.hasCustomName() && entity.getCustomName().getString().contains("Bloodfiend")) { + //Grab the players username + String username = MinecraftClient.getInstance().getSession().getUsername(); + //Check all armor stands around the boss + for (Entity armorStand : getEntityArmorStands(entity)) { + //Check if the display name contains the players username + if (armorStand.getDisplayName().getString().contains(username)) { + return entity; + } + } + } + } + } + return null; + } + + public static boolean isInSlayer() { + try { + for (int i = 0; i < Utils.STRING_SCOREBOARD.size(); i++) { + String line = Utils.STRING_SCOREBOARD.get(i); + + if (line.contains("Slay the boss!")) return true; + } + } catch (NullPointerException e) { + LOGGER.error("[Skyblocker] Error while checking if player is in slayer", e); + } + + return false; + } +}
\ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/utils/Utils.java b/src/main/java/de/hysky/skyblocker/utils/Utils.java new file mode 100644 index 00000000..f046bffb --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -0,0 +1,370 @@ +package de.hysky.skyblocker.utils; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import de.hysky.skyblocker.events.SkyblockEvents; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import de.hysky.skyblocker.skyblock.item.PriceInfoTooltip; +import de.hysky.skyblocker.skyblock.rift.TheRift; +import de.hysky.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; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.ScoreboardDisplaySlot; +import net.minecraft.scoreboard.ScoreboardObjective; +import net.minecraft.scoreboard.ScoreboardPlayerScore; +import net.minecraft.scoreboard.Team; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; + +/** + * Utility variables and methods for retrieving Skyblock related information. + */ +public class Utils { + private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class); + private static final String ALTERNATE_HYPIXEL_ADDRESS = System.getProperty("skyblocker.alternateHypixelAddress", ""); + private static final String PROFILE_PREFIX = "Profile: "; + private static boolean isOnHypixel = false; + private static boolean isOnSkyblock = false; + private static boolean isInDungeons = false; + private static boolean isInjected = false; + /** + * The following fields store data returned from /locraw: {@link #profile}, {@link #server}, {@link #gameType}, {@link #locationRaw}, and {@link #map}. + */ + @SuppressWarnings("JavadocDeclaration") + private static String profile = ""; + private static String server = ""; + private static String gameType = ""; + private static String locationRaw = ""; + private static String map = ""; + private static long clientWorldJoinTime = 0; + private static boolean sentLocRaw = false; + private static boolean canSendLocRaw = false; + + /** + * @implNote The parent text will always be empty, the actual text content is inside the text's siblings. + */ + public static final ObjectArrayList<Text> TEXT_SCOREBOARD = new ObjectArrayList<>(); + public static final ObjectArrayList<String> STRING_SCOREBOARD = new ObjectArrayList<>(); + + public static boolean isOnHypixel() { + return isOnHypixel; + } + + public static boolean isOnSkyblock() { + return isOnSkyblock; + } + + public static boolean isInDungeons() { + return isInDungeons; + } + + public static boolean isInTheRift() { + return getLocationRaw().equals(TheRift.LOCATION); + } + + public static boolean isInjected() { + return isInjected; + } + + /** + * @return the profile parsed from the player list. + */ + public static String getProfile() { + return profile; + } + + /** + * @return the server parsed from /locraw. + */ + public static String getServer() { + return server; + } + + /** + * @return the game type parsed from /locraw. + */ + public static String getGameType() { + return gameType; + } + + /** + * @return the location raw parsed from /locraw. + */ + public static String getLocationRaw() { + return locationRaw; + } + + /** + * @return the map parsed from /locraw. + */ + public static String getMap() { + return map; + } + + public static void init() { + ClientPlayConnectionEvents.JOIN.register(Utils::onClientWorldJoin); + ClientReceiveMessageEvents.ALLOW_GAME.register(Utils::onChatMessage); + ClientReceiveMessageEvents.GAME_CANCELED.register(Utils::onChatMessage); // Somehow this works even though onChatMessage returns a boolean + } + + /** + * Updates all the fields stored in this class from the sidebar, player list, and /locraw. + */ + public static void update() { + MinecraftClient client = MinecraftClient.getInstance(); + updateScoreboard(client); + updatePlayerPresenceFromScoreboard(client); + updateFromPlayerList(client); + updateLocRaw(); + } + + /** + * Updates {@link #isOnSkyblock}, {@link #isInDungeons}, and {@link #isInjected} from the scoreboard. + */ + public static void updatePlayerPresenceFromScoreboard(MinecraftClient client) { + List<String> sidebar = STRING_SCOREBOARD; + + FabricLoader fabricLoader = FabricLoader.getInstance(); + if ((client.world == null || client.isInSingleplayer() || sidebar == null || sidebar.isEmpty())) { + if (fabricLoader.isDevelopmentEnvironment()) { + sidebar = Collections.emptyList(); + } else { + isOnSkyblock = false; + isInDungeons = false; + return; + } + } + + if (sidebar.isEmpty() && !fabricLoader.isDevelopmentEnvironment()) return; + String string = sidebar.toString(); + + if (fabricLoader.isDevelopmentEnvironment() || isConnectedToHypixel(client)) { + if (!isOnHypixel) { + isOnHypixel = true; + } + if (fabricLoader.isDevelopmentEnvironment() || sidebar.get(0).contains("SKYBLOCK") || sidebar.get(0).contains("SKIBLOCK")) { + if (!isOnSkyblock) { + if (!isInjected) { + isInjected = true; + ItemTooltipCallback.EVENT.register(PriceInfoTooltip::onInjectTooltip); + } + isOnSkyblock = true; + SkyblockEvents.JOIN.invoker().onSkyblockJoin(); + } + } else { + onLeaveSkyblock(); + } + isInDungeons = fabricLoader.isDevelopmentEnvironment() || isOnSkyblock && string.contains("The Catacombs"); + } else if (isOnHypixel) { + isOnHypixel = false; + onLeaveSkyblock(); + } + } + + private static boolean isConnectedToHypixel(MinecraftClient client) { + String serverAddress = (client.getCurrentServerEntry() != null) ? client.getCurrentServerEntry().address.toLowerCase() : ""; + String serverBrand = (client.player != null && client.player.networkHandler != null && client.player.networkHandler.getBrand() != null) ? client.player.networkHandler.getBrand() : ""; + + return serverAddress.equalsIgnoreCase(ALTERNATE_HYPIXEL_ADDRESS) || serverAddress.contains("hypixel.net") || serverAddress.contains("hypixel.io") || serverBrand.contains("Hypixel BungeeCord"); + } + + private static void onLeaveSkyblock() { + if (isOnSkyblock) { + isOnSkyblock = false; + isInDungeons = false; + SkyblockEvents.LEAVE.invoker().onSkyblockLeave(); + } + } + + public static String getLocation() { + String location = null; + List<String> sidebarLines = STRING_SCOREBOARD; + try { + if (sidebarLines != null) { + for (String sidebarLine : sidebarLines) { + if (sidebarLine.contains("⏣")) location = sidebarLine; + if (sidebarLine.contains("ф")) location = sidebarLine; //Rift + } + if (location == null) location = "Unknown"; + location = location.strip(); + } + } catch (IndexOutOfBoundsException e) { + LOGGER.error("[Skyblocker] Failed to get location from sidebar", e); + } + return location; + } + + public static double getPurse() { + String purseString = null; + double purse = 0; + + List<String> sidebarLines = STRING_SCOREBOARD; + try { + + if (sidebarLines != null) { + for (String sidebarLine : sidebarLines) { + if (sidebarLine.contains("Piggy:")) purseString = sidebarLine; + if (sidebarLine.contains("Purse:")) purseString = sidebarLine; + } + } + if (purseString != null) purse = Double.parseDouble(purseString.replaceAll("[^0-9.]", "").strip()); + else purse = 0; + + } catch (IndexOutOfBoundsException e) { + LOGGER.error("[Skyblocker] Failed to get purse from sidebar", e); + } + return purse; |
