mirror of
				https://github.com/IntellectualSites/PlotSquared.git
				synced 2025-10-31 09:33:43 +01:00 
			
		
		
		
	cleanup
This commit is contained in:
		| @@ -16,61 +16,62 @@ import org.apache.commons.lang.Validate; | ||||
|  * @param <E> The type of elements in the array. | ||||
|  * @see Arrays | ||||
|  */ | ||||
| public final class ArrayWrapper<E> { | ||||
| public final class ArrayWrapper<E> | ||||
| { | ||||
|  | ||||
| 	/** | ||||
| 	 * Creates an array wrapper with some elements. | ||||
| 	 * @param elements The elements of the array. | ||||
| 	 */ | ||||
| 	public ArrayWrapper(E... elements){ | ||||
| 		setArray(elements); | ||||
| 	} | ||||
| 	 | ||||
| 	private E[] _array; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Retrieves a reference to the wrapped array instance. | ||||
| 	 * @return The array wrapped by this instance. | ||||
| 	 */ | ||||
| 	public E[] getArray(){ | ||||
| 		return _array;	 | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Set this wrapper to wrap a new array instance. | ||||
| 	 * @param array The new wrapped array. | ||||
| 	 */ | ||||
| 	public void setArray(E[] array){ | ||||
| 		Validate.notNull(array, "The array must not be null."); | ||||
| 		_array = array; | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Determines if this object has a value equivalent to another object. | ||||
| 	 * @see Arrays#equals(Object[], Object[]) | ||||
| 	 */ | ||||
| 	@SuppressWarnings("rawtypes") | ||||
| 	@Override | ||||
| 	public boolean equals(Object other) | ||||
|     /** | ||||
|      * Creates an array wrapper with some elements. | ||||
|      * @param elements The elements of the array. | ||||
|      */ | ||||
|     public ArrayWrapper(final E... elements) | ||||
|     { | ||||
|         if (!(other instanceof ArrayWrapper)) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         return Arrays.equals(_array, ((ArrayWrapper)other)._array); | ||||
|         setArray(elements); | ||||
|     } | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the hash code represented by this objects value. | ||||
| 	 * @see Arrays#hashCode(Object[]) | ||||
| 	 * @return This object's hash code. | ||||
| 	 */ | ||||
|     private E[] _array; | ||||
|  | ||||
|     /** | ||||
|      * Retrieves a reference to the wrapped array instance. | ||||
|      * @return The array wrapped by this instance. | ||||
|      */ | ||||
|     public E[] getArray() | ||||
|     { | ||||
|         return _array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set this wrapper to wrap a new array instance. | ||||
|      * @param array The new wrapped array. | ||||
|      */ | ||||
|     public void setArray(final E[] array) | ||||
|     { | ||||
|         Validate.notNull(array, "The array must not be null."); | ||||
|         _array = array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Determines if this object has a value equivalent to another object. | ||||
|      * @see Arrays#equals(Object[], Object[]) | ||||
|      */ | ||||
|     @SuppressWarnings("rawtypes") | ||||
|     @Override | ||||
|     public boolean equals(final Object other) | ||||
|     { | ||||
|         if (!(other instanceof ArrayWrapper)) { return false; } | ||||
|         return Arrays.equals(_array, ((ArrayWrapper) other)._array); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the hash code represented by this objects value. | ||||
|      * @see Arrays#hashCode(Object[]) | ||||
|      * @return This object's hash code. | ||||
|      */ | ||||
|     @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. | ||||
| @@ -78,29 +79,34 @@ public final class ArrayWrapper<E> { | ||||
|      * @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) { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static <T> T[] toArray(final Iterable<? extends T> list, final Class<T> c) | ||||
|     { | ||||
|         int size = -1; | ||||
|         if(list instanceof Collection<?>){ | ||||
|         	@SuppressWarnings("rawtypes") | ||||
| 			Collection coll = (Collection)list; | ||||
|         	size = coll.size(); | ||||
|         if (list instanceof Collection<?>) | ||||
|         { | ||||
|             @SuppressWarnings("rawtypes") | ||||
|             final Collection coll = (Collection) list; | ||||
|             size = coll.size(); | ||||
|         } | ||||
|          | ||||
|          | ||||
|         if(size < 0){ | ||||
|         	size = 0; | ||||
|         	// Ugly hack: Count it ourselves | ||||
|         	for(@SuppressWarnings("unused") T element : list){ | ||||
|         		size++; | ||||
|         	} | ||||
|  | ||||
|         if (size < 0) | ||||
|         { | ||||
|             size = 0; | ||||
|             // Ugly hack: Count it ourselves | ||||
|             for (@SuppressWarnings("unused") | ||||
|             final T element : list) | ||||
|             { | ||||
|                 size++; | ||||
|             } | ||||
|         } | ||||
|     	 | ||||
|         T[] result = (T[]) Array.newInstance(c, size); | ||||
|  | ||||
|         final 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 | ||||
|     	} | ||||
|         for (final T element : list) | ||||
|         { // Assumes iteration order is consistent | ||||
|             result[i++] = element; // Assign array element at index THEN increment counter | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -7,13 +7,14 @@ import com.google.gson.stream.JsonWriter; | ||||
| /** | ||||
|  * Represents an object that can be serialized to a JSON writer instance. | ||||
|  */ | ||||
| interface JsonRepresentedObject { | ||||
| 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. | ||||
|      */ | ||||
|     void writeJson(final JsonWriter writer) throws IOException; | ||||
|  | ||||
| 	/** | ||||
| 	 * 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. | ||||
| 	 */ | ||||
| 	void writeJson(JsonWriter writer) throws IOException; | ||||
| 	 | ||||
| } | ||||
|   | ||||
| @@ -12,35 +12,43 @@ import com.intellectualcrafters.configuration.serialization.ConfigurationSeriali | ||||
|  * Writes by this object will not write name values nor begin/end objects in the JSON stream. | ||||
|  * All writes merely write the represented string value. | ||||
|  */ | ||||
| final class JsonString implements JsonRepresentedObject, ConfigurationSerializable { | ||||
| final class JsonString implements JsonRepresentedObject, ConfigurationSerializable | ||||
| { | ||||
|  | ||||
| 	private String _value; | ||||
| 	 | ||||
| 	public JsonString(CharSequence value){ | ||||
| 		_value = value == null ? null : value.toString(); | ||||
| 	} | ||||
|     private final String _value; | ||||
|  | ||||
| 	@Override | ||||
| 	public void writeJson(JsonWriter writer) throws IOException { | ||||
| 		writer.value(getValue()); | ||||
| 	} | ||||
| 	 | ||||
| 	public String getValue(){ | ||||
| 		return _value; | ||||
| 	} | ||||
|     public JsonString(final CharSequence value) | ||||
|     { | ||||
|         _value = value == null ? null : value.toString(); | ||||
|     } | ||||
|  | ||||
| 	public Map<String, Object> serialize() { | ||||
| 		HashMap<String, Object> theSingleValue = new HashMap<String, Object>(); | ||||
| 		theSingleValue.put("stringValue", _value); | ||||
| 		return theSingleValue; | ||||
| 	} | ||||
| 	 | ||||
| 	public static JsonString deserialize(Map<String, Object> map){ | ||||
| 		return new JsonString(map.get("stringValue").toString()); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public String toString(){ | ||||
| 		return _value; | ||||
| 	} | ||||
|     @Override | ||||
|     public void writeJson(final JsonWriter writer) throws IOException | ||||
|     { | ||||
|         writer.value(getValue()); | ||||
|     } | ||||
|  | ||||
|     public String getValue() | ||||
|     { | ||||
|         return _value; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Map<String, Object> serialize() | ||||
|     { | ||||
|         final HashMap<String, Object> theSingleValue = new HashMap<String, Object>(); | ||||
|         theSingleValue.put("stringValue", _value); | ||||
|         return theSingleValue; | ||||
|     } | ||||
|  | ||||
|     public static JsonString deserialize(final Map<String, Object> map) | ||||
|     { | ||||
|         return new JsonString(map.get("stringValue").toString()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() | ||||
|     { | ||||
|         return _value; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -18,137 +18,167 @@ import com.intellectualcrafters.configuration.serialization.ConfigurationSeriali | ||||
| /** | ||||
|  * Internal class: Represents a component of a JSON-serializable {@link FancyMessage}. | ||||
|  */ | ||||
| final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable { | ||||
| final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable | ||||
| { | ||||
|  | ||||
| 	ChatColor color = ChatColor.WHITE; | ||||
| 	ArrayList<ChatColor> styles = new ArrayList<ChatColor>(); | ||||
| 	String clickActionName = null, clickActionData = null, | ||||
| 			hoverActionName = null; | ||||
| 	JsonRepresentedObject hoverActionData = null; | ||||
| 	TextualComponent text = null; | ||||
| 	String insertionData = null; | ||||
| 	ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<JsonRepresentedObject>(); | ||||
|     ChatColor color = ChatColor.WHITE; | ||||
|     ArrayList<ChatColor> styles = new ArrayList<ChatColor>(); | ||||
|     String clickActionName = null, clickActionData = null, | ||||
|     hoverActionName = null; | ||||
|     JsonRepresentedObject hoverActionData = null; | ||||
|     TextualComponent text = null; | ||||
|     String insertionData = null; | ||||
|     ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<JsonRepresentedObject>(); | ||||
|  | ||||
| 	MessagePart(final TextualComponent text){ | ||||
| 		this.text = text; | ||||
| 	} | ||||
|     MessagePart(final TextualComponent text) | ||||
|     { | ||||
|         this.text = text; | ||||
|     } | ||||
|  | ||||
| 	MessagePart() { | ||||
| 		this.text = null; | ||||
| 	} | ||||
|     MessagePart() | ||||
|     { | ||||
|         text = null; | ||||
|     } | ||||
|  | ||||
| 	boolean hasText() { | ||||
| 		return 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; | ||||
|     @Override | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public MessagePart clone() throws CloneNotSupportedException | ||||
|     { | ||||
|         final 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 final BiMap<ChatColor, String> stylesToNames; | ||||
|  | ||||
| 	static{ | ||||
| 		ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder(); | ||||
| 		for (final ChatColor style : ChatColor.values()){ | ||||
| 			if(!style.isFormat()){ | ||||
| 				continue; | ||||
| 			} | ||||
|     static | ||||
|     { | ||||
|         final ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder(); | ||||
|         for (final ChatColor style : ChatColor.values()) | ||||
|         { | ||||
|             if (!style.isFormat()) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
| 			String styleName; | ||||
| 			switch (style) { | ||||
| 			case MAGIC: | ||||
| 				styleName = "obfuscated"; break; | ||||
| 			case UNDERLINE: | ||||
| 				styleName = "underlined"; break; | ||||
| 			default: | ||||
| 				styleName = style.name().toLowerCase(); break; | ||||
| 			} | ||||
| 			 | ||||
| 			builder.put(style, styleName); | ||||
| 		} | ||||
| 		stylesToNames = builder.build(); | ||||
| 	} | ||||
|             String styleName; | ||||
|             switch (style) | ||||
|             { | ||||
|                 case MAGIC: | ||||
|                     styleName = "obfuscated"; | ||||
|                     break; | ||||
|                 case UNDERLINE: | ||||
|                     styleName = "underlined"; | ||||
|                     break; | ||||
|                 default: | ||||
|                     styleName = style.name().toLowerCase(); | ||||
|                     break; | ||||
|             } | ||||
|  | ||||
| 	public void writeJson(JsonWriter json) { | ||||
| 		try { | ||||
| 			json.beginObject(); | ||||
| 			text.writeJson(json); | ||||
| 			json.name("color").value(color.name().toLowerCase()); | ||||
| 			for (final ChatColor style : styles) { | ||||
| 				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(); | ||||
| 			} | ||||
| 			if (hoverActionName != null && hoverActionData != null) { | ||||
| 				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)){ | ||||
| 				json.name("with").beginArray(); | ||||
| 				for(JsonRepresentedObject obj : translationReplacements){ | ||||
| 					obj.writeJson(json); | ||||
| 				} | ||||
| 				json.endArray(); | ||||
| 			} | ||||
| 			json.endObject(); | ||||
| 		} catch(IOException e){ | ||||
| 			Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e); | ||||
| 		} | ||||
| 	} | ||||
|             builder.put(style, styleName); | ||||
|         } | ||||
|         stylesToNames = builder.build(); | ||||
|     } | ||||
|  | ||||
| 	public Map<String, Object> serialize() { | ||||
| 		HashMap<String, Object> map = new HashMap<String, Object>(); | ||||
| 		map.put("text", text); | ||||
| 		map.put("styles", styles); | ||||
| 		map.put("color", color.getChar()); | ||||
| 		map.put("hoverActionName", hoverActionName); | ||||
| 		map.put("hoverActionData", hoverActionData); | ||||
| 		map.put("clickActionName", clickActionName); | ||||
| 		map.put("clickActionData", clickActionData); | ||||
| 		map.put("insertion", insertionData); | ||||
| 		map.put("translationReplacements", translationReplacements); | ||||
| 		return map; | ||||
| 	} | ||||
|     @Override | ||||
|     public void writeJson(final JsonWriter json) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             json.beginObject(); | ||||
|             text.writeJson(json); | ||||
|             json.name("color").value(color.name().toLowerCase()); | ||||
|             for (final ChatColor style : styles) | ||||
|             { | ||||
|                 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(); | ||||
|             } | ||||
|             if ((hoverActionName != null) && (hoverActionData != null)) | ||||
|             { | ||||
|                 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)) | ||||
|             { | ||||
|                 json.name("with").beginArray(); | ||||
|                 for (final JsonRepresentedObject obj : translationReplacements) | ||||
|                 { | ||||
|                     obj.writeJson(json); | ||||
|                 } | ||||
|                 json.endArray(); | ||||
|             } | ||||
|             json.endObject(); | ||||
|         } | ||||
|         catch (final IOException e) | ||||
|         { | ||||
|             Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| 	@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; | ||||
| 	} | ||||
|     @Override | ||||
|     public Map<String, Object> serialize() | ||||
|     { | ||||
|         final HashMap<String, Object> map = new HashMap<String, Object>(); | ||||
|         map.put("text", text); | ||||
|         map.put("styles", styles); | ||||
|         map.put("color", color.getChar()); | ||||
|         map.put("hoverActionName", hoverActionName); | ||||
|         map.put("hoverActionData", hoverActionData); | ||||
|         map.put("clickActionName", clickActionName); | ||||
|         map.put("clickActionData", clickActionData); | ||||
|         map.put("insertion", insertionData); | ||||
|         map.put("translationReplacements", translationReplacements); | ||||
|         return map; | ||||
|     } | ||||
|  | ||||
| 	static{ | ||||
| 		ConfigurationSerialization.registerClass(MessagePart.class); | ||||
| 	} | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static MessagePart deserialize(final Map<String, Object> serialized) | ||||
|     { | ||||
|         final 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); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -12,202 +12,227 @@ import org.bukkit.Bukkit; | ||||
|  * A class containing static utility methods and caches which are intended as reflective conveniences. | ||||
|  * Unless otherwise noted, upon failure methods will return {@code null}. | ||||
|  */ | ||||
| public final class Reflection { | ||||
| public final class Reflection | ||||
| { | ||||
|  | ||||
| 	private static String _versionString; | ||||
| 	 | ||||
| 	private Reflection(){ | ||||
| 		 | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Gets the version string from the package name of the CraftBukkit server implementation. | ||||
| 	 * This is needed to bypass the JAR package name changing on each update. | ||||
| 	 * @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>. | ||||
| 	 */ | ||||
| 	public synchronized static String getVersion() { | ||||
| 		if(_versionString == null){ | ||||
| 			if(Bukkit.getServer() == null){ | ||||
| 				// The server hasn't started, static initializer call? | ||||
| 				return null; | ||||
| 			} | ||||
| 			String name = Bukkit.getServer().getClass().getPackage().getName(); | ||||
| 			_versionString = name.substring(name.lastIndexOf('.') + 1) + "."; | ||||
| 		} | ||||
| 		 | ||||
| 		return _versionString; | ||||
| 	} | ||||
|     private static String _versionString; | ||||
|  | ||||
| 	/** | ||||
| 	 * Stores loaded classes from the {@code net.minecraft.server} package. | ||||
| 	 */ | ||||
| 	private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<String, Class<?>>(); | ||||
| 	/** | ||||
| 	 * Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages). | ||||
| 	 */ | ||||
| 	private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<String, Class<?>>(); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package. | ||||
| 	 * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). | ||||
| 	 * @param className The name of the class, excluding the package, within NMS. | ||||
| 	 * @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded. | ||||
| 	 */ | ||||
| 	public synchronized static Class<?> getNMSClass(String className) { | ||||
| 		if(_loadedNMSClasses.containsKey(className)){ | ||||
| 			return _loadedNMSClasses.get(className); | ||||
| 		} | ||||
| 		 | ||||
| 		String fullName = "net.minecraft.server." + getVersion() + className; | ||||
| 		Class<?> clazz = null; | ||||
| 		try { | ||||
| 			clazz = Class.forName(fullName); | ||||
| 		} catch (Exception e) { | ||||
| 			e.printStackTrace(); | ||||
| 			_loadedNMSClasses.put(className, null); | ||||
| 			return null; | ||||
| 		} | ||||
| 		_loadedNMSClasses.put(className, clazz); | ||||
| 		return clazz; | ||||
| 	} | ||||
|     private Reflection() | ||||
|     { | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package. | ||||
| 	 * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). | ||||
| 	 * @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}. | ||||
| 	 * @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded. | ||||
| 	 */ | ||||
| 	public synchronized static Class<?> getOBCClass(String className) { | ||||
| 		if(_loadedOBCClasses.containsKey(className)){ | ||||
| 			return _loadedOBCClasses.get(className); | ||||
| 		} | ||||
| 		 | ||||
| 		String fullName = "org.bukkit.craftbukkit." + getVersion() + className; | ||||
| 		Class<?> clazz = null; | ||||
| 		try { | ||||
| 			clazz = Class.forName(fullName); | ||||
| 		} catch (Exception e) { | ||||
| 			e.printStackTrace(); | ||||
| 			_loadedOBCClasses.put(className, null); | ||||
| 			return null; | ||||
| 		} | ||||
| 		_loadedOBCClasses.put(className, clazz); | ||||
| 		return clazz; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
| 	/** | ||||
| 	 * Attempts to get the NMS handle of a CraftBukkit object. | ||||
| 	 * <p> | ||||
| 	 * The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object. | ||||
| 	 * </p> | ||||
| 	 * @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) { | ||||
| 		try { | ||||
| 			return getMethod(obj.getClass(), "getHandle").invoke(obj); | ||||
| 		} catch (Exception e) { | ||||
| 			e.printStackTrace(); | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|     /** | ||||
|      * Gets the version string from the package name of the CraftBukkit server implementation. | ||||
|      * This is needed to bypass the JAR package name changing on each update. | ||||
|      * @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>. | ||||
|      */ | ||||
|     public synchronized static String getVersion() | ||||
|     { | ||||
|         if (_versionString == null) | ||||
|         { | ||||
|             if (Bukkit.getServer() == null) | ||||
|             { | ||||
|                 // The server hasn't started, static initializer call? | ||||
|                 return null; | ||||
|             } | ||||
|             final String name = Bukkit.getServer().getClass().getPackage().getName(); | ||||
|             _versionString = name.substring(name.lastIndexOf('.') + 1) + "."; | ||||
|         } | ||||
|  | ||||
| 	private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<Class<?>, Map<String, Field>>(); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Retrieves a {@link Field} instance declared by the specified class with the specified name. | ||||
| 	 * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field | ||||
| 	 * returned will be an instance or static field. | ||||
| 	 * <p> | ||||
| 	 * A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that | ||||
| 	 * no field will be reflectively looked up twice. | ||||
| 	 * </p> | ||||
| 	 * <p> | ||||
| 	 * If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. | ||||
| 	 * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. | ||||
| 	 * </p> | ||||
| 	 * @param clazz The class which contains the field to retrieve. | ||||
| 	 * @param name The declared name of the field in the class. | ||||
| 	 * @return A field object with the specified name declared by the specified class. | ||||
| 	 * @see Class#getDeclaredField(String) | ||||
| 	 */ | ||||
| 	public synchronized static Field getField(Class<?> clazz, String name) { | ||||
| 		Map<String, Field> loaded; | ||||
| 		if(!_loadedFields.containsKey(clazz)){ | ||||
| 			loaded = new HashMap<String, Field>(); | ||||
| 			_loadedFields.put(clazz, loaded); | ||||
| 		}else{ | ||||
| 			loaded = _loadedFields.get(clazz); | ||||
| 		} | ||||
| 		if(loaded.containsKey(name)){ | ||||
| 			// If the field is loaded (or cached as not existing), return the relevant value, which might be null | ||||
| 			return loaded.get(name); | ||||
| 		} | ||||
| 		try { | ||||
| 			Field field = clazz.getDeclaredField(name); | ||||
| 			field.setAccessible(true); | ||||
| 			loaded.put(name, field); | ||||
| 			return field; | ||||
| 		} catch (Exception e) { | ||||
| 			// Error loading | ||||
| 			e.printStackTrace(); | ||||
| 			// Cache field as not existing | ||||
| 			loaded.put(name, null); | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
|         return _versionString; | ||||
|     } | ||||
|  | ||||
| 	/** | ||||
| 	 * 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<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>>(); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types. | ||||
| 	 * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field | ||||
| 	 * returned will be an instance or static field. | ||||
| 	 * <p> | ||||
| 	 * A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that | ||||
| 	 * no method will be reflectively looked up twice. | ||||
| 	 * </p> | ||||
| 	 * <p> | ||||
| 	 * If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. | ||||
| 	 * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. | ||||
| 	 * </p> | ||||
| 	 * <p> | ||||
| 	 * This method does <em>not</em> search superclasses of the specified type for methods with the specified signature. | ||||
| 	 * Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}. | ||||
| 	 * @param clazz The class which contains the method to retrieve. | ||||
| 	 * @param name The declared name of the method in the class. | ||||
| 	 * @param args The formal argument types of the method. | ||||
| 	 * @return A method object with the specified name declared by the specified class. | ||||
| 	 */ | ||||
| 	public synchronized static Method getMethod(Class<?> clazz, String name, | ||||
| 			Class<?>... args) { | ||||
| 		if(!_loadedMethods.containsKey(clazz)){ | ||||
| 			_loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>()); | ||||
| 		} | ||||
| 		 | ||||
| 		Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz); | ||||
| 		if(!loadedMethodNames.containsKey(name)){ | ||||
| 			loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>()); | ||||
| 		} | ||||
| 		 | ||||
| 		Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name); | ||||
| 		ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<Class<?>>(args); | ||||
| 		if(loadedSignatures.containsKey(wrappedArg)){ | ||||
| 			return loadedSignatures.get(wrappedArg); | ||||
| 		} | ||||
| 		 | ||||
| 		for (Method m : clazz.getMethods()) | ||||
| 			if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) { | ||||
| 				m.setAccessible(true); | ||||
| 				loadedSignatures.put(wrappedArg, m); | ||||
| 				return m; | ||||
| 			} | ||||
| 		loadedSignatures.put(wrappedArg, null); | ||||
| 		return null; | ||||
| 	} | ||||
|     /** | ||||
|      * Stores loaded classes from the {@code net.minecraft.server} package. | ||||
|      */ | ||||
|     private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<String, Class<?>>(); | ||||
|     /** | ||||
|      * Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages). | ||||
|      */ | ||||
|     private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<String, Class<?>>(); | ||||
|  | ||||
|     /** | ||||
|      * Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package. | ||||
|      * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). | ||||
|      * @param className The name of the class, excluding the package, within NMS. | ||||
|      * @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded. | ||||
|      */ | ||||
|     public synchronized static Class<?> getNMSClass(final String className) | ||||
|     { | ||||
|         if (_loadedNMSClasses.containsKey(className)) { return _loadedNMSClasses.get(className); } | ||||
|  | ||||
|         final String fullName = "net.minecraft.server." + getVersion() + className; | ||||
|         Class<?> clazz = null; | ||||
|         try | ||||
|         { | ||||
|             clazz = Class.forName(fullName); | ||||
|         } | ||||
|         catch (final Exception e) | ||||
|         { | ||||
|             e.printStackTrace(); | ||||
|             _loadedNMSClasses.put(className, null); | ||||
|             return null; | ||||
|         } | ||||
|         _loadedNMSClasses.put(className, clazz); | ||||
|         return clazz; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package. | ||||
|      * The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously). | ||||
|      * @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}. | ||||
|      * @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded. | ||||
|      */ | ||||
|     public synchronized static Class<?> getOBCClass(final String className) | ||||
|     { | ||||
|         if (_loadedOBCClasses.containsKey(className)) { return _loadedOBCClasses.get(className); } | ||||
|  | ||||
|         final String fullName = "org.bukkit.craftbukkit." + getVersion() + className; | ||||
|         Class<?> clazz = null; | ||||
|         try | ||||
|         { | ||||
|             clazz = Class.forName(fullName); | ||||
|         } | ||||
|         catch (final Exception e) | ||||
|         { | ||||
|             e.printStackTrace(); | ||||
|             _loadedOBCClasses.put(className, null); | ||||
|             return null; | ||||
|         } | ||||
|         _loadedOBCClasses.put(className, clazz); | ||||
|         return clazz; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Attempts to get the NMS handle of a CraftBukkit object. | ||||
|      * <p> | ||||
|      * The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object. | ||||
|      * </p> | ||||
|      * @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(final Object obj) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             return getMethod(obj.getClass(), "getHandle").invoke(obj); | ||||
|         } | ||||
|         catch (final Exception e) | ||||
|         { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<Class<?>, Map<String, Field>>(); | ||||
|  | ||||
|     /** | ||||
|      * Retrieves a {@link Field} instance declared by the specified class with the specified name. | ||||
|      * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field | ||||
|      * returned will be an instance or static field. | ||||
|      * <p> | ||||
|      * A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that | ||||
|      * no field will be reflectively looked up twice. | ||||
|      * </p> | ||||
|      * <p> | ||||
|      * If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. | ||||
|      * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. | ||||
|      * </p> | ||||
|      * @param clazz The class which contains the field to retrieve. | ||||
|      * @param name The declared name of the field in the class. | ||||
|      * @return A field object with the specified name declared by the specified class. | ||||
|      * @see Class#getDeclaredField(String) | ||||
|      */ | ||||
|     public synchronized static Field getField(final Class<?> clazz, final String name) | ||||
|     { | ||||
|         Map<String, Field> loaded; | ||||
|         if (!_loadedFields.containsKey(clazz)) | ||||
|         { | ||||
|             loaded = new HashMap<String, Field>(); | ||||
|             _loadedFields.put(clazz, loaded); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             loaded = _loadedFields.get(clazz); | ||||
|         } | ||||
|         if (loaded.containsKey(name)) | ||||
|         { | ||||
|             // If the field is loaded (or cached as not existing), return the relevant value, which might be null | ||||
|             return loaded.get(name); | ||||
|         } | ||||
|         try | ||||
|         { | ||||
|             final Field field = clazz.getDeclaredField(name); | ||||
|             field.setAccessible(true); | ||||
|             loaded.put(name, field); | ||||
|             return field; | ||||
|         } | ||||
|         catch (final Exception e) | ||||
|         { | ||||
|             // Error loading | ||||
|             e.printStackTrace(); | ||||
|             // Cache field as not existing | ||||
|             loaded.put(name, null); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>>(); | ||||
|  | ||||
|     /** | ||||
|      * Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types. | ||||
|      * Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field | ||||
|      * returned will be an instance or static field. | ||||
|      * <p> | ||||
|      * A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that | ||||
|      * no method will be reflectively looked up twice. | ||||
|      * </p> | ||||
|      * <p> | ||||
|      * If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned. | ||||
|      * This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance. | ||||
|      * </p> | ||||
|      * <p> | ||||
|      * This method does <em>not</em> search superclasses of the specified type for methods with the specified signature. | ||||
|      * Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}. | ||||
|      * @param clazz The class which contains the method to retrieve. | ||||
|      * @param name The declared name of the method in the class. | ||||
|      * @param args The formal argument types of the method. | ||||
|      * @return A method object with the specified name declared by the specified class. | ||||
|      */ | ||||
|     public synchronized static Method getMethod(final Class<?> clazz, final String name, | ||||
|     final Class<?>... args) | ||||
|     { | ||||
|         if (!_loadedMethods.containsKey(clazz)) | ||||
|         { | ||||
|             _loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>()); | ||||
|         } | ||||
|  | ||||
|         final Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz); | ||||
|         if (!loadedMethodNames.containsKey(name)) | ||||
|         { | ||||
|             loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>()); | ||||
|         } | ||||
|  | ||||
|         final Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name); | ||||
|         final ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<Class<?>>(args); | ||||
|         if (loadedSignatures.containsKey(wrappedArg)) { return loadedSignatures.get(wrappedArg); } | ||||
|  | ||||
|         for (final Method m : clazz.getMethods()) | ||||
|         { | ||||
|             if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) | ||||
|             { | ||||
|                 m.setAccessible(true); | ||||
|                 loadedSignatures.put(wrappedArg, m); | ||||
|                 return m; | ||||
|             } | ||||
|         } | ||||
|         loadedSignatures.put(wrappedArg, null); | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -16,276 +16,326 @@ import com.intellectualcrafters.configuration.serialization.ConfigurationSeriali | ||||
|  * but also to represent localized strings and other text values. | ||||
|  * <p>Different instances of this class can be created with static constructor methods.</p> | ||||
|  */ | ||||
| public abstract class TextualComponent implements Cloneable { | ||||
| public abstract class TextualComponent implements Cloneable | ||||
| { | ||||
|  | ||||
| 	static{ | ||||
| 		ConfigurationSerialization.registerClass(TextualComponent.ArbitraryTextTypeComponent.class); | ||||
| 		ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class); | ||||
| 	} | ||||
| 	 | ||||
| 	@Override | ||||
| 	public String toString() { | ||||
| 		return getReadableString(); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
|          * @return The JSON key used to represent text components of this type. | ||||
| 	 */ | ||||
| 	public abstract String getKey(); | ||||
| 	 | ||||
|         /** | ||||
|          * @return A readable String | ||||
| 	 */ | ||||
| 	public abstract String getReadableString(); | ||||
|          | ||||
| 	/** | ||||
| 	 * 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; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Writes the text data represented by this textual component to the specified JSON writer object. | ||||
| 	 * A new object within the writer is not started. | ||||
| 	 * @param writer The object to which to write the JSON data. | ||||
| 	 * @throws IOException If an error occurs while writing to the stream. | ||||
| 	 */ | ||||
| 	public abstract void writeJson(JsonWriter writer) throws IOException; | ||||
| 	 | ||||
| 	static TextualComponent deserialize(Map<String, Object> map){ | ||||
| 		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 */){ | ||||
| 			// Complex JSON object | ||||
| 			return ComplexTextTypeComponent.deserialize(map); | ||||
| 		} | ||||
| 		 | ||||
| 		return null; | ||||
| 	} | ||||
| 	 | ||||
| 	static boolean isTextKey(String key){ | ||||
| 		return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector"); | ||||
| 	} | ||||
| 	 | ||||
| 	static boolean isTranslatableText(TextualComponent component){ | ||||
| 		return component instanceof ComplexTextTypeComponent && ((ComplexTextTypeComponent)component).getKey().equals("translate"); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * 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 { | ||||
|     static | ||||
|     { | ||||
|         ConfigurationSerialization.registerClass(TextualComponent.ArbitraryTextTypeComponent.class); | ||||
|         ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class); | ||||
|     } | ||||
|  | ||||
| 		public ArbitraryTextTypeComponent(String key, String value){ | ||||
| 			setKey(key); | ||||
| 			setValue(value); | ||||
| 		} | ||||
| 		 | ||||
| 		@Override | ||||
| 		public String getKey() { | ||||
| 			return _key; | ||||
| 		} | ||||
|     @Override | ||||
|     public String toString() | ||||
|     { | ||||
|         return getReadableString(); | ||||
|     } | ||||
|  | ||||
| 		public void setKey(String key) { | ||||
| 			Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified."); | ||||
| 			_key = key; | ||||
| 		} | ||||
| 		 | ||||
| 		public String getValue() { | ||||
| 			return _value; | ||||
| 		} | ||||
|     /** | ||||
|      * @return The JSON key used to represent text components of this type. | ||||
|      */ | ||||
|     public abstract String getKey(); | ||||
|  | ||||
| 		public void setValue(String value) { | ||||
| 			Preconditions.checkArgument(value != null, "The value must be specified."); | ||||
| 			_value = value; | ||||
| 		} | ||||
|     /** | ||||
|      * @return A readable String | ||||
|      */ | ||||
|     public abstract String getReadableString(); | ||||
|  | ||||
| 		private String _key; | ||||
| 		private String _value; | ||||
| 		 | ||||
| 		@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()); | ||||
| 		} | ||||
|     /** | ||||
|      * 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 void writeJson(JsonWriter writer) throws IOException { | ||||
| 			writer.name(getKey()).value(getValue()); | ||||
| 		} | ||||
|     /** | ||||
|      * Writes the text data represented by this textual component to the specified JSON writer object. | ||||
|      * A new object within the writer is not started. | ||||
|      * @param writer The object to which to write the JSON data. | ||||
|      * @throws IOException If an error occurs while writing to the stream. | ||||
|      */ | ||||
|     public abstract void writeJson(final JsonWriter writer) throws IOException; | ||||
|  | ||||
| 		@SuppressWarnings("serial") | ||||
| 		public Map<String, Object> serialize() { | ||||
| 			return new HashMap<String, Object>(){{ | ||||
| 				put("key", getKey()); | ||||
| 				put("value", getValue()); | ||||
| 			}}; | ||||
| 		} | ||||
| 		 | ||||
| 		public static ArbitraryTextTypeComponent deserialize(Map<String, Object> map){ | ||||
| 			return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString()); | ||||
| 		} | ||||
|     static TextualComponent deserialize(final Map<String, Object> map) | ||||
|     { | ||||
|         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 */) | ||||
|         { | ||||
|             // Complex JSON object | ||||
|             return ComplexTextTypeComponent.deserialize(map); | ||||
|         } | ||||
|  | ||||
| 		@Override | ||||
|         public String getReadableString() { | ||||
| 			return getValue(); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Internal class used to represent a text component with a nested JSON value. | ||||
| 	 * Exception validating done is on keys and values. | ||||
| 	 */ | ||||
| 	private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable{ | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| 		public ComplexTextTypeComponent(String key, Map<String, String> values){ | ||||
| 			setKey(key); | ||||
| 			setValue(values); | ||||
| 		} | ||||
| 		 | ||||
| 		@Override | ||||
| 		public String getKey() { | ||||
| 			return _key; | ||||
| 		} | ||||
|     static boolean isTextKey(final String key) | ||||
|     { | ||||
|         return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector"); | ||||
|     } | ||||
|  | ||||
| 		public void setKey(String key) { | ||||
| 			Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified."); | ||||
| 			_key = key; | ||||
| 		} | ||||
| 		 | ||||
| 		public Map<String, String> getValue() { | ||||
| 			return _value; | ||||
| 		} | ||||
|     static boolean isTranslatableText(final TextualComponent component) | ||||
|     { | ||||
|         return (component instanceof ComplexTextTypeComponent) && ((ComplexTextTypeComponent) component).getKey().equals("translate"); | ||||
|     } | ||||
|  | ||||
| 		public void setValue(Map<String, String> value) { | ||||
| 			Preconditions.checkArgument(value != null, "The value must be specified."); | ||||
| 			_value = value; | ||||
| 		} | ||||
|     /** | ||||
|      * 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 String _key; | ||||
| 		private Map<String, String> _value; | ||||
| 		 | ||||
| 		@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 ComplexTextTypeComponent(getKey(), getValue()); | ||||
| 		} | ||||
|         public ArbitraryTextTypeComponent(final String key, final String value) | ||||
|         { | ||||
|             setKey(key); | ||||
|             setValue(value); | ||||
|         } | ||||
|  | ||||
| 		@Override | ||||
| 		public void writeJson(JsonWriter writer) throws IOException { | ||||
| 			writer.name(getKey()); | ||||
| 			writer.beginObject(); | ||||
| 			for(Map.Entry<String, String> jsonPair : _value.entrySet()){ | ||||
| 				writer.name(jsonPair.getKey()).value(jsonPair.getValue()); | ||||
| 			} | ||||
| 			writer.endObject(); | ||||
| 		} | ||||
| 		 | ||||
| 		@SuppressWarnings("serial") | ||||
| 		public Map<String, Object> serialize() { | ||||
| 			return new java.util.HashMap<String, Object>(){{ | ||||
| 				put("key", getKey()); | ||||
| 				for(Map.Entry<String, String> valEntry : getValue().entrySet()){ | ||||
| 					put("value." + valEntry.getKey(), valEntry.getValue()); | ||||
| 				} | ||||
| 			}}; | ||||
| 		} | ||||
| 		 | ||||
| 		public static ComplexTextTypeComponent deserialize(Map<String, Object> map){ | ||||
| 			String key = null; | ||||
| 			Map<String, String> value = new HashMap<String, String>(); | ||||
| 			for(Map.Entry<String, Object> valEntry : map.entrySet()){ | ||||
| 				if(valEntry.getKey().equals("key")){ | ||||
| 					key = (String) valEntry.getValue(); | ||||
| 				}else if(valEntry.getKey().startsWith("value.")){ | ||||
| 					value.put(((String) valEntry.getKey()).substring(6) /* Strips out the value prefix */, valEntry.getValue().toString()); | ||||
| 				} | ||||
| 			} | ||||
| 			return new ComplexTextTypeComponent(key, value); | ||||
| 		} | ||||
| 		 | ||||
| 		@Override | ||||
| 		public String getReadableString() { | ||||
| 			return getKey(); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Create a textual component representing a string literal. | ||||
| 	 * This is the default type of textual component when a single string literal is given to a method. | ||||
| 	 * @param textValue The text which will be represented. | ||||
| 	 * @return The text component representing the specified literal text. | ||||
| 	 */ | ||||
| 	public static TextualComponent rawText(String textValue){ | ||||
| 		return new ArbitraryTextTypeComponent("text", textValue); | ||||
| 	} | ||||
| 	 | ||||
|         @Override | ||||
|         public String getKey() | ||||
|         { | ||||
|             return _key; | ||||
|         } | ||||
|  | ||||
| 	/** | ||||
| 	 * Create a textual component representing a localized string. | ||||
| 	 * The client will see this text component as their localized version of the specified string <em>key</em>, which can be overridden by a resource pack. | ||||
| 	 * <p> | ||||
| 	 * If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to the client. | ||||
| 	 * </p> | ||||
| 	 * @param translateKey The string key which maps to localized text. | ||||
| 	 * @return The text component representing the specified localized text. | ||||
| 	 */ | ||||
| 	public static TextualComponent localizedText(String translateKey){ | ||||
| 		return new ArbitraryTextTypeComponent("translate", translateKey); | ||||
| 	} | ||||
| 	 | ||||
| 	private static void throwUnsupportedSnapshot(){ | ||||
| 		throw new UnsupportedOperationException("This feature is only supported in snapshot releases."); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Create a textual component representing a scoreboard value. | ||||
| 	 * The client will see their own score for the specified objective as the text represented by this component. | ||||
| 	 * <p> | ||||
| 	 * <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b> | ||||
| 	 * </p> | ||||
| 	 * @param scoreboardObjective The name of the objective for which to display the score. | ||||
| 	 * @return The text component representing the specified scoreboard score (for the viewing player), or {@code null} if an error occurs during JSON serialization. | ||||
| 	 */ | ||||
| 	public static TextualComponent objectiveScore(String scoreboardObjective){ | ||||
| 		return objectiveScore("*", scoreboardObjective); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * 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> | ||||
| 	 * <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b> | ||||
| 	 * </p> | ||||
| 	 * @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 for the specified player, or {@code null} if an error occurs during JSON serialization. | ||||
| 	 */ | ||||
| 	public static TextualComponent objectiveScore(String playerName, String scoreboardObjective){ | ||||
| 		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()); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Create a textual component representing a player name, retrievable by using a standard minecraft selector. | ||||
| 	 * The client will see the players or entities captured by the specified selector as the text represented by this component. | ||||
| 	 * <p> | ||||
| 	 * <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b> | ||||
| 	 * </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. | ||||
| 	 * @return The text component representing the name of the entities captured by the selector. | ||||
| 	 */ | ||||
| 	public static TextualComponent selector(String selector){ | ||||
| 		throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly | ||||
| 		 | ||||
| 		return new ArbitraryTextTypeComponent("selector", selector); | ||||
| 	} | ||||
|         public void setKey(final String key) | ||||
|         { | ||||
|             Preconditions.checkArgument((key != null) && !key.isEmpty(), "The key must be specified."); | ||||
|             _key = key; | ||||
|         } | ||||
|  | ||||
|         public String getValue() | ||||
|         { | ||||
|             return _value; | ||||
|         } | ||||
|  | ||||
|         public void setValue(final String value) | ||||
|         { | ||||
|             Preconditions.checkArgument(value != null, "The value must be specified."); | ||||
|             _value = value; | ||||
|         } | ||||
|  | ||||
|         private String _key; | ||||
|         private String _value; | ||||
|  | ||||
|         @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(final JsonWriter writer) throws IOException | ||||
|         { | ||||
|             writer.name(getKey()).value(getValue()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         @SuppressWarnings("serial") | ||||
|         public Map<String, Object> serialize() | ||||
|         { | ||||
|             return new HashMap<String, Object>() | ||||
|             { | ||||
|                 { | ||||
|                     put("key", getKey()); | ||||
|                     put("value", getValue()); | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         public static ArbitraryTextTypeComponent deserialize(final Map<String, Object> map) | ||||
|         { | ||||
|             return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public String getReadableString() | ||||
|         { | ||||
|             return getValue(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Internal class used to represent a text component with a nested JSON value. | ||||
|      * Exception validating done is on keys and values. | ||||
|      */ | ||||
|     private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable | ||||
|     { | ||||
|  | ||||
|         public ComplexTextTypeComponent(final String key, final Map<String, String> values) | ||||
|         { | ||||
|             setKey(key); | ||||
|             setValue(values); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public String getKey() | ||||
|         { | ||||
|             return _key; | ||||
|         } | ||||
|  | ||||
|         public void setKey(final String key) | ||||
|         { | ||||
|             Preconditions.checkArgument((key != null) && !key.isEmpty(), "The key must be specified."); | ||||
|             _key = key; | ||||
|         } | ||||
|  | ||||
|         public Map<String, String> getValue() | ||||
|         { | ||||
|             return _value; | ||||
|         } | ||||
|  | ||||
|         public void setValue(final Map<String, String> value) | ||||
|         { | ||||
|             Preconditions.checkArgument(value != null, "The value must be specified."); | ||||
|             _value = value; | ||||
|         } | ||||
|  | ||||
|         private String _key; | ||||
|         private Map<String, String> _value; | ||||
|  | ||||
|         @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 ComplexTextTypeComponent(getKey(), getValue()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void writeJson(final JsonWriter writer) throws IOException | ||||
|         { | ||||
|             writer.name(getKey()); | ||||
|             writer.beginObject(); | ||||
|             for (final Map.Entry<String, String> jsonPair : _value.entrySet()) | ||||
|             { | ||||
|                 writer.name(jsonPair.getKey()).value(jsonPair.getValue()); | ||||
|             } | ||||
|             writer.endObject(); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         @SuppressWarnings("serial") | ||||
|         public Map<String, Object> serialize() | ||||
|         { | ||||
|             return new java.util.HashMap<String, Object>() | ||||
|             { | ||||
|                 { | ||||
|                     put("key", getKey()); | ||||
|                     for (final Map.Entry<String, String> valEntry : getValue().entrySet()) | ||||
|                     { | ||||
|                         put("value." + valEntry.getKey(), valEntry.getValue()); | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         public static ComplexTextTypeComponent deserialize(final Map<String, Object> map) | ||||
|         { | ||||
|             String key = null; | ||||
|             final Map<String, String> value = new HashMap<String, String>(); | ||||
|             for (final Map.Entry<String, Object> valEntry : map.entrySet()) | ||||
|             { | ||||
|                 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()); | ||||
|                 } | ||||
|             } | ||||
|             return new ComplexTextTypeComponent(key, value); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public String getReadableString() | ||||
|         { | ||||
|             return getKey(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a textual component representing a string literal. | ||||
|      * This is the default type of textual component when a single string literal is given to a method. | ||||
|      * @param textValue The text which will be represented. | ||||
|      * @return The text component representing the specified literal text. | ||||
|      */ | ||||
|     public static TextualComponent rawText(final String textValue) | ||||
|     { | ||||
|         return new ArbitraryTextTypeComponent("text", textValue); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a textual component representing a localized string. | ||||
|      * The client will see this text component as their localized version of the specified string <em>key</em>, which can be overridden by a resource pack. | ||||
|      * <p> | ||||
|      * If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to the client. | ||||
|      * </p> | ||||
|      * @param translateKey The string key which maps to localized text. | ||||
|      * @return The text component representing the specified localized text. | ||||
|      */ | ||||
|     public static TextualComponent localizedText(final String translateKey) | ||||
|     { | ||||
|         return new ArbitraryTextTypeComponent("translate", translateKey); | ||||
|     } | ||||
|  | ||||
|     private static void throwUnsupportedSnapshot() | ||||
|     { | ||||
|         throw new UnsupportedOperationException("This feature is only supported in snapshot releases."); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a textual component representing a scoreboard value. | ||||
|      * The client will see their own score for the specified objective as the text represented by this component. | ||||
|      * <p> | ||||
|      * <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b> | ||||
|      * </p> | ||||
|      * @param scoreboardObjective The name of the objective for which to display the score. | ||||
|      * @return The text component representing the specified scoreboard score (for the viewing player), or {@code null} if an error occurs during JSON serialization. | ||||
|      */ | ||||
|     public static TextualComponent objectiveScore(final String scoreboardObjective) | ||||
|     { | ||||
|         return objectiveScore("*", scoreboardObjective); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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> | ||||
|      * <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b> | ||||
|      * </p> | ||||
|      * @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 for the specified player, or {@code null} if an error occurs during JSON serialization. | ||||
|      */ | ||||
|     public static TextualComponent objectiveScore(final String playerName, final String scoreboardObjective) | ||||
|     { | ||||
|         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()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a textual component representing a player name, retrievable by using a standard minecraft selector. | ||||
|      * The client will see the players or entities captured by the specified selector as the text represented by this component. | ||||
|      * <p> | ||||
|      * <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b> | ||||
|      * </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. | ||||
|      * @return The text component representing the name of the entities captured by the selector. | ||||
|      */ | ||||
|     public static TextualComponent selector(final String selector) | ||||
|     { | ||||
|         throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly | ||||
|  | ||||
|         return new ArbitraryTextTypeComponent("selector", selector); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 boy0001
					boy0001