From c2c9c2774b56e8f5132455fd2d1616c877c29bd9 Mon Sep 17 00:00:00 2001 From: feildmaster <admin@feildmaster.com> Date: Sun, 8 Dec 2013 18:34:42 -0600 Subject: [PATCH 1/2] The start of the setup for the Message API. --- src/main/java/org/bukkit/message/Message.java | 397 ++++++++++++++++++ .../java/org/bukkit/message/MessageClick.java | 69 +++ .../java/org/bukkit/message/MessageHover.java | 69 +++ 3 files changed, 535 insertions(+) create mode 100644 src/main/java/org/bukkit/message/Message.java create mode 100644 src/main/java/org/bukkit/message/MessageClick.java create mode 100644 src/main/java/org/bukkit/message/MessageHover.java diff --git a/src/main/java/org/bukkit/message/Message.java b/src/main/java/org/bukkit/message/Message.java new file mode 100644 index 0000000000..5dcd3458a8 --- /dev/null +++ b/src/main/java/org/bukkit/message/Message.java @@ -0,0 +1,397 @@ +package org.bukkit.message; + +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang.Validate; +import org.bukkit.ChatColor; +import org.bukkit.inventory.ItemStack; + +/** + * Represents a chat message. + */ +public final class Message implements Cloneable { + /** + * Instantiates a new Message Builder. + * + * @return the new builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates a builder using the provided message as a base + * + * @param message message to use as a base + * @return the new builder + * @throws IllegalArgumentException if message is null + */ + public static Builder builder(Message message) { + Validate.notNull(message); + return new Builder(message); + } + + /** + * Creates and formats a message from the provided string. + * + * @param string String to format + * @return formatted message + * @throws IllegalArgumentException if string is null + */ + public static Message format(String string) { + Validate.notNull(string); + if (string.indexOf(ChatColor.COLOR_CHAR) == -1) { + return of(string); + } + return new Builder(string).build(); + } + + /** + * Creates a message with the provided text. + * + * @param string The text for the message + * @return the new message + * @throws IllegalArgumentException if string is null + */ + public static Message of(String string) { + Validate.notNull(string); + Builder builder = builder(); + builder.setText(string); + return builder.build(); + } + + /** + * Creates a message for the provided itemstack. + * + * @param itemstack the itemstack to create a message for + * @return the message + * @throws IllegalArgumentException if itemstack is null + */ + public static Message of(ItemStack itemstack) { + Validate.notNull(itemstack); + Builder builder = builder(); + // default = WHITE; record = AQUA; goldenapple:0 = AQUA else LIGHT_PURPLE; enchantedBook+enchants = YELLOW; enchanted = AQUA + // The way for determining colors is horrendous... Lets just leave it white - feildmaster + builder.setColor(ChatColor.WHITE); + builder.setHoverAction(MessageHover.of(itemstack)); + // TODO: getDisplayName doesn't return the item name, need a way to get base item name! + builder.append("[").append(format(itemstack.getItemMeta().getDisplayName())).append("]"); + return builder.build(); + } + + /** + * The Message Builder. + */ + public static final class Builder { + // TODO: store messages or builders? - builders allow more mutability + final List<Message> children = new ArrayList<Message>(); + String message = ""; + ChatColor color; + boolean bold; + boolean italic; + boolean underline; + boolean obfuscate; + MessageClick click; + MessageHover hover; + + Builder() {} + + // This constructor attempts to format the provided string + Builder(String string) { + // TODO: Parse through string + } + + Builder(Builder parent) { + color = parent.color; + bold = parent.bold; + italic = parent.italic; + underline = parent.underline; + obfuscate = parent.obfuscate; + click = parent.click == null ? null : parent.click; + hover = parent.hover == null ? null : parent.hover; + children.addAll(parent.children); + } + + // The idea here is to take messages and make them "mutable" + Builder(Message parent) { + color = parent.color; + bold = parent.bold; + italic = parent.italic; + underline = parent.underline; + obfuscate = parent.obfuscate; + } + + /** + * Appends the provided itemstack to the message. + * + * @param item Item to append + * @return this builder + * @throws IllegalArgumentException if item is null + */ + public Builder append(ItemStack item) { + Validate.notNull(item); + return append(of(item)); + } + + /** + * Appends the provided messages to the message. + * + * @param messages The messages to append + * @return this builder + * @throws IllegalArgumentException if any message is null + */ + public Builder append(Message... messages) { + Validate.noNullElements(messages, "Cannot have null messages"); + for (Message child : messages) { + children.add(child); + } + return this; + } + + /** + * Appends the provided string to the message. + * + * @param message The message to append + * @return this builder + * @throws IllegalArgumentException if the message is null + */ + public Builder append(String message) { + Validate.notNull(message); + append(of(message)); + return this; + } + + /** + * Sets the base text for the message. + * + * @param message The text to set the message to + * @return this builder + * @throws IllegalArgumentException if the message is null + */ + public Builder setText(String message) { + Validate.notNull(message); + this.message = message; + return this; + } + + /** + * Set the color of the message. + * <br /> + * May be null (no color) + * + * @param color The color this message should have + * @return this builder + * @throws IllegalArgumentException if the color is not a color + */ + public Builder setColor(ChatColor color) { + Validate.isTrue(color == null || color.isColor(), "[" + color + "] is not a valid color!"); + this.color = color; + return this; + } + + /** + * Sets the format to the value provided. + * + * @param format The format to set on this message + * @param value true to have that format present, false to remove it + * @return this builder + * @throws IllegalArgumentException if the format is null or not a valid format + */ + public Builder setFormat(ChatColor format, boolean value) { + Validate.isTrue(format != null && format.isFormat(), "[" + format + "] is not a valid format!"); + switch (format) { + case BOLD: + return setBold(value); + case ITALIC: + return setItalic(value); + case UNDERLINE: + return setUnderline(value); + case MAGIC: + return setObfuscate(value); + default: + throw new AssertionError(format); + } + } + + /** + * Makes the message bold. + * + * @param value true to set the message bold + * @return this builder + */ + public Builder setBold(boolean value) { + bold = value; + return this; + } + + /** + * Makes the message italicized. + * + * @param value true to set the message italicized + * @return this builder + */ + public Builder setItalic(boolean value) { + italic = value; + return this; + } + + /** + * Makes the message underlined. + * + * @param value true to set the message underlined + * @return this builder + */ + public Builder setUnderline(boolean value) { + underline = value; + return this; + } + + /** + * Makes the message obfuscated. + * + * @param value true to set the message obfuscated + * @return this builder + */ + public Builder setObfuscate(boolean value) { + obfuscate = value; + return this; + } + + /** + * Sets the action when hovering over the message. + * <br /> + * May be null for no action. + * + * @param hover the hover action + * @return this builder + */ + public Builder setHoverAction(MessageHover hover) { + this.hover = hover == null ? null : hover.clone(); + return this; + } + + /** + * Sets the action when clicking the message. + * <br /> + * May be null for no action. + * + * @param click the click action + * @return this builder + */ + public Builder setClickAction(MessageClick click) { + this.click = click == null ? null : click.clone(); + return this; + } + + /** + * Builds the message + * @return the message + */ + public Message build() { + return new Message(this); + } + } + + List<Message> children; + + final String text; + final ChatColor color; + final boolean bold; + final boolean italic; + final boolean underline; + final boolean obfuscate; + final MessageClick click; + final MessageHover hover; + + Message(Builder builder) { + text = builder.message; + color = builder.color; + bold = builder.bold; + italic = builder.italic; + underline = builder.underline; + obfuscate = builder.obfuscate; + click = builder.click.clone(); + hover = builder.hover.clone(); + children = ImmutableList.<Message>copyOf(builder.children); + } + + /** + * Gets the base text for this message. + * <br /> + * May be empty, but not null + * + * @return the base message + */ + public String getText() { + return text; + } + + /** + * Returns the color of the message. + * <br /> + * May be null + * + * @return the color of this message or null + */ + public ChatColor getColor() { + return color; + } + + /** + * Returns if this message is bold. + * + * @return True if the message is bold + */ + public boolean isBold() { + return bold; + } + + /** + * Returns if this message is italicized. + * + * @return True if the message is italicized + */ + public boolean isItalic() { + return italic; + } + + /** + * Returns if this message is underlined. + * + * @return True if the message is underlined + */ + public boolean isUnderlined() { + return underline; + } + + /** + * Returns if this message is obfuscated. + * + * @return True if the message is obfuscated + */ + public boolean isObfuscated() { + return obfuscate; + } + + /** + * Returns the children of this message. + * <br /> + * This list is immutable. + * + * @return A list of children + */ + public List<Message> getChildren() { + return children; + } + + @Override + public Message clone() { + try { + Message message = (Message) super.clone(); + return message; + } catch (CloneNotSupportedException e) { + throw new Error(e); + } + } +} diff --git a/src/main/java/org/bukkit/message/MessageClick.java b/src/main/java/org/bukkit/message/MessageClick.java new file mode 100644 index 0000000000..a21419e563 --- /dev/null +++ b/src/main/java/org/bukkit/message/MessageClick.java @@ -0,0 +1,69 @@ +package org.bukkit.message; + +import org.apache.commons.lang.Validate; + +/** + * Represents a click action + */ +public final class MessageClick implements Cloneable { + public static MessageClick ofOpenURL(String url) { + return forType(Type.OPEN_URL, url); + } + + public static MessageClick ofRunCommand(String command) { + return forType(Type.RUN_COMMAND, command); + } + + public static MessageClick ofSetCommand(String command) { + return forType(Type.SET_COMMAND, command); + } + + private static MessageClick forType(Type type, String action) { + Validate.notEmpty(action); // TODO: Null or Empty? + return new MessageClick(type, action); + } + + /** + * An enum for the various ways text can be clicked + */ + public enum Type { + /** + * Opens specified URL + */ + OPEN_URL, + /** + * Runs specified command + */ + RUN_COMMAND, + /** + * Sets the players text box with the provided text + */ + SET_COMMAND, + ; + } + + private final Type type; + private final String action; + + private MessageClick(Type type, String action) { + this.type = type; + this.action = action; + } + + public Type getType() { + return type; + } + + public String getAction() { + return action; + } + + @Override + public MessageClick clone(){ + try { + return (MessageClick) super.clone(); + } catch (CloneNotSupportedException ex) { + throw new Error(ex); + } + } +} diff --git a/src/main/java/org/bukkit/message/MessageHover.java b/src/main/java/org/bukkit/message/MessageHover.java new file mode 100644 index 0000000000..4efcac5aa7 --- /dev/null +++ b/src/main/java/org/bukkit/message/MessageHover.java @@ -0,0 +1,69 @@ +package org.bukkit.message; + +import org.apache.commons.lang.Validate; +import org.bukkit.Achievement; +import org.bukkit.inventory.ItemStack; + +/** + * Represents a hover action + */ +public final class MessageHover implements Cloneable { + public static MessageHover of(String string) { + Validate.notNull(string); + return of(Message.of(string)); + } + + public static MessageHover of(Message message) { + Validate.notNull(message); + return of(Type.SHOW_ACHIEVEMENT, message.clone()); + } + + public static MessageHover of(Achievement achievement) { + Validate.notNull(achievement); + return of(Type.SHOW_ACHIEVEMENT, achievement); + } + + public static MessageHover of(ItemStack item) { + Validate.notNull(item); + return of(Type.SHOW_ACHIEVEMENT, item.clone()); + } + + private static MessageHover of(Type type, Object object) { + return new MessageHover(type, object); + } + + public enum Type { + SHOW_TEXT, + SHOW_ACHIEVEMENT, + SHOW_ITEM, + ; + } + + private final Type type; + private final Object object; + + private MessageHover(Type type, Object object) { + this.type = type; + this.object = object; + } + + public Type getType() { + return type; + } + + public Object getValue() { + if (type == Type.SHOW_ITEM) { // We need to return a clone, since items are mutable + return ((ItemStack) object).clone(); + } + return object; + } + + @Override + public MessageHover clone() { + try { + return (MessageHover) super.clone(); + } catch (CloneNotSupportedException e) { + throw new Error(e); + } + } +} From ea41d6959927fb98671c1a5f89a526a417e92de1 Mon Sep 17 00:00:00 2001 From: feildmaster <admin@feildmaster.com> Date: Thu, 17 Jul 2014 04:30:35 -0500 Subject: [PATCH 2/2] Slight updates to api --- src/main/java/org/bukkit/message/Message.java | 27 ++++++++++++------- .../java/org/bukkit/message/MessageClick.java | 20 ++++++++------ .../java/org/bukkit/message/MessageHover.java | 8 +++--- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/bukkit/message/Message.java b/src/main/java/org/bukkit/message/Message.java index 5dcd3458a8..5876d96bd5 100644 --- a/src/main/java/org/bukkit/message/Message.java +++ b/src/main/java/org/bukkit/message/Message.java @@ -84,7 +84,6 @@ public static Message of(ItemStack itemstack) { * The Message Builder. */ public static final class Builder { - // TODO: store messages or builders? - builders allow more mutability final List<Message> children = new ArrayList<Message>(); String message = ""; ChatColor color; @@ -293,16 +292,16 @@ public Message build() { } } - List<Message> children; + private List<Message> children; - final String text; - final ChatColor color; - final boolean bold; - final boolean italic; - final boolean underline; - final boolean obfuscate; - final MessageClick click; - final MessageHover hover; + private final String text; + private final ChatColor color; + private final boolean bold; + private final boolean italic; + private final boolean underline; + private final boolean obfuscate; + private final MessageClick click; + private final MessageHover hover; Message(Builder builder) { text = builder.message; @@ -385,6 +384,14 @@ public List<Message> getChildren() { return children; } + public MessageClick getClickAction() { + return click; + } + + public MessageHover getHoverAction() { + return hover; + } + @Override public Message clone() { try { diff --git a/src/main/java/org/bukkit/message/MessageClick.java b/src/main/java/org/bukkit/message/MessageClick.java index a21419e563..d161e89f2f 100644 --- a/src/main/java/org/bukkit/message/MessageClick.java +++ b/src/main/java/org/bukkit/message/MessageClick.java @@ -1,25 +1,29 @@ package org.bukkit.message; +import java.util.regex.Pattern; import org.apache.commons.lang.Validate; /** * Represents a click action */ public final class MessageClick implements Cloneable { + private static final Pattern HTTP_REGEX = Pattern.compile("^https?://.*", Pattern.CASE_INSENSITIVE); + public static MessageClick ofOpenURL(String url) { + Validate.isTrue(HTTP_REGEX.matcher(url).matches(), "Valid url is required"); return forType(Type.OPEN_URL, url); } - public static MessageClick ofRunCommand(String command) { - return forType(Type.RUN_COMMAND, command); + public static MessageClick ofSendText(String text) { + return forType(Type.SEND_TEXT, text); } - public static MessageClick ofSetCommand(String command) { - return forType(Type.SET_COMMAND, command); + public static MessageClick ofSetText(String text) { + return forType(Type.SET_TEXT, text); } private static MessageClick forType(Type type, String action) { - Validate.notEmpty(action); // TODO: Null or Empty? + Validate.notEmpty(action); return new MessageClick(type, action); } @@ -32,13 +36,13 @@ public enum Type { */ OPEN_URL, /** - * Runs specified command + * Sends provided text to the server (as if the player sent it) */ - RUN_COMMAND, + SEND_TEXT, /** * Sets the players text box with the provided text */ - SET_COMMAND, + SET_TEXT, ; } diff --git a/src/main/java/org/bukkit/message/MessageHover.java b/src/main/java/org/bukkit/message/MessageHover.java index 4efcac5aa7..3a7d628132 100644 --- a/src/main/java/org/bukkit/message/MessageHover.java +++ b/src/main/java/org/bukkit/message/MessageHover.java @@ -15,7 +15,7 @@ public static MessageHover of(String string) { public static MessageHover of(Message message) { Validate.notNull(message); - return of(Type.SHOW_ACHIEVEMENT, message.clone()); + return of(Type.SHOW_TEXT, message.clone()); } public static MessageHover of(Achievement achievement) { @@ -25,7 +25,7 @@ public static MessageHover of(Achievement achievement) { public static MessageHover of(ItemStack item) { Validate.notNull(item); - return of(Type.SHOW_ACHIEVEMENT, item.clone()); + return of(Type.SHOW_ITEM ,item.clone()); } private static MessageHover of(Type type, Object object) { @@ -52,7 +52,8 @@ public Type getType() { } public Object getValue() { - if (type == Type.SHOW_ITEM) { // We need to return a clone, since items are mutable + if (type == Type.SHOW_ITEM) { + // We need to return a clone, since items are mutable return ((ItemStack) object).clone(); } return object; @@ -61,6 +62,7 @@ public Object getValue() { @Override public MessageHover clone() { try { + // No need to hard clone, internals are "safe" return (MessageHover) super.clone(); } catch (CloneNotSupportedException e) { throw new Error(e);