Added a new Chat API

This commit is contained in:
Felix Cravic 2020-06-22 23:25:00 +02:00
parent 37440c51cf
commit f892213e8c
31 changed files with 810 additions and 261 deletions

View File

@ -43,7 +43,6 @@ dependencies {
// https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl
api group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.13.2'
api 'net.kyori:text-api:3.0.3'
api 'net.kyori:text-serializer-legacy:3.0.3'
api 'net.kyori:text-serializer-gson:3.0.3'
api 'net.kyori:text-serializer-plain:3.0.3'

View File

@ -1,14 +1,15 @@
package fr.themode.demo;
import fr.themode.demo.entity.ChickenCreature;
import fr.themode.demo.generator.ChunkGeneratorDemo;
import fr.themode.demo.generator.NoiseTestGenerator;
import net.minestom.server.MinecraftServer;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.chat.*;
import net.minestom.server.entity.*;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.type.EntityZombie;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.ItemUpdateStateEvent;
@ -39,19 +40,13 @@ import java.util.Map;
import java.util.UUID;
public class PlayerInit {
private static String textures = "ewogICJ0aW1lc3RhbXAiIDogMTU5MDg1NTI3NjIwNCwKICAicHJvZmlsZUlkIiA6ICI0NTY2ZTY5ZmM5MDc0OGVlOGQ3MWQ3YmE1YWEwMGQyMCIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGlua29mZGVhdGgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRkMWUwOGIwYmI3ZTlmNTkwYWYyNzc1ODEyNWJiZWQxNzc4YWM2Y2VmNzI5YWVkZmNiOTYxM2U5OTExYWU3NSIKICAgIH0sCiAgICAiQ0FQRSIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjBjYzA4ODQwNzAwNDQ3MzIyZDk1M2EwMmI5NjVmMWQ2NWExM2E2MDNiZjY0YjE3YzgwM2MyMTQ0NmZlMTYzNSIKICAgIH0KICB9Cn0=";
private static String signature = "rCVVwVpLF9ovy+Hm4cOXOLSPOMjNo5WoBfHo9K2OcTUPqcZJ1P/1k4lAnQkChD/Ri11iJ84PejWJzDkHMXM8196Wh+jf12d2GJVhca9/SRLms0cFJjdZZjs72+82AdX0OtO3+qzwKRHzHoEYb+ZVZLfgx37ZKKo4DD3IKmaSnwEjOVJ4BOhnsXLmcNW37kdZUmv2/hlg7ZuWZaayWPhadCYEMnkpVtDIpnpzAeV9EcRfg/ysQoynO2v6WEW0RtnfFEczMN6vXtfiuC8UqyA2SK9aiLnBgpGaehDfFIq/0dpo2uFilVDS/Il6uQ1JSwq7yNT5lNF+i1AlH9SGf1VVy5mT9ShmkVmRxCXX5cSNLXZD0acsNNJb/GAuDHuXpE32GsfgKxWAXMHLw0GnbADbFDfdl5nQyQTDS7FRfUjsFpF8a8Z83muFXaty2WLFy1zxy2JEkI/q+ltLaEG6mQbWI2zhOS7ARvK0OmPz4lDYVInfrwL93AIdMUg2Re817hsapkN6Dm1ND+iirvayR90gqQ9C9J0dMMBlSyTSoKBQeLsi8qETS+7LuhvletPTDFolnTIvP8hj2bWLmQ7LfXJ2arJCUw86YEavVYuF0gYrBuKcEYTC4DA0kO4yLj63gwEgOj9dEigCgyqUcenzmZBffSZ365/QF0cGrG7HC7HmF0w=";
private static PlayerSkin skin = new PlayerSkin(textures, signature);
private static volatile InstanceContainer instanceContainer;
private static volatile InstanceContainer netherTest;
private static volatile Inventory inventory;
static {
//StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("chunk_data");
//StorageFolder storageFolder = MinecraftServer.getStorageManager().getFolder("instance_data");
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator();
//instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(storageFolder);
@ -96,23 +91,26 @@ public class PlayerInit {
for (Map.Entry<String, ThreadResult> resultEntry : benchmarkManager.getResultMap().entrySet()) {
String name = resultEntry.getKey();
ThreadResult result = resultEntry.getValue();
benchmarkMessage += "&7" + name;
benchmarkMessage += ChatColor.GRAY + name;
benchmarkMessage += ": ";
benchmarkMessage += "&e" + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
benchmarkMessage += "&c" + MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
benchmarkMessage += "&d" + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
benchmarkMessage += "&a" + MathUtils.round(result.getWaitedPercentage(), 2) + "% WAITED ";
benchmarkMessage += ChatColor.YELLOW.toString() + MathUtils.round(result.getCpuPercentage(), 2) + "% CPU ";
benchmarkMessage += ChatColor.RED.toString() + MathUtils.round(result.getUserPercentage(), 2) + "% USER ";
benchmarkMessage += ChatColor.PINK.toString() + MathUtils.round(result.getBlockedPercentage(), 2) + "% BLOCKED ";
benchmarkMessage += ChatColor.BRIGHT_GREEN.toString() + MathUtils.round(result.getWaitedPercentage(), 2) + "% WAITED ";
benchmarkMessage += "\n";
}
for (Player player : connectionManager.getOnlinePlayers()) {
player.sendHeaderFooter("RAM USAGE: " + ramUsage + " MB", benchmarkMessage, '&');
ColoredText header = ColoredText.of("RAM USAGE: " + ramUsage + " MB");
ColoredText footer = ColoredText.of(benchmarkMessage);
player.sendHeaderFooter(header, footer);
}
}
}, new UpdateOption(10, TimeUnit.TICK));
connectionManager.addPacketConsumer((player, packetController, packet) -> {
// Listen to all received packet
//System.out.println("PACKET: "+packet.getClass().getSimpleName());
packetController.setCancel(false);
});
@ -153,9 +151,13 @@ public class PlayerInit {
p.teleport(player.getPosition());
}*/
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
/*ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
chickenCreature.setInstance(player.getInstance());
chickenCreature.setAttribute(Attribute.MOVEMENT_SPEED, 0.4f);
chickenCreature.setAttribute(Attribute.MOVEMENT_SPEED, 0.4f);*/
EntityZombie zombie = new EntityZombie(player.getPosition());
zombie.setAttribute(Attribute.MOVEMENT_SPEED, 0.25f);
zombie.setInstance(player.getInstance());
/*FakePlayer fakePlayer = new FakePlayer(UUID.randomUUID(), "test");
fakePlayer.addEventCallback(EntityDeathEvent.class, e -> {
@ -198,7 +200,12 @@ public class PlayerInit {
});
player.addEventCallback(PlayerLoginEvent.class, event -> {
//final String url = "https://download.mc-packs.net/pack/a83a04f5d78061e0890e13519fea925550461c74.zip";
//final String hash = "a83a04f5d78061e0890e13519fea925550461c74";
//player.setResourcePack(new ResourcePack(url, hash));
event.setSpawningInstance(instanceContainer);
player.setEnableRespawnScreen(false);
player.setPermissionLevel(4);
@ -217,10 +224,6 @@ public class PlayerInit {
scoreboard.setTitle("test");*/
});
player.addEventCallback(PlayerSkinInitEvent.class, event -> {
event.setSkin(skin);
});
player.addEventCallback(PlayerSpawnEvent.class, event -> {
player.setGameMode(GameMode.CREATIVE);
player.teleport(new Position(0, 41f, 0));
@ -228,16 +231,18 @@ public class PlayerInit {
player.setGlowing(true);
ItemStack item = new ItemStack(Material.STONE_SWORD, (byte) 1);
item.setDisplayName("Item name");
item.getLore().add("a lore line");
item.setDisplayName(ColoredText.of(ChatColor.BLUE + "Item name"));
item.getLore().add(ColoredText.of(ChatColor.RED + "a lore line"));
item.addItemFlags(ItemFlag.HIDE_ENCHANTS);
item.setEnchantment(Enchantment.SHARPNESS, (short) 50);
player.getInventory().addItemStack(item);
inventory.addItemStack(item.clone());
player.openInventory(inventory);
//player.setHelmet(new ItemStack(Material.DIAMOND_HELMET, (byte) 1));
player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 100));
inventory.addItemStack(item.clone());
//player.openInventory(inventory);
//player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte) 100));
Instance instance = player.getInstance();
WorldBorder worldBorder = instance.getWorldBorder();
@ -264,6 +269,23 @@ public class PlayerInit {
setBelowNameScoreboard(belowNameScoreboard);
belowNameScoreboard.updateScore(this, 50);*/
ColoredText coloredText1 = ColoredText.of(ChatColor.BLUE, "I am colored")
.append(ChatColor.BLUE, "I am the next")
.appendFormat("I am {#blue}here");
ColoredText coloredText2 =
ColoredText.ofFormat(
"I am {#green}colo{#red}red {#white}{&key.jump} keybind, {@attack.fall} translatable");
RichMessage richMessage1 = RichMessage.of(coloredText1)
.setClickEvent(ChatClickEvent.runCommand("/test"))
.setHoverEvent(ChatHoverEvent.showText("I'm a text"))
.append(coloredText2)
.setHoverEvent(ChatHoverEvent.showText("I'm a second text"));
player.sendMessage(richMessage1);
});
player.addEventCallback(PlayerRespawnEvent.class, event -> {

View File

@ -1,7 +1,7 @@
package net.minestom.server;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.EntityManager;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.InstanceManager;
@ -48,9 +48,7 @@ public final class UpdateManager {
player.refreshKeepAlive(time);
player.getPlayerConnection().sendPacket(keepAlivePacket);
} else if (lastKeepAlive >= KEEP_ALIVE_KICK) {
TextComponent textComponent = TextComponent.of("Timeout")
.color(TextColor.RED);
player.kick(textComponent);
player.kick(ColoredText.of(ChatColor.RED + "Timeout"));
}
}

View File

@ -1,7 +1,7 @@
package net.minestom.server.bossbar;
import net.minestom.server.Viewable;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.BossBarPacket;
import net.minestom.server.utils.MathUtils;
@ -20,13 +20,13 @@ public class BossBar implements Viewable {
private UUID uuid = UUID.randomUUID();
private Set<Player> viewers = new CopyOnWriteArraySet<>();
private String title;
private ColoredText title;
private float progress;
private BarColor color;
private BarDivision division;
private byte flags;
public BossBar(String title, BarColor color, BarDivision division) {
public BossBar(ColoredText title, BarColor color, BarDivision division) {
this.title = title;
this.color = color;
this.division = division;
@ -58,7 +58,7 @@ public class BossBar implements Viewable {
*
* @return the current title of the bossbar
*/
public String getTitle() {
public ColoredText getTitle() {
return title;
}
@ -67,7 +67,7 @@ public class BossBar implements Viewable {
*
* @param title the new title of the bossbar
*/
public void setTitle(String title) {
public void setTitle(ColoredText title) {
this.title = title;
}
@ -146,7 +146,7 @@ public class BossBar implements Viewable {
BossBarPacket bossBarPacket = new BossBarPacket();
bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.ADD;
bossBarPacket.title = Chat.fromLegacyText(title);
bossBarPacket.title = title;
bossBarPacket.health = progress;
bossBarPacket.color = color;
bossBarPacket.division = division;
@ -165,7 +165,7 @@ public class BossBar implements Viewable {
BossBarPacket bossBarPacket = new BossBarPacket();
bossBarPacket.uuid = uuid;
bossBarPacket.action = BossBarPacket.Action.UPDATE_TITLE;
bossBarPacket.title = Chat.fromLegacyText(title);
bossBarPacket.title = title;
sendPacketToViewers(bossBarPacket);
}

View File

@ -1,22 +1,11 @@
package net.minestom.server.chat;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.serializer.gson.GsonComponentSerializer;
import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
/**
* Thank for the minecraft-text library made by rbrick:
* https://github.com/ctmclub/minecraft-text
*/
public class Chat {
public static final char COLOR_CHAR = (char) 0xA7; // Represent the character '§'
public static String toJsonString(Component component) {
return GsonComponentSerializer.INSTANCE.serialize(component);
}
public static Component fromJsonString(String json) {
return GsonComponentSerializer.INSTANCE.deserialize(json);
}
@ -24,12 +13,4 @@ public class Chat {
public static String toLegacyText(Component component) {
return LegacyComponentSerializer.legacyLinking().serialize(component);
}
public static TextComponent fromLegacyText(String text, char colorChar) {
return LegacyComponentSerializer.legacyLinking().deserialize(text, colorChar);
}
public static TextComponent fromLegacyText(String text) {
return fromLegacyText(text, COLOR_CHAR);
}
}

View File

@ -0,0 +1,32 @@
package net.minestom.server.chat;
public class ChatClickEvent {
private String action;
private String value;
private ChatClickEvent(String action, String value) {
this.action = action;
this.value = value;
}
public static ChatClickEvent openUrl(String url) {
return new ChatClickEvent("open_url", url);
}
public static ChatClickEvent runCommand(String command) {
return new ChatClickEvent("run_command", command);
}
public static ChatClickEvent suggestCommand(String command) {
return new ChatClickEvent("suggest_command", command);
}
protected String getAction() {
return action;
}
protected String getValue() {
return value;
}
}

View File

@ -0,0 +1,135 @@
package net.minestom.server.chat;
import java.util.HashMap;
import java.util.Map;
public class ChatColor {
public static final ChatColor NO_COLOR = new ChatColor();
public static final ChatColor BLACK = new ChatColor("black", 0);
public static final ChatColor DARK_BLUE = new ChatColor("dark_blue", 1);
public static final ChatColor DARK_GREEN = new ChatColor("dark_green", 2);
public static final ChatColor DARK_CYAN = new ChatColor("dark_cyan", 3);
public static final ChatColor DARK_RED = new ChatColor("dark_red", 4);
public static final ChatColor PURPLE = new ChatColor("dark_purple", 5);
public static final ChatColor GOLD = new ChatColor("gold", 6);
public static final ChatColor GRAY = new ChatColor("gray", 7);
public static final ChatColor DARK_GRAY = new ChatColor("dark_gray", 8);
public static final ChatColor BLUE = new ChatColor("blue", 9);
public static final ChatColor BRIGHT_GREEN = new ChatColor("green", 10);
public static final ChatColor CYAN = new ChatColor("cyan", 11);
public static final ChatColor RED = new ChatColor("red", 12);
public static final ChatColor PINK = new ChatColor("light_purple", 13);
public static final ChatColor YELLOW = new ChatColor("yellow", 14);
public static final ChatColor WHITE = new ChatColor("white", 15);
/*public static final ChatColor BLACK = fromRGB(0, 0, 0);
public static final ChatColor DARK_BLUE = fromRGB(0, 0, 170);
public static final ChatColor DARK_GREEN = fromRGB(0, 170, 0);
public static final ChatColor DARK_CYAN = fromRGB(0, 170, 170);
public static final ChatColor DARK_RED = fromRGB(170, 0, 0);
public static final ChatColor PURPLE = fromRGB(170, 0, 170);
public static final ChatColor GOLD = fromRGB(255, 170, 0);
public static final ChatColor GRAY = fromRGB(170, 170, 170);
public static final ChatColor DARK_GRAY = fromRGB(85, 85, 85);
public static final ChatColor BLUE = fromRGB(85, 85, 255);
public static final ChatColor BRIGHT_GREEN = fromRGB(85, 255, 85);
public static final ChatColor CYAN = fromRGB(85, 255, 255);
public static final ChatColor RED = fromRGB(255, 85, 85);
public static final ChatColor PINK = fromRGB(255, 85, 255);
public static final ChatColor YELLOW = fromRGB(255, 255, 85);
public static final ChatColor WHITE = fromRGB(255, 255, 255);*/
private static Map<String, ChatColor> colorCode = new HashMap<>();
static {
colorCode.put("black", BLACK);
colorCode.put("dark_blue", DARK_BLUE);
colorCode.put("dark_green", DARK_GREEN);
colorCode.put("dark_cyan", DARK_CYAN);
colorCode.put("dark_red", DARK_RED);
colorCode.put("purple", PURPLE);
colorCode.put("gold", GOLD);
colorCode.put("gray", GRAY);
colorCode.put("dark_gray", DARK_GRAY);
colorCode.put("blue", BLUE);
colorCode.put("bright_green", BRIGHT_GREEN);
colorCode.put("cyan", CYAN);
colorCode.put("red", RED);
colorCode.put("pink", PINK);
colorCode.put("yellow", YELLOW);
colorCode.put("white", WHITE);
}
private boolean empty;
private int red, green, blue;
private int id;
// 1.15
private String name;
// 1.15
private ChatColor(String name, int id) {
this.name = name;
this.id = id;
}
// 1.16
private ChatColor(int r, int g, int b) {
this.empty = false;
this.red = r;
this.green = g;
this.blue = b;
}
private ChatColor() {
this.empty = true;
}
public static ChatColor fromRGB(int r, int g, int b) {
return new ChatColor(r, g, b);
}
public static ChatColor fromName(String name) {
return colorCode.getOrDefault(name.toLowerCase(), NO_COLOR);
}
public boolean isEmpty() {
return empty;
}
public int getRed() {
return red;
}
public int getGreen() {
return green;
}
public int getBlue() {
return blue;
}
public int getId() {
return id;
}
// 1.15
public String getName() {
return name;
}
@Override
public String toString() {
// 1.15
if (name != null)
return "{#" + name + "}";
// 1.16
if (empty)
return "";
String redH = Integer.toHexString(red);
String greenH = Integer.toHexString(green);
String blueH = Integer.toHexString(blue);
return "{#" + redH + greenH + blueH + "}";
}
}

View File

@ -0,0 +1,59 @@
package net.minestom.server.chat;
import com.google.gson.JsonObject;
import net.minestom.server.entity.Entity;
import net.minestom.server.item.ItemStack;
public class ChatHoverEvent {
private String action;
private String value;
private JsonObject valueObject;
private boolean isJson;
private ChatHoverEvent(String action, String value) {
this.action = action;
this.value = value;
}
private ChatHoverEvent(String action, JsonObject valueObject) {
this.action = action;
this.valueObject = valueObject;
this.isJson = true;
}
public static ChatHoverEvent showText(ColoredText text) {
return new ChatHoverEvent("show_text", text.getJsonObject());
}
public static ChatHoverEvent showText(String text) {
return new ChatHoverEvent("show_text", text);
}
public static ChatHoverEvent showItem(ItemStack itemStack) {
throw new UnsupportedOperationException("Feature in progress");
//return new ChatHoverEvent("show_item", parsedItem);
}
public static ChatHoverEvent showEntity(Entity entity) {
throw new UnsupportedOperationException("Feature in progress");
//return new ChatHoverEvent("show_entity", parsedEntity);
}
protected String getAction() {
return action;
}
protected String getValue() {
return value;
}
protected JsonObject getValueObject() {
return valueObject;
}
protected boolean isJson() {
return isJson;
}
}

View File

@ -0,0 +1,180 @@
package net.minestom.server.chat;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.List;
public class ColoredText {
private String message;
private ColoredText(String message) {
this.message = message;
}
public static ColoredText of(ChatColor color, String message) {
return new ColoredText(color + message);
}
public static ColoredText of(String message) {
return of(ChatColor.WHITE, message);
}
public static ColoredText ofFormat(String message) {
return new ColoredText(message);
}
public ColoredText append(ChatColor color, String message) {
this.message += color + message;
return this;
}
public ColoredText append(String message) {
return append(ChatColor.NO_COLOR, message);
}
public ColoredText appendFormat(String message) {
this.message += message;
return this;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return getJsonObject().toString();
}
protected JsonObject getJsonObject() {
List<JsonObject> components = getComponents();
// No message, return empty object
if (components.isEmpty()) {
return new JsonObject();
}
// Get the first element and remove it
JsonObject mainObject = components.remove(0);
// Append all the components
if (!components.isEmpty()) {
JsonArray extraArray = new JsonArray();
for (JsonObject component : components) {
extraArray.add(component);
}
mainObject.add("extra", extraArray);
}
return mainObject;
}
/**
* Get the list of objects composing the message
*
* @return the list of objects composing the message
*/
protected List<JsonObject> getComponents() {
final List<JsonObject> objects = new ArrayList<>();
// No message, return empty list
if (message.isEmpty())
return objects;
boolean inFormat = false;
int formatStart = 0;
int formatEnd = 0;
String currentColor = "";
for (int i = 0; i < message.length(); i++) {
// Last char or null
Character p = i == 0 ? null : message.charAt(i - 1);
// Current char
char c = message.charAt(i);
if ((p == null || (p != '/')) && c == '{' && !inFormat) {
formatEnd = formatEnd > 0 ? formatEnd + 1 : formatEnd;
String rawMessage = message.substring(formatEnd, i);
if (!rawMessage.isEmpty()) {
objects.add(getMessagePart(MessageType.RAW, rawMessage, currentColor));
}
inFormat = true;
formatStart = i;
continue;
} else if ((p == null || (p != '/')) && c == '}' && inFormat) {
// Represent the custom format between the brackets
String formatString = message.substring(formatStart + 1, i);
if (formatString.isEmpty())
continue;
inFormat = false;
formatStart = 0;
formatEnd = i;
// Color component
if (formatString.startsWith("#")) {
// Remove the first # character to get code
String colorCode = formatString.substring(1);
ChatColor color = ChatColor.fromName(colorCode);
if (color == ChatColor.NO_COLOR) {
// Use rgb formatting
currentColor = colorCode;
} else {
// Use color name formatiing
currentColor = color.getName();
}
continue;
}
// Translatable component
if (formatString.startsWith("@")) {
String translatableCode = formatString.substring(1);
objects.add(getMessagePart(MessageType.TRANSLATABLE, translatableCode, currentColor));
continue;
}
// Keybind component
if (formatString.startsWith("&")) {
String keybindCode = formatString.substring(1);
objects.add(getMessagePart(MessageType.KEYBIND, keybindCode, currentColor));
continue;
}
}
}
// Add the remaining of the message as a raw message when any
if (formatEnd < message.length()) {
String lastRawMessage = message.substring(formatEnd + 1);
objects.add(getMessagePart(MessageType.RAW, lastRawMessage, currentColor));
}
return objects;
}
private JsonObject getMessagePart(MessageType messageType, String message, String color) {
JsonObject object = new JsonObject();
switch (messageType) {
case RAW:
object.addProperty("text", message);
break;
case KEYBIND:
object.addProperty("keybind", message);
break;
case TRANSLATABLE:
object.addProperty("translate", message);
break;
}
if (!color.isEmpty()) {
object.addProperty("color", color);
}
return object;
}
private enum MessageType {
RAW, KEYBIND, TRANSLATABLE
}
}

View File

@ -0,0 +1,178 @@
package net.minestom.server.chat;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minestom.server.utils.validate.Check;
import java.util.ArrayList;
import java.util.List;
public class RichMessage {
private List<RichComponent> components = new ArrayList<>();
private RichComponent currentComponent;
public static RichMessage of(ColoredText coloredText, FormatRetention formatRetention) {
Check.notNull(coloredText, "ColoredText cannot be null");
RichMessage richMessage = new RichMessage();
appendText(richMessage, coloredText, formatRetention);
return richMessage;
}
public static RichMessage of(ColoredText coloredText) {
return of(coloredText, FormatRetention.ALL);
}
private static void appendText(RichMessage richMessage, ColoredText coloredText, FormatRetention formatRetention) {
RichComponent component = new RichComponent(coloredText, formatRetention);
richMessage.components.add(component);
richMessage.currentComponent = component;
}
public RichMessage setClickEvent(ChatClickEvent clickEvent) {
Check.notNull(clickEvent, "ChatClickEvent cannot be null");
currentComponent.setClickEvent(clickEvent);
return this;
}
public RichMessage setHoverEvent(ChatHoverEvent hoverEvent) {
Check.notNull(hoverEvent, "ChatHoverEvent cannot be null");
currentComponent.setHoverEvent(hoverEvent);
return this;
}
public RichMessage append(ColoredText coloredText, FormatRetention formatRetention) {
Check.notNull(coloredText, "ColoredText cannot be null");
appendText(this, coloredText, formatRetention);
return this;
}
public RichMessage append(ColoredText coloredText) {
return append(coloredText, FormatRetention.ALL);
}
@Override
public String toString() {
return getJsonObject().toString();
}
private JsonObject getJsonObject() {
// No component, return empty json object
if (components.isEmpty())
return new JsonObject();
RichComponent firstComponent = components.remove(0);
List<JsonObject> firstComponentObjects = getComponentObject(firstComponent);
JsonObject mainObject = firstComponentObjects.remove(0);
if (components.isEmpty() && firstComponentObjects.isEmpty())
return mainObject;
JsonArray extraArray = new JsonArray();
for (JsonObject firstComponentObject : firstComponentObjects) {
extraArray.add(firstComponentObject);
}
for (RichComponent component : components) {
List<JsonObject> componentObjects = getComponentObject(component);
for (JsonObject componentObject : componentObjects) {
extraArray.add(componentObject);
}
}
mainObject.add("extra", extraArray);
return mainObject;
}
private List<JsonObject> getComponentObject(RichComponent component) {
ColoredText coloredText = component.getText();
List<JsonObject> componentObjects = coloredText.getComponents();
ChatClickEvent clickEvent = component.getClickEvent();
ChatHoverEvent hoverEvent = component.getHoverEvent();
// Nothing to process
if (clickEvent == null && hoverEvent == null) {
return componentObjects;
}
for (JsonObject componentObject : componentObjects) {
if (clickEvent != null) {
final JsonObject clickObject =
getEventObject(clickEvent.getAction(), clickEvent.getValue());
componentObject.add("clickEvent", clickObject);
}
if (hoverEvent != null) {
final JsonObject hoverObject;
if (hoverEvent.isJson()) {
// The value is a JsonObject
hoverObject = new JsonObject();
hoverObject.addProperty("action", hoverEvent.getAction());
hoverObject.add("value", hoverEvent.getValueObject());
} else {
// The value is a raw string
hoverObject = getEventObject(hoverEvent.getAction(), hoverEvent.getValue());
}
componentObject.add("hoverEvent", hoverObject);
}
}
return componentObjects;
}
private JsonObject getEventObject(String action, String value) {
JsonObject eventObject = new JsonObject();
eventObject.addProperty("action", action);
eventObject.addProperty("value", value);
return eventObject;
}
public enum FormatRetention {
ALL, CLICK_EVENT, HOVER_EVENT, NONE
}
private static class RichComponent {
private ColoredText text;
private FormatRetention formatRetention;
private ChatClickEvent clickEvent;
private ChatHoverEvent hoverEvent;
private RichComponent(ColoredText text, FormatRetention formatRetention) {
this.text = text;
this.formatRetention = formatRetention;
}
public ColoredText getText() {
return text;
}
public FormatRetention getFormatRetention() {
return formatRetention;
}
public ChatClickEvent getClickEvent() {
return clickEvent;
}
public void setClickEvent(ChatClickEvent clickEvent) {
this.clickEvent = clickEvent;
}
public ChatHoverEvent getHoverEvent() {
return hoverEvent;
}
public void setHoverEvent(ChatHoverEvent hoverEvent) {
this.hoverEvent = hoverEvent;
}
}
}

View File

@ -2,7 +2,7 @@ package net.minestom.server.entity;
import net.minestom.server.MinecraftServer;
import net.minestom.server.Viewable;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.data.Data;
@ -95,7 +95,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
protected boolean glowing;
protected boolean usingElytra;
protected int air = 300;
protected String customName;
protected ColoredText customName;
protected boolean customNameVisible;
protected boolean silent;
protected boolean noGravity;
@ -824,7 +824,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
*
* @return the custom name of the entity, null if there is not
*/
public String getCustomName() {
public ColoredText getCustomName() {
return customName;
}
@ -833,7 +833,7 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
*
* @param customName the custom name of the entity, null to remove it
*/
public void setCustomName(String customName) {
public void setCustomName(ColoredText customName) {
this.customName = customName;
sendMetadataIndex(2);
}
@ -1227,13 +1227,13 @@ public abstract class Entity implements Viewable, EventHandler, DataContainer {
}
private void fillCustomNameMetaData(PacketWriter packet) {
boolean hasCustomName = customName != null && !customName.isEmpty();
boolean hasCustomName = customName != null;
packet.writeByte((byte) 2);
packet.writeByte(METADATA_OPTCHAT);
packet.writeBoolean(hasCustomName);
if (hasCustomName) {
packet.writeSizedString(Chat.toJsonString(Chat.fromLegacyText(customName)));
packet.writeSizedString(customName.toString());
}
}

View File

@ -1,11 +1,10 @@
package net.minestom.server.entity;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.minestom.server.MinecraftServer;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.bossbar.BossBar;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.RichMessage;
import net.minestom.server.collision.BoundingBox;
import net.minestom.server.command.CommandManager;
import net.minestom.server.command.CommandSender;
@ -63,7 +62,7 @@ public class Player extends LivingEntity implements CommandSender {
private ConcurrentLinkedQueue<ClientPlayPacket> packets = new ConcurrentLinkedQueue<>();
private int latency;
private String displayName;
private ColoredText displayName;
private PlayerSkin skin;
private Dimension dimension;
@ -163,7 +162,7 @@ public class Player extends LivingEntity implements CommandSender {
}
/**
* Used when the player is created ({@link EntityManager#waitingPlayersTick()})
* Used when the player is created (EntityManager#waitingPlayersTick())
* Init the player and spawn him
*/
protected void init() {
@ -402,21 +401,23 @@ public class Player extends LivingEntity implements CommandSender {
public void kill() {
if (!isDead()) {
// send death message to player
Component deathMessage;
ColoredText deathMessage;
if (lastDamageSource != null) {
deathMessage = lastDamageSource.buildDeathScreenMessage(this);
} else { // may happen if killed by the server without applying damage
deathMessage = TextComponent.of("Killed by poor programming.");
deathMessage = ColoredText.of("Killed by poor programming.");
}
CombatEventPacket deathPacket = CombatEventPacket.death(this, Optional.empty(), deathMessage);
playerConnection.sendPacket(deathPacket);
// send death message to chat
Component chatMessage;
RichMessage chatMessage;
if (lastDamageSource != null) {
chatMessage = lastDamageSource.buildChatMessage(this);
} else { // may happen if killed by the server without applying damage
chatMessage = TextComponent.of(getUsername() + " was killed by poor programming.");
ColoredText coloredChatMessage =
ColoredText.of(getUsername() + " was killed by poor programming.");
chatMessage = RichMessage.of(coloredChatMessage);
}
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player -> {
player.sendMessage(chatMessage);
@ -593,27 +594,25 @@ public class Player extends LivingEntity implements CommandSender {
// Use legacy color formatting
@Override
public void sendMessage(String message) {
sendMessage(Chat.fromLegacyText(message));
sendMessage(ColoredText.of(message));
}
/**
* Send a message to the player
*
* @param message the message to send
* @param colorChar the character used to represent the color
* @param coloredText the text to send
*/
public void sendMessage(String message, char colorChar) {
sendMessage(Chat.fromLegacyText(message, colorChar));
public void sendMessage(ColoredText coloredText) {
playerConnection.sendPacket(new ChatMessagePacket(coloredText.toString(), ChatMessagePacket.Position.CHAT));
}
/**
* Send a message to the player
*
* @param component the text component
* @param richMessage the rich text to send
*/
public void sendMessage(Component component) {
String json = Chat.toJsonString(component);
playerConnection.sendPacket(new ChatMessagePacket(json, ChatMessagePacket.Position.CHAT));
public void sendMessage(RichMessage richMessage) {
playerConnection.sendPacket(new ChatMessagePacket(richMessage.toString(), ChatMessagePacket.Position.CHAT));
}
public void playSound(Sound sound, SoundCategory soundCategory, int x, int y, int z, float volume, float pitch) {
@ -656,33 +655,29 @@ public class Player extends LivingEntity implements CommandSender {
playerConnection.sendPacket(stopSoundPacket);
}
public void sendHeaderFooter(Component header, Component footer) {
public void sendHeaderFooter(ColoredText header, ColoredText footer) {
PlayerListHeaderAndFooterPacket playerListHeaderAndFooterPacket = new PlayerListHeaderAndFooterPacket();
playerListHeaderAndFooterPacket.emptyHeader = header == null;
playerListHeaderAndFooterPacket.emptyFooter = footer == null;
playerListHeaderAndFooterPacket.header = Chat.toJsonString(header);
playerListHeaderAndFooterPacket.footer = Chat.toJsonString(footer);
playerListHeaderAndFooterPacket.header = header.toString();
playerListHeaderAndFooterPacket.footer = footer.toString();
playerConnection.sendPacket(playerListHeaderAndFooterPacket);
}
public void sendHeaderFooter(String header, String footer, char colorChar) {
sendHeaderFooter(Chat.fromLegacyText(header, colorChar), Chat.fromLegacyText(footer, colorChar));
}
private void sendTitle(Component title, TitlePacket.Action action) {
private void sendTitle(ColoredText text, TitlePacket.Action action) {
TitlePacket titlePacket = new TitlePacket();
titlePacket.action = action;
switch (action) {
case SET_TITLE:
titlePacket.titleText = Chat.toJsonString(title);
titlePacket.titleText = text.toString();
break;
case SET_SUBTITLE:
titlePacket.subtitleText = Chat.toJsonString(title);
titlePacket.subtitleText = text.toString();
break;
case SET_ACTION_BAR:
titlePacket.actionBarText = Chat.toJsonString(title);
titlePacket.actionBarText = text.toString();
default:
throw new UnsupportedOperationException("Invalid TitlePacket.Action type!");
}
@ -690,47 +685,23 @@ public class Player extends LivingEntity implements CommandSender {
playerConnection.sendPacket(titlePacket);
}
public void sendTitleSubtitleMessage(Component title, Component subtitle) {
public void sendTitleSubtitleMessage(ColoredText title, ColoredText subtitle) {
sendTitle(title, TitlePacket.Action.SET_TITLE);
sendTitle(subtitle, TitlePacket.Action.SET_SUBTITLE);
}
public void sendTitleMessage(Component title) {
public void sendTitleMessage(ColoredText title) {
sendTitle(title, TitlePacket.Action.SET_TITLE);
}
public void sendTitleMessage(String title, char colorChar) {
sendTitleMessage(Chat.fromLegacyText(title, colorChar));
}
public void sendTitleMessage(String title) {
sendTitleMessage(title, Chat.COLOR_CHAR);
}
public void sendSubtitleMessage(Component subtitle) {
public void sendSubtitleMessage(ColoredText subtitle) {
sendTitle(subtitle, TitlePacket.Action.SET_SUBTITLE);
}
public void sendSubtitleMessage(String subtitle, char colorChar) {
sendSubtitleMessage(Chat.fromLegacyText(subtitle, colorChar));
}
public void sendSubtitleMessage(String subtitle) {
sendSubtitleMessage(subtitle, Chat.COLOR_CHAR);
}
public void sendActionBarMessage(Component actionBar) {
public void sendActionBarMessage(ColoredText actionBar) {
sendTitle(actionBar, TitlePacket.Action.SET_ACTION_BAR);
}
public void sendActionBarMessage(String message, char colorChar) {
sendActionBarMessage(Chat.fromLegacyText(message, colorChar));
}
public void sendActionBarMessage(String message) {
sendActionBarMessage(message, Chat.COLOR_CHAR);
}
@Override
public boolean isImmune(DamageType type) {
if (!getGameMode().canTakeDamage()) {
@ -839,7 +810,7 @@ public class Player extends LivingEntity implements CommandSender {
* @return the player display name,
* null means that {@link #getUsername()} is displayed
*/
public String getDisplayName() {
public ColoredText getDisplayName() {
return displayName;
}
@ -850,10 +821,10 @@ public class Player extends LivingEntity implements CommandSender {
*
* @param displayName the display name
*/
public void setDisplayName(String displayName) {
public void setDisplayName(ColoredText displayName) {
this.displayName = displayName;
String jsonDisplayName = displayName != null ? Chat.toJsonString(Chat.fromLegacyText(displayName)) : null;
String jsonDisplayName = displayName != null ? displayName.toString() : null;
PlayerInfoPacket infoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.UPDATE_DISPLAY_NAME);
infoPacket.playerInfos.add(new PlayerInfoPacket.UpdateDisplayName(getUuid(), jsonDisplayName));
sendPacketToViewersAndSelf(infoPacket);
@ -1286,11 +1257,11 @@ public class Player extends LivingEntity implements CommandSender {
/**
* Kick the player with a reason
*
* @param textComponent the kick reason
* @param text the kick reason
*/
public void kick(TextComponent textComponent) {
public void kick(ColoredText text) {
DisconnectPacket disconnectPacket = new DisconnectPacket();
disconnectPacket.message = Chat.toJsonString(textComponent);
disconnectPacket.message = text.toString();
playerConnection.sendPacket(disconnectPacket);
playerConnection.disconnect();
playerConnection.refreshOnline(false);
@ -1302,7 +1273,7 @@ public class Player extends LivingEntity implements CommandSender {
* @param message the kick reason
*/
public void kick(String message) {
kick(Chat.fromLegacyText(message));
kick(ColoredText.of(message));
}
public LevelType getLevelType() {
@ -1883,7 +1854,7 @@ public class Player extends LivingEntity implements CommandSender {
final String textures = skin == null ? "" : skin.getTextures();
final String signature = skin == null ? null : skin.getSignature();
String jsonDisplayName = displayName != null ? Chat.toJsonString(Chat.fromLegacyText(displayName)) : null;
String jsonDisplayName = displayName != null ? displayName.toString() : null;
PlayerInfoPacket playerInfoPacket = new PlayerInfoPacket(PlayerInfoPacket.Action.ADD_PLAYER);
PlayerInfoPacket.AddPlayer addPlayer =

View File

@ -1,8 +1,7 @@
package net.minestom.server.entity.damage;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.TranslatableComponent;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.RichMessage;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
@ -35,8 +34,10 @@ public class DamageType {
return new EntityProjectileDamage(shooter, projectile);
}
public Component buildChatMessage(Player killed) {
return TranslatableComponent.of("death." + identifier, TextComponent.of(killed.getUsername()));
public RichMessage buildChatMessage(Player killed) {
RichMessage richMessage = RichMessage.of(ColoredText.ofFormat("{@death." + identifier + "}"))
.append(ColoredText.ofFormat(killed.getUsername()));
return richMessage;
}
public static EntityDamage fromPlayer(Player player) {
@ -47,8 +48,8 @@ public class DamageType {
return new EntityDamage(entity);
}
public Component buildDeathScreenMessage(Player killed) {
return buildChatMessage(killed);
public ColoredText buildDeathScreenMessage(Player killed) {
return ColoredText.ofFormat("{@death." + identifier + "}");
}
/**

View File

@ -1,5 +1,6 @@
package net.minestom.server.entity.hologram;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.type.EntityArmorStand;
import net.minestom.server.instance.Instance;
import net.minestom.server.utils.Position;
@ -12,11 +13,11 @@ public class Hologram {
private HologramEntity entity;
private Position position;
private String text;
private ColoredText text;
private boolean removed;
public Hologram(Instance instance, Position spawnPosition, String text, boolean autoViewable) {
public Hologram(Instance instance, Position spawnPosition, ColoredText text, boolean autoViewable) {
this.entity = new HologramEntity(spawnPosition.clone().add(0, OFFSET_Y, 0));
this.entity.setInstance(instance);
this.entity.setAutoViewable(autoViewable);
@ -25,7 +26,7 @@ public class Hologram {
setText(text);
}
public Hologram(Instance instance, Position spawnPosition, String text) {
public Hologram(Instance instance, Position spawnPosition, ColoredText text) {
this(instance, spawnPosition, text, true);
}
@ -40,11 +41,11 @@ public class Hologram {
this.entity.teleport(position);
}
public String getText() {
public ColoredText getText() {
return text;
}
public void setText(String text) {
public void setText(ColoredText text) {
checkRemoved();
this.text = text;
this.entity.setCustomName(text);
@ -70,7 +71,7 @@ public class Hologram {
setSmall(true);
setNoGravity(true);
setCustomName("");
setCustomName(ColoredText.of(""));
setCustomNameVisible(true);
setInvisible(true);
}

View File

@ -1,6 +1,6 @@
package net.minestom.server.event.player;
import net.kyori.text.TextComponent;
import net.minestom.server.chat.RichMessage;
import net.minestom.server.entity.Player;
import net.minestom.server.event.CancellableEvent;
@ -17,7 +17,7 @@ public class PlayerChatEvent extends CancellableEvent {
private Player sender;
private Collection<Player> recipients;
private String message;
private Function<PlayerChatEvent, TextComponent> chatFormat;
private Function<PlayerChatEvent, RichMessage> chatFormat;
public PlayerChatEvent(Player sender, Collection<Player> recipients, String message) {
this.sender = sender;
@ -28,7 +28,7 @@ public class PlayerChatEvent extends CancellableEvent {
/**
* @param chatFormat the custom chat format
*/
public void setChatFormat(Function<PlayerChatEvent, TextComponent> chatFormat) {
public void setChatFormat(Function<PlayerChatEvent, RichMessage> chatFormat) {
this.chatFormat = chatFormat;
}
@ -71,7 +71,7 @@ public class PlayerChatEvent extends CancellableEvent {
*
* @return the chat format which will be used
*/
public Function<PlayerChatEvent, TextComponent> getChatFormatFunction() {
public Function<PlayerChatEvent, RichMessage> getChatFormatFunction() {
return chatFormat;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.item;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.item.attribute.ItemAttribute;
@ -24,9 +25,9 @@ public class ItemStack implements DataContainer {
private byte amount;
private short damage;
private String displayName;
private ColoredText displayName;
private boolean unbreakable;
private ArrayList<String> lore;
private ArrayList<ColoredText> lore;
private Map<Enchantment, Short> enchantmentMap;
private Map<Enchantment, Short> storedEnchantmentMap;
@ -103,7 +104,7 @@ public class ItemStack implements DataContainer {
*/
public synchronized boolean isSimilar(ItemStack itemStack) {
synchronized (itemStack) {
final String itemDisplayName = itemStack.getDisplayName();
final ColoredText itemDisplayName = itemStack.getDisplayName();
final boolean displayNameCheck = (displayName == null && itemDisplayName == null) ||
(displayName != null && itemDisplayName != null && displayName.equals(itemDisplayName));
@ -179,7 +180,7 @@ public class ItemStack implements DataContainer {
*
* @return the item display name, can be null if not present
*/
public String getDisplayName() {
public ColoredText getDisplayName() {
return displayName;
}
@ -188,7 +189,7 @@ public class ItemStack implements DataContainer {
*
* @param displayName the item display name
*/
public void setDisplayName(String displayName) {
public void setDisplayName(ColoredText displayName) {
this.displayName = displayName;
}
@ -206,7 +207,7 @@ public class ItemStack implements DataContainer {
*
* @return the item lore, can be null if not present
*/
public ArrayList<String> getLore() {
public ArrayList<ColoredText> getLore() {
return lore;
}
@ -215,7 +216,7 @@ public class ItemStack implements DataContainer {
*
* @param lore the item lore, can be null to remove
*/
public void setLore(ArrayList<String> lore) {
public void setLore(ArrayList<ColoredText> lore) {
this.lore = lore;
}

View File

@ -1,12 +1,7 @@
package net.minestom.server.listener;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import net.kyori.text.serializer.plain.PlainComponentSerializer;
import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.*;
import net.minestom.server.command.CommandManager;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerChatEvent;
@ -19,7 +14,7 @@ import java.util.function.Function;
public class ChatMessageListener {
public static void listener(ClientChatMessagePacket packet, Player player) {
String message = PlainComponentSerializer.INSTANCE.serialize(Chat.fromLegacyText(packet.message));
String message = packet.message;
CommandManager commandManager = MinecraftServer.getCommandManager();
String cmdPrefix = commandManager.getCommandPrefix();
@ -43,9 +38,9 @@ public class ChatMessageListener {
// Call the event
player.callCancellableEvent(PlayerChatEvent.class, playerChatEvent, () -> {
Function<PlayerChatEvent, TextComponent> formatFunction = playerChatEvent.getChatFormatFunction();
Function<PlayerChatEvent, RichMessage> formatFunction = playerChatEvent.getChatFormatFunction();
TextComponent textObject;
RichMessage textObject;
if (formatFunction != null) {
// Custom format
@ -63,16 +58,17 @@ public class ChatMessageListener {
}
private static TextComponent buildDefaultChatMessage(PlayerChatEvent chatEvent) {
private static RichMessage buildDefaultChatMessage(PlayerChatEvent chatEvent) {
String username = chatEvent.getSender().getUsername();
TextComponent usernameText = TextComponent.of(String.format("<%s>", username))
.color(TextColor.WHITE)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Its " + username).color(TextColor.GRAY)))
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/msg " + username + " "))
.append(TextComponent.of(" " + chatEvent.getMessage()));
ColoredText usernameText = ColoredText.of(String.format("<%s>", username));
return usernameText;
RichMessage richMessage = RichMessage.of(usernameText)
.setHoverEvent(ChatHoverEvent.showText(ColoredText.of(ChatColor.GRAY + "Its " + username)))
.setClickEvent(ChatClickEvent.suggestCommand("/msg " + username + " "))
.append(ColoredText.of(" " + chatEvent.getMessage()));
return richMessage;
}
}

View File

@ -1,7 +1,7 @@
package net.minestom.server.listener;
import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.play.ClientKeepAlivePacket;
@ -12,9 +12,7 @@ public class KeepAliveListener {
final long playerId = player.getLastKeepAlive();
final boolean equals = packetId == playerId;
if (!equals) {
TextComponent textComponent = TextComponent.of("Bad Keep Alive packet")
.color(TextColor.RED);
player.kick(textComponent);
player.kick(ColoredText.of(ChatColor.RED + "Bad Keep Alive packet"));
return;
}

View File

@ -1,6 +1,6 @@
package net.minestom.server.network;
import net.kyori.text.TextComponent;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.listener.manager.PacketConsumer;
import net.minestom.server.network.player.PlayerConnection;
@ -50,17 +50,17 @@ public final class ConnectionManager {
/**
* Send a message to all online players who validate the condition {@code condition}
*
* @param textComponent the message to send
* @param condition the condition to receive the message
* @param coloredText the message to send
* @param condition the condition to receive the message
*/
public void broadcastMessage(TextComponent textComponent, Function<Player, Boolean> condition) {
public void broadcastMessage(ColoredText coloredText, Function<Player, Boolean> condition) {
if (condition == null) {
getOnlinePlayers().forEach(player -> player.sendMessage(textComponent));
getOnlinePlayers().forEach(player -> player.sendMessage(coloredText));
} else {
getOnlinePlayers().forEach(player -> {
boolean result = condition.apply(player);
if (result)
player.sendMessage(textComponent);
player.sendMessage(coloredText);
});
}
}
@ -68,10 +68,10 @@ public final class ConnectionManager {
/**
* Send a message to all online players without exception
*
* @param textComponent the message to send
* @param coloredText the message to send
*/
public void broadcastMessage(TextComponent textComponent) {
broadcastMessage(textComponent, null);
public void broadcastMessage(ColoredText coloredText) {
broadcastMessage(coloredText, null);
}
/**

View File

@ -1,6 +1,5 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.chat.Chat;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
@ -92,8 +91,8 @@ public class AdvancementsPacket implements ServerPacket {
public float y;
private void write(PacketWriter writer) {
writer.writeSizedString(Chat.toJsonString(Chat.fromLegacyText(title)));
writer.writeSizedString(Chat.toJsonString(Chat.fromLegacyText(title)));
writer.writeSizedString(title);
writer.writeSizedString(description);
writer.writeItemStack(icon);
writer.writeVarInt(frameType.ordinal());
writer.writeInt(flags);

View File

@ -1,9 +1,8 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.text.Component;
import net.minestom.server.bossbar.BarColor;
import net.minestom.server.bossbar.BarDivision;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -15,7 +14,7 @@ public class BossBarPacket implements ServerPacket {
public UUID uuid;
public Action action;
public Component title;
public ColoredText title;
public float health;
public BarColor color;
public BarDivision division;
@ -29,7 +28,7 @@ public class BossBarPacket implements ServerPacket {
switch (action) {
case ADD:
writer.writeSizedString(Chat.toJsonString(title));
writer.writeSizedString(title.toString());
writer.writeFloat(health);
writer.writeVarInt(color.ordinal());
writer.writeVarInt(division.ordinal());
@ -42,7 +41,7 @@ public class BossBarPacket implements ServerPacket {
writer.writeFloat(health);
break;
case UPDATE_TITLE:
writer.writeSizedString(Chat.toJsonString(title));
writer.writeSizedString(title.toString());
break;
case UPDATE_STYLE:
writer.writeVarInt(color.ordinal());

View File

@ -26,7 +26,6 @@ public class ChatMessagePacket implements ServerPacket {
}
public enum Position {
CHAT,
SYSTEM_MESSAGE,
GAME_INFO

View File

@ -1,7 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.text.Component;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.PacketWriter;
@ -20,7 +19,7 @@ public class CombatEventPacket implements ServerPacket {
private int duration;
private int opponent;
private int playerID;
private Component deathMessage;
private ColoredText deathMessage;
private CombatEventPacket() {
}
@ -39,7 +38,7 @@ public class CombatEventPacket implements ServerPacket {
return packet;
}
public static CombatEventPacket death(Player player, Optional<Entity> killer, Component message) {
public static CombatEventPacket death(Player player, Optional<Entity> killer, ColoredText message) {
CombatEventPacket packet = new CombatEventPacket();
packet.type = EventType.DEATH;
packet.playerID = player.getEntityId();
@ -64,7 +63,7 @@ public class CombatEventPacket implements ServerPacket {
case DEATH:
writer.writeVarInt(playerID);
writer.writeInt(opponent);
writer.writeSizedString(Chat.toJsonString(deathMessage));
writer.writeSizedString(deathMessage.toString());
break;
}
}

View File

@ -1,7 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.text.Component;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -10,7 +9,7 @@ public class ScoreboardObjectivePacket implements ServerPacket {
public String objectiveName;
public byte mode;
public Component objectiveValue;
public ColoredText objectiveValue;
public int type;
@Override
@ -19,7 +18,7 @@ public class ScoreboardObjectivePacket implements ServerPacket {
writer.writeByte(mode);
if (mode == 0 || mode == 2) {
writer.writeSizedString(Chat.toJsonString(objectiveValue));
writer.writeSizedString(objectiveValue.toString());
writer.writeVarInt(type);
}
}

View File

@ -1,7 +1,5 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.text.Component;
import net.minestom.server.chat.Chat;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -11,13 +9,13 @@ public class TeamsPacket implements ServerPacket {
public String teamName;
public Action action;
public Component teamDisplayName;
public String teamDisplayName;
public byte friendlyFlags;
public NameTagVisibility nameTagVisibility;
public CollisionRule collisionRule;
public int teamColor;
public Component teamPrefix;
public Component teamSuffix;
public String teamPrefix;
public String teamSuffix;
public String[] entities;
@Override
@ -28,13 +26,13 @@ public class TeamsPacket implements ServerPacket {
switch (action) {
case CREATE_TEAM:
case UPDATE_TEAM_INFO:
writer.writeSizedString(Chat.toJsonString(teamDisplayName));
writer.writeSizedString(teamDisplayName);
writer.writeByte(friendlyFlags);
writer.writeSizedString(nameTagVisibility.getIdentifier());
writer.writeSizedString(collisionRule.getIdentifier());
writer.writeVarInt(teamColor);
writer.writeSizedString(Chat.toJsonString(teamPrefix));
writer.writeSizedString(Chat.toJsonString(teamSuffix));
writer.writeSizedString(teamPrefix);
writer.writeSizedString(teamSuffix);
break;
case REMOVE_TEAM:

View File

@ -1,7 +1,7 @@
package net.minestom.server.scoreboard;
import net.minestom.server.Viewable;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.DisplayScoreboardPacket;
import net.minestom.server.network.packet.server.play.ScoreboardObjectivePacket;
@ -35,7 +35,7 @@ public class BelowNameScoreboard implements Viewable {
scoreboardObjectivePacket = new ScoreboardObjectivePacket();
scoreboardObjectivePacket.objectiveName = objectiveName;
scoreboardObjectivePacket.mode = 0;
scoreboardObjectivePacket.objectiveValue = Chat.fromLegacyText(objectiveName);
scoreboardObjectivePacket.objectiveValue = ColoredText.of(objectiveName);
scoreboardObjectivePacket.type = 0;
displayScoreboardPacket = new DisplayScoreboardPacket();

View File

@ -2,6 +2,7 @@ package net.minestom.server.scoreboard;
import net.minestom.server.Viewable;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.DisplayScoreboardPacket;
import net.minestom.server.network.packet.server.play.ScoreboardObjectivePacket;
@ -53,7 +54,7 @@ public class Sidebar implements Viewable {
ScoreboardObjectivePacket scoreboardObjectivePacket = new ScoreboardObjectivePacket();
scoreboardObjectivePacket.objectiveName = objectiveName;
scoreboardObjectivePacket.mode = 2; // Update display text
scoreboardObjectivePacket.objectiveValue = Chat.fromLegacyText(title);
scoreboardObjectivePacket.objectiveValue = ColoredText.of(title);
scoreboardObjectivePacket.type = 0;
sendPacketToViewers(scoreboardObjectivePacket);
@ -82,7 +83,7 @@ public class Sidebar implements Viewable {
}
}
public void updateLineContent(String id, String content) {
public void updateLineContent(String id, ColoredText content) {
ScoreboardLine scoreboardLine = getLine(id);
if (scoreboardLine != null) {
scoreboardLine.refreshContent(content);
@ -131,7 +132,7 @@ public class Sidebar implements Viewable {
ScoreboardObjectivePacket scoreboardObjectivePacket = new ScoreboardObjectivePacket();
scoreboardObjectivePacket.objectiveName = objectiveName;
scoreboardObjectivePacket.mode = 0; // Create scoreboard
scoreboardObjectivePacket.objectiveValue = Chat.fromLegacyText(title);
scoreboardObjectivePacket.objectiveValue = ColoredText.of(title);
scoreboardObjectivePacket.type = 0; // Type integer
DisplayScoreboardPacket displayScoreboardPacket = new DisplayScoreboardPacket();
@ -172,7 +173,7 @@ public class Sidebar implements Viewable {
public static class ScoreboardLine {
private String id; // ID used to modify the line later
private String content;
private ColoredText content;
private int line;
private String teamName;
@ -180,7 +181,7 @@ public class Sidebar implements Viewable {
private String entityName;
private SidebarTeam sidebarTeam;
public ScoreboardLine(String id, String content, int line) {
public ScoreboardLine(String id, ColoredText content, int line) {
this.id = id;
this.content = content;
this.line = line;
@ -192,7 +193,7 @@ public class Sidebar implements Viewable {
return id;
}
public String getContent() {
public ColoredText getContent() {
return sidebarTeam == null ? content : sidebarTeam.getPrefix();
}
@ -209,7 +210,7 @@ public class Sidebar implements Viewable {
private void createTeam() {
this.entityName = Chat.COLOR_CHAR + Integer.toHexString(colorName);
this.sidebarTeam = new SidebarTeam(teamName, content, "", entityName);
this.sidebarTeam = new SidebarTeam(teamName, content, ColoredText.of(""), entityName);
}
private void returnName(LinkedList<Integer> colors) {
@ -241,7 +242,7 @@ public class Sidebar implements Viewable {
return updateScorePacket;
}
private void refreshContent(String content) {
private void refreshContent(ColoredText content) {
this.sidebarTeam.refreshPrefix(content);
}

View File

@ -1,22 +1,22 @@
package net.minestom.server.scoreboard;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.network.packet.server.play.TeamsPacket;
public class SidebarTeam {
private String teamName;
private String prefix, suffix;
private ColoredText prefix, suffix;
private String entityName;
private String teamDisplayName = "displaynametest";
private ColoredText teamDisplayName = ColoredText.of("displaynametest");
private byte friendlyFlags = 0x00;
private TeamsPacket.NameTagVisibility nameTagVisibility = TeamsPacket.NameTagVisibility.NEVER;
private TeamsPacket.CollisionRule collisionRule = TeamsPacket.CollisionRule.NEVER;
private int teamColor = 2;
protected SidebarTeam(String teamName, String prefix, String suffix, String entityName) {
protected SidebarTeam(String teamName, ColoredText prefix, ColoredText suffix, String entityName) {
this.teamName = teamName;
this.prefix = prefix;
this.suffix = suffix;
@ -27,13 +27,13 @@ public class SidebarTeam {
TeamsPacket teamsPacket = new TeamsPacket();
teamsPacket.teamName = teamName;
teamsPacket.action = TeamsPacket.Action.CREATE_TEAM;
teamsPacket.teamDisplayName = Chat.fromLegacyText(teamDisplayName);
teamsPacket.teamDisplayName = teamDisplayName.toString();
teamsPacket.friendlyFlags = friendlyFlags;
teamsPacket.nameTagVisibility = nameTagVisibility;
teamsPacket.collisionRule = collisionRule;
teamsPacket.teamColor = teamColor;
teamsPacket.teamPrefix = Chat.fromLegacyText(prefix);
teamsPacket.teamSuffix = Chat.fromLegacyText(suffix);
teamsPacket.teamPrefix = prefix.toString();
teamsPacket.teamSuffix = suffix.toString();
teamsPacket.entities = new String[]{entityName};
return teamsPacket;
}
@ -45,17 +45,17 @@ public class SidebarTeam {
return teamsPacket;
}
protected TeamsPacket updatePrefix(String prefix) {
protected TeamsPacket updatePrefix(ColoredText prefix) {
TeamsPacket teamsPacket = new TeamsPacket();
teamsPacket.teamName = teamName;
teamsPacket.action = TeamsPacket.Action.UPDATE_TEAM_INFO;
teamsPacket.teamDisplayName = Chat.fromLegacyText(teamDisplayName);
teamsPacket.teamDisplayName = teamDisplayName.toString();
teamsPacket.friendlyFlags = friendlyFlags;
teamsPacket.nameTagVisibility = nameTagVisibility;
teamsPacket.collisionRule = collisionRule;
teamsPacket.teamColor = teamColor;
teamsPacket.teamPrefix = Chat.fromLegacyText(prefix);
teamsPacket.teamSuffix = Chat.fromLegacyText(suffix);
teamsPacket.teamPrefix = prefix.toString();
teamsPacket.teamSuffix = suffix.toString();
return teamsPacket;
}
@ -63,11 +63,11 @@ public class SidebarTeam {
return entityName;
}
protected String getPrefix() {
protected ColoredText getPrefix() {
return prefix;
}
protected void refreshPrefix(String prefix) {
protected void refreshPrefix(ColoredText prefix) {
this.prefix = prefix;
}
}

View File

@ -1,8 +1,8 @@
package net.minestom.server.scoreboard;
import io.netty.buffer.ByteBuf;
import net.kyori.text.format.TextColor;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.TeamsPacket;
import net.minestom.server.utils.PacketUtils;
@ -14,12 +14,15 @@ import java.util.concurrent.CopyOnWriteArraySet;
public class Team {
private String teamName;
private String teamDisplayName = "";
private ColoredText teamDisplayName = ColoredText.of("");
private byte friendlyFlags = 0x00;
private TeamsPacket.NameTagVisibility nameTagVisibility = TeamsPacket.NameTagVisibility.ALWAYS;
private TeamsPacket.CollisionRule collisionRule = TeamsPacket.CollisionRule.NEVER;
private TextColor teamColor = TextColor.WHITE;
private String prefix = "", suffix = "";
private ChatColor teamColor = ChatColor.WHITE;
private ColoredText prefix = ColoredText.of("");
private ColoredText suffix = ColoredText.of("");
private String[] entities = new String[0];
private Set<Player> players = new CopyOnWriteArraySet<>();
@ -33,13 +36,13 @@ public class Team {
teamsCreationPacket = new TeamsPacket();
teamsCreationPacket.teamName = teamName;
teamsCreationPacket.action = TeamsPacket.Action.CREATE_TEAM;
teamsCreationPacket.teamDisplayName = Chat.fromLegacyText(teamDisplayName);
teamsCreationPacket.teamDisplayName = teamDisplayName.toString();
teamsCreationPacket.friendlyFlags = friendlyFlags;
teamsCreationPacket.nameTagVisibility = nameTagVisibility;
teamsCreationPacket.collisionRule = collisionRule;
teamsCreationPacket.teamColor = teamColor.ordinal();
teamsCreationPacket.teamPrefix = Chat.fromLegacyText(prefix);
teamsCreationPacket.teamSuffix = Chat.fromLegacyText(suffix);
teamsCreationPacket.teamColor = teamColor.getId();
teamsCreationPacket.teamPrefix = prefix.toString();
teamsCreationPacket.teamSuffix = suffix.toString();
teamsCreationPacket.entities = entities;
TeamsPacket destroyPacket = new TeamsPacket();
@ -90,9 +93,9 @@ public class Team {
this.teamsCreationPacket.entities = entities;
}
public void setTeamDisplayName(String teamDisplayName) {
public void setTeamDisplayName(ColoredText teamDisplayName) {
this.teamDisplayName = teamDisplayName;
this.teamsCreationPacket.teamDisplayName = Chat.fromLegacyText(teamDisplayName);
this.teamsCreationPacket.teamDisplayName = teamDisplayName.toString();
sendUpdatePacket();
}
@ -108,21 +111,21 @@ public class Team {
sendUpdatePacket();
}
public void setTeamColor(TextColor teamColor) {
public void setTeamColor(ChatColor teamColor) {
this.teamColor = teamColor;
this.teamsCreationPacket.teamColor = teamColor.ordinal();
this.teamsCreationPacket.teamColor = teamColor.getId();
sendUpdatePacket();
}
public void setPrefix(String prefix) {
public void setPrefix(ColoredText prefix) {
this.prefix = prefix;
this.teamsCreationPacket.teamPrefix = Chat.fromLegacyText(prefix);
this.teamsCreationPacket.teamPrefix = prefix.toString();
sendUpdatePacket();
}
public void setSuffix(String suffix) {
public void setSuffix(ColoredText suffix) {
this.suffix = suffix;
this.teamsCreationPacket.teamSuffix = Chat.fromLegacyText(suffix);
this.teamsCreationPacket.teamSuffix = suffix.toString();
sendUpdatePacket();
}
@ -149,13 +152,13 @@ public class Team {
TeamsPacket updatePacket = new TeamsPacket();
updatePacket.teamName = teamName;
updatePacket.action = TeamsPacket.Action.UPDATE_TEAM_INFO;
updatePacket.teamDisplayName = Chat.fromLegacyText(teamDisplayName);
updatePacket.teamDisplayName = teamDisplayName.toString();
updatePacket.friendlyFlags = friendlyFlags;
updatePacket.nameTagVisibility = nameTagVisibility;
updatePacket.collisionRule = collisionRule;
updatePacket.teamColor = teamColor.ordinal();
updatePacket.teamPrefix = Chat.fromLegacyText(prefix);
updatePacket.teamSuffix = Chat.fromLegacyText(suffix);
updatePacket.teamColor = teamColor.getId();
updatePacket.teamPrefix = prefix.toString();
updatePacket.teamSuffix = suffix.toString();
ByteBuf buffer = PacketUtils.writePacket(updatePacket);
players.forEach(p -> p.getPlayerConnection().sendPacket(buffer));
}

View File

@ -1,7 +1,7 @@
package net.minestom.server.utils;
import io.netty.buffer.ByteBuf;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.instance.Chunk;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemStack;
@ -127,17 +127,16 @@ public class Utils {
if (hasDisplayName || hasLore) {
writer.writeCompound("display", displayWriter -> {
if (hasDisplayName) {
final String name = Chat.toJsonString(Chat.fromLegacyText(itemStack.getDisplayName()));
final String name = itemStack.getDisplayName().toString();
displayWriter.writeString("Name", name);
}
if (hasLore) {
final ArrayList<String> lore = itemStack.getLore();
final ArrayList<ColoredText> lore = itemStack.getLore();
displayWriter.writeList("Lore", NBT.NBT_STRING, lore.size(), () -> {
for (String line : lore) {
line = Chat.toJsonString(Chat.fromLegacyText(line));
packet.writeShortSizedString(line);
for (ColoredText line : lore) {
packet.writeShortSizedString(line.toString());
}
});

View File

@ -4,6 +4,7 @@ import net.kyori.text.Component;
import net.minestom.server.attribute.Attribute;
import net.minestom.server.attribute.AttributeOperation;
import net.minestom.server.chat.Chat;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.attribute.AttributeSlot;
@ -213,7 +214,7 @@ public class NbtReaderUtils {
Component textObject = Chat.fromJsonString(jsonDisplayName);
String displayName = Chat.toLegacyText(textObject);
item.setDisplayName(displayName);
item.setDisplayName(ColoredText.of(displayName));
readItemStackDisplayNBT(reader, item);
}
break;
@ -225,13 +226,13 @@ public class NbtReaderUtils {
reader.readByte(); // lore type, should always be 0x08 (TAG_String)
int size = reader.readInteger();
ArrayList<String> lore = new ArrayList<>(size);
ArrayList<ColoredText> lore = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
String string = reader.readShortSizedString();
Component textObject = Chat.fromJsonString(string);
String line = Chat.toLegacyText(textObject);
lore.add(line);
lore.add(ColoredText.of(line));
if (lore.size() == size) {
item.setLore(lore);
}