diff options
author | syeyoung <cyoung06@naver.com> | 2021-11-27 23:19:16 +0900 |
---|---|---|
committer | syeyoung <cyoung06@naver.com> | 2021-11-27 23:19:16 +0900 |
commit | d239ae4d4748fc4867ab45a5cc7d42bfb5ac547c (patch) | |
tree | 39118080fafa68e896c10cee03f8c1cda9f0defd /src/main/java/kr/syeyoung/dungeonsguide/chat | |
parent | 7c22f439db227552d88d4df20e0cce6da947a2d0 (diff) | |
download | Skyblock-Dungeons-Guide-d239ae4d4748fc4867ab45a5cc7d42bfb5ac547c.tar.gz Skyblock-Dungeons-Guide-d239ae4d4748fc4867ab45a5cc7d42bfb5ac547c.tar.bz2 Skyblock-Dungeons-Guide-d239ae4d4748fc4867ab45a5cc7d42bfb5ac547c.zip |
- Deadlock on ApiFetchur (Waits until lilyweight data and lilyweight data fetcher waits for other tasks to finish)
- New PartyManager
- ChatProcessor now manages all automatic chat messages and msot chat parsing
- PartyFinderSetting now contains option to leave party
- Log StompPayload when debug enabled
Diffstat (limited to 'src/main/java/kr/syeyoung/dungeonsguide/chat')
5 files changed, 842 insertions, 0 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatProcessResult.java b/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatProcessResult.java new file mode 100644 index 00000000..94bafa95 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatProcessResult.java @@ -0,0 +1,31 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.chat; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum ChatProcessResult { + NONE(false, false), REMOVE_LISTENER(true, false), REMOVE_LISTENER_AND_CHAT(true, true), REMOVE_CHAT(false, true); + + private boolean removeListener; + private boolean removeChat; +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatProcessor.java b/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatProcessor.java new file mode 100644 index 00000000..5fc666e2 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatProcessor.java @@ -0,0 +1,115 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.chat; + +import kr.syeyoung.dungeonsguide.DungeonsGuide; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiNewChat; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.Tuple; +import net.minecraftforge.client.event.ClientChatReceivedEvent; +import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.simple.SimpleLogger; + +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CopyOnWriteArrayList; + +public class ChatProcessor { + public static final ChatProcessor INSTANCE = new ChatProcessor(); + + private static final Logger logger = LogManager.getLogger(); + private ChatProcessor() { + Logger l = LogManager.getLogger(GuiNewChat.class); + if (l instanceof SimpleLogger) { + ((SimpleLogger) l).setLevel(Level.OFF); + } else if (l instanceof org.apache.logging.log4j.core.Logger) { + ((org.apache.logging.log4j.core.Logger) l).setLevel(Level.OFF); + } + } + + private Queue<ChatSubscriber> chatSubscriberQueue = new ConcurrentLinkedQueue<>(); + private Queue<Tuple<String, Runnable>> chatQueue = new ConcurrentLinkedQueue<>(); + + public void subscribe(ChatSubscriber chatSubscribed) { + chatSubscriberQueue.add(chatSubscribed); + } + public void addToChatQueue(String chat, Runnable onSend, boolean noDupe) { + if (noDupe && chatQueue.stream().anyMatch(a -> a.getFirst().trim().equalsIgnoreCase(chat.trim()))) return; + chatQueue.add(new Tuple<>(chat, onSend)); + } + + + private long minimumNext = 0; + + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent clientTickEvent) { + try { + if (clientTickEvent.phase == TickEvent.Phase.START && Minecraft.getMinecraft().thePlayer != null && minimumNext < System.currentTimeMillis()) { + if (!chatQueue.isEmpty()) { + Tuple<String, Runnable> tuple = chatQueue.poll(); + Minecraft.getMinecraft().thePlayer.sendChatMessage(tuple.getFirst()); + if (tuple.getSecond() != null) + tuple.getSecond().run(); + minimumNext = System.currentTimeMillis() + 200; + DungeonsGuide.sendDebugChat(new ChatComponentText("Sending " + tuple.getFirst() + " Secretly")); + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + + @SubscribeEvent(priority = EventPriority.HIGHEST, receiveCanceled = true) + public void onMessage(ClientChatReceivedEvent chatReceivedEvent) { + if (chatReceivedEvent.type == 2) return; + String txt = chatReceivedEvent.message.getFormattedText(); + logger.log(Level.INFO, "[CHAT] "+txt); + + int processed = 0; + int listenened = 0; + Map<String, Object> context = new HashMap<>(); + Iterator<ChatSubscriber> it = chatSubscriberQueue.iterator(); + while (it.hasNext()) { + ChatSubscriber chatSubscribed = it.next(); + context.put("removed", processed); + context.put("onceListenered", listenened); + ChatProcessResult chatProcessResult = chatSubscribed.process(txt, context); + if (chatProcessResult.isRemoveChat()) processed++; + if (chatProcessResult.isRemoveListener()) listenened++; + + if (chatProcessResult.isRemoveChat()) chatReceivedEvent.setResult(Event.Result.DENY); + if (chatProcessResult.isRemoveListener()) it.remove(); + } + } + + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void cancelMessage(ClientChatReceivedEvent chatReceivedEvent) { + if (chatReceivedEvent.getResult() == Event.Result.DENY) + chatReceivedEvent.setCanceled(true); + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatSubscriber.java b/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatSubscriber.java new file mode 100644 index 00000000..72879eb0 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/chat/ChatSubscriber.java @@ -0,0 +1,26 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.chat; + +import java.util.Map; + +@FunctionalInterface +public interface ChatSubscriber { + ChatProcessResult process(String txt, Map<String, Object> context); +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/chat/PartyContext.java b/src/main/java/kr/syeyoung/dungeonsguide/chat/PartyContext.java new file mode 100644 index 00000000..87d1a264 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/chat/PartyContext.java @@ -0,0 +1,89 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.chat; + +import lombok.Data; +import net.minecraft.client.Minecraft; + +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; + + +@Data +public class PartyContext { + private String partyID; + + private String partyOwner; + private Set<String> partyModerator; private boolean isModeratorComplete; + private Set<String> partyMember; private boolean isMemberComplete; + + private Set<String> partyRawMembers = new HashSet<>(); private boolean isRawMemberComplete; + + private Boolean allInvite; + + private boolean partyExistHypixel = true; + + public void setPartyOwner(String partyOwner) { + this.partyOwner = partyOwner; + if (partyMember != null) partyMember.remove(partyOwner); + if (partyModerator != null) partyModerator.remove(partyOwner); + addRawMember(partyOwner); + } + public void addPartyModerator(String partyModerator) { + if (partyModerator.equalsIgnoreCase(partyOwner)) partyOwner = null; + if (partyMember != null) partyMember.remove(partyModerator); + + if (this.partyModerator == null) this.partyModerator = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + this.partyModerator.add(partyModerator); + addRawMember(partyModerator); + } + public void addPartyMember(String partyMember) { + if (partyMember.equalsIgnoreCase(partyOwner)) partyOwner = null; + if (partyModerator != null) partyModerator.remove(partyMember); + + if (this.partyMember == null) this.partyMember = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + this.partyMember.add(partyMember); + addRawMember(partyMember); + } + public void addRawMember(String partyMember){ + partyRawMembers.add(partyMember); + } + public void removeFromParty(String username) { + if (username.equalsIgnoreCase(partyOwner)) { + partyOwner = null; + } + if (partyModerator != null) partyModerator.remove(username); + if (partyMember != null) partyMember.remove(username); + partyRawMembers.remove(username); + } + + public boolean hasModerator(String username) { + return partyModerator != null && partyModerator.contains(username); + } + public boolean hasMember(String username) { + return partyMember != null && partyMember.contains(username); + } + public boolean hasLeader(String username) { + return username.equalsIgnoreCase(partyOwner); + } + public boolean isSelfSolo() { + return hasLeader(Minecraft.getMinecraft().getSession().getUsername()) && getPartyRawMembers().size() == 1; + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/chat/PartyManager.java b/src/main/java/kr/syeyoung/dungeonsguide/chat/PartyManager.java new file mode 100644 index 00000000..2a2207f0 --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/chat/PartyManager.java @@ -0,0 +1,581 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +package kr.syeyoung.dungeonsguide.chat; + +import kr.syeyoung.dungeonsguide.DungeonsGuide; +import kr.syeyoung.dungeonsguide.events.HypixelJoinedEvent; +import kr.syeyoung.dungeonsguide.events.StompConnectedEvent; +import kr.syeyoung.dungeonsguide.stomp.*; +import kr.syeyoung.dungeonsguide.utils.TextUtils; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.client.Minecraft; +import net.minecraft.util.ChatComponentText; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.security.SecureRandom; +import java.util.*; +import java.util.function.Consumer; + +public class PartyManager implements StompMessageHandler { + public static final PartyManager INSTANCE = new PartyManager(); + @Getter + private PartyContext partyContext; + + public PartyContext getPartyContext(boolean createIfNeeded) { + PartyContext pc = partyContext == null && createIfNeeded ? partyContext = new PartyContext() : partyContext; + if (createIfNeeded) + pc.addRawMember(Minecraft.getMinecraft().getSession().getUsername()); + return pc; + } + + @Getter + @Setter + private int maxParty = 5; + @Getter + private String askToJoinSecret = null; + + private static final SecureRandom random = new SecureRandom(); + private static final String validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; + + + private Set<Consumer<PartyContext>> partyBuiltCallback = new HashSet<>(); + + public PartyManager() { + ChatProcessor cp = ChatProcessor.INSTANCE; + // Not in Party + cp.subscribe((str, a) -> { + if (str.equals("§cYou are not currently in a party.§r") + || str.equals("§eYou left the party.§r") + || str.equals("§cYou must be in a party to join the party channel!§r") + || str.equals("§cThe party was disbanded because all invites expired and the party was empty§r") + || str.equals("§cYou are not in a party and were moved to the ALL channel.§r") + || str.startsWith("§cThe party was disbanded") + || str.endsWith("§ehas disbanded the party!§r") + || str.endsWith("§cYou are not in a party")) { + leaveParty(); + + for (Consumer<PartyContext> partyContextConsumer : partyBuiltCallback) { + try { + partyContextConsumer.accept(null); + } catch (Exception e) { + e.printStackTrace(); + } + } + partyBuiltCallback.clear(); + a.put("type", "notinparty"); + } + return ChatProcessResult.NONE; + }); + // All invite + cp.subscribe((str, a) -> { + if (str.endsWith("§aenabled All Invite§r")) { + getPartyContext(true).setAllInvite(true); + a.put("type", "allinvite_on"); + } else if (str.endsWith("§cdisabled All Invite§r") + || str.equals("§cYou are not allowed to invite players.§r")) { + getPartyContext(true).setAllInvite(false); + a.put("type", "allinvite_off"); + } + return ChatProcessResult.NONE; + }); + // Member building + cp.subscribe(new ChatSubscriber() { + boolean memberExpected; + PartyContext partyContext = new PartyContext(); + @Override + public ChatProcessResult process(String txt, Map<String, Object> context) { + if (txt.startsWith("§6Party Members ")) { + memberExpected = true; + partyContext = new PartyContext(); + partyContext.setPartyModerator(new TreeSet<>(String.CASE_INSENSITIVE_ORDER)); + partyContext.setPartyMember(new TreeSet<>(String.CASE_INSENSITIVE_ORDER)); + context.put("type", "member_start"); + } else if (txt.startsWith("§eParty ") && txt.contains(":")){ + String role = txt.split(":")[0]; + String playerNames = TextUtils.stripColor(txt.split(":")[1]); + for (String s : playerNames.split(" ")) { + if (s.isEmpty()) continue; + if (s.equals("●")) continue; + if (s.startsWith("[")) continue; + partyContext.addRawMember(s); + if (role.contains("Moder")) partyContext.addPartyModerator(s); + if (role.contains("Member")) partyContext.addPartyMember(s); + if (role.contains("Leader")) partyContext.setPartyOwner(s); + } + if (role.contains("Moder")) { + partyContext.setModeratorComplete(true); + context.put("type", "member_moder"); + } + if (role.contains("Member")) { + partyContext.setMemberComplete(true); + context.put("type", "member_member"); + } + if (role.contains("Leader")) { + context.put("type", "member_leader"); + } + } else if (txt.equals("§9§m-----------------------------§r")) { + if (memberExpected) { + PartyContext old = getPartyContext(true); + old.setPartyOwner(partyContext.getPartyOwner()); + old.setPartyModerator(partyContext.getPartyModerator()); + old.setPartyMember(partyContext.getPartyMember()); + old.setPartyRawMembers(new TreeSet<>(String.CASE_INSENSITIVE_ORDER)); + old.getPartyRawMembers().addAll(old.getPartyMember()); + old.getPartyRawMembers().addAll(old.getPartyModerator()); + old.getPartyRawMembers().add(old.getPartyOwner()); + old.setModeratorComplete(true); old.setMemberComplete(true); + old.setRawMemberComplete(true); + old.setPartyExistHypixel(true); + + memberExpected = false; + context.put("type", "member_end"); + + for (Consumer<PartyContext> partyContextConsumer : partyBuiltCallback) { + try { + partyContextConsumer.accept(partyContext); + } catch (Exception e) { + e.printStackTrace(); + } + } + partyBuiltCallback.clear(); + + if (old.getPartyID() == null) { + joinedParty(); + } + } + } + return ChatProcessResult.NONE; + } + }); + // Player party join / leave + cp.subscribe((str ,a) -> { + if (str.endsWith("§ejoined the party.§r")) { + String username = null; + for (String s : TextUtils.stripColor(str).split(" ")) { + if (s.startsWith("[")) continue; + username = s; + break; + } + if (username != null) { + getPartyContext(true).addPartyMember(username); + } + a.put("type", "party_join"); + } else if (str.endsWith("§ehas been removed from the party.§r") + || str.endsWith("§ehas left the party.§r")) { + String username = null; + for (String s : TextUtils.stripColor(str).split(" ")) { + if (s.startsWith("[")) continue; + username = s; + break; + } + if (username != null && partyContext != null) { + getPartyContext().removeFromParty(username); + } + a.put("type", "party_leave"); + } else if (str.endsWith(" They have §r§c60 §r§eseconds to accept.§r")) { + String[] messageSplit = TextUtils.stripColor(str).split(" "); + String inviter = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + inviter = s; + break; + } + if (inviter != null && partyContext != null) { + if (getPartyContext().hasMember(inviter)) { + getPartyContext().setAllInvite(true); + } + } + getPartyContext(true).setPartyExistHypixel(true); + a.put("type", "party_invite_exist"); + } else if (str.equals("§cCouldn't find a player with that name!§r") || str.equals("§cYou cannot invite that player since they're not online.")) { + a.put("type", "party_invite_noexist"); + String username = Minecraft.getMinecraft().getSession().getUsername(); + if (partyContext != null && getPartyContext().hasMember(username)) { + getPartyContext().setAllInvite(true); + } + } + return ChatProcessResult.NONE; + }); + // Promotion + cp.subscribe((str, a) -> { + if (str.startsWith("§eThe party was transferred to ")) { + // §eThe party was transferred to §r§b[MVP§r§f+§r§b] apotato321 §r§eby §r§a[VIP§r§6+§r§a] syeyoung§r + String[] messageSplit = TextUtils.stripColor(str.substring(31)).split(" "); + String newLeader = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + newLeader = s; + break; + } + String oldLeader = messageSplit[messageSplit.length-1]; + + if (oldLeader != null && newLeader != null ) { + getPartyContext(true).setPartyOwner(newLeader); + getPartyContext(true).addPartyModerator(oldLeader); + } + a.put("type", "party_transfer"); + } else if (str.endsWith("§eto Party Leader§r")) { + // §a[VIP§r§6+§r§a] syeyoung§r§e has promoted §r§b[MVP§r§f+§r§b] apotato321 §r§eto Party Leader§r + String[] messageSplit = TextUtils.stripColor(str).split(" "); + String oldLeader = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + oldLeader = s; + break; + } + messageSplit = TextUtils.stripColor(str.substring(str.indexOf("has promoted") + 13)).split(" "); + String newLeader = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + newLeader = s; + break; + } + + if (oldLeader != null && newLeader != null) { + getPartyContext(true).setPartyOwner(newLeader); + getPartyContext(true).addPartyModerator(oldLeader); + } + a.put("type", "party_transfer"); + } else if (str.endsWith("§r§eto Party Moderator§r")) { + // §b[MVP§r§f+§r§b] apotato321§r§e has promoted §r§a[VIP§r§6+§r§a] syeyoung §r§eto Party Moderator§r + String[] messageSplit = TextUtils.stripColor(str).split(" "); + String oldLeader = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + oldLeader = s; + break; + } + messageSplit = TextUtils.stripColor(str.substring(str.indexOf("has promoted") + 13)).split(" "); + String newModerator = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + newModerator = s; + break; + } + + if (oldLeader != null && newModerator != null) { + getPartyContext(true).setPartyOwner(oldLeader); + getPartyContext(true).addPartyModerator(newModerator); + } + a.put("type", "party_promotion"); + } else if (str.endsWith("§r§eto Party Member§r")) { + String[] messageSplit = TextUtils.stripColor(str).split(" "); + String oldLeader = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + oldLeader = s; + break; + } + messageSplit = TextUtils.stripColor(str.substring(str.indexOf("has demoted") + 12)).split(" "); + String newMember = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + newMember = s; + break; + } + + if (oldLeader != null && newMember != null) { + getPartyContext(true).setPartyOwner(oldLeader); + getPartyContext(true).addPartyMember(newMember); + } + a.put("type", "party_demotion"); + } + return ChatProcessResult.NONE; + }); + // Player Join + cp.subscribe(new ChatSubscriber() { + boolean joined; + @Override + public ChatProcessResult process(String str, Map<String, Object> context) { + if (str.startsWith("§eYou have joined ")) { + String[] messageSplit = TextUtils.stripColor(str.substring(18)).split(" "); + String leader = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + leader = s; + break; + } + leader = leader.substring(0, leader.length()-2); // remove 's + partyContext = new PartyContext(); + getPartyContext().setPartyOwner(leader); + getPartyContext().addPartyMember(Minecraft.getMinecraft().getSession().getUsername()); + context.put("type", "party_selfjoin_leader"); + joined= true; + } else if (str.startsWith("§eYou'll be partying with: ")) { + String[] players = TextUtils.stripColor(str.substring(27)).split(" "); + for (String player : players) { + if (player.startsWith("[")) continue; + getPartyContext().addRawMember(player); + } + context.put("type", "party_selfjoin_players"); + } else if (str.equals("§9§m-----------------------------§r") && joined) { + joined = false; + getPartyContext().setRawMemberComplete(true); + joinedParty(); + } + return ChatProcessResult.NONE; + }}); + // Player Join Dungon + cp.subscribe((str, a)-> { + if (str.contains("§r§ejoined the dungeon group! (§r§b")) { + String username = TextUtils.stripColor(str).split(" ")[3]; + if (username.equalsIgnoreCase(Minecraft.getMinecraft().getSession().getUsername())) { + partyContext = new PartyContext(); + requestPartyList((str2) -> {}); + } else { + getPartyContext(true).setMemberComplete(false); + requestPartyList((str2) -> {}); + } + } + return ChatProcessResult.NONE; + }); + } + + public void toggleAllowAskToJoin() { + if (canInvite()) { + if (askToJoinSecret != null) askToJoinSecret = null; + else { + updateAskToJoin(); + } + } + } + + public void updateAskToJoin() { + StringBuilder secretBuilder = new StringBuilder(); + for (int i = 0; i < 20; i++) { + secretBuilder.append(validChars.charAt(random.nextInt(validChars.length()))); + } + askToJoinSecret = secretBuilder.toString(); + + StompInterface stompInterface = DungeonsGuide.getDungeonsGuide().getStompConnection(); + stompInterface.send(new StompPayload().payload(new JSONObject().put("secret", askToJoinSecret).toString()).header("destination", "/app/party.setjoinsecret")); + } + + public static ChatSubscriber dashShredder() { + return (str, a) -> (int)a.get("removed") == 0 && str.equals("§9§m-----------------------------§r") ? ChatProcessResult.REMOVE_LISTENER_AND_CHAT : ChatProcessResult.NONE; + } + + public static ChatSubscriber typeShredder(boolean end, String... types) { + return (str, a) -> (int)a.get("removed") == 0 &&Arrays.stream(types).anyMatch(s -> s.equals(a.getOrDefault("type", null))) ? (end ? ChatProcessResult.REMOVE_LISTENER_AND_CHAT : ChatProcessResult.REMOVE_CHAT) : ChatProcessResult.NONE; + } + + public static ChatSubscriber combinedShredder(ChatSubscriber... chatSubscribers) { + return (str, a) -> { + boolean removeChat = false; + boolean removeListener = false; + for (ChatSubscriber chatSubscriber : chatSubscribers) { + ChatProcessResult chatProcessResult = chatSubscriber.process(str, a); + if (chatProcessResult.isRemoveChat()) removeChat = true; + if (chatProcessResult.isRemoveListener()) removeListener = true; + } + return (removeChat && removeListener) ? ChatProcessResult.REMOVE_LISTENER_AND_CHAT : (removeChat ? ChatProcessResult.REMOVE_CHAT : (removeListener ? ChatProcessResult.REMOVE_LISTENER : ChatProcessResult.NONE)); + }; + } + + @SubscribeEvent + public void onHypixelJoin(HypixelJoinedEvent skyblockJoinedEvent) { + partyContext = null; + requestPartyList((a) -> { + if (a == null) return; + if (isLeader() || isModerator()) return; + if (a.getAllInvite() != null) return; + requestAllInvite(); + }); + } + + private void leaveParty() { + if (partyContext != null) { + getPartyContext().setPartyExistHypixel(false); + if (getPartyContext().isSelfSolo()) return; + if (getPartyContext().getPartyID() != null) { + JSONObject object = new JSONObject(); + object.put("partyid", getPartyContext().getPartyID()); + StompInterface stompInterface = DungeonsGuide.getDungeonsGuide().getStompConnection(); + stompInterface.send(new StompPayload().payload(object.toString()).header("destination", "/app/party.leave")); + } + } + + partyContext = new PartyContext(); + playerInvAntiSpam.clear(); + + getPartyContext().setPartyExistHypixel(false); + getPartyContext().setPartyOwner(Minecraft.getMinecraft().getSession().getUsername()); + getPartyContext().setPartyModerator(new TreeSet<>(String.CASE_INSENSITIVE_ORDER)); getPartyContext().setMemberComplete(true); + getPartyContext().setPartyMember(new TreeSet<>(String.CASE_INSENSITIVE_ORDER)); getPartyContext().setModeratorComplete(true); + getPartyContext().setAllInvite(false); + joinedParty(); + } + private void joinedParty() { + JSONArray jsonArray = new JSONArray(); + for (String member : getPartyContext().getPartyRawMembers()) { + jsonArray.put(member); + } + JSONObject object = new JSONObject(); + object.put("members", jsonArray); + StompInterface stompInterface = DungeonsGuide.getDungeonsGuide().getStompConnection(); + stompInterface.send(new StompPayload().payload(object.toString()).header("destination", "/app/party.join")); + + getPartyContext().setPartyID("!@#!@#!@#..........FETCHING..........$!@$!@$!@$"+UUID.randomUUID().toString()); + } + + public boolean isLeader() { + return partyContext != null && getPartyContext().hasLeader(Minecraft.getMinecraft().getSession().getUsername()); // "getUsername" + } + public boolean isModerator() { + return partyContext != null && getPartyContext().hasModerator(Minecraft.getMinecraft().getSession().getUsername()); + } + public boolean canInvite() { + return isLeader() || isModerator() || (partyContext != null && getPartyContext().getAllInvite() != null && getPartyContext().getAllInvite()); + } + + private boolean requested = false; + public void requestPartyList(Consumer<PartyContext> onPartyCallback) { + if (requested) { + partyBuiltCallback.add(onPartyCallback); + return; + } + requested = true; + + ChatProcessor.INSTANCE.addToChatQueue("/pl", () -> { + ChatProcessor.INSTANCE.subscribe(dashShredder()); + ChatProcessor.INSTANCE.subscribe(combinedShredder(typeShredder(true, "member_end"), dashShredder(), typeShredder(false,"notinparty", "member_start", "member_moder", "member_leader", "member_member"))); + }, true); + partyBuiltCallback.add(onPartyCallback); + partyBuiltCallback.add(pc -> requested=false); + } + + public void requestAllInvite() { + if (isLeader() || isModerator()) return; + if (partyContext != null && getPartyContext().getAllInvite() != null) return; + + ChatProcessor.INSTANCE.addToChatQueue("/p invite -", () -> { + ChatProcessor.INSTANCE.subscribe(dashShredder()); + ChatProcessor.INSTANCE.subscribe(typeShredder(true, "notinparty", "allinvite_off", "party_invite_noexist")); + ChatProcessor.INSTANCE.subscribe(dashShredder()); + }, true); + } + + private Map<String, Long> playerInvAntiSpam = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + + @Override + public void handle(StompInterface stompInterface, StompPayload stompPayload) { + JSONObject object = new JSONObject(stompPayload.payload()); + if ("/user/queue/party.check".equals(stompPayload.headers().get("destination"))) { + String playerName = object.getString("player"); + String token = object.getString("token"); + if (partyContext == null) { + requestPartyList((pc) -> { + boolean contains = pc.getPartyRawMembers().contains(playerName); + if (!contains) { + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().payload(new JSONObject().put("status", "failure").put("token", token).toString()).header("destination", "/app/party.check.resp")); + } else { + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().payload(new JSONObject().put("status", "success").put("token", token).toString()).header("destination", "/app/party.check.resp")); + } + }); + } else { + if (getPartyContext().getPartyRawMembers().contains(playerName)) { + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().payload(new JSONObject().put("status", "success").put("token", token).toString()).header("destination", "/app/party.check.resp")); + } else if (getPartyContext().isMemberComplete() && getPartyContext().isModeratorComplete() && getPartyContext().getPartyOwner() != null) { + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().payload(new JSONObject().put("status", "failure").put("token", token).toString()).header("destination", "/app/party.check.resp")); + } else { + requestPartyList((pc) -> { + boolean contains = pc.getPartyRawMembers().contains(playerName); + if (!contains) { + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().payload(new JSONObject().put("status", "failure").put("token", token).toString()).header("destination", "/app/party.check.resp")); + } else { + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().payload(new JSONObject().put("status", "success").put("token", token).toString()).header("destination", "/app/party.check.resp")); + } + }); + } + } + } else if ("/user/queue/party.broadcast".equals(stompPayload.headers().get("destination"))) { + try { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: Message Broadcasted from player:: \n" + new JSONObject(stompPayload.payload()).getString("payload"))); + } catch (Exception e) { + e.printStackTrace(); + } + } else if ("/user/queue/party.join".equals(stompPayload.headers().get("destination"))) { + String playerName = object.getString("player"); + String secret = object.getString("secret"); + if (secret.equals(askToJoinSecret) && partyContext != null && getPartyContext().getPartyRawMembers().size() < maxParty && playerInvAntiSpam.getOrDefault(playerName, 0L) < System.currentTimeMillis() - 5000) { + playerInvAntiSpam.put(playerName, System.currentTimeMillis()); + ChatProcessor.INSTANCE.addToChatQueue("/p invite "+playerName,() -> {}, true); + } + } else if ("/user/queue/party.askedtojoin.resp".equals(stompPayload.headers().get("destination"))) { + String invFrom = object.getString("username"); + String token2 = object.getString("token"); + if (!token2.equals(lastToken)) return; + lastToken = null; + ChatProcessor.INSTANCE.addToChatQueue("/p accept "+invFrom, () -> {}, true); + long end = System.currentTimeMillis() + 3000; + ChatProcessor.INSTANCE.subscribe((str, a) -> { + if (!str.contains("§r§ehas invited you to join their party!")) return System.currentTimeMillis() > end ? ChatProcessResult.REMOVE_LISTENER : ChatProcessResult.NONE; + String[] messageSplit = TextUtils.stripColor(str).split(" "); + String inviter = null; + for (String s : messageSplit) { + if (s.startsWith("[")) continue; + if (s.startsWith("-")) continue;; + inviter = s; + break; + } + if (invFrom.equalsIgnoreCase(inviter)) { + ChatProcessor.INSTANCE.addToChatQueue("/p accept "+invFrom, () -> {}, true); + } + return ChatProcessResult.NONE; + }); + } else { + String str = object.getString("status"); + if ("success".equals(str) && partyContext != null) { + getPartyContext().setPartyID(object.getString("partyId")); + if (askToJoinSecret != null) { + updateAskToJoin(); + } + } else if (partyContext != null){ + getPartyContext().setPartyID(null); + } + } + } + + @SubscribeEvent + public void stompConnect(StompConnectedEvent stompConnectedEvent) { + stompConnectedEvent.getStompInterface().subscribe(StompSubscription.builder() + .stompMessageHandler(this).ackMode(StompSubscription.AckMode.AUTO).destination("/user/queue/party.resp").build()); + stompConnectedEvent.getStompInterface().subscribe(StompSubscription.builder() + .stompMessageHandler(this).ackMode(StompSubscription.AckMode.AUTO).destination("/user/queue/party.check").build()); + stompConnectedEvent.getStompInterface().subscribe(StompSubscription.builder() + .stompMessageHandler(this).ackMode(StompSubscription.AckMode.AUTO).destination("/user/queue/party.broadcast").build()); + stompConnectedEvent.getStompInterface().subscribe(StompSubscription.builder() + .stompMessageHandler(this).ackMode(StompSubscription.AckMode.AUTO).destination("/user/queue/party.join").build()); + stompConnectedEvent.getStompInterface().subscribe(StompSubscription.builder() + .stompMessageHandler(this).ackMode(StompSubscription.AckMode.AUTO).destination("/user/queue/party.askedtojoin.resp").build()); + } + + private String lastToken; + public void joinWithToken(String secret) { + lastToken = secret; + if (partyContext != null && getPartyContext().isPartyExistHypixel()) + ChatProcessor.INSTANCE.addToChatQueue("/p leave", () -> {}, true); + DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().method(StompHeader.SEND) + .header("destination", "/app/party.askedtojoin") + .payload(new JSONObject().put("token", secret).toString())); + } +} |