aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java136
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/README.md5
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorFriendList.java62
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorGuildPartyList.java55
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorJoinLeave.java79
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorPartyMessages.java192
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorProbablyUniversal.java76
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/IChatDetector.java29
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerChatByMe.java106
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerCoop.java119
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerMessage.java106
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerPV.java119
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerSocialOptions.java117
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerViewProfile.java130
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/ReplacementContext.java31
-rw-r--r--mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/SurgicalReplacer.java190
16 files changed, 843 insertions, 709 deletions
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java
index 6482e5d5..707a4a20 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java
@@ -19,7 +19,9 @@
package kr.syeyoung.dungeonsguide.mod.cosmetics;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.chatreplacers.*;
+import kr.syeyoung.dungeonsguide.mod.cosmetics.chatdetectors.*;
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.SurgicalReplacer;
import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerListItemPacketEvent;
import kr.syeyoung.dungeonsguide.mod.events.impl.StompConnectedEvent;
import kr.syeyoung.dungeonsguide.mod.stomp.StompHeader;
@@ -32,6 +34,8 @@ import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.play.server.S38PacketPlayerListItem;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
import net.minecraftforge.client.event.ClientChatReceivedEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
@@ -224,26 +228,134 @@ public class CosmeticsManager {
requestPerms();
}
@Getter @Setter
- private static List<IChatReplacer> iChatReplacers = new ArrayList<>();
+ private static List<IChatDetector> iChatDetectors = new ArrayList<>();
static {
- iChatReplacers.add(new ChatReplacerViewProfile());
- iChatReplacers.add(new ChatReplacerPV());
- iChatReplacers.add(new ChatReplacerSocialOptions());
- iChatReplacers.add(new ChatReplacerCoop());
- iChatReplacers.add(new ChatReplacerMessage());
- iChatReplacers.add(new ChatReplacerChatByMe());
+ iChatDetectors.add(new ChatDetectorProbablyUniversal());
+ iChatDetectors.add(new ChatDetectorFriendList());
+ iChatDetectors.add(new ChatDetectorGuildPartyList());
+ iChatDetectors.add(new ChatDetectorPartyMessages());
+ iChatDetectors.add(new ChatDetectorJoinLeave());
}
- @SubscribeEvent(priority = EventPriority.LOWEST)
+ private final ThreadLocal<List<ReplacementContext>> contextThreadLocal = new ThreadLocal<>();
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
+ public void onChatDetect(ClientChatReceivedEvent clientChatReceivedEvent) {
+ try {
+ if (clientChatReceivedEvent.type == 2) return;
+ List<ReplacementContext> total = new ArrayList<>();
+ for (IChatDetector iChatReplacer : iChatDetectors) {
+ List<ReplacementContext> replacementContext = iChatReplacer.getReplacementContext(clientChatReceivedEvent.message);
+ if (replacementContext != null) {
+ total.addAll(replacementContext);
+ }
+ }
+ contextThreadLocal.set(total);
+ } catch (Throwable t) {
+ System.out.println(clientChatReceivedEvent.message);
+ t.printStackTrace();
+ }
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOWEST, receiveCanceled = true)
public void onChat(ClientChatReceivedEvent clientChatReceivedEvent) {
try {
if (clientChatReceivedEvent.type == 2) return;
- for (IChatReplacer iChatReplacer : iChatReplacers) {
- if (iChatReplacer.isAcceptable(clientChatReceivedEvent)) {
- iChatReplacer.translate(clientChatReceivedEvent, this);
+ if (clientChatReceivedEvent.isCanceled()) {
+ contextThreadLocal.set(null);
+ return;
+ }
+
+ List<ReplacementContext> replacementContexts = contextThreadLocal.get();
+ contextThreadLocal.set(null);
+
+ LinkedList<IChatComponent> chatComponents = SurgicalReplacer.linearifyMoveColorCharToStyle(clientChatReceivedEvent.message);
+ for (ReplacementContext replacementContext : replacementContexts) {
+ if (replacementContext.getUsername().isEmpty()) continue;
+ List<ActiveCosmetic> activeCosmetics = getActiveCosmeticByPlayerNameLowerCase()
+ .get(replacementContext.getUsername().toLowerCase());
+ String color=null, prefix="[coolprefix]";
+ if (activeCosmetics != null) {
+ for (ActiveCosmetic activeCosmetic : activeCosmetics) {
+ CosmeticData cosmeticData = getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
+ if (cosmeticData != null && cosmeticData.getCosmeticType().equals("color")) {
+ color = cosmeticData.getData().replace("&", "§");
+ } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
+ prefix = cosmeticData.getData().replace("&", "§");
+ }
+ }
+ }
+
+ if (color == null && prefix == null) continue;
+
+
+ StringBuilder sb = new StringBuilder();
+ for (IChatComponent chatComponent : chatComponents) {
+ String str = chatComponent.getUnformattedText();
+ sb.append(str);
+ }
+
+ List<Integer> allIdxes = new ArrayList<>();
+ int lastIdx = -1;
+ String theThing = sb.toString();
+ do {
+ lastIdx = theThing.indexOf(replacementContext.getUsername(), lastIdx+1);
+ if (lastIdx != -1)
+ allIdxes.add(lastIdx);
+ } while (lastIdx != -1);
+
+ int idx = allIdxes.stream()
+ .min(Comparator.comparingInt(a -> Math.abs(a - replacementContext.getNearIdx()))).orElse(-1);
+
+ System.out.println("Was expecting to find " +replacementContext.getUsername());
+ if (idx == -1) {
+ System.out.println("WTF?");
+
+ List<IChatComponent> components = SurgicalReplacer.inject(chatComponents,
+ SurgicalReplacer.linearifyMoveColorCharToStyle(
+ new ChatComponentText(prefix+" ")
+ .setChatStyle(SurgicalReplacer.getChatStyleAt(chatComponents, 0))
+ ),
+ 0, 0);
+ clientChatReceivedEvent.message = SurgicalReplacer.combine(components);
+ // since we couldn't find username anywhere, just do this.
return;
}
+
+ int stIdx = theThing.lastIndexOf('\n', idx) + 1;
+ String beforeUsername = theThing.substring(theThing.lastIndexOf('\n', idx) + 1, idx);
+ int startingSearch = beforeUsername.length();
+ while (true) {
+ startingSearch = beforeUsername.lastIndexOf(' ', startingSearch-1);
+ if (startingSearch == -1) break;
+ if (startingSearch-1 >= 0) {
+ char c = beforeUsername.charAt(startingSearch-1);
+ if (c == ' ') continue;
+ if (c == ']') continue;
+ startingSearch ++;
+ break;
+ }
+ }
+
+ if (startingSearch == -1) startingSearch = 0;
+ startingSearch += stIdx;
+
+ if (color != null)
+ chatComponents = SurgicalReplacer.inject(chatComponents,
+ SurgicalReplacer.linearifyMoveColorCharToStyle(
+ new ChatComponentText(color+replacementContext.getUsername())
+ .setChatStyle(SurgicalReplacer.getChatStyleAt(chatComponents, idx))
+ ),
+ idx, replacementContext.getUsername().length());
+
+ if (prefix != null)
+ chatComponents = SurgicalReplacer.inject(chatComponents,
+ SurgicalReplacer.linearifyMoveColorCharToStyle(
+ new ChatComponentText(prefix+" ")
+ .setChatStyle(SurgicalReplacer.getChatStyleAt(chatComponents, 0))
+ ),
+ startingSearch, 0);
}
+ clientChatReceivedEvent.message = SurgicalReplacer.combine(chatComponents);
} catch (Throwable t) {
System.out.println(clientChatReceivedEvent.message);
t.printStackTrace();
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/README.md b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/README.md
new file mode 100644
index 00000000..98d13246
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/README.md
@@ -0,0 +1,5 @@
+2 Phase Cosmetic Injection
+1. Gather data
+ - and instruct the thing to replace what near what pos
+2. Actually replace
+ - aghhhhhh
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorFriendList.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorFriendList.java
new file mode 100644
index 00000000..62eb16a7
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorFriendList.java
@@ -0,0 +1,62 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.chatdetectors;
+
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.util.IChatComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ChatDetectorFriendList implements IChatDetector {
+ @Override
+ public List<ReplacementContext> getReplacementContext(IChatComponent chatComponent) {
+ boolean friend = false;
+ int idx = 0;
+ for (IChatComponent iChatComponent : chatComponent) {
+ idx++;
+ if (iChatComponent.getUnformattedText().startsWith(" §6Friends ")) {
+ friend = true;
+ }
+ if (idx > 5 && !friend) return null;
+ }
+
+ if (!friend) return null;
+
+ String formatted = chatComponent.getFormattedText();
+ String strip = TextUtils.stripColor(formatted);
+ int len = 0;
+ List<ReplacementContext> replacementContexts = new ArrayList<>();
+ for (String s : strip.split("\n")) {
+ if (s.charAt(0) == '-' || s.charAt(0) == ' ') {
+ len += s.length()+1;
+ continue;
+ }
+ String username = s.split(" ")[0];
+ System.out.println(username);
+ replacementContexts.add(new ReplacementContext(
+ len, username, null
+ ));
+ len += s.length()+1;
+ }
+
+ return replacementContexts;
+ }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorGuildPartyList.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorGuildPartyList.java
new file mode 100644
index 00000000..7df0b62f
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorGuildPartyList.java
@@ -0,0 +1,55 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.chatdetectors;
+
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.util.IChatComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ChatDetectorGuildPartyList implements IChatDetector {
+ @Override
+ public List<ReplacementContext> getReplacementContext(IChatComponent chatComponent) {
+ String formatted = chatComponent.getFormattedText();
+ if (!(formatted.contains("§c ● ") || formatted.contains("§a ● ") ||
+ formatted.contains("§c●") || formatted.contains("§a●"))) {
+ return null;
+ }
+//
+ String strip = TextUtils.stripColor(formatted);
+// String last = strip.split(": ");
+
+ List<String> players = new ArrayList<>();
+ for (String s : strip.split(" ")) {
+ if (s.contains("●")) continue;
+ if (s.startsWith("[")) continue;
+ if (s.endsWith(":")) continue;
+
+ if (!(formatted.contains(s+"§r") || formatted.contains(s+" §r") )) continue;
+ players.add(s);
+ }
+
+ return players.stream().map(a -> new ReplacementContext(
+ strip.indexOf(a), a, null
+ )).collect(Collectors.toList());
+ }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorJoinLeave.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorJoinLeave.java
new file mode 100644
index 00000000..9de4be0a
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorJoinLeave.java
@@ -0,0 +1,79 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.chatdetectors;
+
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.util.IChatComponent;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ChatDetectorJoinLeave implements IChatDetector {
+ @Override
+ public List<ReplacementContext> getReplacementContext(IChatComponent chatComponent) {
+ String formatted = chatComponent.getFormattedText();
+ if (formatted.startsWith("§aFriend > §r")) {
+ if (formatted.endsWith("§r§eleft.§r") || formatted.endsWith("§r§ejoined.§r")) {
+ String strip = TextUtils.stripColor(formatted);
+ String username = strip.substring(9, strip.indexOf(' ', 9));
+ return Collections.singletonList(new ReplacementContext(
+ 9, username, null
+ ));
+ }
+ } else if (formatted.endsWith("§6joined the lobby!§r")) {
+ String[] messageSplit = TextUtils.stripColor(formatted).split(" ");
+ String oldLeader = null;
+ for (String s : messageSplit) {
+ if (s.startsWith("[")) continue;
+ oldLeader = s;
+ break;
+ }
+ if (oldLeader != null)
+ return Collections.singletonList(new ReplacementContext(
+ TextUtils.stripColor(formatted).indexOf(oldLeader), oldLeader, null
+ ));
+ } else if (formatted.endsWith("§6joined the lobby!§r §a<§c<§b<§r")) {
+ String[] messageSplit = TextUtils.stripColor(formatted.substring(15)).split(" ");
+ String oldLeader = null;
+ for (String s : messageSplit) {
+ if (s.startsWith("[")) continue;
+ oldLeader = s;
+ break;
+ }
+ if (oldLeader != null)
+ return Collections.singletonList(new ReplacementContext(
+ TextUtils.stripColor(formatted).indexOf(oldLeader), oldLeader, null
+ ));
+ } else if (formatted.startsWith("§b✦ ") && formatted.contains("§r§7found a ") && formatted.endsWith("§r§bMystery Box§r§7!§r")) {
+ String[] messageSplit = TextUtils.stripColor(formatted.substring(4)).split(" ");
+ String oldLeader = null;
+ for (String s : messageSplit) {
+ if (s.startsWith("[")) continue;
+ oldLeader = s;
+ break;
+ }
+ if (oldLeader != null)
+ return Collections.singletonList(new ReplacementContext(
+ TextUtils.stripColor(formatted).indexOf(oldLeader), oldLeader, null
+ ));
+ }
+ return null;
+ }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorPartyMessages.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorPartyMessages.java
new file mode 100644
index 00000000..6637b7a9
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorPartyMessages.java
@@ -0,0 +1,192 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.chatdetectors;
+
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import kr.syeyoung.dungeonsguide.mod.party.PartyManager;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.util.IChatComponent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ChatDetectorPartyMessages implements IChatDetector {
+ @Override
+ public List<ReplacementContext> getReplacementContext(IChatComponent chatComponent) {
+ String str = chatComponent.getFormattedText();
+ String strip = TextUtils.stripColor(str);
+
+ List<ReplacementContext> detectors = new ArrayList<>();
+ if (str.endsWith("§aenabled All Invite§r") || str.endsWith("§cdisabled All Invite§r") || str.endsWith("§ejoined the party.§r") || 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)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(username), username, null
+ ));
+ } else if (str.endsWith(" They have §r§c60 §r§eseconds to accept.§r")) {
+ String username = null;
+ for (String s : TextUtils.stripColor(str).split(" ")) {
+ if (s.startsWith("[")) continue;
+ username = s;
+ break;
+ }
+ if (username != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(username), username, null
+ ));
+ username = null;
+ for (String s : TextUtils.stripColor(str.substring(str.indexOf("§r§einvited ")+12)).split(" ")) {
+ if (s.startsWith("[")) continue;
+ username = s;
+ break;
+ }
+ if (username != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(username), username, null
+ ));
+ } else if (str.startsWith("§eThe party was transferred to ")) {
+ String[] messageSplit = TextUtils.stripColor(str.substring(31)).split(" ");
+ String newLeader = null;
+ for (String s : messageSplit) {
+ if (s.startsWith("[")) continue;
+ newLeader = s;
+ break;
+ }
+ String oldLeader;
+ if (str.endsWith("§r§eleft§r")) {
+ oldLeader = messageSplit[messageSplit.length - 2];
+ } else {
+ oldLeader = messageSplit[messageSplit.length - 1];
+ }
+
+ if (oldLeader != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(oldLeader), oldLeader, null
+ ));
+ if (newLeader != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(newLeader), newLeader, null
+ ));
+ } else if (str.endsWith("§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)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(oldLeader), oldLeader, null
+ ));
+ if (newLeader != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(newLeader), newLeader, null
+ ));
+ } else if (str.endsWith("§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)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(oldLeader), oldLeader, null
+ ));
+ if (newModerator != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(newModerator), newModerator, null
+ ));
+
+ } 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)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(oldLeader), oldLeader, null
+ ));
+ if (newMember != null)
+ detectors.add(new ReplacementContext(
+ strip.indexOf(newMember), newMember, null
+ ));
+
+ } else if (str.startsWith("§eYou have joined ")) {
+ String[] messageSplit = strip.split(" ");
+ String leader = null;
+ for (String s : messageSplit) {
+ if (s.startsWith("[")) continue;
+ leader = s;
+ break;
+ }
+ if (leader == null) return null;
+ String username = leader.substring(0, leader.length()-2);
+ detectors.add(new ReplacementContext(
+ strip.indexOf(username), username, null
+ ));
+ } else if (str.startsWith("§eYou'll be partying with: ")) {
+ String[] players = strip.split(" ");
+ for (String player : players) {
+ if (player.startsWith("[")) continue;
+ // player
+ detectors.add(new ReplacementContext(
+ strip.indexOf(player), player, null
+ ));
+ }
+ } else if (str.contains("§r§ejoined the dungeon group! (§r§b")) {
+ String username = TextUtils.stripColor(str).split(" ")[3];
+ detectors.add(new ReplacementContext(
+ strip.indexOf(username), username, null
+ ));
+ }
+ return detectors;
+ }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorProbablyUniversal.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorProbablyUniversal.java
new file mode 100644
index 00000000..fc3188be
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/ChatDetectorProbablyUniversal.java
@@ -0,0 +1,76 @@
+/*
+ * 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.mod.cosmetics.chatdetectors;
+
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.IChatComponent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ChatDetectorProbablyUniversal implements IChatDetector {
+ @Override
+ public List<ReplacementContext> getReplacementContext(IChatComponent chatComponent) {
+ String formatted = chatComponent.getFormattedText();
+ if (!formatted.contains(": ")) return null;
+
+
+ boolean correspondingEvFound = false;
+ for (IChatComponent iChatComponent : chatComponent) {
+ ClickEvent ev = iChatComponent.getChatStyle().getChatClickEvent();
+ if (ev != null) {
+ if (ev.getValue().startsWith("/msg")) correspondingEvFound = true;
+ if (ev.getValue().startsWith("/socialoptions")) correspondingEvFound = true;
+ if (ev.getValue().startsWith("/viewprofile")) correspondingEvFound = true;
+ }
+ }
+
+ formatted = formatted.substring(0, formatted.indexOf(": "));
+ String name = TextUtils.stripColor(formatted);
+
+ String[] splited = name.split(" ");
+ int backLen = 0;
+ label: for (int i = splited.length - 1; i >= 0; i--) {
+ String potentialName = splited[i];
+ backLen += potentialName.length() + 1;
+ for (char c : potentialName.toCharArray()) {
+ if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '_' || c == '-')) {
+ continue;
+ }
+ continue label;
+ }
+ if (potentialName.equalsIgnoreCase(Minecraft.getMinecraft().thePlayer.getName()))
+ return Collections.singletonList(new ReplacementContext(
+ name.length() - backLen, potentialName, null
+ ));
+ else if (correspondingEvFound)
+ return Collections.singletonList(new ReplacementContext(
+ name.length() - backLen, potentialName, null
+ ));
+ else return null;
+ }
+ return null;
+ }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/IChatDetector.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/IChatDetector.java
new file mode 100644
index 00000000..2b1d47b5
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatdetectors/IChatDetector.java
@@ -0,0 +1,29 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.chatdetectors;
+
+import kr.syeyoung.dungeonsguide.mod.cosmetics.surgical.ReplacementContext;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.client.event.ClientChatReceivedEvent;
+
+import java.util.List;
+
+public interface IChatDetector {
+ List<ReplacementContext> getReplacementContext(IChatComponent chatComponent);
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerChatByMe.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerChatByMe.java
deleted file mode 100644
index 4e50b110..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerChatByMe.java
+++ /dev/null
@@ -1,106 +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.mod.cosmetics.chatreplacers;
-
-import kr.syeyoung.dungeonsguide.mod.cosmetics.ActiveCosmetic;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticData;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.IChatReplacer;
-import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.ChatStyle;
-import net.minecraft.util.IChatComponent;
-import net.minecraft.util.Tuple;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ChatReplacerChatByMe implements IChatReplacer {
- @Override
- public boolean isAcceptable(ClientChatReceivedEvent event) {
- for (IChatComponent sibling : event.message.getSiblings()) {
- if (sibling.getUnformattedTextForChat().startsWith(": ")) return true;
- }
- return false;
- }
-
- @Override
- public void translate(ClientChatReceivedEvent event, CosmeticsManager cosmeticsManager) {
- List<Tuple<IChatComponent, IChatComponent>> replaceMents = new ArrayList<>();
- List<IChatComponent> iChatComponents = new ArrayList<>( event.message.getSiblings() );
- List<IChatComponent> hasMsg = new ArrayList<>();
- for (IChatComponent sibling : iChatComponents) {
- if (sibling.getUnformattedTextForChat().startsWith(": ")) break;
- hasMsg.add(sibling);
- }
- iChatComponents.removeAll(hasMsg);
-
- ChatComponentText chatComponents = new ChatComponentText("");
- chatComponents.getSiblings().addAll(hasMsg);
- ChatStyle origStyle = hasMsg.get(0).getChatStyle();
- String name = chatComponents.getFormattedText();
-
- String[] splited = name.split(" ");
- String actualName = splited[splited.length-1];
-
- List<ActiveCosmetic> cDatas = cosmeticsManager.getActiveCosmeticByPlayerNameLowerCase().get(TextUtils.stripColor(actualName).toLowerCase());
- if (cDatas == null) return;
- CosmeticData color=null, prefix=null;
- for (ActiveCosmetic activeCosmetic : cDatas) {
- CosmeticData cosmeticData = cosmeticsManager.getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
- if (cosmeticData !=null && cosmeticData.getCosmeticType().equals("color")) {
- color = cosmeticData;
- } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
- prefix = cosmeticData;
- }
- }
-
- String building = "";
- if (prefix != null) building += prefix.getData().replace("&", "§") + " ";
- for (int i = 0; i < splited.length-1; i++) {
- building += splited[i] +" ";
- }
-
- if (color != null) {
- String nick = splited[splited.length-1];
- building += color.getData().replace("&","§");
- boolean foundLegitChar = false;
- boolean foundColor = false;
- for (char c : nick.toCharArray()) {
- if (foundColor) {
- foundColor = false; continue;
- }
- if (c == '§' && !foundLegitChar) foundColor = true;
- else {
- foundLegitChar = true;
- building += c;
- }
- }
- } else {
- building += splited[splited.length-1] ;
- }
-
- ChatComponentText chatComponents1 = new ChatComponentText(building);
- chatComponents1.setChatStyle(origStyle);
- event.message.getSiblings().clear();
- event.message.getSiblings().add(chatComponents1);
- event.message.getSiblings().addAll(iChatComponents);
- }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerCoop.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerCoop.java
deleted file mode 100644
index df003ec7..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerCoop.java
+++ /dev/null
@@ -1,119 +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.mod.cosmetics.chatreplacers;
-
-import kr.syeyoung.dungeonsguide.mod.cosmetics.ActiveCosmetic;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticData;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.IChatReplacer;
-import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.IChatComponent;
-import net.minecraft.util.Tuple;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ChatReplacerCoop implements IChatReplacer {
- @Override
- public boolean isAcceptable(ClientChatReceivedEvent event) {
- for (IChatComponent sibling : event.message.getSiblings()) {
- if (sibling.getUnformattedTextForChat().startsWith("§bCo-op > ")) return true;
- }
- return false;
- }
-
- @Override
- public void translate(ClientChatReceivedEvent event, CosmeticsManager cosmeticsManager) {
- List<Tuple<IChatComponent, IChatComponent>> replaceMents = new ArrayList<>();
- List<IChatComponent> iChatComponents = new ArrayList<>( event.message.getSiblings() );
- IChatComponent sibling = iChatComponents.get(0); iChatComponents.remove(sibling);
-
-
- String[] splitInto = sibling.getUnformattedTextForChat().split(" ");
- int lastValidNickname = -1;
- int lastprefix = -1;
- for (int i = 0; i < splitInto.length; i++) {
- String s = TextUtils.stripColor(splitInto[i]);
- char c = s.charAt(0);
- if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-') {
- lastValidNickname = i;
- }
- }
- if (lastValidNickname == -1) return;
-
- if (lastValidNickname -1 >= 0 && TextUtils.stripColor(splitInto[lastValidNickname - 1]).charAt(0) == '[') lastprefix = lastValidNickname -1;
- else lastprefix = lastValidNickname;
-
-
- List<ActiveCosmetic> cDatas = cosmeticsManager.getActiveCosmeticByPlayerNameLowerCase().get(TextUtils.stripColor(splitInto[lastValidNickname].substring(0, splitInto[lastValidNickname].length()-1)).toLowerCase());
-
- if (cDatas == null) return;
-
- CosmeticData color = null, prefix = null;
- for (ActiveCosmetic activeCosmetic : cDatas) {
- CosmeticData cosmeticData = cosmeticsManager.getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
- if (cosmeticData != null && cosmeticData.getCosmeticType().equals("color")) {
- color = cosmeticData;
- } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
- prefix = cosmeticData;
- }
- }
-
- String building = "";
- for (int i = 0; i < lastprefix; i++) {
- building += splitInto[i] +" ";
- }
- if (prefix != null) building += prefix.getData().replace("&", "§") + " ";
- for (int i = lastprefix; i < lastValidNickname; i++) {
- building += splitInto[i] +" ";
- }
- if (color != null) {
- String nick = splitInto[lastValidNickname];
- building += color.getData().replace("&","§");
- boolean foundLegitChar = false;
- boolean foundColor = false;
- for (char c : nick.toCharArray()) {
- if (foundColor) {
- foundColor = false; continue;
- }
- if (c == '§' && !foundLegitChar) foundColor = true;
- else {
- foundLegitChar = true;
- building += c;
- }
- }
- building += " ";
- } else {
- building += splitInto[lastValidNickname] + " ";
- }
- for (int i = lastValidNickname+1; i<splitInto.length; i++) {
- building += splitInto[i] + " ";
- }
- if (sibling.getUnformattedTextForChat().charAt(sibling.getUnformattedText().length()-1) != ' ')
- building = building.substring(0, building.length() - 1);
-
- ChatComponentText chatComponents1 = new ChatComponentText(building);
- chatComponents1.setChatStyle(sibling.getChatStyle());
- event.message.getSiblings().clear();
- event.message.getSiblings().add(chatComponents1);
- event.message.getSiblings().addAll(iChatComponents);
- }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerMessage.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerMessage.java
deleted file mode 100644
index e819ca7f..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerMessage.java
+++ /dev/null
@@ -1,106 +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.mod.cosmetics.chatreplacers;
-
-import kr.syeyoung.dungeonsguide.mod.cosmetics.ActiveCosmetic;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticData;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.IChatReplacer;
-import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.ChatStyle;
-import net.minecraft.util.IChatComponent;
-import net.minecraft.util.Tuple;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ChatReplacerMessage implements IChatReplacer {
- @Override
- public boolean isAcceptable(ClientChatReceivedEvent event) {
- for (IChatComponent sibling : event.message.getSiblings()) {
- if (sibling.getChatStyle() != null && sibling.getChatStyle().getChatClickEvent() != null && sibling.getChatStyle().getChatClickEvent().getValue().startsWith("/msg")) return true;
- }
- return false;
- }
-
- @Override
- public void translate(ClientChatReceivedEvent event, CosmeticsManager cosmeticsManager) {
- List<Tuple<IChatComponent, IChatComponent>> replaceMents = new ArrayList<>();
- List<IChatComponent> iChatComponents = new ArrayList<>( event.message.getSiblings() );
- List<IChatComponent> hasMsg = new ArrayList<>();
- for (IChatComponent sibling : iChatComponents) {
- if (sibling.getChatStyle() != null && sibling.getChatStyle().getChatClickEvent() != null && sibling.getChatStyle().getChatClickEvent().getValue().startsWith("/msg")) {
- hasMsg.add(sibling);
- }
- }
- iChatComponents.removeAll(hasMsg);
-
- ChatComponentText chatComponents = new ChatComponentText("");
- chatComponents.getSiblings().addAll(hasMsg);
- ChatStyle origStyle = hasMsg.get(0).getChatStyle();
- String name = chatComponents.getFormattedText();
-
-
- String[] splited = name.split(" ");
- String actualName = splited[splited.length-1];
-
- List<ActiveCosmetic> cDatas = cosmeticsManager.getActiveCosmeticByPlayerNameLowerCase().get(TextUtils.stripColor(actualName).toLowerCase());
- if (cDatas == null || splited.length > 2) return;
- CosmeticData color=null, prefix=null;
- for (ActiveCosmetic activeCosmetic : cDatas) {
- CosmeticData cosmeticData = cosmeticsManager.getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
- if (cosmeticData !=null && cosmeticData.getCosmeticType().equals("color")) {
- color = cosmeticData;
- } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
- prefix = cosmeticData;
- }
- }
-
- String building = "";
- if (prefix != null) building += prefix.getData().replace("&", "§") + " ";
- if (splited.length == 2) building += splited[0] +" ";
-
- if (color != null) {
- String nick = splited[1];
- building += color.getData().replace("&","§");
- boolean foundLegitChar = false;
- boolean foundColor = false;
- for (char c : nick.toCharArray()) {
- if (foundColor) {
- foundColor = false; continue;
- }
- if (c == '§' && !foundLegitChar) foundColor = true;
- else {
- foundLegitChar = true;
- building += c;
- }
- }
- } else {
- building += splited[1] ;
- }
-
- ChatComponentText chatComponents1 = new ChatComponentText(building);
- chatComponents1.setChatStyle(origStyle);
- event.message.getSiblings().clear();
- event.message.getSiblings().add(chatComponents1);
- event.message.getSiblings().addAll(iChatComponents);
- }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerPV.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerPV.java
deleted file mode 100644
index b4e1b777..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerPV.java
+++ /dev/null
@@ -1,119 +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.mod.cosmetics.chatreplacers;
-
-import kr.syeyoung.dungeonsguide.mod.cosmetics.ActiveCosmetic;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticData;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.IChatReplacer;
-import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.util.ChatComponentText;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-
-import java.util.List;
-
-
-// Bug 289 - mod conflict with NEU (Replaces /socialoptions with /pv)
-public class ChatReplacerPV implements IChatReplacer {
- @Override
- public boolean isAcceptable(ClientChatReceivedEvent event) {
- if (event.message.getChatStyle() != null && event.message.getChatStyle().getChatClickEvent() != null && event.message.getChatStyle().getChatClickEvent().getValue().startsWith("/pv")) return true;
- return false;
- }
-
- @Override
- public void translate(ClientChatReceivedEvent event, CosmeticsManager cosmeticsManager) {
- if (event.message.getChatStyle() != null && event.message.getChatStyle().getChatClickEvent() != null && event.message.getChatStyle().getChatClickEvent().getValue().startsWith("/pv")) {
- String username = event.message.getChatStyle().getChatClickEvent().getValue().split(" ")[1];
- List<ActiveCosmetic> cDatas = cosmeticsManager.getActiveCosmeticByPlayerNameLowerCase().get(username.toLowerCase());
-
- if (cDatas != null) {
- CosmeticData color=null, prefix=null;
- for (ActiveCosmetic activeCosmetic : cDatas) {
- CosmeticData cosmeticData = cosmeticsManager.getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
- if (cosmeticData !=null && cosmeticData.getCosmeticType().equals("color")) {
- color = cosmeticData;
- } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
- prefix = cosmeticData;
- }
- }
-
- String[] splitInto = event.message.getUnformattedTextForChat().split(" ");
- int lastValidNickname = -1;
- int lastprefix = -1;
- for (int i = 0; i < splitInto.length; i++) {
- String s = splitInto[i];
- if (s.startsWith("§7")) s = s.substring(2);
- char c = s.charAt(0);
- if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-') {
- lastValidNickname = i;
- if (i >= 1) {
- String str = TextUtils.stripColor(splitInto[i-1]);
- if (str.startsWith("[") && str.endsWith("]"))break;
- }
- }
- }
- if (lastValidNickname == -1) return;
-
- if (lastValidNickname -1 >= 0 && TextUtils.stripColor(splitInto[lastValidNickname - 1]).charAt(0) == '[') lastprefix = lastValidNickname -1;
- else lastprefix = lastValidNickname;
-
- String building = "";
- for (int i = 0; i < lastprefix; i++) {
- building += splitInto[i] +" ";
- }
- if (prefix != null) building += prefix.getData().replace("&", "§") + " ";
- for (int i = lastprefix; i < lastValidNickname; i++) {
- building += splitInto[i] +" ";
- }
- if (color != null) {
- String nick = splitInto[lastValidNickname];
- building += color.getData().replace("&","§");
- boolean foundLegitChar = false;
- boolean foundColor = false;
- for (char c : nick.toCharArray()) {
- if (foundColor) {
- foundColor = false; continue;
- }
- if (c == '§' && !foundLegitChar) foundColor = true;
- else {
- foundLegitChar = true;
- building += c;
- }
- }
- building += " ";
- } else {
- building += splitInto[lastValidNickname] + " ";
- }
- for (int i = lastValidNickname+1; i<splitInto.length; i++) {
- building += splitInto[i] + " ";
- }
- if (event.message.getUnformattedTextForChat().charAt(event.message.getUnformattedTextForChat().length()-1) != ' ')
- building = building.substring(0, building.length() - 1);
-
- ChatComponentText newChatCompText = new ChatComponentText(building);
- newChatCompText.setChatStyle(event.message.getChatStyle());
- newChatCompText.getSiblings().addAll(event.message.getSiblings());
-
- event.message = newChatCompText;
- }
- }
-
- }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerSocialOptions.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerSocialOptions.java
deleted file mode 100644
index acbdf623..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerSocialOptions.java
+++ /dev/null
@@ -1,117 +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.mod.cosmetics.chatreplacers;
-
-import kr.syeyoung.dungeonsguide.mod.cosmetics.ActiveCosmetic;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticData;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.IChatReplacer;
-import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.util.ChatComponentText;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-
-import java.util.List;
-
-public class ChatReplacerSocialOptions implements IChatReplacer {
- @Override
- public boolean isAcceptable(ClientChatReceivedEvent event) {
- if (event.message.getChatStyle() != null && event.message.getChatStyle().getChatClickEvent() != null && event.message.getChatStyle().getChatClickEvent().getValue().startsWith("/socialoptions")) return true;
- return false;
- }
-
- @Override
- public void translate(ClientChatReceivedEvent event, CosmeticsManager cosmeticsManager) {
- if (event.message.getChatStyle() != null && event.message.getChatStyle().getChatClickEvent() != null && event.message.getChatStyle().getChatClickEvent().getValue().startsWith("/socialoptions")) {
- String username = event.message.getChatStyle().getChatClickEvent().getValue().split(" ")[1];
- List<ActiveCosmetic> cDatas = cosmeticsManager.getActiveCosmeticByPlayerNameLowerCase().get(username.toLowerCase());
-
- if (cDatas != null) {
- CosmeticData color=null, prefix=null;
- for (ActiveCosmetic activeCosmetic : cDatas) {
- CosmeticData cosmeticData = cosmeticsManager.getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
- if (cosmeticData !=null && cosmeticData.getCosmeticType().equals("color")) {
- color = cosmeticData;
- } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
- prefix = cosmeticData;
- }
- }
-
- String[] splitInto = event.message.getUnformattedTextForChat().split(" ");
- int lastValidNickname = -1;
- int lastprefix = -1;
- for (int i = 0; i < splitInto.length; i++) {
- String s = splitInto[i];
- if (s.startsWith("§7")) s = s.substring(2);
- char c = s.charAt(0);
- if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-') {
- lastValidNickname = i;
- if (i >= 1) {
- String str = TextUtils.stripColor(splitInto[i-1]);
- if (str.startsWith("[") && str.endsWith("]"))break;
- }
- }
- }
- if (lastValidNickname == -1) return;
-
- if (lastValidNickname -1 >= 0 && TextUtils.stripColor(splitInto[lastValidNickname - 1]).charAt(0) == '[') lastprefix = lastValidNickname -1;
- else lastprefix = lastValidNickname;
-
- String building = "";
- for (int i = 0; i < lastprefix; i++) {
- building += splitInto[i] +" ";
- }
- if (prefix != null) building += prefix.getData().replace("&", "§") + " ";
- for (int i = lastprefix; i < lastValidNickname; i++) {
- building += splitInto[i] +" ";
- }
- if (color != null) {
- String nick = splitInto[lastValidNickname];
- building += color.getData().replace("&","§");
- boolean foundLegitChar = false;
- boolean foundColor = false;
- for (char c : nick.toCharArray()) {
- if (foundColor) {
- foundColor = false; continue;
- }
- if (c == '§' && !foundLegitChar) foundColor = true;
- else {
- foundLegitChar = true;
- building += c;
- }
- }
- building += " ";
- } else {
- building += splitInto[lastValidNickname] + " ";
- }
- for (int i = lastValidNickname+1; i<splitInto.length; i++) {
- building += splitInto[i] + " ";
- }
- if (event.message.getUnformattedTextForChat().charAt(event.message.getUnformattedTextForChat().length()-1) != ' ')
- building = building.substring(0, building.length() - 1);
-
- ChatComponentText newChatCompText = new ChatComponentText(building);
- newChatCompText.setChatStyle(event.message.getChatStyle());
- newChatCompText.getSiblings().addAll(event.message.getSiblings());
-
- event.message = newChatCompText;
- }
- }
-
- }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerViewProfile.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerViewProfile.java
deleted file mode 100644
index 28d1d3d0..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/chatreplacers/ChatReplacerViewProfile.java
+++ /dev/null
@@ -1,130 +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.mod.cosmetics.chatreplacers;
-
-import kr.syeyoung.dungeonsguide.mod.cosmetics.ActiveCosmetic;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticData;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager;
-import kr.syeyoung.dungeonsguide.mod.cosmetics.IChatReplacer;
-import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.IChatComponent;
-import net.minecraft.util.Tuple;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ChatReplacerViewProfile implements IChatReplacer {
- @Override
- public boolean isAcceptable(ClientChatReceivedEvent event) {
- for (IChatComponent sibling : event.message.getSiblings()) {
- if (sibling.getChatStyle() != null && sibling.getChatStyle().getChatClickEvent() != null && sibling.getChatStyle().getChatClickEvent().getValue().startsWith("/viewprofile ")) return true;
- }
- return false;
- }
-
- @Override
- public void translate(ClientChatReceivedEvent event, CosmeticsManager cosmeticsManager) {
- List<Tuple<IChatComponent, IChatComponent>> replaceMents = new ArrayList<>();
- for (IChatComponent sibling : event.message.getSiblings()) {
- if (sibling.getChatStyle() != null && sibling.getChatStyle().getChatClickEvent() != null && sibling.getChatStyle().getChatClickEvent().getValue().startsWith("/viewprofile ")) {
- String uid = sibling.getChatStyle().getChatClickEvent().getValue().split(" ")[1];
- // TODO: make cosmeticsManager handle usernames instead of uuids
- // apperantly now hypixels /viewprofile command gives the nickname
-// List<ActiveCosmetic> cDatas = cosmeticsManager.getActiveCosmeticByPlayer().get(UUID.fromString(uid));
- List<ActiveCosmetic> cDatas = null;
-
- if (cDatas != null) {
- CosmeticData color=null, prefix=null;
- for (ActiveCosmetic activeCosmetic : cDatas) {
- CosmeticData cosmeticData = cosmeticsManager.getCosmeticDataMap().get(activeCosmetic.getCosmeticData());
- if (cosmeticData !=null && cosmeticData.getCosmeticType().equals("color")) {
- color = cosmeticData;
- } else if (cosmeticData != null && cosmeticData.getCosmeticType().equals("prefix")) {
- prefix = cosmeticData;
- }
- }
-
- String[] splitInto = sibling.getUnformattedTextForChat().split(" ");
- int lastValidNickname = -1;
- int lastprefix = -1;
- for (int i = 0; i < splitInto.length; i++) {
- String s = TextUtils.stripColor(splitInto[i]);
- char c = s.charAt(0);
- if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-') {
- lastValidNickname = i;
- if (i >= 1) {
- String str = TextUtils.stripColor(splitInto[i-1]);
- if (str.startsWith("[") && str.endsWith("]"))break;
- }
- }
- }
- if (lastValidNickname == -1) continue;
-
- if (lastValidNickname -1 >= 0 && TextUtils.stripColor(splitInto[lastValidNickname - 1]).charAt(0) == '[') lastprefix = lastValidNickname -1;
- else lastprefix = lastValidNickname;
-
- String building = "";
- for (int i = 0; i < lastprefix; i++) {
- building += splitInto[i] +" ";
- }
- if (prefix != null) building += prefix.getData().replace("&", "§") + " ";
- for (int i = lastprefix; i < lastValidNickname; i++) {
- building += splitInto[i] +" ";
- }
- if (color != null) {
- String nick = splitInto[lastValidNickname];
- building += color.getData().replace("&","§");
- boolean foundLegitChar = false;
- boolean foundColor = false;
- for (char c : nick.toCharArray()) {
- if (foundColor) {
- foundColor = false; continue;
- }
- if (c == '§' && !foundLegitChar) foundColor = true;
- else {
- foundLegitChar = true;
- building += c;
- }
- }
- building += " ";
- } else {
- building += splitInto[lastValidNickname] + " ";
- }
- for (int i = lastValidNickname+1; i<splitInto.length; i++) {
- building += splitInto[i] + " ";
- }
- if (sibling.getUnformattedTextForChat().charAt(sibling.getUnformattedText().length()-1) != ' ')
- building = building.substring(0, building.length() - 1);
-
- ChatComponentText newChatCompText = new ChatComponentText(building);
- newChatCompText.setChatStyle(sibling.getChatStyle());
- replaceMents.add(new Tuple<>(sibling, newChatCompText));
- break;
- }
- }
- }
-
- for (Tuple<IChatComponent, IChatComponent> replaceMent : replaceMents) {
- int index = event.message.getSiblings().indexOf(replaceMent.getFirst());
- event.message.getSiblings().set(index, replaceMent.getSecond());
- }
- }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/ReplacementContext.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/ReplacementContext.java
new file mode 100644
index 00000000..b1ebc717
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/ReplacementContext.java
@@ -0,0 +1,31 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.surgical;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class ReplacementContext {
+ private int nearIdx;
+
+ private String username;
+ private String uuid; // aiding uuid.
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/SurgicalReplacer.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/SurgicalReplacer.java
new file mode 100644
index 00000000..475b10f9
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/surgical/SurgicalReplacer.java
@@ -0,0 +1,190 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023 cyoung06 (syeyoung)
+ *
+ * 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.mod.cosmetics.surgical;
+
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+
+import java.util.*;
+
+public class SurgicalReplacer {
+
+ public static List<ChatComponentText> getChatStyleOf(String str, ChatStyle parentStyle) {
+ boolean randomStyle = parentStyle.getObfuscated();
+ boolean boldStyle = parentStyle.getBold();
+ boolean strikethroughStyle = parentStyle.getStrikethrough();
+ boolean underlineStyle = parentStyle.getUnderlined();
+ boolean italicStyle = parentStyle.getItalic();
+ int colorStyle = parentStyle.getColor() == null ? 15 : parentStyle.getColor().getColorIndex();
+ char[] charArr = str.toCharArray();
+
+ List<ChatComponentText> list = new LinkedList<>();
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < charArr.length; i++) {
+ char c0 = charArr[i];
+ if (c0 == 167 && i + 1 < charArr.length) {
+ if (stringBuilder.length() != 0) {
+ ChatComponentText chatComponents = new ChatComponentText(stringBuilder.toString());
+ chatComponents.setChatStyle(new ChatStyle()
+ .setBold(boldStyle)
+ .setObfuscated(randomStyle)
+ .setStrikethrough(strikethroughStyle)
+ .setUnderlined(underlineStyle)
+ .setItalic(italicStyle)
+ .setColor(EnumChatFormatting.func_175744_a(colorStyle))
+ .setChatHoverEvent(parentStyle.getChatHoverEvent())
+ .setChatClickEvent(parentStyle.getChatClickEvent()));
+ list.add(chatComponents);
+ stringBuilder = new StringBuilder();
+ }
+ int i1 = "0123456789abcdefklmnor".indexOf(Character.toLowerCase(charArr[i + 1]));
+ if (i1 < 16) {
+ randomStyle = false;
+ boldStyle = false;
+ strikethroughStyle = false;
+ underlineStyle = false;
+ italicStyle = false;
+ if (i1 < 0) {
+ i1 = 15;
+ }
+ colorStyle = i1;
+ } else if (i1 == 16) {
+ randomStyle = true;
+ } else if (i1 == 17) {
+ boldStyle = true;
+ } else if (i1 == 18) {
+ strikethroughStyle = true;
+ } else if (i1 == 19) {
+ underlineStyle = true;
+ } else if (i1 == 20) {
+ italicStyle = true;
+ } else {
+ randomStyle = false;
+ boldStyle = false;
+ strikethroughStyle = false;
+ underlineStyle = false;
+ italicStyle = false;
+ colorStyle = 15;
+ }
+
+ ++i;
+ } else {
+ stringBuilder.append(c0);
+ }
+ }
+ ChatComponentText chatComponents = new ChatComponentText(stringBuilder.toString());
+ chatComponents.setChatStyle(new ChatStyle()
+ .setBold(boldStyle)
+ .setObfuscated(randomStyle)
+ .setStrikethrough(strikethroughStyle)
+ .setUnderlined(underlineStyle)
+ .setItalic(italicStyle)
+ .setColor(EnumChatFormatting.func_175744_a(colorStyle))
+ .setChatHoverEvent(parentStyle.getChatHoverEvent())
+ .setChatClickEvent(parentStyle.getChatClickEvent()));
+ list.add(chatComponents);
+ return list;
+ }
+
+ public static LinkedList<IChatComponent> linearifyMoveColorCharToStyle(IChatComponent iChatComponent) {
+ LinkedList<IChatComponent> chatComponents = new LinkedList<>();
+ for (IChatComponent component : iChatComponent) {
+ if (component instanceof ChatComponentText) {
+ chatComponents.addAll(getChatStyleOf(((ChatComponentText) component).getChatComponentText_TextValue(), component.getChatStyle().createDeepCopy()));
+ } else {
+ IChatComponent neuCopy = component.createCopy();
+ neuCopy.getSiblings().clear();
+ chatComponents.add(neuCopy.setChatStyle(component.getChatStyle().createDeepCopy()));
+ }
+ }
+ return chatComponents;
+ }
+
+ public static ChatStyle getChatStyleAt(List<IChatComponent> chatComponents, int idx) {
+ int i = 0;
+ for (IChatComponent chatComponent : chatComponents) {
+ i += chatComponent.getUnformattedTextForChat().length();
+ if (i > idx) return chatComponent.getChatStyle().createDeepCopy();
+ }
+ return null;
+ }
+ public static LinkedList<IChatComponent> inject(LinkedList<IChatComponent> linearified, List<IChatComponent> toInjectLinearified, int idx, int len) {
+ LinkedList<IChatComponent> clone = new LinkedList<>();
+ int currLen = 0;
+ boolean injected = false;
+ while (!linearified.isEmpty()) {
+ if (currLen == idx && !injected) {
+ clone.addAll(toInjectLinearified);
+ injected = true;
+ }
+
+ IChatComponent toProcess = linearified.poll();
+ int procLen = toProcess.getUnformattedTextForChat().length();
+
+ if (currLen + procLen <= idx) {
+ clone.add(toProcess);
+ currLen += procLen;
+ continue;
+ }
+
+ if (currLen + procLen > idx && currLen < idx) {
+ ChatComponentText chatComponents = new ChatComponentText(
+ toProcess.getUnformattedTextForChat().substring(0, idx - currLen)
+ );
+ chatComponents.setChatStyle(toProcess.getChatStyle());
+
+ clone.add(chatComponents);
+
+ ChatComponentText next = new ChatComponentText(
+ toProcess.getUnformattedTextForChat().substring(idx-currLen)
+ );
+ next.setChatStyle(toProcess.getChatStyle());
+ linearified.addFirst(next);
+
+ currLen = idx;
+ continue;
+ }
+
+ if (currLen + procLen <= idx + len) {
+ currLen += procLen;
+ continue;
+ }
+ if (currLen + procLen > idx + len && currLen < idx + len) {
+ ChatComponentText next = new ChatComponentText(
+ toProcess.getUnformattedTextForChat().substring(idx + len - currLen)
+ );
+ next.setChatStyle(toProcess.getChatStyle());
+ clone.add(next);
+ currLen += procLen;
+ continue;
+ }
+ clone.add(toProcess);
+ currLen += procLen;
+ }
+ return clone;
+ }
+ public static IChatComponent combine(List<IChatComponent> components) {
+ ChatComponentText chatComponents = new ChatComponentText("");
+ chatComponents.getSiblings().addAll(components);
+ return chatComponents;
+ }
+}