From 88ebcc8db59eb9a8aeb9a7ca4480db2042df9789 Mon Sep 17 00:00:00 2001 From: Erik Broes Date: Mon, 25 Apr 2011 18:14:06 +0200 Subject: [PATCH] Fix TextWrapping issues; Now limits the packets send to the client to either: 119 chars or 320 width. This will strip disallowed characters, propagate colors properly to the next line and not 'eat' multiple color-codes. --- .../minecraft/server/NetServerHandler.java | 9 +- .../java/net/minecraft/server/Packet.java | 4 +- .../net/minecraft/server/Packet3Chat.java | 38 +++++++++ .../org/bukkit/craftbukkit/TextWrapper.java | 82 ++++++++++++------- .../craftbukkit/entity/CraftPlayer.java | 10 +-- 5 files changed, 103 insertions(+), 40 deletions(-) create mode 100644 src/main/java/net/minecraft/server/Packet3Chat.java diff --git a/src/main/java/net/minecraft/server/NetServerHandler.java b/src/main/java/net/minecraft/server/NetServerHandler.java index 747c054864..12c2cd4f1b 100644 --- a/src/main/java/net/minecraft/server/NetServerHandler.java +++ b/src/main/java/net/minecraft/server/NetServerHandler.java @@ -14,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.event.CraftEventFactory; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.TextWrapper; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.block.*; @@ -579,9 +580,15 @@ public class NetServerHandler extends NetHandler implements ICommandListener { if (packet instanceof Packet6SpawnPosition) { Packet6SpawnPosition packet6 = (Packet6SpawnPosition) packet; this.player.compassTarget = new Location(getPlayer().getWorld(), packet6.x, packet6.y, packet6.z); + } else if (packet instanceof Packet3Chat) { + String message = ((Packet3Chat) packet).a; + for (final String line: TextWrapper.wrapText(message)) { + this.networkManager.a(new Packet3Chat(line)); + } + packet = null; } + if (packet != null) this.networkManager.a(packet); // CraftBukkit - this.networkManager.a(packet); this.g = this.f; } diff --git a/src/main/java/net/minecraft/server/Packet.java b/src/main/java/net/minecraft/server/Packet.java index ba71f4f9eb..116468a2e2 100644 --- a/src/main/java/net/minecraft/server/Packet.java +++ b/src/main/java/net/minecraft/server/Packet.java @@ -150,9 +150,9 @@ public abstract class Packet { } } - public abstract void a(DataInputStream datainputstream); + public abstract void a(DataInputStream datainputstream) throws IOException; // CraftBukkit - public abstract void a(DataOutputStream dataoutputstream); + public abstract void a(DataOutputStream dataoutputstream) throws IOException; // CraftBukkit public abstract void a(NetHandler nethandler); diff --git a/src/main/java/net/minecraft/server/Packet3Chat.java b/src/main/java/net/minecraft/server/Packet3Chat.java new file mode 100644 index 0000000000..613cfcab43 --- /dev/null +++ b/src/main/java/net/minecraft/server/Packet3Chat.java @@ -0,0 +1,38 @@ +package net.minecraft.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet3Chat extends Packet { + + public String a; + + public Packet3Chat() {} + + public Packet3Chat(String s) { + // CraftBukkit start - handle this later + //if (s.length() > 119) { + // s = s.substring(0, 119); + //} + // CraftBukkit end + + this.a = s; + } + + public void a(DataInputStream datainputstream) throws IOException { // CraftBukkit + this.a = a(datainputstream, 119); + } + + public void a(DataOutputStream dataoutputstream) throws IOException { // CraftBukkit + a(this.a, dataoutputstream); + } + + public void a(NetHandler nethandler) { + nethandler.a(this); + } + + public int a() { + return this.a.length(); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/TextWrapper.java b/src/main/java/org/bukkit/craftbukkit/TextWrapper.java index f20388d93e..836fe7d16b 100644 --- a/src/main/java/org/bukkit/craftbukkit/TextWrapper.java +++ b/src/main/java/org/bukkit/craftbukkit/TextWrapper.java @@ -2,6 +2,8 @@ package org.bukkit.craftbukkit; import java.util.regex.Pattern; +import javax.sound.sampled.LineListener; + public class TextWrapper { private static final int[] characterWidths = new int[] { 1, 9, 9, 8, 8, 8, 8, 7, 9, 8, 9, 9, 8, 9, 9, 9, @@ -21,50 +23,70 @@ public class TextWrapper { 8, 7, 7, 8, 7, 8, 8, 8, 7, 8, 8, 7, 9, 9, 6, 7, 7, 7, 7, 7, 9, 6, 7, 8, 7, 6, 6, 9, 7, 6, 7, 1 }; + private static final char COLOR_CHAR = '\u00A7'; private static final int CHAT_WINDOW_WIDTH = 320; - private static final Pattern pattern = Pattern.compile("\n.*\u00A7", Pattern.DOTALL); + private static final int CHAT_STRING_LENGTH = 119; + private static final String allowedChars = net.minecraft.server.FontAllowedCharacters.a; public static String[] wrapText(final String text) { final StringBuilder out = new StringBuilder(); char colorChar = 'f'; int lineWidth = 0; - int lineCount = 0; - boolean hasColored = true; + int lineLenght = 0; + + // Go over the message char by char. for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); - if (ch == '\u00A7' && i < text.length() - 1) { - colorChar = text.charAt(++i); - hasColored = false; - continue; - } else if (ch >= characterWidths.length) { - ch = (char) (characterWidths.length - 1); - } - final int width = characterWidths[(int) ch]; - if (lineWidth + width >= CHAT_WINDOW_WIDTH) { - out.append('\n'); - lineCount++; - if (colorChar != 'f') { - out.append('\u00A7'); - out.append(colorChar); + + // Get the color + if (ch == COLOR_CHAR && i < text.length() - 1) { + // We might need a linebreak ... so ugly ;( + if (lineLenght + 2 > CHAT_STRING_LENGTH) { + out.append('\n'); + lineLenght = 0; + if (colorChar != 'f') { + out.append(COLOR_CHAR).append(colorChar); + lineLenght += 2; + } + } + colorChar = text.charAt(++i); + out.append(COLOR_CHAR).append(colorChar); + lineLenght += 2; + continue; + } + + // Figure out if it's allowed + int index = allowedChars.indexOf(ch); + if (index == -1) { + // Invalid character .. skip it. + continue; + } else { + // Sadly needed as the allowedChars string misses the first + index += 32; + } + + // Find the width + final int width = characterWidths[ index ]; + + // See if we need a linebreak + if (lineLenght + 1 > CHAT_STRING_LENGTH || lineWidth + width >= CHAT_WINDOW_WIDTH) { + out.append('\n'); + lineLenght = 0; + + // Re-apply the last color if it isn't the default + if (colorChar != 'f') { + out.append(COLOR_CHAR).append(colorChar); + lineLenght += 2; } - out.append(ch); lineWidth = width; } else { - if (!hasColored) { - out.append('\u00A7'); - out.append(colorChar); - hasColored = true; - } - out.append(ch); lineWidth += width; } + out.append(ch); + lineLenght++; } - // See if we need to split the string - String result = out.toString(); - if (pattern.matcher(result).find()) return result.split("\n"); - - if (lineCount > 0) result.replace("\n", ""); - return new String[] {result}; + // Return it split + return out.toString().split("\n"); } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 694c14b332..bbd1c20991 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -5,7 +5,6 @@ import java.net.SocketAddress; import net.minecraft.server.EntityHuman; import net.minecraft.server.EntityPlayer; import net.minecraft.server.ItemInWorldManager; -import net.minecraft.server.Packet; import net.minecraft.server.Packet200Statistic; import net.minecraft.server.Packet3Chat; import net.minecraft.server.Packet6SpawnPosition; @@ -17,7 +16,6 @@ import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.TextWrapper; import org.bukkit.entity.Player; public class CraftPlayer extends CraftHumanEntity implements Player { @@ -84,9 +82,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { } public void sendMessage(String message) { - for (final String line: TextWrapper.wrapText(message)) { - getHandle().netServerHandler.sendPacket(new Packet3Chat(line)); - } + this.sendRawMessage(message); } public String getDisplayName() { @@ -256,7 +252,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { if (!material.isBlock()) { mat -= 255; } - + sendStatistic(statistic.getId() + mat, amount); } @@ -265,7 +261,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { sendStatistic(id, Byte.MAX_VALUE); amount -= Byte.MAX_VALUE; } - + getHandle().netServerHandler.sendPacket(new Packet200Statistic(id, amount)); } }