From d5ede3bd6dc19f645864f251d501a1765ed505f7 Mon Sep 17 00:00:00 2001 From: Thinkofdeath Date: Sat, 13 Dec 2014 10:26:06 +0000 Subject: [PATCH] Rework the vanilla link fix so that hover/click events aren't lost --- nms-patches/PlayerList.patch | 27 +++--- .../craftbukkit/util/CraftChatMessage.java | 86 ++++++++++++++++++- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/nms-patches/PlayerList.patch b/nms-patches/PlayerList.patch index 11e3e49c8b..fee1ed619d 100644 --- a/nms-patches/PlayerList.patch +++ b/nms-patches/PlayerList.patch @@ -1,5 +1,5 @@ ---- ../work/decompile-8eb82bde/net/minecraft/server/PlayerList.java 2014-12-13 09:37:43.506950406 +0000 -+++ src/main/java/net/minecraft/server/PlayerList.java 2014-12-13 09:35:13.993746030 +0000 +--- ../work/decompile-8eb82bde/net/minecraft/server/PlayerList.java 2014-12-13 10:25:48.845021085 +0000 ++++ src/main/java/net/minecraft/server/PlayerList.java 2014-12-13 10:25:34.093021245 +0000 @@ -18,6 +18,26 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -558,7 +558,8 @@ + double d1 = entity.locZ; + double d2 = 8.0D; + float f = entity.yaw; -+ + +- entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(entityplayer.getId(), mobeffect)); + worldserver.methodProfiler.a("moving"); + */ + if (worldserver1.dimension == -1) { @@ -599,8 +600,8 @@ + worldserver.entityJoinedWorld(entity, false); + } + */ -+ } -+ + } + + // worldserver.methodProfiler.b(); + if (i != 1) { + worldserver.methodProfiler.a("placing"); @@ -613,12 +614,11 @@ + worldserver1.addEntity(entity); + worldserver1.entityJoinedWorld(entity, false); + } - -- entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityEffect(entityplayer.getId(), mobeffect)); ++ + worldserver.methodProfiler.b(); + */ - } - ++ } ++ + // entity.spawnIn(worldserver1); + return new Location(worldserver1.getWorld(), d0, y, d1, yaw, pitch); } @@ -796,7 +796,7 @@ } public boolean getHasWhitelist() { -@@ -711,16 +1097,28 @@ +@@ -711,16 +1097,25 @@ public void v() { for (int i = 0; i < this.players.size(); ++i) { @@ -819,15 +819,12 @@ - this.sendAll(new PacketPlayOutChat(ichatbasecomponent, (byte) i)); + // CraftBukkit start - we run this through our processor first so we can get web links etc -+ // PAIL: Rename -+ for (IChatBaseComponent component : CraftChatMessage.fromString(CraftChatMessage.fromComponent(ichatbasecomponent, EnumChatFormat.WHITE))) { -+ this.sendAll(new PacketPlayOutChat(component, (byte) i)); -+ } ++ this.sendAll(new PacketPlayOutChat(CraftChatMessage.fixComponent(ichatbasecomponent), (byte) i)); + // CraftBukkit end } public void sendMessage(IChatBaseComponent ichatbasecomponent) { -@@ -754,11 +1152,10 @@ +@@ -754,11 +1149,10 @@ public void a(int i) { this.r = i; if (this.server.worldServer != null) { diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java index c3f27f1fe4..d2b41c302e 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java @@ -15,11 +15,14 @@ import net.minecraft.server.IChatBaseComponent; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; +import net.minecraft.server.ChatMessage; public final class CraftChatMessage { + + private static final Pattern LINK_PATTERN = Pattern.compile("((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " \\n]|$))))"); 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); + private static final Pattern INCREMENTAL_PATTERN = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-or])|(\\n)|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " \\n]|$))))", Pattern.CASE_INSENSITIVE); static { Builder builder = ImmutableMap.builder(); @@ -89,6 +92,9 @@ public final class CraftChatMessage { } break; case 3: + if ( !( match.startsWith( "http://" ) || match.startsWith( "https://" ) ) ) { + match = "http://" + match; + } modifier.setChatClickable(new ChatClickable(EnumClickAction.OPEN_URL, match)); appendNewComponent(matcher.end(groupId)); modifier.setChatClickable((ChatClickable) null); @@ -100,7 +106,7 @@ public final class CraftChatMessage { appendNewComponent(message.length()); } - output = list.toArray(new IChatBaseComponent[0]); + output = list.toArray(new IChatBaseComponent[list.size()]); } private void appendNewComponent(int index) { @@ -161,6 +167,82 @@ public final class CraftChatMessage { return out.toString().replaceFirst("^(" + defaultColor + ")*", ""); } + public static IChatBaseComponent fixComponent(IChatBaseComponent component) { + Matcher matcher = LINK_PATTERN.matcher(""); + return fixComponent(component, matcher); + } + + private static IChatBaseComponent fixComponent(IChatBaseComponent component, Matcher matcher) { + if (component instanceof ChatComponentText) { + ChatComponentText text = ((ChatComponentText) component); + String msg = text.g(); + if (matcher.reset(msg).find()) { + matcher.reset(); + + ChatModifier modifier = text.getChatModifier() != null ? + text.getChatModifier() : new ChatModifier(); + List extras = new ArrayList(); + List extrasOld = new ArrayList(text.a()); + component = text = new ChatComponentText(""); + + int pos = 0; + while (matcher.find()) { + String match = matcher.group(); + + if ( !( match.startsWith( "http://" ) || match.startsWith( "https://" ) ) ) { + match = "http://" + match; + } + + ChatComponentText prev = new ChatComponentText(msg.substring(pos, matcher.start())); + prev.setChatModifier(modifier); + extras.add(prev); + + ChatComponentText link = new ChatComponentText(matcher.group()); + ChatModifier linkModi = modifier.clone(); + linkModi.setChatClickable(new ChatClickable(EnumClickAction.OPEN_URL, match)); + link.setChatModifier(linkModi); + extras.add(link); + + pos = matcher.end(); + } + + ChatComponentText prev = new ChatComponentText(msg.substring(pos)); + prev.setChatModifier(modifier); + extras.add(prev); + extras.addAll(extrasOld); + + for (IChatBaseComponent c : extras) { + text.addSibling(c); + } + } + } + + List extras = component.a(); + for (int i = 0; i < extras.size(); i++) { + IChatBaseComponent comp = (IChatBaseComponent) extras.get(i); + if (comp.getChatModifier() != null && comp.getChatModifier().h() == null) { + extras.set(i, fixComponent(comp, matcher)); + } + } + + if (component instanceof ChatMessage) { + Object[] subs = ((ChatMessage) component).j(); + for (int i = 0; i < subs.length; i++) { + Object comp = subs[i]; + if (comp instanceof IChatBaseComponent) { + IChatBaseComponent c = (IChatBaseComponent) comp; + if (c.getChatModifier() != null && c.getChatModifier().h() == null) { + subs[i] = fixComponent(c, matcher); + } + } else if (comp instanceof String && matcher.reset((String)comp).find()) { + subs[i] = fixComponent(new ChatComponentText((String) comp), matcher); + } + } + } + + return component; + } + private CraftChatMessage() { } }