/* * 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 . */ package kr.syeyoung.dungeonsguide.party; import kr.syeyoung.dungeonsguide.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.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.json.JSONArray; import org.json.JSONObject; import java.security.SecureRandom; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.SynchronousQueue; 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>> runOnMembersReceived = new LinkedList<>(); @Getter @Setter private int maxParty = 5; 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) { generateNewAskToJoinSecret(); } else { RichPresenceManager.INSTANCE.updatePresence(); } } 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")); RichPresenceManager.INSTANCE.updatePresence(); } private int partyJoin =0; private final Set members = new HashSet<>(); private final Map recentlyJoined = new HashMap<>(); @SubscribeEvent(priority = EventPriority.HIGHEST) public void onMessage(ClientChatReceivedEvent chatReceivedEvent) { if (chatReceivedEvent.type == 2) return; String str = chatReceivedEvent.message.getFormattedText(); 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")) { System.out.println(checkPlayer + " - "+partyJoin + " - "+invitedDash); if ((checkPlayer > 0 || partyJoin > 0) && partyJoin != 100) { chatReceivedEvent.setCanceled(true); } if (partyJoin == 2 || partyJoin == 100) { partyJoin = 0; // REQ PARTY JOIN Consumer> 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 = ""; RichPresenceManager.INSTANCE.updatePresence(); } 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 = ""; RichPresenceManager.INSTANCE.updatePresence(); 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 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> 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()); } }