mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-07-14 11:24:44 +02:00
Reformat code
This commit is contained in:
@ -19,6 +19,8 @@ import java.util.Collection;
|
||||
*/
|
||||
public final class ArrayWrapper<E> {
|
||||
|
||||
private E[] _array;
|
||||
|
||||
/**
|
||||
* Creates an array wrapper with some elements.
|
||||
*
|
||||
@ -28,7 +30,38 @@ public final class ArrayWrapper<E> {
|
||||
setArray(elements);
|
||||
}
|
||||
|
||||
private E[] _array;
|
||||
/**
|
||||
* Converts an iterable element collection to an array of elements.
|
||||
* The iteration order of the specified object will be used as the array element order.
|
||||
*
|
||||
* @param list The iterable of objects which will be converted to an array.
|
||||
* @param c The type of the elements of the array.
|
||||
* @return An array of elements in the specified iterable.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") public static <T> T[] toArray(Iterable<? extends T> list,
|
||||
Class<T> c) {
|
||||
int size = -1;
|
||||
if (list instanceof Collection<?>) {
|
||||
@SuppressWarnings("rawtypes") Collection coll = (Collection) list;
|
||||
size = coll.size();
|
||||
}
|
||||
|
||||
|
||||
if (size < 0) {
|
||||
size = 0;
|
||||
// Ugly hack: Count it ourselves
|
||||
for (@SuppressWarnings("unused") T element : list) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
T[] result = (T[]) Array.newInstance(c, size);
|
||||
int i = 0;
|
||||
for (T element : list) { // Assumes iteration order is consistent
|
||||
result[i++] = element; // Assign array element at index THEN increment counter
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a reference to the wrapped array instance.
|
||||
@ -54,9 +87,7 @@ public final class ArrayWrapper<E> {
|
||||
*
|
||||
* @see Arrays#equals(Object[], Object[])
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
@SuppressWarnings("rawtypes") @Override public boolean equals(Object other) {
|
||||
if (!(other instanceof ArrayWrapper)) {
|
||||
return false;
|
||||
}
|
||||
@ -69,43 +100,8 @@ public final class ArrayWrapper<E> {
|
||||
* @return This object's hash code.
|
||||
* @see Arrays#hashCode(Object[])
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@Override public int hashCode() {
|
||||
return Arrays.hashCode(_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an iterable element collection to an array of elements.
|
||||
* The iteration order of the specified object will be used as the array element order.
|
||||
*
|
||||
* @param list The iterable of objects which will be converted to an array.
|
||||
* @param c The type of the elements of the array.
|
||||
* @return An array of elements in the specified iterable.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] toArray(Iterable<? extends T> list, Class<T> c) {
|
||||
int size = -1;
|
||||
if (list instanceof Collection<?>) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Collection coll = (Collection) list;
|
||||
size = coll.size();
|
||||
}
|
||||
|
||||
|
||||
if (size < 0) {
|
||||
size = 0;
|
||||
// Ugly hack: Count it ourselves
|
||||
for (@SuppressWarnings("unused") T element : list) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
T[] result = (T[]) Array.newInstance(c, size);
|
||||
int i = 0;
|
||||
for (T element : list) { // Assumes iteration order is consistent
|
||||
result[i++] = element; // Assign array element at index THEN increment counter
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,17 +1,11 @@
|
||||
package com.plotsquared.bukkit.chat;
|
||||
|
||||
import static com.plotsquared.bukkit.chat.TextualComponent.rawText;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.bukkit.Achievement;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.Statistic.Type;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
@ -22,19 +16,12 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static com.plotsquared.bukkit.chat.TextualComponent.rawText;
|
||||
|
||||
/**
|
||||
* Represents a formattable message. Such messages can use elements such as colors, formatting codes, hover and click data, and other features provided by the vanilla Minecraft <a href="http://minecraft.gamepedia.com/Tellraw#Raw_JSON_Text">JSON message formatter</a>.
|
||||
* This class allows plugins to emulate the functionality of the vanilla Minecraft <a href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw command</a>.
|
||||
@ -45,7 +32,14 @@ import java.util.logging.Level;
|
||||
* optionally initializing it with text. Further property-setting method calls will affect that editing component.
|
||||
* </p>
|
||||
*/
|
||||
public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<MessagePart>, ConfigurationSerializable {
|
||||
public class FancyMessage
|
||||
implements JsonRepresentedObject, Cloneable, Iterable<MessagePart>, ConfigurationSerializable {
|
||||
|
||||
private static Constructor<?> nmsPacketPlayOutChatConstructor;
|
||||
// The ChatSerializer's instance of Gson
|
||||
private static Object nmsChatSerializerGsonInstance;
|
||||
private static Method fromJsonMethod;
|
||||
private static JsonParser _stringParser = new JsonParser();
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(FancyMessage.class);
|
||||
@ -55,20 +49,6 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
private String jsonString;
|
||||
private boolean dirty;
|
||||
|
||||
private static Constructor<?> nmsPacketPlayOutChatConstructor;
|
||||
|
||||
@Override
|
||||
public FancyMessage clone() throws CloneNotSupportedException {
|
||||
FancyMessage instance = (FancyMessage) super.clone();
|
||||
instance.messageParts = new ArrayList<>(messageParts.size());
|
||||
for (int i = 0; i < messageParts.size(); i++) {
|
||||
instance.messageParts.add(i, messageParts.get(i).clone());
|
||||
}
|
||||
instance.dirty = false;
|
||||
instance.jsonString = null;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON message with text.
|
||||
*
|
||||
@ -85,10 +65,12 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
dirty = false;
|
||||
if (nmsPacketPlayOutChatConstructor == null) {
|
||||
try {
|
||||
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
|
||||
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat")
|
||||
.getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
|
||||
nmsPacketPlayOutChatConstructor.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
|
||||
} catch (SecurityException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e);
|
||||
}
|
||||
@ -102,6 +84,112 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
this((TextualComponent) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a JSON-represented message from a mapping of key-value pairs.
|
||||
* This is called by the Bukkit serialization API.
|
||||
* It is not intended for direct public API consumption.
|
||||
*
|
||||
* @param serialized The key-value mapping which represents a fancy message.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") public static FancyMessage deserialize(
|
||||
Map<String, Object> serialized) {
|
||||
FancyMessage msg = new FancyMessage();
|
||||
msg.messageParts = (List<MessagePart>) serialized.get("messageParts");
|
||||
msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null;
|
||||
msg.dirty = !serialized.containsKey("JSON");
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a fancy message from its JSON representation. This JSON representation is of the format of
|
||||
* that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
|
||||
*
|
||||
* @param json The JSON string which represents a fancy message.
|
||||
* @return A {@code FancyMessage} representing the parameterized JSON message.
|
||||
*/
|
||||
public static FancyMessage deserialize(String json) {
|
||||
JsonObject serialized = _stringParser.parse(json).getAsJsonObject();
|
||||
JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component
|
||||
FancyMessage returnVal = new FancyMessage();
|
||||
returnVal.messageParts.clear();
|
||||
for (JsonElement mPrt : extra) {
|
||||
MessagePart component = new MessagePart();
|
||||
JsonObject messagePart = mPrt.getAsJsonObject();
|
||||
for (Map.Entry<String, JsonElement> entry : messagePart.entrySet()) {
|
||||
// Deserialize text
|
||||
if (TextualComponent.isTextKey(entry.getKey())) {
|
||||
// The map mimics the YAML serialization, which has a "key" field and one or more "value" fields
|
||||
Map<String, Object> serializedMapForm =
|
||||
new HashMap<>(); // Must be object due to Bukkit serializer API compliance
|
||||
serializedMapForm.put("key", entry.getKey());
|
||||
if (entry.getValue().isJsonPrimitive()) {
|
||||
// Assume string
|
||||
serializedMapForm.put("value", entry.getValue().getAsString());
|
||||
} else {
|
||||
// Composite object, but we assume each element is a string
|
||||
for (Map.Entry<String, JsonElement> compositeNestedElement : entry
|
||||
.getValue().getAsJsonObject().entrySet()) {
|
||||
serializedMapForm.put("value." + compositeNestedElement.getKey(),
|
||||
compositeNestedElement.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
component.text = TextualComponent.deserialize(serializedMapForm);
|
||||
} else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) {
|
||||
if (entry.getValue().getAsBoolean()) {
|
||||
component.styles
|
||||
.add(MessagePart.stylesToNames.inverse().get(entry.getKey()));
|
||||
}
|
||||
} else if (entry.getKey().equals("color")) {
|
||||
component.color =
|
||||
ChatColor.valueOf(entry.getValue().getAsString().toUpperCase());
|
||||
} else if (entry.getKey().equals("clickEvent")) {
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.clickActionName = object.get("action").getAsString();
|
||||
component.clickActionData = object.get("value").getAsString();
|
||||
} else if (entry.getKey().equals("hoverEvent")) {
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.hoverActionName = object.get("action").getAsString();
|
||||
if (object.get("value").isJsonPrimitive()) {
|
||||
// Assume string
|
||||
component.hoverActionData =
|
||||
new JsonString(object.get("value").getAsString());
|
||||
} else {
|
||||
// Assume composite type
|
||||
// The only composite type we currently store is another FancyMessage
|
||||
// Therefore, recursion time!
|
||||
component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */);
|
||||
}
|
||||
} else if (entry.getKey().equals("insertion")) {
|
||||
component.insertionData = entry.getValue().getAsString();
|
||||
} else if (entry.getKey().equals("with")) {
|
||||
for (JsonElement object : entry.getValue().getAsJsonArray()) {
|
||||
if (object.isJsonPrimitive()) {
|
||||
component.translationReplacements
|
||||
.add(new JsonString(object.getAsString()));
|
||||
} else {
|
||||
// Only composite type stored in this array is - again - FancyMessages
|
||||
// Recurse within this function to parse this as a translation replacement
|
||||
component.translationReplacements.add(deserialize(object.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
returnVal.messageParts.add(component);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
@Override public FancyMessage clone() throws CloneNotSupportedException {
|
||||
FancyMessage instance = (FancyMessage) super.clone();
|
||||
instance.messageParts = new ArrayList<>(messageParts.size());
|
||||
for (int i = 0; i < messageParts.size(); i++) {
|
||||
instance.messageParts.add(i, messageParts.get(i).clone());
|
||||
}
|
||||
instance.dirty = false;
|
||||
instance.jsonString = null;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the current editing component to a value.
|
||||
*
|
||||
@ -242,8 +330,12 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
*/
|
||||
public FancyMessage achievementTooltip(final Achievement which) {
|
||||
try {
|
||||
Object achievement = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", Achievement.class).invoke(null, which);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name").get(achievement));
|
||||
Object achievement = Reflection
|
||||
.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement",
|
||||
Achievement.class).invoke(null, which);
|
||||
return achievementTooltip(
|
||||
(String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name")
|
||||
.get(achievement));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
@ -251,7 +343,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -267,11 +360,16 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
public FancyMessage statisticTooltip(final Statistic which) {
|
||||
Type type = which.getType();
|
||||
if (type != Type.UNTYPED) {
|
||||
throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!");
|
||||
throw new IllegalArgumentException(
|
||||
"That statistic requires an additional " + type + " parameter!");
|
||||
}
|
||||
try {
|
||||
Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic", Statistic.class).invoke(null, which);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
|
||||
Object statistic = Reflection
|
||||
.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic",
|
||||
Statistic.class).invoke(null, which);
|
||||
return achievementTooltip(
|
||||
(String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name")
|
||||
.get(statistic));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
@ -279,7 +377,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -299,11 +398,16 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
throw new IllegalArgumentException("That statistic needs no additional parameter!");
|
||||
}
|
||||
if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) {
|
||||
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
|
||||
throw new IllegalArgumentException(
|
||||
"Wrong parameter type for that statistic - needs " + type + "!");
|
||||
}
|
||||
try {
|
||||
Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic", Statistic.class, Material.class).invoke(null, which, item);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
|
||||
Object statistic = Reflection
|
||||
.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic",
|
||||
Statistic.class, Material.class).invoke(null, which, item);
|
||||
return achievementTooltip(
|
||||
(String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name")
|
||||
.get(statistic));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
@ -311,7 +415,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -331,11 +436,16 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
throw new IllegalArgumentException("That statistic needs no additional parameter!");
|
||||
}
|
||||
if (type != Type.ENTITY) {
|
||||
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
|
||||
throw new IllegalArgumentException(
|
||||
"Wrong parameter type for that statistic - needs " + type + "!");
|
||||
}
|
||||
try {
|
||||
Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic", Statistic.class, EntityType.class).invoke(null, which, entity);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
|
||||
Object statistic = Reflection
|
||||
.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic",
|
||||
Statistic.class, EntityType.class).invoke(null, which, entity);
|
||||
return achievementTooltip(
|
||||
(String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name")
|
||||
.get(statistic));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
@ -343,7 +453,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -356,7 +467,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage itemTooltip(final String itemJSON) {
|
||||
onHover("show_item", new JsonString(itemJSON)); // Seems a bit hacky, considering we have a JSON object as a parameter
|
||||
onHover("show_item", new JsonString(
|
||||
itemJSON)); // Seems a bit hacky, considering we have a JSON object as a parameter
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -369,8 +481,13 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
*/
|
||||
public FancyMessage itemTooltip(final ItemStack itemStack) {
|
||||
try {
|
||||
Object nmsItem = Reflection.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy", ItemStack.class).invoke(null, itemStack);
|
||||
return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save", Reflection.getNMSClass("NBTTagCompound")).invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance()).toString());
|
||||
Object nmsItem = Reflection
|
||||
.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy",
|
||||
ItemStack.class).invoke(null, itemStack);
|
||||
return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save",
|
||||
Reflection.getNMSClass("NBTTagCompound"))
|
||||
.invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance())
|
||||
.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return this;
|
||||
@ -400,6 +517,22 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
tooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, String.class));
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific message.
|
||||
* @return This builder instance.
|
||||
*/ /* ------------
|
||||
public FancyMessage translationReplacements(final Iterable<? extends CharSequence> replacements){
|
||||
for(CharSequence str : replacements){
|
||||
latest().translationReplacements.add(new JsonString(str));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw text when the client hovers over the text.
|
||||
@ -453,15 +586,19 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
}
|
||||
|
||||
FancyMessage result = new FancyMessage();
|
||||
result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object
|
||||
result.messageParts
|
||||
.clear(); // Remove the one existing text component that exists by default, which destabilizes the object
|
||||
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
try {
|
||||
for (MessagePart component : lines[i]) {
|
||||
if (component.clickActionData != null && component.clickActionName != null) {
|
||||
throw new IllegalArgumentException("The tooltip text cannot have click data.");
|
||||
} else if (component.hoverActionData != null && component.hoverActionName != null) {
|
||||
throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
|
||||
throw new IllegalArgumentException(
|
||||
"The tooltip text cannot have click data.");
|
||||
} else if (component.hoverActionData != null
|
||||
&& component.hoverActionName != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"The tooltip text cannot have a tooltip.");
|
||||
}
|
||||
if (component.hasText()) {
|
||||
result.messageParts.add(component.clone());
|
||||
@ -475,7 +612,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return formattedTooltip(result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended
|
||||
return formattedTooltip(
|
||||
result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended
|
||||
}
|
||||
|
||||
/**
|
||||
@ -486,7 +624,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(final Iterable<FancyMessage> lines) {
|
||||
return formattedTooltip(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class));
|
||||
return formattedTooltip(
|
||||
com.plotsquared.bukkit.chat.ArrayWrapper.toArray(lines, FancyMessage.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -503,22 +642,6 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific message.
|
||||
* @return This builder instance.
|
||||
*/ /* ------------
|
||||
public FancyMessage translationReplacements(final Iterable<? extends CharSequence> replacements){
|
||||
for(CharSequence str : replacements){
|
||||
latest().translationReplacements.add(new JsonString(str));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
@ -543,7 +666,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(final Iterable<FancyMessage> replacements) {
|
||||
return translationReplacements(com.plotsquared.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class));
|
||||
return translationReplacements(
|
||||
com.plotsquared.bukkit.chat.ArrayWrapper.toArray(replacements, FancyMessage.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -588,8 +712,7 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
@Override public void writeJson(JsonWriter writer) throws IOException {
|
||||
if (messageParts.size() == 1) {
|
||||
latest().writeJson(writer);
|
||||
} else {
|
||||
@ -641,8 +764,11 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
Player player = (Player) sender;
|
||||
try {
|
||||
Object handle = Reflection.getHandle(player);
|
||||
Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle);
|
||||
Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString));
|
||||
Object connection =
|
||||
Reflection.getField(handle.getClass(), "playerConnection").get(handle);
|
||||
Reflection
|
||||
.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet"))
|
||||
.invoke(connection, createChatPacket(jsonString));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
@ -650,7 +776,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
} catch (InstantiationException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A error has occurred during invoking of method.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
@ -658,11 +785,9 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
}
|
||||
}
|
||||
|
||||
// The ChatSerializer's instance of Gson
|
||||
private static Object nmsChatSerializerGsonInstance;
|
||||
private static Method fromJsonMethod;
|
||||
|
||||
private Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
|
||||
private Object createChatPacket(String json)
|
||||
throws IllegalArgumentException, IllegalAccessException, InstantiationException,
|
||||
InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
|
||||
if (nmsChatSerializerGsonInstance == null) {
|
||||
// Find the field and its value, completely bypassing obfuscation
|
||||
Class<?> chatSerializerClazz;
|
||||
@ -673,7 +798,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
// Y = minor
|
||||
// Z = revision
|
||||
final String version = Reflection.getVersion();
|
||||
String[] split = version.substring(1, version.length() - 1).split("_"); // Remove trailing dot
|
||||
String[] split =
|
||||
version.substring(1, version.length() - 1).split("_"); // Remove trailing dot
|
||||
//int majorVersion = Integer.parseInt(split[0]);
|
||||
int minorVersion = Integer.parseInt(split[1]);
|
||||
int revisionVersion = Integer.parseInt(split[2].substring(1)); // Substring to ignore R
|
||||
@ -689,11 +815,14 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
}
|
||||
|
||||
for (Field declaredField : chatSerializerClazz.getDeclaredFields()) {
|
||||
if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) {
|
||||
if (Modifier.isFinal(declaredField.getModifiers()) && Modifier
|
||||
.isStatic(declaredField.getModifiers()) && declaredField.getType().getName()
|
||||
.endsWith("Gson")) {
|
||||
// We've found our field
|
||||
declaredField.setAccessible(true);
|
||||
nmsChatSerializerGsonInstance = declaredField.get(null);
|
||||
fromJsonMethod = nmsChatSerializerGsonInstance.getClass().getMethod("fromJson", String.class, Class.class);
|
||||
fromJsonMethod = nmsChatSerializerGsonInstance.getClass()
|
||||
.getMethod("fromJson", String.class, Class.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -701,7 +830,8 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
|
||||
// Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it
|
||||
// Of course, the implementation may change, but fuzzy matches might break with signature changes
|
||||
Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent"));
|
||||
Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json,
|
||||
Reflection.getNMSClass("IChatBaseComponent"));
|
||||
|
||||
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
|
||||
}
|
||||
@ -782,26 +912,10 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("messageParts", messageParts);
|
||||
// map.put("JSON", toJSONString());
|
||||
// map.put("JSON", toJSONString());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a JSON-represented message from a mapping of key-value pairs.
|
||||
* This is called by the Bukkit serialization API.
|
||||
* It is not intended for direct public API consumption.
|
||||
*
|
||||
* @param serialized The key-value mapping which represents a fancy message.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static FancyMessage deserialize(Map<String, Object> serialized) {
|
||||
FancyMessage msg = new FancyMessage();
|
||||
msg.messageParts = (List<MessagePart>) serialized.get("messageParts");
|
||||
msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null;
|
||||
msg.dirty = !serialized.containsKey("JSON");
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Internally called method. Not for API consumption.</b>
|
||||
*/
|
||||
@ -809,78 +923,4 @@ public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<
|
||||
return messageParts.iterator();
|
||||
}
|
||||
|
||||
private static JsonParser _stringParser = new JsonParser();
|
||||
|
||||
/**
|
||||
* Deserializes a fancy message from its JSON representation. This JSON representation is of the format of
|
||||
* that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
|
||||
*
|
||||
* @param json The JSON string which represents a fancy message.
|
||||
* @return A {@code FancyMessage} representing the parameterized JSON message.
|
||||
*/
|
||||
public static FancyMessage deserialize(String json) {
|
||||
JsonObject serialized = _stringParser.parse(json).getAsJsonObject();
|
||||
JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component
|
||||
FancyMessage returnVal = new FancyMessage();
|
||||
returnVal.messageParts.clear();
|
||||
for (JsonElement mPrt : extra) {
|
||||
MessagePart component = new MessagePart();
|
||||
JsonObject messagePart = mPrt.getAsJsonObject();
|
||||
for (Map.Entry<String, JsonElement> entry : messagePart.entrySet()) {
|
||||
// Deserialize text
|
||||
if (TextualComponent.isTextKey(entry.getKey())) {
|
||||
// The map mimics the YAML serialization, which has a "key" field and one or more "value" fields
|
||||
Map<String, Object> serializedMapForm = new HashMap<>(); // Must be object due to Bukkit serializer API compliance
|
||||
serializedMapForm.put("key", entry.getKey());
|
||||
if (entry.getValue().isJsonPrimitive()) {
|
||||
// Assume string
|
||||
serializedMapForm.put("value", entry.getValue().getAsString());
|
||||
} else {
|
||||
// Composite object, but we assume each element is a string
|
||||
for (Map.Entry<String, JsonElement> compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) {
|
||||
serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
component.text = TextualComponent.deserialize(serializedMapForm);
|
||||
} else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) {
|
||||
if (entry.getValue().getAsBoolean()) {
|
||||
component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey()));
|
||||
}
|
||||
} else if (entry.getKey().equals("color")) {
|
||||
component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase());
|
||||
} else if (entry.getKey().equals("clickEvent")) {
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.clickActionName = object.get("action").getAsString();
|
||||
component.clickActionData = object.get("value").getAsString();
|
||||
} else if (entry.getKey().equals("hoverEvent")) {
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.hoverActionName = object.get("action").getAsString();
|
||||
if (object.get("value").isJsonPrimitive()) {
|
||||
// Assume string
|
||||
component.hoverActionData = new JsonString(object.get("value").getAsString());
|
||||
} else {
|
||||
// Assume composite type
|
||||
// The only composite type we currently store is another FancyMessage
|
||||
// Therefore, recursion time!
|
||||
component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */);
|
||||
}
|
||||
} else if (entry.getKey().equals("insertion")) {
|
||||
component.insertionData = entry.getValue().getAsString();
|
||||
} else if (entry.getKey().equals("with")) {
|
||||
for (JsonElement object : entry.getValue().getAsJsonArray()) {
|
||||
if (object.isJsonPrimitive()) {
|
||||
component.translationReplacements.add(new JsonString(object.getAsString()));
|
||||
} else {
|
||||
// Only composite type stored in this array is - again - FancyMessages
|
||||
// Recurse within this function to parse this as a translation replacement
|
||||
component.translationReplacements.add(deserialize(object.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
returnVal.messageParts.add(component);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ interface JsonRepresentedObject {
|
||||
|
||||
/**
|
||||
* Writes the JSON representation of this object to the specified writer.
|
||||
*
|
||||
* @param writer The JSON writer which will receive the object.
|
||||
* @throws IOException If an error occurs writing to the stream.
|
||||
*/
|
||||
|
@ -20,8 +20,11 @@ final class JsonString implements JsonRepresentedObject, ConfigurationSerializab
|
||||
_value = value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
public static JsonString deserialize(Map<String, Object> map) {
|
||||
return new JsonString(map.get("stringValue").toString());
|
||||
}
|
||||
|
||||
@Override public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.value(getValue());
|
||||
}
|
||||
|
||||
@ -35,12 +38,7 @@ final class JsonString implements JsonRepresentedObject, ConfigurationSerializab
|
||||
return theSingleValue;
|
||||
}
|
||||
|
||||
public static JsonString deserialize(Map<String, Object> map) {
|
||||
return new JsonString(map.get("stringValue").toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@Override public String toString() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
|
@ -19,43 +19,6 @@ import java.util.logging.Level;
|
||||
*/
|
||||
final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable {
|
||||
|
||||
ChatColor color = ChatColor.WHITE;
|
||||
ArrayList<ChatColor> styles = new ArrayList<>();
|
||||
String clickActionName = null;
|
||||
String clickActionData = null;
|
||||
String hoverActionName = null;
|
||||
JsonRepresentedObject hoverActionData = null;
|
||||
TextualComponent text = null;
|
||||
String insertionData = null;
|
||||
ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<>();
|
||||
|
||||
MessagePart(final TextualComponent text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
MessagePart() {
|
||||
this.text = null;
|
||||
}
|
||||
|
||||
boolean hasText() {
|
||||
return text != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MessagePart clone() throws CloneNotSupportedException {
|
||||
MessagePart obj = (MessagePart) super.clone();
|
||||
obj.styles = (ArrayList<ChatColor>) styles.clone();
|
||||
if (hoverActionData instanceof JsonString) {
|
||||
obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
|
||||
} else if (hoverActionData instanceof FancyMessage) {
|
||||
obj.hoverActionData = ((FancyMessage) hoverActionData).clone();
|
||||
}
|
||||
obj.translationReplacements = (ArrayList<JsonRepresentedObject>) translationReplacements.clone();
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
static final BiMap<ChatColor, String> stylesToNames;
|
||||
|
||||
static {
|
||||
@ -83,6 +46,62 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
|
||||
stylesToNames = builder.build();
|
||||
}
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(MessagePart.class);
|
||||
}
|
||||
|
||||
ChatColor color = ChatColor.WHITE;
|
||||
ArrayList<ChatColor> styles = new ArrayList<>();
|
||||
String clickActionName = null;
|
||||
String clickActionData = null;
|
||||
String hoverActionName = null;
|
||||
JsonRepresentedObject hoverActionData = null;
|
||||
TextualComponent text = null;
|
||||
String insertionData = null;
|
||||
ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<>();
|
||||
|
||||
MessagePart(final TextualComponent text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
MessagePart() {
|
||||
this.text = null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static MessagePart deserialize(Map<String, Object> serialized) {
|
||||
MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
|
||||
part.styles = (ArrayList<ChatColor>) serialized.get("styles");
|
||||
part.color = ChatColor.getByChar(serialized.get("color").toString());
|
||||
part.hoverActionName = (String) serialized.get("hoverActionName");
|
||||
part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
|
||||
part.clickActionName = (String) serialized.get("clickActionName");
|
||||
part.clickActionData = (String) serialized.get("clickActionData");
|
||||
part.insertionData = (String) serialized.get("insertion");
|
||||
part.translationReplacements =
|
||||
(ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements");
|
||||
return part;
|
||||
}
|
||||
|
||||
boolean hasText() {
|
||||
return text != null;
|
||||
}
|
||||
|
||||
@Override @SuppressWarnings("unchecked") public MessagePart clone()
|
||||
throws CloneNotSupportedException {
|
||||
MessagePart obj = (MessagePart) super.clone();
|
||||
obj.styles = (ArrayList<ChatColor>) styles.clone();
|
||||
if (hoverActionData instanceof JsonString) {
|
||||
obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
|
||||
} else if (hoverActionData instanceof FancyMessage) {
|
||||
obj.hoverActionData = ((FancyMessage) hoverActionData).clone();
|
||||
}
|
||||
obj.translationReplacements =
|
||||
(ArrayList<JsonRepresentedObject>) translationReplacements.clone();
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
public void writeJson(JsonWriter json) {
|
||||
try {
|
||||
json.beginObject();
|
||||
@ -92,24 +111,20 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
|
||||
json.name(stylesToNames.get(style)).value(true);
|
||||
}
|
||||
if (clickActionName != null && clickActionData != null) {
|
||||
json.name("clickEvent")
|
||||
.beginObject()
|
||||
.name("action").value(clickActionName)
|
||||
.name("value").value(clickActionData)
|
||||
.endObject();
|
||||
json.name("clickEvent").beginObject().name("action").value(clickActionName)
|
||||
.name("value").value(clickActionData).endObject();
|
||||
}
|
||||
if (hoverActionName != null && hoverActionData != null) {
|
||||
json.name("hoverEvent")
|
||||
.beginObject()
|
||||
.name("action").value(hoverActionName)
|
||||
.name("value");
|
||||
json.name("hoverEvent").beginObject().name("action").value(hoverActionName)
|
||||
.name("value");
|
||||
hoverActionData.writeJson(json);
|
||||
json.endObject();
|
||||
}
|
||||
if (insertionData != null) {
|
||||
json.name("insertion").value(insertionData);
|
||||
}
|
||||
if (translationReplacements.size() > 0 && text != null && TextualComponent.isTranslatableText(text)) {
|
||||
if (translationReplacements.size() > 0 && text != null && TextualComponent
|
||||
.isTranslatableText(text)) {
|
||||
json.name("with").beginArray();
|
||||
for (JsonRepresentedObject obj : translationReplacements) {
|
||||
obj.writeJson(json);
|
||||
@ -118,7 +133,8 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
|
||||
}
|
||||
json.endObject();
|
||||
} catch (IOException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
|
||||
Bukkit.getLogger()
|
||||
.log(Level.WARNING, "A problem occured during writing of JSON string", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,22 +152,4 @@ final class MessagePart implements JsonRepresentedObject, ConfigurationSerializa
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static MessagePart deserialize(Map<String, Object> serialized) {
|
||||
MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
|
||||
part.styles = (ArrayList<ChatColor>) serialized.get("styles");
|
||||
part.color = ChatColor.getByChar(serialized.get("color").toString());
|
||||
part.hoverActionName = (String) serialized.get("hoverActionName");
|
||||
part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
|
||||
part.clickActionName = (String) serialized.get("clickActionName");
|
||||
part.clickActionData = (String) serialized.get("clickActionData");
|
||||
part.insertionData = (String) serialized.get("insertion");
|
||||
part.translationReplacements = (ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements");
|
||||
return part;
|
||||
}
|
||||
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(MessagePart.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,10 +28,12 @@ public final class Reflection {
|
||||
* Contains loaded methods in a cache.
|
||||
* The map maps [types to maps of [method names to maps of [parameter types to method instances]]].
|
||||
*/
|
||||
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<>();
|
||||
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>>
|
||||
_loadedMethods = new HashMap<>();
|
||||
private static String _versionString;
|
||||
|
||||
private Reflection() { }
|
||||
private Reflection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version string from the package name of the CraftBukkit server implementation.
|
||||
@ -109,8 +111,9 @@ public final class Reflection {
|
||||
* @param obj The object for which to retrieve an NMS handle.
|
||||
* @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}.
|
||||
*/
|
||||
public synchronized static Object getHandle(Object obj) throws InvocationTargetException, IllegalAccessException, IllegalArgumentException {
|
||||
return getMethod(obj.getClass(), "getHandle").invoke(obj);
|
||||
public synchronized static Object getHandle(Object obj)
|
||||
throws InvocationTargetException, IllegalAccessException, IllegalArgumentException {
|
||||
return getMethod(obj.getClass(), "getHandle").invoke(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,7 +184,8 @@ public final class Reflection {
|
||||
_loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>());
|
||||
}
|
||||
|
||||
Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
|
||||
Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames =
|
||||
_loadedMethods.get(clazz);
|
||||
if (!loadedMethodNames.containsKey(name)) {
|
||||
loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>());
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ public abstract class TextualComponent implements Cloneable {
|
||||
if (map.containsKey("key") && map.size() == 2 && map.containsKey("value")) {
|
||||
// Arbitrary text component
|
||||
return ArbitraryTextTypeComponent.deserialize(map);
|
||||
} else if (map.size() >= 2 && map.containsKey("key") && !map.containsKey("value") /* It contains keys that START WITH value */) {
|
||||
} else if (map.size() >= 2 && map.containsKey("key") && !map
|
||||
.containsKey("value") /* It contains keys that START WITH value */) {
|
||||
// Complex JSON object
|
||||
return ComplexTextTypeComponent.deserialize(map);
|
||||
}
|
||||
@ -36,16 +37,18 @@ public abstract class TextualComponent implements Cloneable {
|
||||
}
|
||||
|
||||
static boolean isTextKey(String key) {
|
||||
return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector");
|
||||
return key.equals("translate") || key.equals("text") || key.equals("score") || key
|
||||
.equals("selector");
|
||||
}
|
||||
|
||||
static boolean isTranslatableText(TextualComponent component) {
|
||||
return component instanceof ComplexTextTypeComponent && component.getKey().equals("translate");
|
||||
return component instanceof ComplexTextTypeComponent && component.getKey()
|
||||
.equals("translate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textual component representing a string literal.
|
||||
*
|
||||
* <p>
|
||||
* <p>This is the default type of textual component when a single string
|
||||
* literal is given to a method.
|
||||
*
|
||||
@ -73,7 +76,8 @@ public abstract class TextualComponent implements Cloneable {
|
||||
}
|
||||
|
||||
private static void throwUnsupportedSnapshot() {
|
||||
throw new UnsupportedOperationException("This feature is only supported in snapshot releases.");
|
||||
throw new UnsupportedOperationException(
|
||||
"This feature is only supported in snapshot releases.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,15 +98,15 @@ public abstract class TextualComponent implements Cloneable {
|
||||
/**
|
||||
* Create a textual component representing a scoreboard value.
|
||||
* The client will see the score of the specified player for the specified objective as the text represented by this component.
|
||||
*
|
||||
* <p>
|
||||
* <p><b>This method is currently guaranteed to throw an {@code UnsupportedOperationException}
|
||||
* as it is only supported on snapshot clients.</b>
|
||||
*
|
||||
* @param playerName The name of the player whos score will be shown. If
|
||||
* this string represents the single-character sequence
|
||||
* "*", the viewing player's score will be displayed.
|
||||
* Standard minecraft selectors (@a, @p, etc)
|
||||
* are <em>not</em> supported.
|
||||
* @param playerName The name of the player whos score will be shown. If
|
||||
* this string represents the single-character sequence
|
||||
* "*", the viewing player's score will be displayed.
|
||||
* Standard minecraft selectors (@a, @p, etc)
|
||||
* are <em>not</em> supported.
|
||||
* @param scoreboardObjective The name of the objective for
|
||||
* which to display the score.
|
||||
* @return The text component representing the specified scoreboard score
|
||||
@ -112,10 +116,9 @@ public abstract class TextualComponent implements Cloneable {
|
||||
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE
|
||||
// OVERLOADS documentation accordingly
|
||||
|
||||
return new ComplexTextTypeComponent("score", ImmutableMap.<String, String>builder()
|
||||
.put("name", playerName)
|
||||
.put("objective", scoreboardObjective)
|
||||
.build());
|
||||
return new ComplexTextTypeComponent("score",
|
||||
ImmutableMap.<String, String>builder().put("name", playerName)
|
||||
.put("objective", scoreboardObjective).build());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,7 +129,7 @@ public abstract class TextualComponent implements Cloneable {
|
||||
* </p>
|
||||
*
|
||||
* @param selector The minecraft player or entity selector which will capture the entities whose string representations will be displayed in
|
||||
* the place of this text component.
|
||||
* the place of this text component.
|
||||
* @return The text component representing the name of the entities captured by the selector.
|
||||
*/
|
||||
public static TextualComponent selector(String selector) {
|
||||
@ -136,8 +139,7 @@ public abstract class TextualComponent implements Cloneable {
|
||||
return new ArbitraryTextTypeComponent("selector", selector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@Override public String toString() {
|
||||
return getReadableString();
|
||||
}
|
||||
|
||||
@ -155,8 +157,7 @@ public abstract class TextualComponent implements Cloneable {
|
||||
* Clones a textual component instance.
|
||||
* The returned object should not reference this textual component instance, but should maintain the same key and value.
|
||||
*/
|
||||
@Override
|
||||
public abstract TextualComponent clone() throws CloneNotSupportedException;
|
||||
@Override public abstract TextualComponent clone() throws CloneNotSupportedException;
|
||||
|
||||
/**
|
||||
* Writes the text data represented by this textual component to the specified JSON writer object.
|
||||
@ -171,7 +172,8 @@ public abstract class TextualComponent implements Cloneable {
|
||||
* Internal class used to represent all types of text components.
|
||||
* Exception validating done is on keys and values.
|
||||
*/
|
||||
private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
|
||||
private static final class ArbitraryTextTypeComponent extends TextualComponent
|
||||
implements ConfigurationSerializable {
|
||||
|
||||
private String key;
|
||||
private String value;
|
||||
@ -182,16 +184,17 @@ public abstract class TextualComponent implements Cloneable {
|
||||
}
|
||||
|
||||
public static ArbitraryTextTypeComponent deserialize(Map<String, Object> map) {
|
||||
return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString());
|
||||
return new ArbitraryTextTypeComponent(map.get("key").toString(),
|
||||
map.get("value").toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
@Override public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
|
||||
Preconditions
|
||||
.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@ -204,20 +207,16 @@ public abstract class TextualComponent implements Cloneable {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextualComponent clone() throws CloneNotSupportedException {
|
||||
@Override public TextualComponent clone() throws CloneNotSupportedException {
|
||||
// Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
|
||||
return new ArbitraryTextTypeComponent(getKey(), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
@Override public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.name(getKey()).value(getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("serial")
|
||||
public Map<String, Object> serialize() {
|
||||
@Override @SuppressWarnings("serial") public Map<String, Object> serialize() {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put("key", getKey());
|
||||
@ -226,19 +225,20 @@ public abstract class TextualComponent implements Cloneable {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadableString() {
|
||||
@Override public String getReadableString() {
|
||||
return getValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal class used to represent a text component with a nested JSON
|
||||
* value.
|
||||
*
|
||||
* <p>
|
||||
* <p>Exception validating done is on keys and values.
|
||||
*/
|
||||
private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
|
||||
private static final class ComplexTextTypeComponent extends TextualComponent
|
||||
implements ConfigurationSerializable {
|
||||
|
||||
private String key;
|
||||
private Map<String, String> value;
|
||||
@ -255,19 +255,20 @@ public abstract class TextualComponent implements Cloneable {
|
||||
if (valEntry.getKey().equals("key")) {
|
||||
key = (String) valEntry.getValue();
|
||||
} else if (valEntry.getKey().startsWith("value.")) {
|
||||
value.put(valEntry.getKey().substring(6) /* Strips out the value prefix */, valEntry.getValue().toString());
|
||||
value.put(valEntry.getKey().substring(6) /* Strips out the value prefix */,
|
||||
valEntry.getValue().toString());
|
||||
}
|
||||
}
|
||||
return new ComplexTextTypeComponent(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
@Override public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
|
||||
Preconditions
|
||||
.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@ -280,14 +281,12 @@ public abstract class TextualComponent implements Cloneable {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextualComponent clone() {
|
||||
@Override public TextualComponent clone() {
|
||||
// Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
|
||||
return new ComplexTextTypeComponent(getKey(), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
@Override public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.name(getKey());
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, String> jsonPair : value.entrySet()) {
|
||||
@ -296,9 +295,7 @@ public abstract class TextualComponent implements Cloneable {
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("serial")
|
||||
public Map<String, Object> serialize() {
|
||||
@Override @SuppressWarnings("serial") public Map<String, Object> serialize() {
|
||||
return new java.util.HashMap<String, Object>() {
|
||||
{
|
||||
put("key", getKey());
|
||||
@ -309,8 +306,7 @@ public abstract class TextualComponent implements Cloneable {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadableString() {
|
||||
@Override public String getReadableString() {
|
||||
return getKey();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user