Allow for custom chat message serializer using JsonMessage

This commit is contained in:
themode 2020-10-06 03:43:57 +02:00
parent 67c93e73ab
commit 37d3c9c6bc
5 changed files with 71 additions and 56 deletions

View File

@ -10,17 +10,14 @@ import java.util.regex.Pattern;
/** /**
* Represent a text with one or multiple colors * Represent a text with one or multiple colors
* <p>
* Used when the message can contain colors but not events like in {@link RichMessage}
*/ */
public class ColoredText { public class ColoredText extends JsonMessage {
// the raw text // the raw text
private String message; private String message;
// true if the compiled string is up-to-date, false otherwise
private boolean updated;
// the compiled json string of this colored text (can be outdated)
private String compiledJson;
private ColoredText(String message) { private ColoredText(String message) {
this.message = message; this.message = message;
refreshUpdate(); refreshUpdate();
@ -97,21 +94,6 @@ public class ColoredText {
return message; return message;
} }
/**
* Compile this text and cache it for further execution
*
* @return the raw json string of this colored text
*/
@Override
public String toString() {
if (!updated) {
this.compiledJson = getJsonObject().toString();
this.updated = true;
}
return compiledJson;
}
/** /**
* Get the Json representation of this colored text * Get the Json representation of this colored text
* <p> * <p>
@ -119,6 +101,7 @@ public class ColoredText {
* *
* @return the Json representation of the text * @return the Json representation of the text
*/ */
@Override
public JsonObject getJsonObject() { public JsonObject getJsonObject() {
final List<JsonObject> components = getComponents(); final List<JsonObject> components = getComponents();
@ -169,7 +152,7 @@ public class ColoredText {
if ((p == null || (p != '/')) && c == '{' && !inFormat) { if ((p == null || (p != '/')) && c == '{' && !inFormat) {
formatEnd = formatEnd > 0 ? formatEnd + 1 : formatEnd; formatEnd = formatEnd > 0 ? formatEnd + 1 : formatEnd;
String rawMessage = message.substring(formatEnd, i); final String rawMessage = message.substring(formatEnd, i);
if (!rawMessage.isEmpty()) { if (!rawMessage.isEmpty()) {
objects.add(getMessagePart(MessageType.RAW, rawMessage, currentColor, specialComponentContainer)); objects.add(getMessagePart(MessageType.RAW, rawMessage, currentColor, specialComponentContainer));
} }
@ -179,7 +162,7 @@ public class ColoredText {
continue; continue;
} else if ((p == null || (p != '/')) && c == '}' && inFormat) { } else if ((p == null || (p != '/')) && c == '}' && inFormat) {
// Represent the custom format between the brackets // Represent the custom format between the brackets
String formatString = message.substring(formatStart + 1, i); final String formatString = message.substring(formatStart + 1, i);
if (formatString.isEmpty()) if (formatString.isEmpty())
continue; continue;
@ -223,6 +206,8 @@ public class ColoredText {
final String translatableCode = formatString.substring(1); final String translatableCode = formatString.substring(1);
final boolean hasArgs = translatableCode.contains(","); final boolean hasArgs = translatableCode.contains(",");
if (!hasArgs) { if (!hasArgs) {
// Without argument
// ex: {@translatable.key}
objects.add(getMessagePart(MessageType.TRANSLATABLE, translatableCode, currentColor, specialComponentContainer)); objects.add(getMessagePart(MessageType.TRANSLATABLE, translatableCode, currentColor, specialComponentContainer));
} else { } else {
// Arguments parsing // Arguments parsing
@ -245,6 +230,7 @@ public class ColoredText {
} }
// Keybind component // Keybind component
if (formatString.startsWith("&")) { if (formatString.startsWith("&")) {
// ex: {&key.drop}
final String keybindCode = formatString.substring(1); final String keybindCode = formatString.substring(1);
objects.add(getMessagePart(MessageType.KEYBIND, keybindCode, currentColor, specialComponentContainer)); objects.add(getMessagePart(MessageType.KEYBIND, keybindCode, currentColor, specialComponentContainer));
continue; continue;
@ -301,14 +287,13 @@ public class ColoredText {
return value ? "true" : "false"; return value ? "true" : "false";
} }
private void refreshUpdate() {
this.updated = false;
}
private enum MessageType { private enum MessageType {
RAW, KEYBIND, TRANSLATABLE RAW, KEYBIND, TRANSLATABLE
} }
/**
* Used to keep a "color" state in the text
*/
private static class SpecialComponentContainer { private static class SpecialComponentContainer {
boolean bold = false; boolean bold = false;

View File

@ -0,0 +1,49 @@
package net.minestom.server.chat;
import com.google.gson.JsonObject;
/**
* Represent a json message which can be send to a player
* <p>
* Examples are {@link ColoredText} and {@link RichMessage}
*
* @see <a href="https://wiki.vg/Chat">Chat Format</a>
*/
public abstract class JsonMessage {
// true if the compiled string is up-to-date, false otherwise
private boolean updated;
// the compiled json string of this colored text (can be outdated)
private String compiledJson;
/**
* Get the json representation of this message
* <p>
* Sent directly to the client
*
* @return the json representation of the message
*/
public abstract JsonObject getJsonObject();
/**
* Signal that the final json string changed and that it will need to be updated
*/
protected void refreshUpdate() {
this.updated = false;
}
/**
* Get the string json representation
*
* @return the string json representation
*/
@Override
public String toString() {
if (!updated) {
this.compiledJson = getJsonObject().toString();
this.updated = true;
}
return compiledJson;
}
}

View File

@ -10,8 +10,10 @@ import java.util.List;
/** /**
* Represent multiple {@link ColoredText} batched together with the possibility to add * Represent multiple {@link ColoredText} batched together with the possibility to add
* click and hover events * click and hover events
* <p>
* Used when the message can contain both colored text and event (otherwise, use {@link ColoredText)})
*/ */
public class RichMessage { public class RichMessage extends JsonMessage {
private List<RichComponent> components = new ArrayList<>(); private List<RichComponent> components = new ArrayList<>();
private RichComponent currentComponent; private RichComponent currentComponent;
@ -101,22 +103,8 @@ public class RichMessage {
return append(coloredText, FormatRetention.ALL); return append(coloredText, FormatRetention.ALL);
} }
/**
* Get the string representation of this json message
*
* @return the string representation of this json message
*/
@Override @Override
public String toString() { public JsonObject getJsonObject() {
return getJsonObject().toString();
}
/**
* Get the json object representing the whole rich message
*
* @return the json representation of this rich message
*/
private JsonObject getJsonObject() {
List<RichComponent> cacheComponents = new ArrayList<>(components); List<RichComponent> cacheComponents = new ArrayList<>(components);
// No component, return empty json object // No component, return empty json object

View File

@ -4,6 +4,7 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.attribute.Attribute; import net.minestom.server.attribute.Attribute;
import net.minestom.server.chat.ChatParser; import net.minestom.server.chat.ChatParser;
import net.minestom.server.chat.ColoredText; import net.minestom.server.chat.ColoredText;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.chat.RichMessage; import net.minestom.server.chat.RichMessage;
import net.minestom.server.collision.BoundingBox; import net.minestom.server.collision.BoundingBox;
import net.minestom.server.command.CommandManager; import net.minestom.server.command.CommandManager;
@ -661,19 +662,11 @@ public class Player extends LivingEntity implements CommandSender {
/** /**
* Send a message to the player * Send a message to the player
* *
* @param coloredText the text to send * @param message the message to send,
* you can use {@link ColoredText} and/or {@link RichMessage} to create it easily
*/ */
public void sendMessage(ColoredText coloredText) { public void sendMessage(JsonMessage message) {
sendJsonMessage(coloredText.toString()); sendJsonMessage(message.toString());
}
/**
* Send a rich message to the player
*
* @param richMessage the rich text to send
*/
public void sendMessage(RichMessage richMessage) {
sendJsonMessage(richMessage.toString());
} }
/** /**

View File

@ -168,7 +168,7 @@ public abstract class Chunk implements Viewable, DataContainer {
* @param x the block X * @param x the block X
* @param y the block Y * @param y the block Y
* @param z the block Z * @param z the block Z
* @param data the new data * @param data the new data, can be null
*/ */
public abstract void setBlockData(int x, int y, int z, Data data); public abstract void setBlockData(int x, int y, int z, Data data);