Merge pull request #59 from TBMCPlugins/chatformat

Fixed chat formatting - Mostly ¯\_(ツ)_/¯
This commit is contained in:
Norbi Peti 2016-12-30 22:05:01 +01:00 committed by GitHub
commit e8fa82d10d
4 changed files with 131 additions and 79 deletions

View file

@ -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");

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}