Fixed issue with color markers in messages sent to the client.

This fix eliminates crashes related to color markers being at end-of-line, and also makes colors persist across line breaks.

- The broadcast message is split up in multiple packets, one per line
- Color markers are reorganized, so that color 'sticks across lines'
- The wrapping method calculates the *rendered* line length. Thus, if the user has a weird font, it might look weird.
This commit is contained in:
David Flemström 2011-02-20 13:38:27 +01:00 committed by Erik Broes
parent 09026095b6
commit 5121ebb65d
3 changed files with 71 additions and 5 deletions

View File

@ -17,6 +17,7 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.TextWrapper;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event.Type; import org.bukkit.event.Event.Type;
import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockDamageEvent;
@ -608,10 +609,12 @@ public class NetServerHandler extends NetHandler implements ICommandListener {
if (event.isCancelled()) { if (event.isCancelled()) {
return true; return true;
} }
// CraftBukkit end
a.info(msg); a.info(msg);
this.d.f.a((Packet) (new Packet3Chat(msg))); for (final String line: TextWrapper.wrapText(msg)) {
this.d.f.a((Packet) (new Packet3Chat(line)));
}
// CraftBukkit end
} }
return false; return false;

View File

@ -0,0 +1,60 @@
package org.bukkit.craftbukkit;
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,
8, 8, 8, 8, 9, 9, 8, 9, 8, 8, 8, 8, 8, 9, 9, 9,
4, 2, 5, 6, 6, 6, 6, 3, 5, 5, 5, 6, 2, 6, 2, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 5, 6, 5, 6,
7, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 4, 6, 6,
3, 6, 6, 6, 6, 6, 5, 6, 6, 2, 6, 5, 3, 6, 6, 6,
6, 6, 6, 6, 4, 6, 6, 6, 6, 6, 6, 5, 2, 5, 7, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6, 3, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 6,
6, 3, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 2, 6, 6,
8, 9, 9, 6, 6, 6, 8, 8, 6, 8, 8, 8, 8, 8, 6, 6,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9, 9, 9, 5, 9, 9,
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 int CHAT_WINDOW_WIDTH = 318;
public static String[] wrapText(final String text) {
final StringBuilder out = new StringBuilder();
char colorChar = 'f';
int lineWidth = 0;
boolean hasColored = true;
for (int i = 0; i < text.length(); i++) {
char ch = text.charAt(i);
if (ch == '\u00A7' && i < text.length() - 1) {
i++;
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');
if (colorChar != 'f') {
out.append('\u00A7');
out.append(colorChar);
}
out.append(ch);
lineWidth = width;
} else {
if (!hasColored) {
out.append('\u00A7');
out.append(colorChar);
hasColored = true;
}
out.append(ch);
lineWidth += width;
}
}
return out.toString().split("\n");
}
}

View File

@ -14,6 +14,7 @@ import net.minecraft.server.WorldServer;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.TextWrapper;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class CraftPlayer extends CraftHumanEntity implements Player { public class CraftPlayer extends CraftHumanEntity implements Player {
@ -80,7 +81,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
} }
public void sendMessage(String message) { public void sendMessage(String message) {
entity.a.b(new Packet3Chat(message)); for (final String line: TextWrapper.wrapText(message)) {
entity.a.b(new Packet3Chat(line));
}
} }
public String getDisplayName() { public String getDisplayName() {