diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java | 172 | ||||
-rw-r--r-- | src/main/java/de/hysky/skyblocker/utils/Utils.java | 126 | ||||
-rw-r--r-- | src/main/resources/assets/skyblocker/lang/en_us.json | 5 | ||||
-rw-r--r-- | src/main/resources/fabric.mod.json | 1 |
4 files changed, 170 insertions, 134 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java index 6165ac6a..80753c1d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/Reparty.java @@ -1,94 +1,112 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.chat.ChatFilterResult; import de.hysky.skyblocker.utils.chat.ChatPatternListener; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import net.azureaaron.hmapi.data.party.PartyRole; +import net.azureaaron.hmapi.events.HypixelPacketEvents; +import net.azureaaron.hmapi.network.HypixelNetworking; +import net.azureaaron.hmapi.network.packet.s2c.ErrorS2CPacket; +import net.azureaaron.hmapi.network.packet.s2c.HypixelS2CPacket; +import net.azureaaron.hmapi.network.packet.v2.s2c.PartyInfoS2CPacket; 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.client.network.ClientPlayerEntity; import net.minecraft.text.Text; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import org.slf4j.Logger; + +import com.mojang.brigadier.Command; +import com.mojang.logging.LogUtils; public class Reparty extends ChatPatternListener { - private static final MinecraftClient client = MinecraftClient.getInstance(); - public static final Pattern PLAYER = Pattern.compile(" ([a-zA-Z0-9_]{2,16}) ●"); - private static final int BASE_DELAY = 10; - - private String[] players; - private int playersSoFar; - private boolean repartying; - private String partyLeader; - - public Reparty() { - super("^(?:You are not currently in a party\\." + - "|Party (?:Membe|Moderato)rs(?: \\(([0-9]+)\\)|:( .*))" + - "|([\\[A-z+\\]]* )?(?<disband>.*) has disbanded .*" + - "|.*\n([\\[A-z+\\]]* )?(?<invite>.*) has invited you to join their party!" + - "\nYou have 60 seconds to accept. Click here to join!\n.*)$"); - - this.repartying = false; - 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; - MessageScheduler.INSTANCE.sendMessageAfterCooldown("/p list"); - return 0; - }))); - } - - @Override - public ChatFilterResult state() { - return (SkyblockerConfigManager.get().general.acceptReparty || this.repartying) ? ChatFilterResult.FILTER : ChatFilterResult.PASS; - } - - @Override - public boolean onMatch(Text message, Matcher matcher) { - if (matcher.group(1) != null && repartying) { - this.playersSoFar = 0; - this.players = new String[Integer.parseInt(matcher.group(1)) - 1]; - } else if (matcher.group(2) != null && repartying) { - Matcher m = PLAYER.matcher(matcher.group(2)); - while (m.find()) { - this.players[playersSoFar++] = m.group(1); - } - } else if (matcher.group("disband") != null && !matcher.group("disband").equals(client.getSession().getUsername())) { - partyLeader = matcher.group("disband"); - Scheduler.INSTANCE.schedule(() -> partyLeader = null, 61); - return false; - } else if (matcher.group("invite") != null && matcher.group("invite").equals(partyLeader)) { - String command = "/party accept " + partyLeader; - sendCommand(command, 0); - return false; - } else { - this.repartying = false; - return false; - } - if (this.playersSoFar == this.players.length) { - reparty(); - } - return false; - } - - private void reparty() { - ClientPlayerEntity playerEntity = client.player; - if (playerEntity == null) { - this.repartying = false; - return; - } - sendCommand("/p disband", 1); - for (int i = 0; i < this.players.length; ++i) { - String command = "/p invite " + this.players[i]; - sendCommand(command, i + 2); - } - Scheduler.INSTANCE.schedule(() -> this.repartying = false, this.players.length + 2); - } - - private void sendCommand(String command, int delay) { - MessageScheduler.INSTANCE.queueMessage(command, delay * BASE_DELAY); - } + private static final Logger LOGGER = LogUtils.getLogger(); + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + private static final int BASE_DELAY = 10; + + private boolean repartying; + private String partyLeader; + + public Reparty() { + super("^(?:([\\[A-z+\\]]* )?(?<disband>.*) has disbanded .*" + + "|.*\n([\\[A-z+\\]]* )?(?<invite>.*) has invited you to join their party!" + + "\nYou have 60 seconds to accept. Click here to join!\n.*)$"); + + this.repartying = false; + HypixelPacketEvents.PARTY_INFO.register(this::onPacket); + 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; + HypixelNetworking.sendPartyInfoC2SPacket(2); + + return Command.SINGLE_SUCCESS; + }))); + } + + private void onPacket(HypixelS2CPacket packet) { + switch (packet) { + case PartyInfoS2CPacket(var inParty, var members) when this.repartying -> { + UUID ourUuid = Objects.requireNonNull(CLIENT.getSession().getUuidOrNull()); + + if (inParty && members.get(ourUuid) == PartyRole.LEADER) { + sendCommand("/p disband", 1); + int count = 0; + + for (Map.Entry<UUID, PartyRole> entry : members.entrySet()) { + UUID uuid = entry.getKey(); + PartyRole role = entry.getValue(); + + //Don't invite ourself + if (role != PartyRole.LEADER) sendCommand("/p " + uuid.toString(), ++count + 2); + } + + Scheduler.INSTANCE.schedule(() -> this.repartying = false, count * BASE_DELAY); + } else { + CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.reparty.notInPartyOrNotLeader"))); + this.repartying = false; + } + } + + case ErrorS2CPacket(var id, var error) when id.equals(PartyInfoS2CPacket.ID) && this.repartying -> { + CLIENT.player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.reparty.error"))); + LOGGER.error("[Skyblocker Reparty] The party info packet returned an unexpected error! {}", error); + + this.repartying = false; + } + + default -> {} //Do nothing + } + } + + @Override + public ChatFilterResult state() { + return SkyblockerConfigManager.get().general.acceptReparty ? ChatFilterResult.FILTER : ChatFilterResult.PASS; + } + + @Override + public boolean onMatch(Text message, Matcher matcher) { + if (matcher.group("disband") != null && !matcher.group("disband").equals(CLIENT.getSession().getUsername())) { + partyLeader = matcher.group("disband"); + Scheduler.INSTANCE.schedule(() -> partyLeader = null, 61); + } else if (matcher.group("invite") != null && matcher.group("invite").equals(partyLeader)) { + String command = "/party accept " + partyLeader; + sendCommand(command, 0); + } + + return false; + } + + private void sendCommand(String command, int delay) { + MessageScheduler.INSTANCE.queueMessage(command, delay * BASE_DELAY); + } }
\ 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 index 051110b2..bbeb11b5 100644 --- a/src/main/java/de/hysky/skyblocker/utils/Utils.java +++ b/src/main/java/de/hysky/skyblocker/utils/Utils.java @@ -6,21 +6,27 @@ 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.MessageScheduler; 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; +import net.azureaaron.hmapi.events.HypixelPacketEvents; +import net.azureaaron.hmapi.network.HypixelNetworking; +import net.azureaaron.hmapi.network.packet.s2c.ErrorS2CPacket; +import net.azureaaron.hmapi.network.packet.s2c.HelloS2CPacket; +import net.azureaaron.hmapi.network.packet.s2c.HypixelS2CPacket; +import net.azureaaron.hmapi.network.packet.v1.s2c.LocationUpdateS2CPacket; 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.*; 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; @@ -45,7 +51,7 @@ public class Utils { private static boolean isOnSkyblock = false; private static boolean isInjected = false; /** - * Current Skyblock location (from /locraw) + * Current Skyblock location (from the Mod API) */ @NotNull private static Location location = Location.UNKNOWN; @@ -60,10 +66,12 @@ public class Utils { @NotNull private static String profileId = ""; /** - * The following fields store data returned from /locraw: {@link #server}, {@link #gameType}, {@link #locationRaw}, and {@link #map}. + * The following fields store data returned from the Mod API: {@link #environment}, {@link #server}, {@link #gameType}, {@link #locationRaw}, and {@link #map}. */ @SuppressWarnings("JavadocDeclaration") @NotNull + private static Environment environment = Environment.PRODUCTION; + @NotNull private static String server = ""; @NotNull private static String gameType = ""; @@ -71,11 +79,6 @@ public class Utils { private static String locationRaw = ""; @NotNull private static String map = ""; - private static long clientWorldJoinTime = 0; - private static boolean sentLocRaw = false; - private static boolean canSendLocRaw = false; - //This is required to prevent the location change event from being fired twice. - private static boolean locationChanged = true; private static boolean mayorTickScheduled = false; private static int mayorTickRetryAttempts = 0; private static String mayor = ""; @@ -146,7 +149,7 @@ public class Utils { } /** - * @return the location parsed from /locraw. + * @return the location parsed from the Mod API. */ @NotNull public static Location getLocation() { @@ -154,7 +157,17 @@ public class Utils { } /** - * @return the server parsed from /locraw. + * Can be used to restrict features to being active only on the Alpha network. + * + * @return the current environment parsed from the Mod API. + */ + @NotNull + public static Environment getEnvironment() { + return environment; + } + + /** + * @return the server parsed from the Mod API. */ @NotNull public static String getServer() { @@ -162,7 +175,7 @@ public class Utils { } /** - * @return the game type parsed from /locraw. + * @return the game type parsed from the Mod API. */ @NotNull public static String getGameType() { @@ -170,7 +183,7 @@ public class Utils { } /** - * @return the location raw parsed from /locraw. + * @return the location raw parsed from the the Mod API. */ @NotNull public static String getLocationRaw() { @@ -178,7 +191,7 @@ public class Utils { } /** - * @return the map parsed from /locraw. + * @return the map parsed from the Mod API. */ @NotNull public static String getMap() { @@ -201,20 +214,23 @@ public class Utils { mayorTickScheduled = true; } }); - 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 + + //Register Mod API stuff + HypixelNetworking.registerToEvents(Util.make(new Object2IntOpenHashMap<>(), map -> map.put(LocationUpdateS2CPacket.ID, 1))); + HypixelPacketEvents.HELLO.register(Utils::onPacket); + HypixelPacketEvents.LOCATION_UPDATE.register(Utils::onPacket); } /** - * Updates all the fields stored in this class from the sidebar, player list, and /locraw. + * Updates all the fields stored in this class from the sidebar, and player list. */ public static void update() { MinecraftClient client = MinecraftClient.getInstance(); updateScoreboard(client); updatePlayerPresenceFromScoreboard(client); updateFromPlayerList(client); - updateLocRaw(); } /** @@ -244,7 +260,7 @@ public class Utils { if (!isInjected) { isInjected = true; } - isOnSkyblock = true; + isOnSkyblock = true; //TODO in the future we can probably replace these skyblock checks entirely with the Mod API SkyblockEvents.JOIN.invoker().onSkyblockJoin(); } } else { @@ -260,7 +276,7 @@ public class Utils { 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"); + return (!serverAddress.isEmpty() && serverAddress.equalsIgnoreCase(ALTERNATE_HYPIXEL_ADDRESS)) || serverAddress.contains("hypixel.net") || serverAddress.contains("hypixel.io") || serverBrand.contains("Hypixel BungeeCord"); } private static void onLeaveSkyblock() { @@ -395,25 +411,39 @@ public class Utils { } } - public static void onClientWorldJoin(ClientPlayNetworkHandler handler, PacketSender sender, MinecraftClient client) { - clientWorldJoinTime = System.currentTimeMillis(); - resetLocRawInfo(); - } + private static void onPacket(HypixelS2CPacket packet) { + switch (packet) { + case HelloS2CPacket(var environment) -> { + Utils.environment = environment; + } - /** - * Sends /locraw to the server if the player is on skyblock and on a new island. - */ - private static void updateLocRaw() { - if (isOnSkyblock) { - long currentTime = System.currentTimeMillis(); - if (!sentLocRaw && canSendLocRaw && currentTime > clientWorldJoinTime + 1000) { - MessageScheduler.INSTANCE.sendMessageAfterCooldown("/locraw"); - sentLocRaw = true; - canSendLocRaw = false; - locationChanged = true; + case LocationUpdateS2CPacket(var serverName, var serverType, var _lobbyName, var mode, var map) -> { + Utils.server = serverName; + Utils.gameType = serverType.orElse(""); + Utils.locationRaw = mode.orElse(""); + Utils.location = Location.from(locationRaw); + Utils.map = map.orElse(""); + + SkyblockEvents.LOCATION_CHANGE.invoker().onSkyblockLocationChange(location); } - } else { - resetLocRawInfo(); + + case ErrorS2CPacket(var id, var error) when id.equals(LocationUpdateS2CPacket.ID) -> { + server = ""; + gameType = ""; + locationRaw = ""; + location = Location.UNKNOWN; + map = ""; + + ClientPlayerEntity player = MinecraftClient.getInstance().player; + + if (player != null) { + player.sendMessage(Constants.PREFIX.get().append(Text.translatable("skyblocker.utils.locationUpdateError").formatted(Formatting.RED))); + } + + LOGGER.error("[Skyblocker] Failed to update your current location! Some features of the mod may not work correctly :( - Error: {}", error); + } + + default -> {} //Do Nothing } } @@ -423,6 +453,7 @@ public class Utils { * * @param message json message from chat */ + @Deprecated private static void parseLocRaw(String message) { JsonObject locRaw = JsonParser.parseString(message).getAsJsonObject(); @@ -441,11 +472,6 @@ public class Utils { if (locRaw.has("map")) { map = locRaw.get("map").getAsString(); } - - if (locationChanged) { - SkyblockEvents.LOCATION_CHANGE.invoker().onSkyblockLocationChange(location); - locationChanged = false; - } } /** @@ -458,10 +484,6 @@ public class Utils { if (message.startsWith("{\"server\":") && message.endsWith("}")) { parseLocRaw(message); - boolean shouldFilter = !sentLocRaw; - sentLocRaw = false; - - return shouldFilter; } if (isOnSkyblock) { @@ -481,16 +503,6 @@ public class Utils { return true; } - private static void resetLocRawInfo() { - sentLocRaw = false; - canSendLocRaw = true; - server = ""; - gameType = ""; - locationRaw = ""; - map = ""; - location = Location.UNKNOWN; - } - 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 diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index bf154048..6ea6cd70 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -654,6 +654,11 @@ "skyblocker.config.uiAndVisuals.waypoints.waypointType.@Tooltip": "Waypoint: Displays a highlight and a beacon beam.\n\nOutlined Waypoint: Displays both a waypoint and an outline.\n\nHighlight: Only displays a highlight.\n\nOutlined Highlight: Displays both a highlight and an outline.\n\nOutline: Only displays an outline.", "skyblocker.config.uiAndVisuals.waypoints.waypointType.generalNote": "\n\n\nThis option does not apply to all waypoints. Some waypoints such as secret waypoints have their own waypoint type option.", + "skyblocker.utils.locationUpdateError": "Failed to update your location! Some features of the mod may not work properly :(", + + "skyblocker.reparty.notInPartyOrNotLeader": "You must be in a party and be the leader of it in order to reparty!", + "skyblocker.reparty.error": "Failed to reparty, try again in a moment!", + "skyblocker.itemTooltip.noData": "\u00a7cNo Data", "skyblocker.itemTooltip.nullMessage": "\u00a7cItem price information on tooltip will renew in max 60 seconds. If not, check latest.log", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index e46085de..1361c00a 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -36,6 +36,7 @@ "fabricloader": ">=0.15.11", "fabric-api": ">=0.100.1+1.21", "yet_another_config_lib_v3": ">=3.5.0+1.21", + "hm-api": ">=1.0.0+1.21", "minecraft": "~1.21", "java": ">=21" }, |