diff --git a/src/main/java/buttondevteam/chat/ChatProcessing.java b/src/main/java/buttondevteam/chat/ChatProcessing.java index 467f987..a606686 100644 --- a/src/main/java/buttondevteam/chat/ChatProcessing.java +++ b/src/main/java/buttondevteam/chat/ChatProcessing.java @@ -2,6 +2,7 @@ package buttondevteam.chat; import java.util.ArrayList; import java.util.Collection; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import org.bukkit.Bukkit; @@ -11,6 +12,7 @@ import org.bukkit.entity.Player; import org.bukkit.scoreboard.Objective; import com.earth2me.essentials.Essentials; +import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import buttondevteam.chat.commands.UnlolCommand; @@ -36,48 +38,47 @@ public class ChatProcessing { private static final Pattern UNDERLINED_PATTERN = Pattern.compile("\\_"); private static final Pattern ITALIC_PATTERN = Pattern.compile("\\*"); private static final Pattern BOLD_PATTERN = Pattern.compile("\\*\\*"); - private static final String[] RainbowPresserColors = new String[] { "red", "gold", "yellow", "green", "blue", - "dark_purple" }; // TODO + private static final Color[] RainbowPresserColors = new Color[] { Color.Red, Color.Gold, Color.Yellow, Color.Green, + Color.Blue, Color.DarkPurple }; private static boolean pingedconsole = false; - private static ArrayList commonFormatters = new ArrayList<>(); - private static Gson gson; - public static final ChatFormatter ESCAPE_FORMATTER = new ChatFormatterBuilder().setRegex(ESCAPE_PATTERN).build(); + private static ArrayList commonFormatters = Lists.newArrayList( + new ChatFormatterBuilder().setRegex(BOLD_PATTERN).setBold(true).setRemoveCharCount((short) 2).setRange(true) + .setPriority(Priority.High).build(), + new ChatFormatterBuilder().setRegex(ITALIC_PATTERN).setItalic(true).setRemoveCharCount((short) 1) + .setRange(true).build(), + new ChatFormatterBuilder().setRegex(UNDERLINED_PATTERN).setUnderlined(true).setRemoveCharCount((short) 1) + .setRange(true).build(), + ESCAPE_FORMATTER, + new ChatFormatterBuilder().setRegex(URL_PATTERN).setUnderlined(true).setOpenlink("$1").setRange(true) + .build(), + new ChatFormatterBuilder().setRegex(NULL_MENTION_PATTERN).setColor(Color.DarkRed).build(), // Properly added a bug as a feature + new ChatFormatterBuilder().setRegex(CONSOLE_PING_PATTERN).setColor(Color.Aqua) + .setOnmatch((match, builder) -> + + { + if (!pingedconsole) { + System.out.print("\007"); + pingedconsole = true; // Will set it to false in ProcessChat + } + return match; + }).setPriority(Priority.High).build(), + + new ChatFormatterBuilder().setRegex(HASHTAG_PATTERN).setColor(Color.Blue) + .setOpenlink("https://twitter.com/hashtag/$1").setPriority(Priority.High).build(), + new ChatFormatterBuilder().setRegex(CYAN_PATTERN).setColor(Color.Aqua).build() // #55 + ); + private static Gson gson = new GsonBuilder() + .registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum()) + .registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection()) + .registerTypeAdapter(Boolean.class, new TellrawSerializer.TwBool()) + .registerTypeAdapter(boolean.class, new TellrawSerializer.TwBool()).disableHtmlEscaping().create(); + private ChatProcessing() { } - static { - commonFormatters.add(new ChatFormatterBuilder().setRegex(BOLD_PATTERN).setBold(true) - .setRemoveCharCount((short) 2).setRange(true).setPriority(Priority.High).build()); - commonFormatters.add(new ChatFormatterBuilder().setRegex(ITALIC_PATTERN).setItalic(true) - .setRemoveCharCount((short) 1).setRange(true).build()); - commonFormatters.add(new ChatFormatterBuilder().setRegex(UNDERLINED_PATTERN).setUnderlined(true) - .setRemoveCharCount((short) 1).setRange(true).build()); - commonFormatters.add(ESCAPE_FORMATTER); - commonFormatters.add(new ChatFormatterBuilder().setRegex(URL_PATTERN).setUnderlined(true).setOpenlink("$1") - .setRange(true).build()); - commonFormatters.add(new ChatFormatterBuilder().setRegex(NULL_MENTION_PATTERN).setColor(Color.DarkRed).build()); // Properly added a bug as a feature - commonFormatters.add(new ChatFormatterBuilder().setRegex(CONSOLE_PING_PATTERN).setColor(Color.Aqua) - .setOnmatch((String match) -> { - if (!pingedconsole) { - System.out.print("\007"); - pingedconsole = true; // Will set it to false in ProcessChat - } - return match; - }).setPriority(Priority.High).build()); - - commonFormatters.add(new ChatFormatterBuilder().setRegex(HASHTAG_PATTERN).setColor(Color.Blue) - .setOpenlink("https://twitter.com/hashtag/$1").setPriority(Priority.High).build()); - commonFormatters.add(new ChatFormatterBuilder().setRegex(CYAN_PATTERN).setColor(Color.Aqua).build()); // #55 - gson = new GsonBuilder() - .registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum()) - .registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection()) - .registerTypeAdapter(Boolean.class, new TellrawSerializer.TwBool()) - .registerTypeAdapter(boolean.class, new TellrawSerializer.TwBool()).disableHtmlEscaping().create(); - } - public static boolean ProcessChat(TBMCChatEvent e) { Channel channel = e.getChannel(); CommandSender sender = e.getSender(); @@ -99,13 +100,19 @@ public class ChatProcessing { Color colormode = channel.color; if (mp != null && mp.OtherColorMode != null) colormode = mp.OtherColorMode; - if (mp != null && mp.RainbowPresserColorMode) - colormode = Color.RPC; if (message.startsWith(">")) colormode = Color.Green; // If greentext, ignore channel or player colors ArrayList formatters = addFormatters(colormode); + if (colormode == channel.color && mp != null && mp.RainbowPresserColorMode) { // Only overwrite channel color + final AtomicInteger rpc = new AtomicInteger(0); + formatters.add(new ChatFormatterBuilder().setColor(colormode).setOnmatch((match, builder) -> { + builder.setColor( + RainbowPresserColors[rpc.getAndUpdate(i -> ++i < RainbowPresserColors.length ? i : 0)]); + return match; + }).build()); + } pingedconsole = false; // Will set it to true onmatch (static constructor) final String channelidentifier = getChannelID(channel, sender, mp); @@ -125,9 +132,8 @@ public class ChatProcessing { if (channel.filteranderrormsg != null) { Objective obj = PluginMain.SB.getObjective(channel.ID); int score = -1; - for (Player p : Bukkit.getOnlinePlayers()) { - obj.getScore(p.getUniqueId().toString()).setScore(score = e.getMCScore(p)); - } + for (Player p : Bukkit.getOnlinePlayers()) + obj.getScore(p.getName()).setScore(score = e.getMCScore(p)); PluginMain.Instance.getServer().dispatchCommand(PluginMain.Console, String.format( "tellraw @a[score_%s=%d,score_%s_min=%d] %s", channel.ID, score, channel.ID, score, jsonstr)); } else @@ -243,7 +249,7 @@ public class ChatProcessing { nicksb.append(")"); formatters.add(new ChatFormatterBuilder().setRegex(Pattern.compile(namesb.toString())).setColor(Color.Aqua) - .setOnmatch((String match) -> { + .setOnmatch((match, builder) -> { Player p = Bukkit.getPlayer(match); if (p == null) { PluginMain.Instance.getLogger() @@ -262,7 +268,7 @@ public class ChatProcessing { if (addNickFormatter) formatters.add(new ChatFormatterBuilder().setRegex(Pattern.compile(nicksb.toString())) - .setColor(Color.Aqua).setOnmatch((String match) -> { + .setColor(Color.Aqua).setOnmatch((match, builder) -> { if (PlayerListener.nicknames.containsKey(match)) { Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match)); if (p == null) { diff --git a/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java b/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java index f2d9f2c..68ff611 100644 --- a/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java +++ b/src/main/java/buttondevteam/chat/formatting/ChatFormatter.java @@ -7,45 +7,23 @@ import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Matcher; -import java.util.regex.Pattern; - import buttondevteam.chat.ChatProcessing; import buttondevteam.chat.commands.ucmds.admin.DebugCommand; import buttondevteam.lib.chat.*; +/** + * A {@link ChatFormatter} shows what formatting to use based on regular expressions. {@link ChatFormatter#Combine(List, String, TellrawPart)} is used to turn it into a {@link TellrawPart}, combining + * intersecting parts found, for example when {@code _abc*def*ghi_} is said in chat, it'll turn it into an underlined part, then an underlined and italics part, finally an underlined part + * again. + * + * @author NorbiPeti + * + */ public final class ChatFormatter { - private Pattern regex; - private boolean italic; - private boolean bold; - private boolean underlined; - private boolean strikethrough; - private boolean obfuscated; - private Color color; - private Function onmatch; - private String openlink; - private Priority priority; - private short removecharcount = 0; - private boolean isrange; + private ChatFormatterBuilder builder; - public ChatFormatter(Pattern regex, boolean italic, boolean bold, boolean underlined, boolean strikethrough, - boolean obfuscated, Color color, Function onmatch, String openlink, Priority priority, - short removecharcount, boolean isrange) { - super(); - this.regex = regex; - this.italic = italic; - this.bold = bold; - this.underlined = underlined; - this.strikethrough = strikethrough; - this.obfuscated = obfuscated; - this.color = color; - this.onmatch = onmatch; - this.openlink = openlink; - if (priority == null) - this.priority = Priority.Normal; - else - this.priority = priority; - this.removecharcount = removecharcount; - this.isrange = isrange; + public ChatFormatter(ChatFormatterBuilder builder) { + this.builder = builder; } public static void Combine(List formatters, String str, TellrawPart tp) { @@ -55,7 +33,7 @@ public final class ChatFormatter { header("ChatFormatter.Combine begin"); ArrayList sections = new ArrayList(); for (ChatFormatter formatter : formatters) { - Matcher matcher = formatter.regex.matcher(str); + Matcher matcher = formatter.builder.regex.matcher(str); while (matcher.find()) { DebugCommand.SendDebugMessage("Found match from " + matcher.start() + " to " + (matcher.end() - 1)); DebugCommand.SendDebugMessage("With formatter:" + formatter); @@ -66,13 +44,13 @@ public final class ChatFormatter { if (groups.size() > 0) DebugCommand.SendDebugMessage("First group: " + groups.get(0)); FormattedSection section = new FormattedSection(formatter, matcher.start(), matcher.end() - 1, groups, - formatter.removecharcount, formatter.removecharcount, formatter.isrange); + formatter.builder.removecharcount, formatter.builder.removecharcount, formatter.builder.range); sections.add(section); } } sections.sort((s1, s2) -> s1.Start == s2.Start - ? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).priority.GetValue(), - s1.Formatters.get(0).priority.GetValue()) : Integer.compare(s2.End, s1.End) + ? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).builder.priority.GetValue(), + s1.Formatters.get(0).builder.priority.GetValue()) : Integer.compare(s2.End, s1.End) : Integer.compare(s1.Start, s2.Start)); header("Range section conversion"); @@ -265,10 +243,11 @@ public final class ChatFormatter { if (found) { i = 1; found = false; - sections.sort((s1, s2) -> s1.Start == s2.Start - ? s1.End == s2.End ? Integer.compare(s2.Formatters.get(0).priority.GetValue(), - s1.Formatters.get(0).priority.GetValue()) : Integer.compare(s2.End, s1.End) - : Integer.compare(s1.Start, s2.Start)); + sections.sort((s1, + s2) -> s1.Start == s2.Start ? s1.End == s2.End + ? Integer.compare(s2.Formatters.get(0).builder.priority.GetValue(), + s1.Formatters.get(0).builder.priority.GetValue()) + : Integer.compare(s2.End, s1.End) : Integer.compare(s1.Start, s2.Start)); } else cont = false; } @@ -279,34 +258,33 @@ public final class ChatFormatter { FormattedSection section = sections.get(i); DebugCommand.SendDebugMessage("Applying section: " + section); String originaltext; - int start = section.Start + section.RemCharFromStart, end = section.End + 1 - section.RemCharFromEnd; // TODO: RemCharPos + int start = section.Start + section.RemCharFromStart, end = section.End + 1 - section.RemCharFromEnd; DebugCommand.SendDebugMessage("Start: " + start + " - End: " + end); sendMessageWithPointer(str, start, end); - StringBuilder textsb = new StringBuilder(str.substring(start, end)); - originaltext = textsb.toString(); + originaltext = str.substring(start, end); DebugCommand.SendDebugMessage("Section text: " + originaltext); Color color = null; boolean bold = false, italic = false, underlined = false, strikethrough = false, obfuscated = false; String openlink = null; - section.Formatters.sort((cf2, cf1) -> cf1.priority.compareTo(cf2.priority)); + section.Formatters.sort((cf2, cf1) -> cf1.builder.priority.compareTo(cf2.builder.priority)); for (ChatFormatter formatter : section.Formatters) { DebugCommand.SendDebugMessage("Applying formatter: " + formatter); - if (formatter.onmatch != null) - originaltext = formatter.onmatch.apply(originaltext); - if (formatter.color != null) - color = formatter.color; - if (formatter.bold) + if (formatter.builder.onmatch != null) + originaltext = formatter.builder.onmatch.apply(originaltext, formatter.builder); + if (formatter.builder.color != null) + color = formatter.builder.color; + if (formatter.builder.bold) bold = true; - if (formatter.italic) + if (formatter.builder.italic) italic = true; - if (formatter.underlined) + if (formatter.builder.underlined) underlined = true; - if (formatter.strikethrough) + if (formatter.builder.strikethrough) strikethrough = true; - if (formatter.obfuscated) + if (formatter.builder.obfuscated) obfuscated = true; - if (formatter.openlink != null) - openlink = formatter.openlink; + if (formatter.builder.openlink != null) + openlink = formatter.builder.openlink; } TellrawPart newtp = new TellrawPart(""); newtp.setText(originaltext); @@ -330,11 +308,12 @@ public final class ChatFormatter { @Override public String toString() { - return new StringBuilder("F(").append(color).append(", ") - .append((bold ? "bold" : "") + (italic ? "italic" : "") + (underlined ? "underlined" : "") - + (strikethrough ? "strikethrough" : "") + (obfuscated ? "obfuscated" : "")) - .append(", ").append(openlink).append(", ").append(priority).append(", ").append(regex).append(")") - .toString(); + return new StringBuilder("F(").append(builder.color).append(", ") + .append((builder.bold ? "bold" : "") + (builder.italic ? "italic" : "") + + (builder.underlined ? "underlined" : "") + (builder.strikethrough ? "strikethrough" : "") + + (builder.obfuscated ? "obfuscated" : "")) + .append(", ").append(builder.openlink).append(", ").append(builder.priority).append(", ") + .append(builder.regex).append(")").toString(); // TODO: Lombok } /** diff --git a/src/main/java/buttondevteam/chat/formatting/ChatFormatterBuilder.java b/src/main/java/buttondevteam/chat/formatting/ChatFormatterBuilder.java index fea8072..9177a31 100644 --- a/src/main/java/buttondevteam/chat/formatting/ChatFormatterBuilder.java +++ b/src/main/java/buttondevteam/chat/formatting/ChatFormatterBuilder.java @@ -1,27 +1,30 @@ package buttondevteam.chat.formatting; -import java.util.function.Function; +import java.io.Serializable; +import java.util.function.BiFunction; import java.util.regex.Pattern; +import org.apache.commons.lang.SerializationUtils; + import buttondevteam.lib.chat.*; -public class ChatFormatterBuilder { - private Pattern regex; - private boolean italic; - private boolean bold; - private boolean underlined; - private boolean strikethrough; - private boolean obfuscated; - private Color color; - private Function onmatch; - private String openlink; - private Priority priority; - private short removecharcount = 0; - private boolean range = false; +public class ChatFormatterBuilder implements Serializable { + private static final long serialVersionUID = -6115913400749778686L; + Pattern regex; + boolean italic; + boolean bold; + boolean underlined; + boolean strikethrough; + boolean obfuscated; + Color color; + BiFunction onmatch; + String openlink; + Priority priority = Priority.Normal; + short removecharcount = 0; + boolean range = false; public ChatFormatter build() { - return new ChatFormatter(regex, italic, bold, underlined, strikethrough, obfuscated, color, onmatch, openlink, - priority, removecharcount, range); + return new ChatFormatter((ChatFormatterBuilder) SerializationUtils.clone(this)); } public Pattern getRegex() { @@ -87,11 +90,14 @@ public class ChatFormatterBuilder { return this; } - public Function getOnmatch() { + public BiFunction getOnmatch() { return onmatch; } - public ChatFormatterBuilder setOnmatch(Function onmatch) { + /** + * Making any changes here using the builder will not affect the previous matches with the current design + */ + public ChatFormatterBuilder setOnmatch(BiFunction onmatch) { this.onmatch = onmatch; return this; } @@ -110,7 +116,7 @@ public class ChatFormatterBuilder { } public ChatFormatterBuilder setPriority(Priority priority) { - this.priority = priority; + this.priority = priority == null ? Priority.Normal : priority; return this; } diff --git a/src/main/java/buttondevteam/chat/listener/PlayerListener.java b/src/main/java/buttondevteam/chat/listener/PlayerListener.java index ce56d5c..ea96c79 100644 --- a/src/main/java/buttondevteam/chat/listener/PlayerListener.java +++ b/src/main/java/buttondevteam/chat/listener/PlayerListener.java @@ -277,10 +277,11 @@ public class PlayerListener implements Listener { e.setCancelled(ChatProcessing.ProcessChat(e)); } catch (Exception ex) { for (Player p : Bukkit.getOnlinePlayers()) - p.sendMessage("§c!§r[" - + e.getChannel().DisplayName + "] <" + (e.getSender() instanceof Player - ? ((Player) e.getSender()).getDisplayName() : e.getSender().getName()) - + "> " + e.getMessage()); + if (e.shouldSendTo(p)) + p.sendMessage("§c!§r[" + + e.getChannel().DisplayName + "] <" + (e.getSender() instanceof Player + ? ((Player) e.getSender()).getDisplayName() : e.getSender().getName()) + + "> " + e.getMessage()); TBMCCoreAPI.SendException("An error occured while processing a chat message!", ex); } }