mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-09 11:44:19 +01:00
Process URLs as clickable. Adds BUKKIT-4917
In Minecraft 1.7, URL processing was removed from the client while the server gained the ability to designate a URL to be launched in response to clicking text. However, this functionality is not implemented in the vanilla server. This commit adds that functionality to messages sent to the client, processing URLs as clickable. Additionally, char array iteration is replaced with regex. By: mbax <matt@phozop.net>
This commit is contained in:
parent
8809265f76
commit
4caf845eae
1 changed files with 39 additions and 26 deletions
|
@ -3,23 +3,28 @@ package org.bukkit.craftbukkit.util;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.ChatComponentText;
|
||||||
import net.minecraft.server.ChatModifier;
|
import net.minecraft.server.ChatModifier;
|
||||||
import net.minecraft.server.EnumChatFormat;
|
import net.minecraft.server.EnumChatFormat;
|
||||||
|
import net.minecraft.server.EnumClickAction;
|
||||||
import net.minecraft.server.IChatBaseComponent;
|
import net.minecraft.server.IChatBaseComponent;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
|
|
||||||
public final class CraftChatMessage {
|
public final class CraftChatMessage {
|
||||||
private static class FromString {
|
private static class StringMessage {
|
||||||
private static final Map<Character, EnumChatFormat> formatMap;
|
private static final Map<Character, EnumChatFormat> 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 {
|
static {
|
||||||
Builder<Character, EnumChatFormat> builder = ImmutableMap.builder();
|
Builder<Character, EnumChatFormat> builder = ImmutableMap.builder();
|
||||||
for (EnumChatFormat format : EnumChatFormat.values()) {
|
for (EnumChatFormat format : EnumChatFormat.values()) {
|
||||||
builder.put(format.getChar(), format);
|
builder.put(Character.toLowerCase(format.getChar()), format);
|
||||||
}
|
}
|
||||||
formatMap = builder.build();
|
formatMap = builder.build();
|
||||||
}
|
}
|
||||||
|
@ -27,25 +32,29 @@ public final class CraftChatMessage {
|
||||||
private final List<IChatBaseComponent> list = new ArrayList<IChatBaseComponent>();
|
private final List<IChatBaseComponent> list = new ArrayList<IChatBaseComponent>();
|
||||||
private IChatBaseComponent currentChatComponent = new ChatComponentText("");
|
private IChatBaseComponent currentChatComponent = new ChatComponentText("");
|
||||||
private ChatModifier modifier = new ChatModifier();
|
private ChatModifier modifier = new ChatModifier();
|
||||||
private StringBuilder builder = new StringBuilder();
|
|
||||||
private final IChatBaseComponent[] output;
|
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) {
|
if (message == null) {
|
||||||
output = new IChatBaseComponent[] { currentChatComponent };
|
output = new IChatBaseComponent[] { currentChatComponent };
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
list.add(currentChatComponent);
|
list.add(currentChatComponent);
|
||||||
|
|
||||||
EnumChatFormat format = null;
|
Matcher matcher = INCREMENTAL_PATTERN.matcher(message);
|
||||||
|
String match = null;
|
||||||
for (int i = 0; i < message.length(); i++) {
|
while (matcher.find()) {
|
||||||
char currentChar = message.charAt(i);
|
int groupId = 0;
|
||||||
if (currentChar == '\u00A7' && (i < (message.length() - 1)) && (format = formatMap.get(message.charAt(i + 1))) != null) {
|
while ((match = matcher.group(++groupId)) == null) {
|
||||||
if (builder.length() > 0) {
|
// NOOP
|
||||||
appendNewComponent();
|
}
|
||||||
}
|
appendNewComponent(matcher.start(groupId));
|
||||||
|
switch (groupId) {
|
||||||
|
case 1:
|
||||||
|
EnumChatFormat format = formatMap.get(match.toLowerCase().charAt(1));
|
||||||
if (format == EnumChatFormat.RESET) {
|
if (format == EnumChatFormat.RESET) {
|
||||||
modifier = new ChatModifier();
|
modifier = new ChatModifier();
|
||||||
} else if (format.isFormat()) {
|
} else if (format.isFormat()) {
|
||||||
|
@ -71,27 +80,31 @@ public final class CraftChatMessage {
|
||||||
} else { // Color resets formatting
|
} else { // Color resets formatting
|
||||||
modifier = new ChatModifier().setColor(format);
|
modifier = new ChatModifier().setColor(format);
|
||||||
}
|
}
|
||||||
i++;
|
break;
|
||||||
} else if (currentChar == '\n') {
|
case 2:
|
||||||
if (builder.length() > 0) {
|
|
||||||
appendNewComponent();
|
|
||||||
}
|
|
||||||
currentChatComponent = null;
|
currentChatComponent = null;
|
||||||
} else {
|
break;
|
||||||
builder.append(currentChar);
|
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) {
|
if (currentIndex < message.length()) {
|
||||||
appendNewComponent();
|
appendNewComponent(message.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
output = list.toArray(new IChatBaseComponent[0]);
|
output = list.toArray(new IChatBaseComponent[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void appendNewComponent() {
|
private void appendNewComponent(int index) {
|
||||||
IChatBaseComponent addition = new ChatComponentText(builder.toString()).setChatModifier(modifier);
|
if (index <= currentIndex) {
|
||||||
builder = new StringBuilder();
|
return;
|
||||||
|
}
|
||||||
|
IChatBaseComponent addition = new ChatComponentText(message.substring(currentIndex, index)).setChatModifier(modifier);
|
||||||
|
currentIndex = index;
|
||||||
modifier = modifier.clone();
|
modifier = modifier.clone();
|
||||||
if (currentChatComponent == null) {
|
if (currentChatComponent == null) {
|
||||||
currentChatComponent = new ChatComponentText("");
|
currentChatComponent = new ChatComponentText("");
|
||||||
|
@ -106,7 +119,7 @@ public final class CraftChatMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IChatBaseComponent[] fromString(String message) {
|
public static IChatBaseComponent[] fromString(String message) {
|
||||||
return new FromString(message).getOutput();
|
return new StringMessage(message).getOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CraftChatMessage() {
|
private CraftChatMessage() {
|
||||||
|
|
Loading…
Reference in a new issue