parent
0dbfaa65a5
commit
4d0c7c170e
10 changed files with 109 additions and 39 deletions
|
@ -50,26 +50,26 @@ public class ChatProcessing {
|
|||
private static ArrayList<MatchProviderBase> commonFormatters = Lists.newArrayList(
|
||||
new RangeMatchProvider("bold", "**", FormatSettings.builder().bold(true).build()),
|
||||
new RangeMatchProvider("italic", "*", FormatSettings.builder().italic(true).build()),
|
||||
new RangeMatchProvider("italic2", "_", FormatSettings.builder().italic(true).build()),
|
||||
new RangeMatchProvider("underlined", "__", FormatSettings.builder().underlined(true).build()),
|
||||
new RangeMatchProvider("italic2", "_", FormatSettings.builder().italic(true).build()),
|
||||
new RangeMatchProvider("strikethrough", "~~", FormatSettings.builder().strikethrough(true).build()),
|
||||
new RangeMatchProvider("spoiler", "||", FormatSettings.builder().obfuscated(true)
|
||||
.onmatch((match, cf, fs) -> {
|
||||
cf.setHoverText(match);
|
||||
return match;
|
||||
}).build()),
|
||||
new StringMatchProvider("nullMention", FormatSettings.builder().color(Color.DarkRed).build(), "null"), // Properly added a bug as a feature
|
||||
new StringMatchProvider("nullMention", FormatSettings.builder().color(Color.DarkRed).build(), true, "null"), // Properly added a bug as a feature
|
||||
new StringMatchProvider("consolePing", FormatSettings.builder().color(Color.Aqua)
|
||||
.onmatch((match, builder, section) -> {
|
||||
if (!pingedconsole) {
|
||||
System.out.print("\007");
|
||||
pingedconsole = true; // Will set it to false in ProcessChat
|
||||
}
|
||||
return match;
|
||||
}).build(), "@console"),
|
||||
return "@console";
|
||||
}).build(), true, "@console"),
|
||||
|
||||
new RegexMatchProvider("hashtag", HASHTAG_PATTERN, FormatSettings.builder().color(Color.Blue).openlink("https://twitter.com/hashtag/$1").build()),
|
||||
new StringMatchProvider("cyan", FormatSettings.builder().color(Color.Aqua).build(), "cyan"), // #55
|
||||
new StringMatchProvider("cyan", FormatSettings.builder().color(Color.Aqua).build(), true, "cyan"), // #55
|
||||
new RangeMatchProvider("code", "`", FormatSettings.builder().color(Color.DarkGray).build()),
|
||||
new RegexMatchProvider("maskedLink", MASKED_LINK_PATTERN, FormatSettings.builder().underlined(true)
|
||||
.onmatch((match, builder, section) -> {
|
||||
|
@ -88,7 +88,7 @@ public class ChatProcessing {
|
|||
var player = players.get(playerC);
|
||||
playPingSound(player, ComponentManager.getIfEnabled(FormatterComponent.class));
|
||||
return "@someone (" + player.getDisplayName() + "§r)";
|
||||
}).build()));
|
||||
}).build(), true, "@someone"));
|
||||
private static Gson gson = new GsonBuilder()
|
||||
.registerTypeHierarchyAdapter(TellrawSerializableEnum.class, new TellrawSerializer.TwEnum())
|
||||
.registerTypeHierarchyAdapter(Collection.class, new TellrawSerializer.TwCollection())
|
||||
|
@ -265,8 +265,8 @@ public class ChatProcessing {
|
|||
System.out.println(message);
|
||||
};
|
||||
|
||||
if (names.length > 0)
|
||||
formatters.add(new StringMatchProvider("name", FormatSettings.builder().color(Color.Aqua)
|
||||
if (names.length > 0) //Add as first so it handles special characters (_) - TODO: But after URLs
|
||||
formatters.add(0, new StringMatchProvider("name", FormatSettings.builder().color(Color.Aqua)
|
||||
.onmatch((match, builder, section) -> {
|
||||
Player p = Bukkit.getPlayer(match);
|
||||
Optional<String> pn = nottest ? Optional.empty()
|
||||
|
@ -281,10 +281,10 @@ public class ChatProcessing {
|
|||
}
|
||||
String color = String.format("§%x", (mpp.GetFlairColor() == 0x00 ? 0xb : mpp.GetFlairColor()));
|
||||
return color + (nottest ? p.getName() : pn.get()) + "§r"; //Fix name casing, except when testing
|
||||
}).build(), names));
|
||||
}).build(), true, names));
|
||||
|
||||
if (nicknames.length > 0)
|
||||
formatters.add(new StringMatchProvider("nickname", FormatSettings.builder().color(Color.Aqua)
|
||||
if (nicknames.length > 0) //Add as first so it handles special characters
|
||||
formatters.add(0, new StringMatchProvider("nickname", FormatSettings.builder().color(Color.Aqua)
|
||||
.onmatch((match, builder, section) -> {
|
||||
if (PlayerListener.nicknames.containsKey(match.toLowerCase())) { //Made a stream and all that but I can actually store it lowercased
|
||||
Player p = Bukkit.getPlayer(PlayerListener.nicknames.get(match.toLowerCase()));
|
||||
|
@ -299,7 +299,7 @@ public class ChatProcessing {
|
|||
error.accept("Player nicknamed " + match.toLowerCase()
|
||||
+ " not found in nickname map but was reported as online.");
|
||||
return "§c" + match + "§r";
|
||||
}).build(), nicknames));
|
||||
}).build(), true, nicknames));
|
||||
}
|
||||
return formatters;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import buttondevteam.chat.commands.ucmds.admin.DebugCommand;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class ChatFormatUtils {
|
||||
private ChatFormatUtils() {}
|
||||
|
@ -26,6 +27,9 @@ public final class ChatFormatUtils {
|
|||
* Check if the given start and end position is inside any of the ranges
|
||||
*/
|
||||
static boolean isInRange(int start, int end, ArrayList<int[]> ranges) {
|
||||
return ranges.stream().anyMatch(range -> range[1] >= start && range[0] <= end - 1);
|
||||
System.out.println("Ranges: " + ranges.stream().map(x -> x[0] + "-" + x[1]).collect(Collectors.joining(", ")));
|
||||
System.out.println("In range: " + start + " " + end + ": " +
|
||||
ranges.stream().filter(range -> range[1] >= start && range[0] <= end).map(x -> x[0] + "-" + x[1]).findAny().orElse("none"));
|
||||
return ranges.stream().anyMatch(range -> range[1] >= start && range[0] <= end);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.util.function.Predicate;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A {@link ChatFormatter} shows what formatting to use based on regular expressions. {@link ChatFormatter#Combine(List, String, TellrawPart, IHaveConfig)} is used to turn it into a {@link TellrawPart}, combining
|
||||
* A {@link ChatFormatter} shows what formatting to use based on regular expressions. {@link ChatFormatter#Combine(List, String, TellrawPart, IHaveConfig, FormatSettings)}} 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 <i>and italics</i> part, finally an underlined part
|
||||
* again.
|
||||
*
|
||||
|
@ -40,6 +40,8 @@ public final class ChatFormatter {
|
|||
*/
|
||||
val remchars = new ArrayList<int[]>();
|
||||
|
||||
escapeThings(str, excluded, remchars);
|
||||
|
||||
createSections(formatters, str, sections, excluded, remchars, defaults);
|
||||
sortSections(sections);
|
||||
|
||||
|
@ -51,21 +53,35 @@ public final class ChatFormatter {
|
|||
header("ChatFormatter.Combine done");
|
||||
}
|
||||
|
||||
private static void escapeThings(String str, ArrayList<int[]> ignoredAreas, ArrayList<int[]> remchars) {
|
||||
boolean escaped = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (str.charAt(i) == '\\') {
|
||||
remchars.add(new int[]{i, i});
|
||||
ignoredAreas.add(new int[]{i + 1, i + 1});
|
||||
i++; //Ignore a potential second slash
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSections(List<MatchProviderBase> formatters, String str, ArrayList<FormattedSection> sections,
|
||||
ArrayList<int[]> excludedAreas, ArrayList<int[]> removedCharacters, FormatSettings defaults) {
|
||||
sections.add(new FormattedSection(defaults, 0, str.length() - 1, Collections.emptyList())); //Add entire message
|
||||
formatters.forEach(MatchProviderBase::reset); //Reset state information, as we aren't doing deep cloning
|
||||
while (formatters.size() > 0) {
|
||||
for (var iterator = formatters.iterator(); iterator.hasNext(); ) {
|
||||
MatchProviderBase formatter = iterator.next();
|
||||
DebugCommand.SendDebugMessage("Checking provider: " + formatter);
|
||||
var sect = formatter.getNextSection(str, excludedAreas, removedCharacters);
|
||||
if (sect != null)
|
||||
if (sect != null) //Not excluding the area here because the range matcher shouldn't take it all
|
||||
sections.add(sect);
|
||||
if (formatter.isFinished())
|
||||
if (formatter.isFinished()) {
|
||||
DebugCommand.SendDebugMessage("Provider finished");
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void combineSections(String str, ArrayList<FormattedSection> sections) {
|
||||
for (int i = 1; i < sections.size(); i++) {
|
||||
|
@ -103,12 +119,8 @@ public final class ChatFormatter {
|
|||
FormattedSection section = new FormattedSection(firstSection.Settings, lastSection.Start, origend,
|
||||
firstSection.Matches);
|
||||
section.Settings.copyFrom(lastSection.Settings);
|
||||
section.Matches.addAll(lastSection.Matches); // TODO: Clean
|
||||
section.Matches.addAll(lastSection.Matches);
|
||||
sections.add(i, section);
|
||||
// Use the properties of the first section not the second one
|
||||
lastSection.Settings = firstSection.Settings;
|
||||
lastSection.Matches.clear();
|
||||
lastSection.Matches.addAll(firstSection.Matches);
|
||||
|
||||
lastSection.Start = origend + 1;
|
||||
lastSection.End = origend2;
|
||||
|
|
|
@ -19,11 +19,15 @@ public class FormatSettings {
|
|||
|
||||
public void copyFrom(FormatSettings settings) {
|
||||
try {
|
||||
for (var field : FormatSettings.class.getDeclaredFields())
|
||||
if (field.getType() == boolean.class && field.getBoolean(settings))
|
||||
for (var field : FormatSettings.class.getDeclaredFields()) {
|
||||
if (field.getType() == boolean.class) {
|
||||
if (field.getBoolean(settings))
|
||||
field.setBoolean(this, true); //Set to true if either of them are true
|
||||
else if (field.get(this) == null)
|
||||
} else if (field.get(settings) != null) {
|
||||
//System.out.println("Setting " + field.getType() + " " + field.getName() + " from " + field.get(this) + " to " + field.get(settings));
|
||||
field.set(this, field.get(settings));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ public class FormattedSection {
|
|||
FormattedSection(FormatSettings settings, int start, int end, List<String> matches) {
|
||||
Start = start;
|
||||
End = end;
|
||||
Settings = settings;
|
||||
Settings = FormatSettings.builder().build();
|
||||
Settings.copyFrom(settings);
|
||||
Matches.addAll(matches);
|
||||
}
|
||||
}
|
|
@ -10,4 +10,9 @@ public interface MatchProvider {
|
|||
boolean isFinished();
|
||||
|
||||
String getName();
|
||||
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
void reset();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,13 @@ public abstract class MatchProviderBase implements MatchProvider {
|
|||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
protected abstract void resetSubclass();
|
||||
|
||||
public void reset() {
|
||||
finished = false;
|
||||
resetSubclass();
|
||||
}
|
||||
|
||||
ConfigData<Boolean> enabled(IHaveConfig config) {
|
||||
return config.getData(name + ".enabled", true);
|
||||
}
|
||||
|
|
|
@ -24,16 +24,18 @@ public class RangeMatchProvider extends MatchProviderBase {
|
|||
@Override
|
||||
public FormattedSection getNextSection(String message, ArrayList<int[]> ignoredAreas, ArrayList<int[]> removedCharacters) {
|
||||
int i, len;
|
||||
do {
|
||||
i = message.indexOf(pattern, nextIndex);
|
||||
len = pattern.length();
|
||||
nextIndex = i + len; //Set for the next loop if it's escaped or for the next method call
|
||||
} while (i > 0 && message.charAt(i - 1) == '\\');
|
||||
nextIndex = i + len; //Set for the next method call
|
||||
if (i == -1) {
|
||||
finished = true; //Won't find any more - unfinished sections will be garbage collected
|
||||
return null;
|
||||
}
|
||||
removedCharacters.add(new int[]{i, i + len - 1});
|
||||
if (ChatFormatUtils.isInRange(i, i + len - 1, ignoredAreas)) {
|
||||
DebugCommand.SendDebugMessage("Range start is in ignored area, skipping");
|
||||
return null; //Not setting finished to true, so it will go to the next match
|
||||
}
|
||||
ignoredAreas.add(new int[]{i, i + len - 1});
|
||||
if (startedSection == null) {
|
||||
DebugCommand.SendDebugMessage("Started range match from " + i + " to " + (i + len - 1));
|
||||
DebugCommand.SendDebugMessage("With settings: " + settings);
|
||||
|
@ -41,11 +43,21 @@ public class RangeMatchProvider extends MatchProviderBase {
|
|||
startedSection = new FormattedSection(settings, i, i + len - 1, Collections.emptyList());
|
||||
return null;
|
||||
} else {
|
||||
DebugCommand.SendDebugMessage("Finished range match from " + i + " to " + (i + len - 1));
|
||||
var section = startedSection;
|
||||
DebugCommand.SendDebugMessage("Finished range match from " + section.Start + " to " + (i + len - 1));
|
||||
DebugCommand.SendDebugMessage("With settings: " + settings);
|
||||
ChatFormatUtils.sendMessageWithPointer(message, i, i + len - 1);
|
||||
startedSection.End = i + len - 1;
|
||||
return startedSection;
|
||||
ChatFormatUtils.sendMessageWithPointer(message, section.Start, i + len - 1);
|
||||
section.End = i + len - 1;
|
||||
removedCharacters.add(new int[]{section.Start, section.Start + len - 1});
|
||||
removedCharacters.add(new int[]{i, i + len - 1});
|
||||
startedSection = null; //Reset so next find creates a new one
|
||||
return section;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetSubclass() {
|
||||
nextIndex = 0;
|
||||
startedSection = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class RegexMatchProvider extends MatchProviderBase {
|
|||
DebugCommand.SendDebugMessage("With settings: " + settings);
|
||||
ChatFormatUtils.sendMessageWithPointer(message, start, end);
|
||||
if (ChatFormatUtils.isInRange(start, end, ignoredAreas)) {
|
||||
DebugCommand.SendDebugMessage("Formatter is in ignored area, skipping");
|
||||
DebugCommand.SendDebugMessage("Match is in ignored area, skipping");
|
||||
return null; //Not setting finished to true, so it will go to the next match
|
||||
}
|
||||
ArrayList<String> groups = new ArrayList<>();
|
||||
|
@ -43,6 +43,12 @@ public class RegexMatchProvider extends MatchProviderBase {
|
|||
groups.add(matcher.group(i + 1));
|
||||
if (groups.size() > 0)
|
||||
DebugCommand.SendDebugMessage("First group: " + groups.get(0));
|
||||
ignoredAreas.add(new int[]{start, end});
|
||||
return new FormattedSection(settings, matcher.start(), matcher.end() - 1, groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetSubclass() {
|
||||
matcher = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ public class StringMatchProvider extends MatchProviderBase {
|
|||
@ToString.Exclude
|
||||
private final FormatSettings settings;
|
||||
private int nextIndex = 0;
|
||||
private boolean ignoreCase;
|
||||
|
||||
/**
|
||||
* Matches the given strings in the order given
|
||||
|
@ -20,15 +21,23 @@ public class StringMatchProvider extends MatchProviderBase {
|
|||
* @param settings The format settings
|
||||
* @param strings The strings to match in the correct order
|
||||
*/
|
||||
public StringMatchProvider(String name, FormatSettings settings, String... strings) {
|
||||
public StringMatchProvider(String name, FormatSettings settings, boolean ignoreCase, String... strings) {
|
||||
super(name);
|
||||
this.settings = settings;
|
||||
this.strings = strings;
|
||||
this.ignoreCase = ignoreCase;
|
||||
if (ignoreCase) {
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
strings[i] = strings[i].toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public FormattedSection getNextSection(String message, ArrayList<int[]> ignoredAreas, ArrayList<int[]> removedCharacters) {
|
||||
if (ignoreCase)
|
||||
message = message.toLowerCase();
|
||||
int i = -1, len = 0;
|
||||
for (String string : strings) {
|
||||
i = message.indexOf(string, nextIndex);
|
||||
|
@ -40,9 +49,19 @@ public class StringMatchProvider extends MatchProviderBase {
|
|||
return null;
|
||||
}
|
||||
nextIndex = i + len;
|
||||
if (ChatFormatUtils.isInRange(i, i + len - 1, ignoredAreas)) {
|
||||
DebugCommand.SendDebugMessage("String is in ignored area, skipping");
|
||||
return null; //Not setting finished to true, so it will go to the next match
|
||||
}
|
||||
DebugCommand.SendDebugMessage("Found string match from " + i + " to " + (i + len - 1));
|
||||
DebugCommand.SendDebugMessage("With settings: " + settings);
|
||||
ChatFormatUtils.sendMessageWithPointer(message, i, i + len - 1);
|
||||
ignoredAreas.add(new int[]{i, i + len - 1});
|
||||
return new FormattedSection(settings, i, i + len - 1, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetSubclass() {
|
||||
nextIndex = 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue