diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java index cc8e715023..66368f4fdb 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java @@ -3,23 +3,28 @@ package org.bukkit.craftbukkit.util; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import net.minecraft.server.ChatClickable; import net.minecraft.server.ChatComponentText; import net.minecraft.server.ChatModifier; import net.minecraft.server.EnumChatFormat; +import net.minecraft.server.EnumClickAction; import net.minecraft.server.IChatBaseComponent; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; public final class CraftChatMessage { - private static class FromString { + private static class StringMessage { private static final Map formatMap; + private static final Pattern INCREMENTAL_PATTERN = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-or])|(\\n)|(?:(https?://[^ ][^ ]*?)(?=[\\.\\?!,;:]?(?:[ \\n]|$)))", Pattern.CASE_INSENSITIVE); static { Builder builder = ImmutableMap.builder(); for (EnumChatFormat format : EnumChatFormat.values()) { - builder.put(format.getChar(), format); + builder.put(Character.toLowerCase(format.getChar()), format); } formatMap = builder.build(); } @@ -27,25 +32,29 @@ public final class CraftChatMessage { private final List list = new ArrayList(); private IChatBaseComponent currentChatComponent = new ChatComponentText(""); private ChatModifier modifier = new ChatModifier(); - private StringBuilder builder = new StringBuilder(); private final IChatBaseComponent[] output; + private int currentIndex; + private final String message; - private FromString(String message) { + private StringMessage(String message) { + this.message = message; if (message == null) { output = new IChatBaseComponent[] { currentChatComponent }; return; } list.add(currentChatComponent); - EnumChatFormat format = null; - - for (int i = 0; i < message.length(); i++) { - char currentChar = message.charAt(i); - if (currentChar == '\u00A7' && (i < (message.length() - 1)) && (format = formatMap.get(message.charAt(i + 1))) != null) { - if (builder.length() > 0) { - appendNewComponent(); - } - + Matcher matcher = INCREMENTAL_PATTERN.matcher(message); + String match = null; + while (matcher.find()) { + int groupId = 0; + while ((match = matcher.group(++groupId)) == null) { + // NOOP + } + appendNewComponent(matcher.start(groupId)); + switch (groupId) { + case 1: + EnumChatFormat format = formatMap.get(match.toLowerCase().charAt(1)); if (format == EnumChatFormat.RESET) { modifier = new ChatModifier(); } else if (format.isFormat()) { @@ -71,27 +80,31 @@ public final class CraftChatMessage { } else { // Color resets formatting modifier = new ChatModifier().setColor(format); } - i++; - } else if (currentChar == '\n') { - if (builder.length() > 0) { - appendNewComponent(); - } + break; + case 2: currentChatComponent = null; - } else { - builder.append(currentChar); + break; + case 3: + modifier.a(new ChatClickable(EnumClickAction.OPEN_URL, match)); // Should be setChatClickable + appendNewComponent(matcher.end(groupId)); + modifier.a((ChatClickable) null); } + currentIndex = matcher.end(groupId); } - if (builder.length() > 0) { - appendNewComponent(); + if (currentIndex < message.length()) { + appendNewComponent(message.length()); } output = list.toArray(new IChatBaseComponent[0]); } - private void appendNewComponent() { - IChatBaseComponent addition = new ChatComponentText(builder.toString()).setChatModifier(modifier); - builder = new StringBuilder(); + private void appendNewComponent(int index) { + if (index <= currentIndex) { + return; + } + IChatBaseComponent addition = new ChatComponentText(message.substring(currentIndex, index)).setChatModifier(modifier); + currentIndex = index; modifier = modifier.clone(); if (currentChatComponent == null) { currentChatComponent = new ChatComponentText(""); @@ -106,7 +119,7 @@ public final class CraftChatMessage { } public static IChatBaseComponent[] fromString(String message) { - return new FromString(message).getOutput(); + return new StringMessage(message).getOutput(); } private CraftChatMessage() {