Mostly fixed chat formatting #60
4 changed files with 131 additions and 79 deletions
|
@ -20,11 +20,7 @@ import com.palmergames.bukkit.towny.object.Town;
|
|||
|
||||
import buttondevteam.chat.commands.UnlolCommand;
|
||||
import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
|
||||
import buttondevteam.chat.formatting.ChatFormatter;
|
||||
import buttondevteam.chat.formatting.ChatFormatterBuilder;
|
||||
import buttondevteam.chat.formatting.TellrawEvent;
|
||||
import buttondevteam.chat.formatting.TellrawPart;
|
||||
import buttondevteam.chat.formatting.TellrawSerializer;
|
||||
import buttondevteam.chat.formatting.*;
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.TBMCPlayer;
|
||||
import buttondevteam.lib.chat.Channel;
|
||||
|
@ -33,19 +29,51 @@ import buttondevteam.chat.listener.PlayerListener;
|
|||
import buttondevteam.lib.chat.*;
|
||||
|
||||
public class ChatProcessing {
|
||||
private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\\\([\\*\\_\\\\])");
|
||||
private static final Pattern NULL_MENTION_PATTERN = Pattern.compile("null");
|
||||
private static final Pattern ESCAPE_PATTERN = Pattern.compile("\\\\");
|
||||
private static final Pattern CONSOLE_PING_PATTERN = Pattern.compile("(?i)" + Pattern.quote("@console"));
|
||||
private static final Pattern HASHTAG_PATTERN = Pattern.compile("#(\\w+)");
|
||||
private static final Pattern URL_PATTERN = Pattern.compile("(http[\\w:/?=$\\-_.+!*'(),]+)");
|
||||
private static final Pattern ENTIRE_MESSAGE_PATTERN = Pattern.compile(".+");
|
||||
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 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 boolean pingedconsole = false;
|
||||
|
||||
private static ArrayList<ChatFormatter> commonFormatters = new ArrayList<>();
|
||||
|
||||
public static final ChatFormatter ESCAPE_FORMATTER = new ChatFormatterBuilder().setRegex(ESCAPE_PATTERN).build();
|
||||
|
||||
private ChatProcessing() {
|
||||
}
|
||||
|
||||
static {
|
||||
commonFormatters.add(new ChatFormatterBuilder().setRegex(BOLD_PATTERN).setFormat(Format.Bold)
|
||||
.setRemoveCharCount((short) 2).setRange(true).build());
|
||||
commonFormatters.add(new ChatFormatterBuilder().setRegex(ITALIC_PATTERN).setFormat(Format.Italic)
|
||||
.setRemoveCharCount((short) 1).setRange(true).build());
|
||||
commonFormatters.add(new ChatFormatterBuilder().setRegex(UNDERLINED_PATTERN).setFormat(Format.Underlined)
|
||||
.setRemoveCharCount((short) 1).setRange(true).build());
|
||||
commonFormatters.add(ESCAPE_FORMATTER);
|
||||
// URLs + Rainbow text
|
||||
commonFormatters.add(new ChatFormatterBuilder().setRegex(URL_PATTERN).setFormat(Format.Underlined)
|
||||
.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());
|
||||
}
|
||||
|
||||
// Returns e.setCancelled for custom event
|
||||
public static boolean ProcessChat(Channel channel, CommandSender sender, String message) {
|
||||
long processstart = System.nanoTime();
|
||||
|
@ -78,7 +106,8 @@ public class ChatProcessing {
|
|||
}
|
||||
Channel currentchannel = channel;
|
||||
|
||||
ArrayList<ChatFormatter> formatters = new ArrayList<ChatFormatter>();
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<ChatFormatter> formatters = (ArrayList<ChatFormatter>) commonFormatters.clone();
|
||||
|
||||
Color colormode = currentchannel.color;
|
||||
if (mp != null && mp.OtherColorMode != null)
|
||||
|
@ -96,17 +125,6 @@ public class ChatProcessing {
|
|||
|
||||
String suggestmsg = formattedmessage;
|
||||
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(BOLD_PATTERN).setFormat(Format.Bold)
|
||||
.setRemoveCharCount((short) 2).build());
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(ITALIC_PATTERN).setFormat(Format.Italic)
|
||||
.setRemoveCharCount((short) 1).build());
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(UNDERLINED_PATTERN).setFormat(Format.Underlined)
|
||||
.setRemoveCharCount((short) 1).build());
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(ESCAPE_PATTERN).setRemoveCharPos((short) 0).build());
|
||||
|
||||
// URLs + Rainbow text
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(URL_PATTERN).setFormat(Format.Underlined).setOpenlink("$1")
|
||||
.build());
|
||||
if (Bukkit.getOnlinePlayers().size() > 0) {
|
||||
StringBuilder namesb = new StringBuilder();
|
||||
namesb.append("(?i)(");
|
||||
|
@ -116,6 +134,7 @@ public class ChatProcessing {
|
|||
namesb.append(")");
|
||||
StringBuilder nicksb = new StringBuilder();
|
||||
nicksb.append("(?i)(");
|
||||
boolean addNickFormatter = false;
|
||||
{
|
||||
final int size = Bukkit.getOnlinePlayers().size();
|
||||
int index = 0;
|
||||
|
@ -125,6 +144,7 @@ public class ChatProcessing {
|
|||
nicksb.append(nick);
|
||||
if (index < size - 1) {
|
||||
nicksb.append("|");
|
||||
addNickFormatter = true;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
|
@ -132,9 +152,6 @@ public class ChatProcessing {
|
|||
nicksb.append(")");
|
||||
}
|
||||
|
||||
formatters
|
||||
.add(new ChatFormatterBuilder().setRegex(Pattern.compile("null")).setColor(Color.DarkRed).build()); // Properly added a bug as a feature
|
||||
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(Pattern.compile(namesb.toString())).setColor(Color.Aqua)
|
||||
.setOnmatch((String match) -> {
|
||||
Player p = Bukkit.getPlayer(match);
|
||||
|
@ -153,61 +170,46 @@ public class ChatProcessing {
|
|||
return color + p.getName() + "§r";
|
||||
}).setPriority(Priority.High).build());
|
||||
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(Pattern.compile(nicksb.toString())).setColor(Color.Aqua)
|
||||
.setOnmatch((String match) -> {
|
||||
if (PlayerListener.nicknames.containsKey(match)) {
|
||||
Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match));
|
||||
if (p == null) {
|
||||
PluginMain.Instance.getLogger().warning(
|
||||
"Error: Can't find player nicknamed " + match + " but was reported as online.");
|
||||
return "§c" + match + "§r";
|
||||
if (addNickFormatter)
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(Pattern.compile(nicksb.toString()))
|
||||
.setColor(Color.Aqua).setOnmatch((String match) -> {
|
||||
if (PlayerListener.nicknames.containsKey(match)) {
|
||||
Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match));
|
||||
if (p == null) {
|
||||
PluginMain.Instance.getLogger().warning("Error: Can't find player nicknamed "
|
||||
+ match + " but was reported as online.");
|
||||
return "§c" + match + "§r";
|
||||
}
|
||||
if (PlayerListener.NotificationSound == null)
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f);
|
||||
else
|
||||
p.playSound(p.getLocation(), PlayerListener.NotificationSound, 1.0f,
|
||||
(float) PlayerListener.NotificationPitch);
|
||||
return PluginMain.essentials.getUser(p).getNickname();
|
||||
}
|
||||
if (PlayerListener.NotificationSound == null)
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_ARROW_HIT_PLAYER, 1.0f, 0.5f);
|
||||
else
|
||||
p.playSound(p.getLocation(), PlayerListener.NotificationSound, 1.0f,
|
||||
(float) PlayerListener.NotificationPitch);
|
||||
return PluginMain.essentials.getUser(p).getNickname();
|
||||
}
|
||||
Bukkit.getServer().getLogger().warning(
|
||||
"Player nicknamed " + match + " not found in nickname map but was reported as online.");
|
||||
return "§c" + match + "§r";
|
||||
}).setPriority(Priority.High).build());
|
||||
Bukkit.getServer().getLogger().warning("Player nicknamed " + match
|
||||
+ " not found in nickname map but was reported as online.");
|
||||
return "§c" + match + "§r";
|
||||
}).setPriority(Priority.High).build());
|
||||
}
|
||||
|
||||
pingedconsole = false;
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(CONSOLE_PING_PATTERN).setColor(Color.Aqua)
|
||||
.setOnmatch((String match) -> {
|
||||
if (!pingedconsole) {
|
||||
System.out.print("\007");
|
||||
pingedconsole = true;
|
||||
}
|
||||
return match;
|
||||
}).setPriority(Priority.High).build());
|
||||
|
||||
formatters.add(new ChatFormatterBuilder().setRegex(HASHTAG_PATTERN).setColor(Color.Blue)
|
||||
.setOpenlink("https://twitter.com/hashtag/$1").setPriority(Priority.High).build());
|
||||
|
||||
/*
|
||||
* if (!hadurls) { if (formattedmessage.matches("(?i).*" + Pattern.quote("@console") + ".*")) { formattedmessage = formattedmessage.replaceAll( "(?i)" + Pattern.quote("@console"),
|
||||
* "§b@console§r"); formattedmessage = formattedmessage .replaceAll( "(?i)" + Pattern.quote("@console"), String.format(
|
||||
* "\",\"color\":\"%s\"},{\"text\":\"§b@console§r\",\"color\":\"blue\"},{\"text\":\"" , colormode)); System.out.println("\007"); } }
|
||||
*/
|
||||
pingedconsole = false; // Will set it to true onmatch (static constructor)
|
||||
|
||||
TellrawPart json = new TellrawPart("");
|
||||
if (mp != null && mp.ChatOnly) {
|
||||
json.addExtra(new TellrawPart("[C]").setHoverEvent(
|
||||
TellrawEvent.create(TellrawEvent.HoverAC, TellrawEvent.HoverAction.SHOW_TEXT, "Chat only")));
|
||||
}
|
||||
final String channelidentifier = ("[" + (sender instanceof IDiscordSender ? "d|" : "") + currentchannel.DisplayName)
|
||||
+ "]" + (mp != null && !mp.RPMode ? "[OOC]" : "");
|
||||
final String channelidentifier = ("[" + (sender instanceof IDiscordSender ? "d|" : "")
|
||||
+ currentchannel.DisplayName) + "]" + (mp != null && !mp.RPMode ? "[OOC]" : "");
|
||||
json.addExtra(
|
||||
new TellrawPart(channelidentifier).setHoverEvent(
|
||||
new TellrawPart(channelidentifier)
|
||||
.setHoverEvent(
|
||||
TellrawEvent.create(TellrawEvent.HoverAC, TellrawEvent.HoverAction.SHOW_TEXT,
|
||||
new TellrawPart((sender instanceof IDiscordSender ? "From Discord\n" : "")
|
||||
+ "Copy message").setColor(Color.Blue)))
|
||||
.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAC,
|
||||
TellrawEvent.ClickAction.SUGGEST_COMMAND, suggestmsg)));
|
||||
.setClickEvent(TellrawEvent.create(TellrawEvent.ClickAC,
|
||||
TellrawEvent.ClickAction.SUGGEST_COMMAND, suggestmsg)));
|
||||
json.addExtra(new TellrawPart(" <"));
|
||||
json.addExtra(
|
||||
new TellrawPart(
|
||||
|
@ -382,9 +384,8 @@ public class ChatProcessing {
|
|||
player.sendMessage("§cAn error occured while sending the message.");
|
||||
return true;
|
||||
}
|
||||
PluginMain.Instance.getServer().getConsoleSender()
|
||||
.sendMessage(String.format("[%s] <%s> %s", channelidentifier,
|
||||
(player != null ? player.getDisplayName() : sender.getName()), message));
|
||||
PluginMain.Instance.getServer().getConsoleSender().sendMessage(String.format("%s <%s> %s", channelidentifier,
|
||||
(player != null ? player.getDisplayName() : sender.getName()), message));
|
||||
DebugCommand.SendDebugMessage(
|
||||
"-- Full ChatProcessing time: " + (System.nanoTime() - processstart) / 1000000f + " ms");
|
||||
DebugCommand.SendDebugMessage("-- ChatFormatter.Combine time: " + combinetime / 1000000f + " ms");
|
||||
|
|
|
@ -2,11 +2,14 @@ package buttondevteam.chat.formatting;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
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.*;
|
||||
|
||||
|
@ -19,9 +22,10 @@ public final class ChatFormatter {
|
|||
private Priority priority;
|
||||
private short removecharcount = 0;
|
||||
private short removecharpos = -1;
|
||||
private boolean isrange;
|
||||
|
||||
public ChatFormatter(Pattern regex, Format format, Color color, Function<String, String> onmatch, String openlink,
|
||||
Priority priority, short removecharcount, short removecharpos) {
|
||||
Priority priority, short removecharcount, short removecharpos, boolean isrange) {
|
||||
this.regex = regex;
|
||||
this.format = format;
|
||||
this.color = color;
|
||||
|
@ -30,6 +34,7 @@ public final class ChatFormatter {
|
|||
this.priority = Priority.High;
|
||||
this.removecharcount = removecharcount;
|
||||
this.removecharpos = removecharpos;
|
||||
this.isrange = isrange;
|
||||
}
|
||||
|
||||
public static void Combine(List<ChatFormatter> formatters, String str, TellrawPart tp) {
|
||||
|
@ -48,7 +53,8 @@ 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.removecharpos);
|
||||
formatter.removecharcount, formatter.removecharcount, formatter.removecharpos,
|
||||
formatter.isrange);
|
||||
sections.add(section);
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +64,37 @@ public final class ChatFormatter {
|
|||
else
|
||||
return Integer.compare(s1.Start, s2.Start);
|
||||
});
|
||||
ArrayList<FormattedSection> combined = new ArrayList<>();
|
||||
Map<ChatFormatter, FormattedSection> nextSection = new HashMap<>();
|
||||
boolean escaped = false;
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
// Set ending to -1 until closed with another 1 long "section" - only do this if IsRange is true
|
||||
final FormattedSection section = sections.get(i);
|
||||
if (!section.IsRange) {
|
||||
escaped = section.Formatters.contains(ChatProcessing.ESCAPE_FORMATTER) && !escaped; // Enable escaping on first \, disable on second
|
||||
if (escaped) // Don't add the escape character
|
||||
section.RemCharFromStart = 1;
|
||||
combined.add(section);
|
||||
DebugCommand.SendDebugMessage("Added " + (!escaped ? "not " : "") + "escaped section: " + section);
|
||||
continue;
|
||||
}
|
||||
if (!escaped) {
|
||||
if (nextSection.containsKey(section.Formatters.get(0))) {
|
||||
FormattedSection s = nextSection.remove(section.Formatters.get(0));
|
||||
s.End = section.Start;
|
||||
s.IsRange = false; // IsRange means it's a 1 long section indicating a start or an end
|
||||
combined.add(s);
|
||||
DebugCommand.SendDebugMessage("Finished section: " + s);
|
||||
} else {
|
||||
DebugCommand.SendDebugMessage("Adding next section: " + section);
|
||||
nextSection.put(section.Formatters.get(0), section);
|
||||
}
|
||||
} else {
|
||||
DebugCommand.SendDebugMessage("Skipping section: " + section);
|
||||
escaped = false; // Reset escaping if applied, like if we're at the '*' in '\*'
|
||||
}
|
||||
}
|
||||
sections = combined;
|
||||
boolean cont = true;
|
||||
boolean found = false;
|
||||
for (int i = 1; cont;) {
|
||||
|
@ -90,7 +127,7 @@ public final class ChatFormatter {
|
|||
}
|
||||
FormattedSection section = new FormattedSection(firstSection.Formatters, sections.get(i).Start, origend,
|
||||
firstSection.Matches, sections.get(i).RemCharFromStart, firstSection.RemCharFromEnd,
|
||||
Collections.emptyList());
|
||||
Collections.emptyList(), false);
|
||||
section.Formatters.addAll(sections.get(i).Formatters);
|
||||
section.Matches.addAll(sections.get(i).Matches); // TODO: Clean
|
||||
sections.add(i, section);
|
||||
|
@ -169,7 +206,7 @@ public final class ChatFormatter {
|
|||
if (formatter.color != null)
|
||||
color = formatter.color;
|
||||
if (formatter.format != null)
|
||||
format = formatter.format.getFlag(); //TODO: Fix
|
||||
format = formatter.format.getFlag(); // TODO: Fix
|
||||
if (formatter.openlink != null)
|
||||
openlink = formatter.openlink;
|
||||
}
|
||||
|
@ -192,6 +229,6 @@ public final class ChatFormatter {
|
|||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("F(").append(color).append(", ").append(format).append(", ").append(openlink)
|
||||
.append(", ").append(priority).append(")").toString();
|
||||
.append(", ").append(priority).append(", ").append(regex).append(")").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ public class ChatFormatterBuilder {
|
|||
private Priority priority;
|
||||
private short removecharcount = 0;
|
||||
private short removecharpos = -1;
|
||||
private boolean range = false;
|
||||
|
||||
public ChatFormatter build() {
|
||||
return new ChatFormatter(regex, format, color, onmatch, openlink, priority, removecharcount, removecharpos);
|
||||
return new ChatFormatter(regex, format, color, onmatch, openlink, priority, removecharcount, removecharpos,
|
||||
range);
|
||||
}
|
||||
|
||||
public Pattern getRegex() {
|
||||
|
@ -100,4 +102,13 @@ public class ChatFormatterBuilder {
|
|||
this.removecharpos = removecharpos;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
public ChatFormatterBuilder setRange(boolean range) {
|
||||
this.range = range;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ class FormattedSection {
|
|||
short RemCharFromStart;
|
||||
short RemCharFromEnd;
|
||||
ArrayList<Integer> RemCharPos = new ArrayList<Integer>();
|
||||
boolean IsRange;
|
||||
|
||||
FormattedSection(ChatFormatter formatter, int start, int end, ArrayList<String> matches, short remcharfromstart,
|
||||
short remcharfromend, int remcharpos) {
|
||||
short remcharfromend, int remcharpos, boolean isrange) {
|
||||
Start = start;
|
||||
End = end;
|
||||
Formatters.add(formatter);
|
||||
|
@ -21,10 +22,11 @@ class FormattedSection {
|
|||
RemCharFromStart = remcharfromstart;
|
||||
RemCharFromEnd = remcharfromend;
|
||||
RemCharPos.add(remcharpos);
|
||||
IsRange = isrange;
|
||||
}
|
||||
|
||||
FormattedSection(Collection<ChatFormatter> formatters, int start, int end, ArrayList<String> matches,
|
||||
short remcharfromstart, short remcharfromend, Collection<Integer> remcharpos) {
|
||||
short remcharfromstart, short remcharfromend, Collection<Integer> remcharpos, boolean isrange) {
|
||||
Start = start;
|
||||
End = end;
|
||||
Formatters.addAll(formatters);
|
||||
|
@ -32,6 +34,7 @@ class FormattedSection {
|
|||
RemCharFromStart = remcharfromstart;
|
||||
RemCharFromEnd = remcharfromend;
|
||||
RemCharPos.addAll(remcharpos);
|
||||
IsRange = isrange;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,6 +42,6 @@ class FormattedSection {
|
|||
return new StringBuilder("Section(").append(Start).append(", ").append(End).append(", formatters: ")
|
||||
.append(Formatters.toString()).append(", matches: ").append(Matches.toString()).append(", RemChars: ")
|
||||
.append(RemCharFromStart).append(", ").append(RemCharFromEnd).append(", ").append(RemCharPos)
|
||||
.append(")").toString();
|
||||
.append(", ").append(IsRange).append(")").toString();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue