diff options
16 files changed, 1027 insertions, 511 deletions
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java b/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java index 2a0d73e0..e8f3ada5 100755 --- a/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java @@ -19,6 +19,8 @@ package kr.syeyoung.dungeonsguide; import com.google.common.collect.Sets; +import kr.syeyoung.dungeonsguide.chat.ChatProcessor; +import kr.syeyoung.dungeonsguide.chat.PartyManager; import kr.syeyoung.dungeonsguide.commands.*; import kr.syeyoung.dungeonsguide.config.Config; import kr.syeyoung.dungeonsguide.cosmetics.CosmeticsManager; @@ -28,7 +30,6 @@ import kr.syeyoung.dungeonsguide.eventlistener.FeatureListener; import kr.syeyoung.dungeonsguide.eventlistener.PacketListener; import kr.syeyoung.dungeonsguide.events.StompConnectedEvent; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; -import kr.syeyoung.dungeonsguide.party.PartyManager; import kr.syeyoung.dungeonsguide.resources.DGTexturePack; import kr.syeyoung.dungeonsguide.rpc.RichPresenceManager; import kr.syeyoung.dungeonsguide.stomp.CloseListener; @@ -119,6 +120,8 @@ public class DungeonsGuide implements DGInterface, CloseListener { MinecraftForge.EVENT_BUS.register(new PacketListener()); MinecraftForge.EVENT_BUS.register(new Keybinds()); +// MinecraftForge.EVENT_BUS.register(PartyManager.INSTANCE); + MinecraftForge.EVENT_BUS.register(ChatProcessor.INSTANCE); MinecraftForge.EVENT_BUS.register(PartyManager.INSTANCE); MinecraftForge.EVENT_BUS.register(StaticResourceCache.INSTANCE); 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())); + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java index d5fe082e..914ca8e8 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandDungeonsGuide.java @@ -20,7 +20,8 @@ package kr.syeyoung.dungeonsguide.commands; import com.google.gson.JsonObject; import kr.syeyoung.dungeonsguide.DungeonsGuide; -import kr.syeyoung.dungeonsguide.pathfinding.JPSPathfinder; +import kr.syeyoung.dungeonsguide.chat.PartyContext; +import kr.syeyoung.dungeonsguide.chat.PartyManager; import kr.syeyoung.dungeonsguide.rpc.RichPresenceManager; import kr.syeyoung.dungeonsguide.SkyblockStatus; import kr.syeyoung.dungeonsguide.config.guiconfig.GuiConfigV2; @@ -41,7 +42,6 @@ import kr.syeyoung.dungeonsguide.features.AbstractFeature; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; import kr.syeyoung.dungeonsguide.features.impl.party.playerpreview.FeatureViewPlayerOnJoin; import kr.syeyoung.dungeonsguide.features.impl.party.api.ApiFetchur; -import kr.syeyoung.dungeonsguide.party.PartyManager; import kr.syeyoung.dungeonsguide.roomedit.EditingContext; import kr.syeyoung.dungeonsguide.roomedit.gui.GuiDungeonRoomEdit; import kr.syeyoung.dungeonsguide.roomprocessor.GeneralRoomProcessor; @@ -263,17 +263,23 @@ public class CommandDungeonsGuide extends CommandBase { t.printStackTrace(); } } else if (args[0].equalsIgnoreCase("pvall")) { - PartyManager.INSTANCE.getRunOnMembersReceived().add((e) -> { - for (String s : e) { - ApiFetchur.fetchUUIDAsync(s) + PartyManager.INSTANCE.requestPartyList((context) -> { + if (context == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §cNot in Party")); + return; + } + for (String member : context.getPartyRawMembers()) { + ApiFetchur.fetchUUIDAsync(member) .thenAccept(a -> { - if (a == null) return; - ApiFetchur.fetchMostRecentProfileAsync(a.get(), FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e" + s + "§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); + if (a == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+member+"§f's Profile §cCouldn't fetch uuid")); + } else { + ApiFetchur.fetchMostRecentProfileAsync(a.get(), FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e" + member + "§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); + } }); } }); - PartyManager.INSTANCE.requestPartyRetrieval(); // } else if (args[0].equals("fixschematic")) { // File root = new File(e.getDungeonsGuide().getConfigDir(), "schematics"); // Method method = null; @@ -315,11 +321,11 @@ public class CommandDungeonsGuide extends CommandBase { sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §cDiscord GameSDK has been disabled, or it failed to load!")); return; } - if (!PartyManager.INSTANCE.isCanInvite()) { + if (!PartyManager.INSTANCE.canInvite()) { sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §cYou don't have perms in the party to invite people!")); } else { PartyManager.INSTANCE.toggleAllowAskToJoin(); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §fToggled Ask to join to " + (PartyManager.INSTANCE.isAllowAskToJoin() ? "§eon" : "§coff"))); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §fToggled Ask to join to " + (PartyManager.INSTANCE.getAskToJoinSecret() != null ? "§eon" : "§coff"))); } if (!FeatureRegistry.DISCORD_RICHPRESENCE.isEnabled()) { @@ -347,7 +353,7 @@ public class CommandDungeonsGuide extends CommandBase { } } } else if (args[0].equals("partyid")) { - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §fInternal Party id: " + PartyManager.INSTANCE.getPartyID())); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §fInternal Party id: " + Optional.ofNullable(PartyManager.INSTANCE.getPartyContext()).map(PartyContext::getPartyID).orElse(null))); } else if (args[0].equalsIgnoreCase("loc")) { sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §fYou're in " + DungeonsGuide.getDungeonsGuide().getSkyblockStatus().getDungeonName())); } else if (args[0].equalsIgnoreCase("saverun")) { @@ -404,7 +410,7 @@ public class CommandDungeonsGuide extends CommandBase { System.arraycopy(args, 1, payload, 0, payload.length); String actualPayload = String.join(" ", payload).replace("$C$", "§"); DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().header("destination", "/app/party.broadcast").payload( - new JSONObject().put("partyID", PartyManager.INSTANCE.getPartyID()) + new JSONObject().put("partyID", PartyManager.INSTANCE.getPartyContext().getPartyID()) .put("payload", actualPayload).toString() )); } catch (Exception e) { diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java index f87456fa..edb429df 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/FeatureRegistry.java @@ -33,6 +33,7 @@ import kr.syeyoung.dungeonsguide.features.impl.dungeon.*; import kr.syeyoung.dungeonsguide.features.impl.etc.*; import kr.syeyoung.dungeonsguide.features.impl.etc.ability.FeatureAbilityCooldown; import kr.syeyoung.dungeonsguide.features.impl.party.APIKey; +import kr.syeyoung.dungeonsguide.features.impl.party.FeaturePartyList; import kr.syeyoung.dungeonsguide.features.impl.party.customgui.FeatureCustomPartyFinder; import kr.syeyoung.dungeonsguide.features.impl.party.playerpreview.FeatureViewPlayerOnJoin; import kr.syeyoung.dungeonsguide.features.impl.secret.*; @@ -161,6 +162,7 @@ public class FeatureRegistry { public static final APIKey PARTYKICKER_APIKEY = register(new APIKey()); public static final FeatureViewPlayerOnJoin PARTYKICKER_VIEWPLAYER = register(new FeatureViewPlayerOnJoin()); public static final FeatureCustomPartyFinder PARTYKICKER_CUSTOM = register(new FeatureCustomPartyFinder()); + public static final FeaturePartyList PARTY_LIST = register(new FeaturePartyList()); public static final FeatureTooltipDungeonStat ETC_DUNGEONSTAT = register(new FeatureTooltipDungeonStat()); public static final FeatureTooltipPrice ETC_PRICE = register(new FeatureTooltipPrice()); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/FeaturePartyList.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/FeaturePartyList.java new file mode 100644 index 00000000..0222b97b --- /dev/null +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/FeaturePartyList.java @@ -0,0 +1,97 @@ +/* + * 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.features.impl.party; + +import kr.syeyoung.dungeonsguide.chat.PartyContext; +import kr.syeyoung.dungeonsguide.chat.PartyManager; +import kr.syeyoung.dungeonsguide.config.types.AColor; +import kr.syeyoung.dungeonsguide.features.text.StyledText; +import kr.syeyoung.dungeonsguide.features.text.TextHUDFeature; +import kr.syeyoung.dungeonsguide.features.text.TextStyle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FeaturePartyList extends TextHUDFeature { + public FeaturePartyList() { + super("Party","Party List", "Party List as GUI", "party.list", false, getFontRenderer().getStringWidth("Watcher finished spawning all mobs!"), getFontRenderer().FONT_HEIGHT); + getStyles().add(new TextStyle("name", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false)); + getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false)); + getStyles().add(new TextStyle("player", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false)); + getStyles().add(new TextStyle("allinvite", new AColor(0xAA,0xAA,0xAA,255), new AColor(0, 0,0,0), false)); + setEnabled(true); + } + + @Override + public boolean isHUDViewable() { + return PartyManager.INSTANCE.getPartyContext() != null; + } + + @Override + public java.util.List<String> getUsedTextStyle() { + return Arrays.asList("name" ,"separator", "player", "allinvite"); + } + + private static final List<StyledText> dummyText = new ArrayList<StyledText>(); + static { + dummyText.add(new StyledText("\nLeader","name")); + dummyText.add(new StyledText(": ","separator")); + dummyText.add(new StyledText("syeyoung","player")); + dummyText.add(new StyledText("\nModerator","name")); + dummyText.add(new StyledText(": ","separator")); + dummyText.add(new StyledText("rioho, RaidShadowLegends, Tricked","player")); + dummyText.add(new StyledText("\nMember","name")); + dummyText.add(new StyledText(": ","separator")); + dummyText.add(new StyledText("Everyone","player")); + dummyText.add(new StyledText("\nAll invite Off","allinvite")); + } + + @Override + public List<StyledText> getDummyText() { + return dummyText; + } + + @Override + public boolean doesScaleWithHeight() { + return false; + } + + @Override + public List<StyledText> getText() { + PartyContext pc = PartyManager.INSTANCE.getPartyContext(); + List<StyledText> text= new ArrayList<>(); + text.add(new StyledText("\nLeader","name")); + text.add(new StyledText(": ","separator")); + text.add(new StyledText(pc.getPartyOwner()+"","player")); + text.add(new StyledText("\nModerator","name")); + text.add(new StyledText(": ","separator")); + text.add(new StyledText(pc.getPartyModerator() == null ? "????" : String.join(", ", pc.getPartyModerator()) + (pc.isModeratorComplete() ? "" : " ?"),"player")); + text.add(new StyledText("\nMember","name")); + text.add(new StyledText(": ","separator")); + text.add(new StyledText(pc.getPartyMember() == null ? "????" : String.join(", ", pc.getPartyMember()) + (pc.isMemberComplete() ? "" : " ?"),"player")); + if (pc.getAllInvite() != null && !pc.getAllInvite()) + text.add(new StyledText("\nAll invite Off","allinvite")); + else if (pc.getAllInvite() != null) + text.add(new StyledText("\nAll invite On","allinvite")); + else + text.add(new StyledText("\nAll invite Unknown","allinvite")); + return text; + } +} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java index 046d9a8e..0d929697 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/api/ApiFetchur.java @@ -64,8 +64,12 @@ public class ApiFetchur { completableFutureMap3.clear(); completableFutureMap4.clear(); invalidKeys.clear(); - completableFutureMapLily= null; constants = null; + + ex.submit(ApiFetchur::getLilyWeightConstants); + } + static { + ex.submit(ApiFetchur::getLilyWeightConstants); } public static JsonObject getJson(String url) throws IOException { @@ -81,25 +85,16 @@ public class ApiFetchur { return gson.fromJson(new InputStreamReader(connection.getInputStream()), JsonArray.class); } - private static JsonObject constants; - private static CompletableFuture<JsonObject> completableFutureMapLily; - public static CompletableFuture<JsonObject> getLilyWeightConstants() { - if (constants != null) return CompletableFuture.completedFuture(constants); - if (completableFutureMapLily != null) return completableFutureMapLily; - CompletableFuture<JsonObject> completableFuture = new CompletableFuture<>(); - completableFutureMapLily = completableFuture; - ex.submit(() -> { + private static volatile JsonObject constants; + public static JsonObject getLilyWeightConstants() { + if (constants != null) return constants; try { JsonObject jsonObject = getJson("https://raw.githubusercontent.com/Antonio32A/lilyweight/master/lib/constants.json"); constants = jsonObject; - completableFuture.complete(jsonObject); - completableFutureMapLily= null; } catch (Exception e) { - completableFuture.completeExceptionally(e); - completableFutureMapLily= null; + throw new RuntimeException(e); } - }); - return completableFuture; + return constants; } private static final Map<String, CompletableFuture<Optional<GameProfile>>> completableFutureMap4 = new ConcurrentHashMap<>(); @@ -174,7 +169,7 @@ public class ApiFetchur { completableFutureMap.remove(uid); invalidKeys.add(apiKey); } else { - completableFuture.complete(Optional.empty()); + completableFuture.completeExceptionally(e); completableFutureMap.remove(uid); } e.printStackTrace(); @@ -497,7 +492,7 @@ public class ApiFetchur { } private static void calculateLilyWeight(PlayerProfile playerProfile, JsonObject playerData) throws ExecutionException, InterruptedException { - JsonObject constants = getLilyWeightConstants().get(); + JsonObject constants = getLilyWeightConstants(); double[] slayerXP = new double[4]; if (playerData.has("slayer_bosses")) { slayerXP[0] = getOrDefault(playerData.getAsJsonObject("slayer_bosses").getAsJsonObject("zombie"), "xp", 0); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinder.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinder.java index 23c8e253..eef360b2 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinder.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinder.java @@ -18,13 +18,13 @@ package kr.syeyoung.dungeonsguide.features.impl.party.customgui; +import kr.syeyoung.dungeonsguide.chat.PartyManager; import kr.syeyoung.dungeonsguide.config.guiconfig.GuiConfigV2; import kr.syeyoung.dungeonsguide.events.WindowUpdateEvent; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; import kr.syeyoung.dungeonsguide.features.impl.discord.invteTooltip.MTooltipInvite; import kr.syeyoung.dungeonsguide.gui.MPanel; import kr.syeyoung.dungeonsguide.gui.elements.*; -import kr.syeyoung.dungeonsguide.party.PartyManager; import kr.syeyoung.dungeonsguide.rpc.RichPresenceManager; import kr.syeyoung.dungeonsguide.utils.RenderUtils; import lombok.Getter; @@ -41,7 +41,6 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; -import net.minecraft.util.ChatComponentText; import java.awt.*; import java.util.HashMap; @@ -122,7 +121,7 @@ public class PanelPartyFinder extends MPanel { MModalMessage mTooltipInvite = new MModalMessage("Error", "Discord GameSDK has been disabled, or it failed to load", () -> {}); mTooltipInvite.setScale( new ScaledResolution(Minecraft.getMinecraft()).getScaleFactor()); mTooltipInvite.open(this); - } else if (PartyManager.INSTANCE.isAllowAskToJoin()) { + } else if (PartyManager.INSTANCE.getAskToJoinSecret() != null) { MTooltipInvite mTooltipInvite = new MTooltipInvite(); mTooltipInvite.setScale( new ScaledResolution(Minecraft.getMinecraft()).getScaleFactor()); mTooltipInvite.open(this); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinderSettings.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinderSettings.java index 8dad627c..46107ff8 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinderSettings.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/customgui/PanelPartyFinderSettings.java @@ -18,8 +18,10 @@ package kr.syeyoung.dungeonsguide.features.impl.party.customgui; +import kr.syeyoung.dungeonsguide.chat.ChatProcessor; +import kr.syeyoung.dungeonsguide.chat.PartyManager; import kr.syeyoung.dungeonsguide.features.FeatureRegistry; -import kr.syeyoung.dungeonsguide.gui.MPanel; +import kr.syeyoung.dungeonsguide.features.impl.party.api.ApiFetchur; import kr.syeyoung.dungeonsguide.gui.elements.*; import kr.syeyoung.dungeonsguide.utils.TextUtils; import lombok.Getter; @@ -53,22 +55,27 @@ public class PanelPartyFinderSettings extends MPanelScaledGUI { boolean delistable = false; public void setDelistable(boolean delistable) { - createNew.setText(delistable ? "De-list" : "Create New"); this.delistable = delistable; + updateCreateNew(); + } + + public void updateCreateNew() { + createNew.setText((PartyManager.INSTANCE.getPartyContext() != null && !PartyManager.INSTANCE.isLeader()) ? "Leave Party" : (delistable ? "De-list" : "Create New")); } public PanelPartyFinderSettings(PanelPartyFinder panelPartyFinder) { this.panelPartyFinder = panelPartyFinder; - createNew.setText("Create New"); createNew.setOnActionPerformed(this::createNew); createNew.setBackground(0xFF00838F); createNew.setHover(0xFF00ACC1); createNew.setClicked(0xFF0097A7); add(createNew); + updateCreateNew(); refresh.setText("Refresh"); refresh.setOnActionPerformed(this::refresh); add(refresh); + settings.setText("Search Settings"); settings.setOnActionPerformed(this::settings); add(settings); @@ -142,6 +149,10 @@ public class PanelPartyFinderSettings extends MPanelScaledGUI { } private void createNew() { + if (PartyManager.INSTANCE.getPartyContext() != null && !PartyManager.INSTANCE.isLeader()) { + ChatProcessor.INSTANCE.addToChatQueue("/p leave ", () -> {}, true); + return; + } GuiChest chest = panelPartyFinder.getGuiCustomPartyFinder().getGuiChest(); if (delistable) Minecraft.getMinecraft().playerController.windowClick(chest.inventorySlots.windowId, 9*5+7, 0, 0, Minecraft.getMinecraft().thePlayer); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/playerpreview/FeatureViewPlayerOnJoin.java b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/playerpreview/FeatureViewPlayerOnJoin.java index 21fb5d04..ceca0022 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/playerpreview/FeatureViewPlayerOnJoin.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/features/impl/party/playerpreview/FeatureViewPlayerOnJoin.java @@ -24,6 +24,8 @@ import io.github.moulberry.hychat.HyChat; import io.github.moulberry.hychat.chat.ChatManager; import io.github.moulberry.hychat.gui.GuiChatBox; import kr.syeyoung.dungeonsguide.DungeonsGuide; +import kr.syeyoung.dungeonsguide.chat.ChatProcessor; +import kr.syeyoung.dungeonsguide.chat.PartyManager; import kr.syeyoung.dungeonsguide.config.guiconfig.ConfigPanelCreator; import kr.syeyoung.dungeonsguide.config.guiconfig.MFeatureEdit; import kr.syeyoung.dungeonsguide.config.guiconfig.MParameterEdit; @@ -38,7 +40,6 @@ import kr.syeyoung.dungeonsguide.features.listener.ChatListener; import kr.syeyoung.dungeonsguide.features.listener.GuiClickListener; import kr.syeyoung.dungeonsguide.features.listener.GuiPostRenderListener; import kr.syeyoung.dungeonsguide.gui.MPanel; -import kr.syeyoung.dungeonsguide.party.PartyManager; import kr.syeyoung.dungeonsguide.utils.TextUtils; import lombok.Getter; import lombok.Setter; @@ -416,10 +417,10 @@ public class FeatureViewPlayerOnJoin extends SimpleFeature implements GuiPostRen if (Mouse.getEventButton() != -1 && Mouse.isButtonDown(Mouse.getEventButton())) { if (new Rectangle(2, 195, 86, 23).contains(relX, relY)) { // invite - Minecraft.getMinecraft().thePlayer.sendChatMessage("/p invite " + ApiFetchur.fetchNicknameAsync(playerProfile.getMemberUID()).get().orElse("-")); + ChatProcessor.INSTANCE.addToChatQueue("/p invite " + ApiFetchur.fetchNicknameAsync(playerProfile.getMemberUID()).get().orElse("-"), () -> {}, true); } else if (new Rectangle(2, 170, 86, 23).contains(relX, relY)) { // kick - Minecraft.getMinecraft().thePlayer.sendChatMessage("/p kick " + ApiFetchur.fetchNicknameAsync(playerProfile.getMemberUID()).get().orElse("-")); + ChatProcessor.INSTANCE.addToChatQueue("/p kick " + ApiFetchur.fetchNicknameAsync(playerProfile.getMemberUID()).get().orElse("-"), () -> {}, true); } else if (new Rectangle(80,159,10,11).contains(relX, relY)) { drawInv = true; } @@ -456,21 +457,31 @@ public class FeatureViewPlayerOnJoin extends SimpleFeature implements GuiPostRen if (str.contains("§r§ejoined the dungeon group! (§r§b")) { String username = TextUtils.stripColor(str).split(" ")[3]; if (username.equalsIgnoreCase(Minecraft.getMinecraft().getSession().getUsername())) { - PartyManager.INSTANCE.getRunOnMembersReceived().add((e) -> { - for (String s : e) { - ApiFetchur.fetchUUIDAsync(s) - .thenAccept(a -> { - if (a == null) return; - ApiFetchur.fetchMostRecentProfileAsync(a.get(), FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); - Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+s+"§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); - }); + PartyManager.INSTANCE.requestPartyList((context) -> { + if (context == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §cBugged Dungeon Party ")); + } else { + + for (String member : context.getPartyRawMembers()) { + ApiFetchur.fetchUUIDAsync(member) + .thenAccept((a) -> { + if (a == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+member+"§f's Profile §cCouldn't fetch uuid")); + } else { + ApiFetchur.fetchMostRecentProfileAsync(a.get(), FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+member+"§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); + } + }); + } } }); - PartyManager.INSTANCE.requestPartyRetrieval(); } else { ApiFetchur.fetchUUIDAsync(username) .thenAccept(a -> { - if (a == null) return; + if (a == null) { + Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+username+"§f's Profile §cCouldn't fetch uuid")); + return; + } ApiFetchur.fetchMostRecentProfileAsync(a.get(), FeatureRegistry.PARTYKICKER_APIKEY.getAPIKey()); Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e"+username+"§f's Profile ").appendSibling(new ChatComponentText("§7view").setChatStyle(new ChatStyle().setChatHoverEvent(new FeatureViewPlayerOnJoin.HoverEventRenderPlayer(a.orElse(null)))))); }); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java b/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java deleted file mode 100644 index fdeab870..00000000 --- a/src/main/java/kr/syeyoung/dungeonsguide/party/PartyManager.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * 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.party; - -import kr.syeyoung.dungeonsguide.rpc.RichPresenceManager; -import kr.syeyoung.dungeonsguide.DungeonsGuide; -import kr.syeyoung.dungeonsguide.events.HypixelJoinedEvent; -import kr.syeyoung.dungeonsguide.events.StompConnectedEvent; -import kr.syeyoung.dungeonsguide.stomp.StompInterface; -import kr.syeyoung.dungeonsguide.stomp.StompMessageHandler; -import kr.syeyoung.dungeonsguide.stomp.StompPayload; -import kr.syeyoung.dungeonsguide.stomp.StompSubscription; -import kr.syeyoung.dungeonsguide.utils.TextUtils; -import lombok.Getter; -import lombok.Setter; -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.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 org.json.JSONArray; -import org.json.JSONObject; - -import java.security.SecureRandom; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.function.Consumer; - -public class PartyManager implements StompMessageHandler { - public static final PartyManager INSTANCE = new PartyManager(); - - @Getter - private String partyID = "GENERATE_PARTYID_PLEASE_POG_THIS_IS_INVALID_ID_THAT_SHOULD_BE_REGENERATED"; - @Getter - private String askToJoinSecret = null; - - private final SecureRandom random = new SecureRandom(); - private static final String validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; - - @Getter - private boolean allowAskToJoin = false; - @Getter - private boolean canInvite = false; - private int invitedDash =0; - - @Getter - private final Queue<Consumer<Set<String>>> runOnMembersReceived = new LinkedList<>(); - - - @Getter - @Setter - private int maxParty = 5; - - private static final Logger logger = LogManager.getLogger(); - - - private PartyManager() { - 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); - } - } - - public void toggleAllowAskToJoin() { - if (canInvite) allowAskToJoin = !allowAskToJoin; - if (allowAskToJoin) { - generateNewAskToJoinSecret(); - } - } - - public int getMemberCount() { - return Math.max(1, members.size()); - } - - public void setPartyID(String partyID) { - if (this.partyID != null && partyID == null) { - JSONObject object = new JSONObject(); - object.put("members", new JSONArray()); - StompInterface stompInterface = DungeonsGuide.getDungeonsGuide().getStompConnection(); - stompInterface.send(new StompPayload().payload(object.toString()).header("destination", "/app/party.join")); - } - - if (partyID != null && !partyID.equals(this.partyID)) { - sendChat.add(new Tuple<>("/p invite -", () -> {invitedDash = 1;})); - } else { - canInvite = true; - allowAskToJoin = false; - } - this.partyID = partyID; - this.askToJoinSecret = null; - - if (allowAskToJoin && RichPresenceManager.INSTANCE.getLastSetupCode() != -9999) { - generateNewAskToJoinSecret(); - } - } - - public void generateNewAskToJoinSecret() { - if (partyID == null) { - JSONObject object = new JSONObject(); - object.put("members", new JSONArray()); - StompInterface stompInterface = DungeonsGuide.getDungeonsGuide().getStompConnection(); - stompInterface.send(new StompPayload().payload(object.toString()).header("destination", "/app/party.join")); - } - - StringBuilder secretBuilder = new StringBuilder(); - for (int i = 0; i < 20; i++) { - secretBuilder.append(validChars.charAt(random.nextInt(validChars.length()))); - } - this.askToJoinSecret = secretBuilder.toString(); - - StompInterface stompInterface = DungeonsGuide.getDungeonsGuide().getStompConnection(); - stompInterface.send(new StompPayload().payload(new JSONObject().put("secret", askToJoinSecret).toString()).header("destination", "/app/party.setjoinsecret")); - } - - private int partyJoin =0; - private final Set<String> members = new HashSet<>(); - private final Map<String, Long> recentlyJoined = new HashMap<>(); - @SubscribeEvent(priority = EventPriority.HIGHEST) - public void onMessage(ClientChatReceivedEvent chatReceivedEvent) { - if (chatReceivedEvent.type == 2) return; - - String str = chatReceivedEvent.message.getFormattedText(); - logger.log(Level.INFO, "[CHAT] "+str); - - try { - - if (str.startsWith("§eYou have joined ")) { - members.clear(); - String[] strs = TextUtils.stripColor(str).split(" "); - for (String s : strs) { - if (s.endsWith("'s")) { - members.add(s.substring(0, s.indexOf("'s"))); - break; - } - } - members.add(Minecraft.getMinecraft().getSession().getUsername()); - partyJoin = 100; - } 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; - members.add(player); - } - } else if (str.equals("§9§m-----------------------------§r")) { - if ((checkPlayer > 0 || partyJoin > 0) && partyJoin != 100) { - chatReceivedEvent.setCanceled(true); - } - if (partyJoin == 2 || partyJoin == 100) { - partyJoin = 0; - // REQ PARTY JOIN - Consumer<Set<String>> r; - while ((r = runOnMembersReceived.poll()) != null){ - r.accept(members); - } - - JSONArray jsonArray = new JSONArray(); - for (String member : members) { - 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")); - } - if (checkPlayer == 3) { - checkPlayer = 0; - String playerName = theObject.getString("player"); - String token = theObject.getString("token"); - if (!members.contains(playerName)) { - 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")); - } - } - if (invitedDash == 1 || invitedDash == 3) { - chatReceivedEvent.setCanceled(true); - invitedDash++; - } - if (invitedDash == 4) invitedDash = 0; - } else if (str.endsWith("§ejoined the party.§r")) { - String asd = null; - for (String s : TextUtils.stripColor(str).split(" ")) { - if (s.startsWith("[")) continue; - asd = s; - break; - } - if (asd != null) - members.add(asd); - } else if (str.contains("§r§ejoined the dungeon group! (§r§b")) { - String username = TextUtils.stripColor(str).split(" ")[3]; - if (username.equalsIgnoreCase(Minecraft.getMinecraft().getSession().getUsername())) { - sendChat.add(new Tuple<>("/pl", () -> {partyJoin = 1;})); - partyJoin = 1; - } else { - members.add(username); - } - } else if (str.endsWith("§ehas been removed from the party.§r") - || str.endsWith("§ehas left the party.§r")) { - String asd = null; - for (String s : TextUtils.stripColor(str).split(" ")) { - if (s.startsWith("[")) continue; - asd = s; - break; - } - if (asd != null) - members.remove(asd); - } else if ((str.equals("§eYou left the party.§r") - || str.startsWith("§cThe party was disbanded") - || str.endsWith("§ehas disbanded the party!§r")) - ) { - members.clear(); - setPartyID(null); - } else if (str.startsWith("§6Party Members ")) { - if (checkPlayer > 0 || partyJoin > 0) { - chatReceivedEvent.setCanceled(true); - } - if (partyJoin == 1) partyJoin = 2; - if (checkPlayer == 2) checkPlayer = 3; - members.clear(); - } else if (str.startsWith("§cYou are not currently in a party.§r")) { - members.clear(); - if (partyJoin > 0) { - partyJoin = 2; - chatReceivedEvent.setCanceled(true); - } - if (invitedDash > 0) invitedDash = 3; - if (invitedDash > 0) chatReceivedEvent.setCanceled(true); - setPartyID(null); - } else if (TextUtils.stripColor(str).trim().isEmpty()) { - if ((checkPlayer > 0 || partyJoin > 0) && partyJoin != 100) { - chatReceivedEvent.setCanceled(true); - } - } else if (str.startsWith("§cYou are not in a party")) { - members.clear(); - if (partyJoin > 0) { - partyJoin = 2; - chatReceivedEvent.setCanceled(true); - } - if (invitedDash > 0) invitedDash = 3; - if (invitedDash > 0) chatReceivedEvent.setCanceled(true); - setPartyID(null); - } else if (str.startsWith("§eParty ") && str.contains(":")) { - if (checkPlayer > 0 || partyJoin > 0) { - chatReceivedEvent.setCanceled(true); - } - String playerNames = TextUtils.stripColor(str.split(":")[1]); - for (String s : playerNames.split(" ")) { - if (s.isEmpty()) continue; - if (s.equals("●")) continue; - if (s.startsWith("[")) continue; - members.add(s); - } - } else if (str.equals("§cYou are not allowed to invite players.§r")) { - if (invitedDash > 0) invitedDash = 3; - if (invitedDash > 0) chatReceivedEvent.setCanceled(true); - canInvite = false; - allowAskToJoin = false; - askToJoinSecret = ""; - } else if (str.equals("§cCouldn't find a player with that name!§r")) { - canInvite = true; - if (invitedDash > 0) invitedDash = 3; - if (invitedDash > 0) chatReceivedEvent.setCanceled(true); - } else if (str.equals("§cYou cannot invite that player since they're not online.")) { - if (invitedDash > 0) invitedDash = 3; - if (invitedDash > 0) chatReceivedEvent.setCanceled(true); - canInvite = true; - } else if (str.endsWith("§aenabled All Invite§r")) { - canInvite = true; - } else if (str.endsWith("§cdisabled All Invite§r")) { - canInvite = false; - allowAskToJoin = false; - askToJoinSecret = ""; - sendChat.add(new Tuple<>("/p invite -", () -> {invitedDash = 1;})); - } 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[] thetext = TextUtils.stripColor(str).split(" "); - int seenThings = 0; - for (String s : thetext) { - if (s.equals("has") && seenThings == 0) seenThings = 1; - else if (s.equals("promoted") && seenThings == 1) seenThings = 2; - else if (s.equals("[")) continue; - else if (seenThings == 2) { - if (s.equals(Minecraft.getMinecraft().getSession().getUsername())) { - canInvite = true; - } else { - sendChat.add(new Tuple<>("/p invite -", () -> {invitedDash = 1;})); - break; - } - } else { - seenThings = 0; - } - } - } else 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[] thetext = TextUtils.stripColor(str.substring(31)).split(" "); - String asd = null; - for (String s : thetext) { - if (s.startsWith("[")) continue; - asd = s; - break; - } - if (asd != null && Minecraft.getMinecraft().getSession().getUsername().equalsIgnoreCase(asd)) { - canInvite = true; - } else { - sendChat.add(new Tuple<>("/p invite -", () -> {invitedDash = 1;})); - } - } 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[] thetext = TextUtils.stripColor(str).split(" "); - int seenThings = 0; - for (String s : thetext) { - if (s.equals("has") && seenThings == 0) seenThings = 1; - else if (s.equals("promoted") && seenThings == 1) seenThings = 2; - else if (s.equals("[")) continue; - else if (seenThings == 2) { - if (s.equals(Minecraft.getMinecraft().getSession().getUsername())) { - canInvite = true; - } else { - sendChat.add(new Tuple<>("/p invite -", () -> {invitedDash = 1;})); - break; - } - } else { - seenThings = 0; - } - } - } else if (str.endsWith("§r§eto Party Member§r")) { - String[] thetext = TextUtils.stripColor(str).split(" "); - int seenThings = 0; - for (String s : thetext) { - if (s.equals("has") && seenThings == 0) seenThings = 1; - else if (s.equals("demoted") && seenThings == 1) seenThings = 2; - else if (s.equals("[")) continue; - else if (seenThings == 2) { - if (s.equals(Minecraft.getMinecraft().getSession().getUsername())) { - sendChat.add(new Tuple<>("/p invite -", () -> {invitedDash = 1;})); - canInvite = false; - break; - } - } else { - seenThings = 0; - } - } - } - } catch (Exception ex) {ex.printStackTrace(); - DungeonsGuide.sendDebugChat(new ChatComponentText("ERRORRR!! on chat "+ ex));} - } - @SubscribeEvent - public void onTick(TickEvent.ClientTickEvent clientTickEvent) { - try { - if (clientTickEvent.phase == TickEvent.Phase.START && Minecraft.getMinecraft().thePlayer != null && minimumNext < System.currentTimeMillis()) { - if (checkPlayer == 1) { - checkPlayer = -1; - sendChat.add(new Tuple<>("/pl", () -> { - checkPlayer = 2; - })); - } - if (!sendChat.isEmpty()) { - Tuple<String, Runnable> tuple = sendChat.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 - public void onHypixelJoin(HypixelJoinedEvent skyblockJoinedEvent) { - minimumNext = System.currentTimeMillis() + 1000; - sendChat.add(new Tuple<>("/pl", () -> {partyJoin = 1;})); - } - - public void requestPartyRetrieval() { - sendChat.add(new Tuple<>("/pl", () -> {partyJoin = 1;})); - } - - private int checkPlayer = 0; - private JSONObject theObject; - private long minimumNext = 0; - - public static Queue<Tuple<String, Runnable>> sendChat = new ConcurrentLinkedQueue<>(); - - @Override - public void handle(StompInterface stompInterface, StompPayload stompPayload) { - JSONObject object = new JSONObject(stompPayload.payload()); - if ("/user/queue/party.check".equals(stompPayload.headers().get("destination"))) { - checkPlayer = 1; - theObject = object; - } 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) && partyID != null) { - sendChat .add(new Tuple<>("/p invite "+playerName, null)); - } - } 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 { - String str = object.getString("status"); - if ("success".equals(str)) { - setPartyID(object.getString("partyId")); - } else { - 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.join").build()); - stompConnectedEvent.getStompInterface().subscribe(StompSubscription.builder() - .stompMessageHandler(this).ackMode(StompSubscription.AckMode.AUTO).destination("/user/queue/party.broadcast").build()); - } -} diff --git a/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java b/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java index 598b3e49..5ff9852b 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/rpc/RichPresenceManager.java @@ -23,6 +23,8 @@ import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; import kr.syeyoung.dungeonsguide.DungeonsGuide; import kr.syeyoung.dungeonsguide.SkyblockStatus; +import kr.syeyoung.dungeonsguide.chat.PartyContext; +import kr.syeyoung.dungeonsguide.chat.PartyManager; import kr.syeyoung.dungeonsguide.dungeon.DungeonContext; import kr.syeyoung.dungeonsguide.events.DiscordUserJoinRequestEvent; import kr.syeyoung.dungeonsguide.events.DiscordUserUpdateEvent; @@ -33,15 +35,13 @@ import kr.syeyoung.dungeonsguide.gamesdk.jna.datastruct.*; import kr.syeyoung.dungeonsguide.gamesdk.jna.enumuration.*; import kr.syeyoung.dungeonsguide.gamesdk.jna.interfacestruct.*; import kr.syeyoung.dungeonsguide.gamesdk.jna.typedef.*; -import kr.syeyoung.dungeonsguide.party.PartyManager; -import kr.syeyoung.dungeonsguide.stomp.StompHeader; -import kr.syeyoung.dungeonsguide.stomp.StompPayload; import lombok.Getter; import net.minecraftforge.common.MinecraftForge; -import org.json.JSONObject; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import java.util.Set; public class RichPresenceManager implements Runnable { public static RichPresenceManager INSTANCE = new RichPresenceManager(); @@ -90,9 +90,7 @@ public class RichPresenceManager implements Runnable { System.out.println("Received Join Request from "+user.id.longValue()+" ("+GameSDK.readString(user.username)+")"); }; callbacks.OnActivityJoin = (eventData, secret) -> { - DungeonsGuide.getDungeonsGuide().getStompConnection().send(new StompPayload().method(StompHeader.SEND) - .header("destination", "/app/party.askedtojoin") - .payload(new JSONObject().put("token", secret).toString())); + PartyManager.INSTANCE.joinWithToken(secret); System.out.println("Trying to join with token "+secret); }; callbacks.OnActivityJoinRequest = (eventData, user) -> { @@ -195,8 +193,8 @@ public class RichPresenceManager implements Runnable { GameSDK.writeString(latestDiscordActivity.assets.large_text, "mort"); GameSDK.writeString(latestDiscordActivity.state, name); - GameSDK.writeString(latestDiscordActivity.party.id, PartyManager.INSTANCE.getPartyID() == null ? "" : PartyManager.INSTANCE.getPartyID()); - latestDiscordActivity.party.discordActivityParty.current_size = new Int32(PartyManager.INSTANCE.getMemberCount()); + GameSDK.writeString(latestDiscordActivity.party.id, Optional.ofNullable( PartyManager.INSTANCE.getPartyContext()).map(PartyContext::getPartyID).orElse("")); + latestDiscordActivity.party.discordActivityParty.current_size = new Int32(Optional.ofNullable(PartyManager.INSTANCE.getPartyContext()).map(PartyContext::getPartyRawMembers).map(Set::size).orElse(1)); latestDiscordActivity.party.discordActivityParty.max_size = new Int32(PartyManager.INSTANCE.getMaxParty()); if (skyblockStatus.getContext() != null) { @@ -213,7 +211,7 @@ public class RichPresenceManager implements Runnable { latestDiscordActivity.timestamps.start = new DiscordTimestamp(0); GameSDK.writeString(latestDiscordActivity.details, "Dungeons Guide"); } - if (PartyManager.INSTANCE.isAllowAskToJoin()) { + if (PartyManager.INSTANCE.getAskToJoinSecret() != null) { GameSDK.writeString(latestDiscordActivity.secrets.join, PartyManager.INSTANCE.getAskToJoinSecret()); } else { GameSDK.writeString(latestDiscordActivity.secrets.join, ""); diff --git a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java index 6bb45a84..27b1cdc9 100644 --- a/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java +++ b/src/main/java/kr/syeyoung/dungeonsguide/stomp/StompPayload.java @@ -53,10 +53,13 @@ public class StompPayload { if (payload != null) sb.append(payload); sb.append((char) 0); + if (FeatureRegistry.DEBUG.isEnabled()) System.out.println("Sending.. "+sb.toString()); return sb.toString(); } public static StompPayload parse(String payload) { + if (FeatureRegistry.DEBUG.isEnabled()) System.out.println("Receving.. "+payload); + Scanner scanner = new Scanner(payload); StompPayload stompPayload = new StompPayload(); stompPayload.method = StompHeader.valueOf(scanner.nextLine()); |