TYPE_LOOKUP = new HashMap<>();
+
+ private final String minecraftId;
+
+ /**
+ * Construct a new attribute type.
+ *
+ * Remember to {@link #register()} the type.
+ *
+ * @param minecraftId - the ID of the type.
+ */
+ public AttributeType(String minecraftId) {
+ this.minecraftId = minecraftId;
+ }
+
+ /**
+ * Retrieve the associated minecraft ID.
+ *
+ * @return The associated ID.
+ */
+ public String getMinecraftId() {
+ return minecraftId;
+ }
+
+ /**
+ * Register the type in the central registry.
+ *
+ * @return The registered type.
+ */
+ // Constructors should have no side-effects!
+ public AttributeType register() {
+ AttributeType old = LOOKUP.putIfAbsent(minecraftId, this);
+ return old != null ? old : this;
+ }
+
+ /**
+ * Retrieve the attribute type associated with a given ID.
+ *
+ * @param minecraftId The ID to search for.
+ * @return The attribute type, or NULL if not found.
+ */
+ public static AttributeType fromId(String minecraftId) {
+ return LOOKUP.get(minecraftId);
+ }
+
+ /**
+ * Retrieve every registered attribute type.
+ *
+ * @return Every type.
+ */
+ public static Iterable values() {
+ return LOOKUP.values();
+ }
+
+ public static AttributeType valueOf(String name) {
+ if (name == null) return null;
+ String modName = name.replace(' ', '_').toUpperCase();
+ if (TYPE_LOOKUP.containsKey(modName)) {
+ return TYPE_LOOKUP.get("GENERIC_" + modName);
+ } else if (TYPE_LOOKUP.containsKey("GENERIC_" + modName)) {
+ return TYPE_LOOKUP.get("GENERIC_" + modName);
+ } else if (TYPE_LOOKUP.containsKey("ZOMBIE_" + modName)) {
+ return TYPE_LOOKUP.get("ZOMBIE_" + modName);
+ } else if (TYPE_LOOKUP.containsKey("HORSE_" + modName)) {
+ return TYPE_LOOKUP.get("HORSE_" + modName);
+ } else {
+ return fromId(name);
+ }
+ }
+
+ public static void initialiseNameMap() {
+ TYPE_LOOKUP.clear();
+ try {
+ for (Field field : AttributeType.class.getFields()) {
+ if (field.getType() == AttributeType.class) {
+ TYPE_LOOKUP.put(field.getName(), (AttributeType) field.get(null));
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ public static class Attribute implements ConfigurationSerializable {
+ private NbtCompound data;
+
+ private Attribute(Builder builder) {
+ data = NbtFactory.createCompound();
+ setAmount(builder.amount);
+ setOperation(builder.operation);
+ setAttributeType(builder.type);
+ setName(builder.name);
+ setUUID(builder.uuid);
+ }
+
+ private Attribute(NbtCompound data) {
+ this.data = data;
+ }
+
+ public double getAmount() {
+ return data.getDouble("Amount", 0.0);
+ }
+
+ public void setAmount(double amount) {
+ data.put("Amount", amount);
+ }
+
+ public Operation getOperation() {
+ return Operation.fromId(data.getInteger("Operation", 0));
+ }
+
+ public void setOperation(Operation operation) {
+ Preconditions.checkNotNull(operation, "operation cannot be NULL.");
+ data.put("Operation", operation.getId());
+ }
+
+ public AttributeType getAttributeType() {
+ return AttributeType.fromId(data.getString("AttributeName", null));
+ }
+
+ public void setAttributeType(AttributeType type) {
+ Preconditions.checkNotNull(type, "type cannot be NULL.");
+ data.put("AttributeName", type.getMinecraftId());
+ }
+
+ public String getName() {
+ return data.getString("Name", null);
+ }
+
+ public void setName(String name) {
+ Preconditions.checkNotNull(name, "name cannot be NULL.");
+ data.put("Name", name);
+ }
+
+ public UUID getUUID() {
+ return new UUID(data.getLong("UUIDMost", null), data.getLong("UUIDLeast", null));
+ }
+
+ public void setUUID(UUID id) {
+ Preconditions.checkNotNull("id", "id cannot be NULL.");
+ data.put("UUIDLeast", id.getLeastSignificantBits());
+ data.put("UUIDMost", id.getMostSignificantBits());
+ }
+
+ /**
+ * Construct a new attribute builder with a random UUID and default operation of adding numbers.
+ *
+ * @return The attribute builder.
+ */
+ public static Builder newBuilder() {
+ return new Builder().uuid(UUID.randomUUID()).operation(Operation.ADD_NUMBER);
+ }
+
+ @Override
+ public Map serialize() {
+ Map serializedAttribute = new LinkedHashMap<>();
+ serializedAttribute.put("UUID", this.getUUID().toString());
+ serializedAttribute.put("Name", this.getName());
+ serializedAttribute.put("Type", this.getAttributeType().getMinecraftId());
+ serializedAttribute.put("Amount", this.getAmount());
+ Operation operation = this.getOperation();
+ if (operation != null) serializedAttribute.put("Operation", operation.name());
+ return serializedAttribute;
+ }
+
+ public static Attribute deserialize(Map serializedAttribute) {
+ Attribute deserializedAttribute = null;
+ if (serializedAttribute != null && serializedAttribute.containsKey("Name")) {
+ AttributeType attributeType = null;
+ try {
+ attributeType = AttributeType.valueOf(ObjectUtilities.getObject(serializedAttribute, String.class, "Type"));
+ } catch (Exception ignored) {
+ }
+ if (attributeType != null) {
+ UUID attributeUUID = Utilities.isUUID(serializedAttribute.get("UUID")) ? UUID.fromString(serializedAttribute.get("UUID").toString()) : null;
+ double attributeAmount = ObjectUtilities.getObject(serializedAttribute, Number.class, "Amount", 0D).doubleValue();
+ Operation operation = null;
+ try {
+ operation = Operation.valueOf(ObjectUtilities.getObject(serializedAttribute, String.class, "Operation"));
+ } catch (Exception ignored) {
+ }
+ if (operation == null) operation = Operation.ADD_NUMBER;
+ Builder attributeBuilder = new Builder().name(ObjectUtilities.getObject(serializedAttribute, String.class, "Name")).type(attributeType).operation(operation).amount(attributeAmount);
+ if (attributeUUID != null) attributeBuilder.uuid(attributeUUID);
+ deserializedAttribute = attributeBuilder.build();
+ }
+ }
+ return deserializedAttribute;
+ }
+
+ // Makes it easier to construct an attribute
+ public static class Builder {
+ private double amount;
+ private Operation operation = Operation.ADD_NUMBER;
+ private AttributeType type;
+ private String name;
+ private UUID uuid;
+
+ private Builder() {
+ // Don't make this accessible
+ }
+
+ public Builder amount(double amount) {
+ this.amount = amount;
+ return this;
+ }
+
+ public Builder operation(Operation operation) {
+ this.operation = operation;
+ return this;
+ }
+
+ public Builder type(AttributeType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder uuid(UUID uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+
+ public Attribute build() {
+ return new Attribute(this);
+ }
+ }
+ }
+
+ // This may be modified
+ public ItemStack stack;
+ private NbtList attributes;
+
+ public Attributes(ItemStack stack) {
+ // Create a CraftItemStack (under the hood)
+ this.stack = NbtFactory.getCraftItemStack(stack);
+ loadAttributes(false);
+ }
+
+ /**
+ * Load the NBT list from the TAG compound.
+ *
+ * @param createIfMissing - create the list if its missing.
+ */
+ private void loadAttributes(boolean createIfMissing) {
+ if (this.attributes == null) {
+ NbtCompound nbt = NbtFactory.fromItemTag(this.stack);
+ this.attributes = nbt.getList("AttributeModifiers", createIfMissing);
+ }
+ }
+
+ /**
+ * Remove the NBT list from the TAG compound.
+ */
+ private void removeAttributes() {
+ NbtCompound nbt = NbtFactory.fromItemTag(this.stack);
+ nbt.remove("AttributeModifiers");
+ this.attributes = null;
+ }
+
+ /**
+ * Retrieve the modified item stack.
+ *
+ * @return The modified item stack.
+ */
+ public ItemStack getStack() {
+ return stack;
+ }
+
+ /**
+ * Retrieve the number of attributes.
+ *
+ * @return Number of attributes.
+ */
+ public int size() {
+ return attributes != null ? attributes.size() : 0;
+ }
+
+ /**
+ * Add a new attribute to the list.
+ *
+ * @param attribute - the new attribute.
+ */
+ public void add(Attribute attribute) {
+ Preconditions.checkNotNull(attribute.getName(), "must specify an attribute name.");
+ loadAttributes(true);
+ int removeIndex = -1;
+ for (int i = 0; i < this.attributes.size(); i++) {
+ NbtCompound attributeData = (NbtCompound) this.attributes.get(i);
+ if (attribute.getName().equals(attributeData.getString("AttributeName", null))) {
+ removeIndex = i;
+ break;
+ }
+ }
+ if (removeIndex != -1) this.attributes.remove(removeIndex);
+ this.attributes.add(attribute.data);
+ }
+
+ /**
+ * Remove the first instance of the given attribute.
+ *
+ * The attribute will be removed using its UUID.
+ *
+ * @param attribute - the attribute to remove.
+ * @return TRUE if the attribute was removed, FALSE otherwise.
+ */
+ public boolean remove(Attribute attribute) {
+ if (attributes == null)
+ return false;
+ UUID uuid = attribute.getUUID();
+
+ for (Iterator it = values().iterator(); it.hasNext(); ) {
+ if (Objects.equal(it.next().getUUID(), uuid)) {
+ it.remove();
+
+ // Last removed attribute?
+ if (size() == 0) {
+ removeAttributes();
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Remove every attribute.
+ */
+ public void clear() {
+ removeAttributes();
+ }
+
+ /**
+ * Retrieve the attribute at a given index.
+ *
+ * @param index - the index to look up.
+ * @return The attribute at that index.
+ */
+ public Attribute get(int index) {
+ if (size() == 0)
+ throw new IllegalStateException("Attribute list is empty.");
+ return new Attribute((NbtCompound) attributes.get(index));
+ }
+
+ /**
+ * Retrieve all the attributes.
+ *
+ * @return The attributes.
+ */
+ public List getAll() {
+ if (size() == 0) return new ArrayList<>();
+ List attributesList = new ArrayList<>();
+ for (Object attribute : this.attributes) {
+ attributesList.add(new Attribute((NbtCompound) attribute));
+ }
+ return attributesList;
+ }
+
+ // We can't make Attributes itself iterable without splitting it up into separate classes
+ public Iterable values() {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ // Handle the empty case
+ if (size() == 0)
+ return Collections.emptyList().iterator();
+
+ return Iterators.transform(attributes.iterator(),
+ new Function() {
+ @Override
+ public Attribute apply(Object element) {
+ return new Attribute((NbtCompound) element);
+ }
+ });
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/comphenix/attributes/NbtFactory.java b/src/main/java/com/comphenix/attributes/NbtFactory.java
new file mode 100644
index 0000000..991b0db
--- /dev/null
+++ b/src/main/java/com/comphenix/attributes/NbtFactory.java
@@ -0,0 +1,1056 @@
+// The MIT License (MIT)
+//
+// Copyright (c) 2015 Kristian Stangeland
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package com.comphenix.attributes;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+import com.google.common.io.Closeables;
+import com.google.common.io.Files;
+import com.google.common.io.InputSupplier;
+import com.google.common.io.OutputSupplier;
+import com.google.common.primitives.Primitives;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Server;
+import org.bukkit.inventory.ItemStack;
+
+import java.io.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.ConcurrentMap;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+public class NbtFactory {
+ // Convert between NBT id and the equivalent class in java
+ private static final BiMap> NBT_CLASS = HashBiMap.create();
+ private static final BiMap NBT_ENUM = HashBiMap.create();
+
+ /**
+ * Whether or not to enable stream compression.
+ *
+ * @author Kristian
+ */
+ public enum StreamOptions {
+ NO_COMPRESSION,
+ GZIP_COMPRESSION,
+ }
+
+ private enum NbtType {
+ TAG_END(0, Void.class),
+ TAG_BYTE(1, byte.class),
+ TAG_SHORT(2, short.class),
+ TAG_INT(3, int.class),
+ TAG_LONG(4, long.class),
+ TAG_FLOAT(5, float.class),
+ TAG_DOUBLE(6, double.class),
+ TAG_BYTE_ARRAY(7, byte[].class),
+ TAG_INT_ARRAY(11, int[].class),
+ TAG_STRING(8, String.class),
+ TAG_LIST(9, List.class),
+ TAG_COMPOUND(10, Map.class);
+
+ // Unique NBT id
+ public final int id;
+
+ private NbtType(int id, Class> type) {
+ this.id = id;
+ NBT_CLASS.put(id, type);
+ NBT_ENUM.put(id, this);
+ }
+
+ private String getFieldName() {
+ if (this == TAG_COMPOUND)
+ return "map";
+ else if (this == TAG_LIST)
+ return "list";
+ else
+ return "data";
+ }
+ }
+
+ // The NBT base class
+ private Class> BASE_CLASS;
+ private Class> COMPOUND_CLASS;
+ private Class> STREAM_TOOLS;
+ private Class> READ_LIMITER_CLASS;
+ private Method NBT_CREATE_TAG;
+ private Method NBT_GET_TYPE;
+ private Field NBT_LIST_TYPE;
+ private final Field[] DATA_FIELD = new Field[12];
+
+ // CraftItemStack
+ private Class> CRAFT_STACK;
+ private Field CRAFT_HANDLE;
+ private Field STACK_TAG;
+
+ // Loading/saving compounds
+ private LoadCompoundMethod LOAD_COMPOUND;
+ private Method SAVE_COMPOUND;
+
+ // Shared instance
+ private static NbtFactory INSTANCE;
+
+ /**
+ * Represents a root NBT compound.
+ *
+ * All changes to this map will be reflected in the underlying NBT compound. Values may only be one of the following:
+ *
+ * Primitive types
+ * {@link java.lang.String String}
+ * {@link NbtList}
+ * {@link NbtCompound}
+ *
+ *
+ * See also:
+ *
+ * {@link NbtFactory#createCompound()}
+ * {@link NbtFactory#fromCompound(Object)}
+ *
+ *
+ * @author Kristian
+ */
+ public final class NbtCompound extends ConvertedMap {
+ private NbtCompound(Object handle) {
+ super(handle, getDataMap(handle));
+ }
+
+ // Simplifiying access to each value
+ public Byte getByte(String key, Byte defaultValue) {
+ return containsKey(key) ? (Byte) get(key) : defaultValue;
+ }
+
+ public Short getShort(String key, Short defaultValue) {
+ return containsKey(key) ? (Short) get(key) : defaultValue;
+ }
+
+ public Integer getInteger(String key, Integer defaultValue) {
+ return containsKey(key) ? (Integer) get(key) : defaultValue;
+ }
+
+ public Long getLong(String key, Long defaultValue) {
+ return containsKey(key) ? (Long) get(key) : defaultValue;
+ }
+
+ public Float getFloat(String key, Float defaultValue) {
+ return containsKey(key) ? (Float) get(key) : defaultValue;
+ }
+
+ public Double getDouble(String key, Double defaultValue) {
+ return containsKey(key) ? (Double) get(key) : defaultValue;
+ }
+
+ public String getString(String key, String defaultValue) {
+ return containsKey(key) ? (String) get(key) : defaultValue;
+ }
+
+ public byte[] getByteArray(String key, byte[] defaultValue) {
+ return containsKey(key) ? (byte[]) get(key) : defaultValue;
+ }
+
+ public int[] getIntegerArray(String key, int[] defaultValue) {
+ return containsKey(key) ? (int[]) get(key) : defaultValue;
+ }
+
+ /**
+ * Retrieve the list by the given name.
+ *
+ * @param key - the name of the list.
+ * @param createNew - whether or not to create a new list if its missing.
+ * @return An existing list, a new list or NULL.
+ */
+ public NbtList getList(String key, boolean createNew) {
+ NbtList list = (NbtList) get(key);
+
+ if (list == null && createNew)
+ put(key, list = createList());
+ return list;
+ }
+
+ /**
+ * Retrieve the map by the given name.
+ *
+ * @param key - the name of the map.
+ * @param createNew - whether or not to create a new map if its missing.
+ * @return An existing map, a new map or NULL.
+ */
+ public NbtCompound getMap(String key, boolean createNew) {
+ return getMap(Arrays.asList(key), createNew);
+ }
+ // Done
+
+ /**
+ * Set the value of an entry at a given location.
+ *
+ * Every element of the path (except the end) are assumed to be compounds, and will
+ * be created if they are missing.
+ *
+ * @param path - the path to the entry.
+ * @param value - the new value of this entry.
+ * @return This compound, for chaining.
+ */
+ public NbtCompound putPath(String path, Object value) {
+ List entries = getPathElements(path);
+ Map map = getMap(entries.subList(0, entries.size() - 1), true);
+
+ map.put(entries.get(entries.size() - 1), value);
+ return this;
+ }
+
+ /**
+ * Retrieve the value of a given entry in the tree.
+ *
+ * Every element of the path (except the end) are assumed to be compounds. The
+ * retrieval operation will be cancelled if any of them are missing.
+ *
+ * @param path - path to the entry.
+ * @return The value, or NULL if not found.
+ */
+ @SuppressWarnings("unchecked")
+ public T getPath(String path) {
+ List entries = getPathElements(path);
+ NbtCompound map = getMap(entries.subList(0, entries.size() - 1), false);
+
+ if (map != null) {
+ return (T) map.get(entries.get(entries.size() - 1));
+ }
+ return null;
+ }
+
+ /**
+ * Save the content of a NBT compound to a stream.
+ *
+ * Use {@link Files#newOutputStreamSupplier(java.io.File)} to provide a stream supplier to a file.
+ *
+ * @param stream - the output stream.
+ * @param option - whether or not to compress the output.
+ * @throws IOException If anything went wrong.
+ */
+ public void saveTo(OutputSupplier extends OutputStream> stream, StreamOptions option) throws IOException {
+ saveStream(this, stream, option);
+ }
+
+ /**
+ * Retrieve a map from a given path.
+ *
+ * @param path - path of compounds to look up.
+ * @param createNew - whether or not to create new compounds on the way.
+ * @return The map at this location.
+ */
+ private NbtCompound getMap(Iterable path, boolean createNew) {
+ NbtCompound current = this;
+
+ for (String entry : path) {
+ NbtCompound child = (NbtCompound) current.get(entry);
+
+ if (child == null) {
+ if (!createNew)
+ return null;
+ current.put(entry, child = createCompound());
+ }
+ current = child;
+ }
+ return current;
+ }
+
+ /**
+ * Split the path into separate elements.
+ *
+ * @param path - the path to split.
+ * @return The elements.
+ */
+ private List getPathElements(String path) {
+ return Lists.newArrayList(Splitter.on(".").omitEmptyStrings().split(path));
+ }
+ }
+
+ /**
+ * Represents a root NBT list.
+ * See also:
+ *
+ * {@link NbtFactory#createList(Object...)}
+ * {@link NbtFactory#fromList(Object)}
+ *
+ *
+ * @author Kristian
+ */
+ public final class NbtList extends ConvertedList {
+ private NbtList(Object handle) {
+ super(handle, getDataList(handle));
+ }
+ }
+
+ /**
+ * Represents an object that provides a view of a native NMS class.
+ *
+ * @author Kristian
+ */
+ public static interface Wrapper {
+ /**
+ * Retrieve the underlying native NBT tag.
+ *
+ * @return The underlying NBT.
+ */
+ public Object getHandle();
+ }
+
+ /**
+ * Retrieve or construct a shared NBT factory.
+ *
+ * @return The factory.
+ */
+ private static NbtFactory get() {
+ if (INSTANCE == null)
+ INSTANCE = new NbtFactory();
+ return INSTANCE;
+ }
+
+ /**
+ * Construct an instance of the NBT factory by deducing the class of NBTBase.
+ */
+ private NbtFactory() {
+ if (BASE_CLASS == null) {
+ try {
+ // Keep in mind that I do use hard-coded field names - but it's okay as long as we're dealing
+ // with CraftBukkit or its derivatives. This does not work in MCPC+ however.
+ ClassLoader loader = NbtFactory.class.getClassLoader();
+
+ String packageName = getPackageName();
+ Class> offlinePlayer = loader.loadClass(packageName + ".CraftOfflinePlayer");
+
+ // Prepare NBT
+ COMPOUND_CLASS = getMethod(0, Modifier.STATIC, offlinePlayer, "getData").getReturnType();
+ BASE_CLASS = COMPOUND_CLASS.getSuperclass();
+ NBT_GET_TYPE = getMethod(0, Modifier.STATIC, BASE_CLASS, "getTypeId");
+ NBT_CREATE_TAG = getMethod(Modifier.STATIC, 0, BASE_CLASS, "createTag", byte.class);
+
+ // Prepare CraftItemStack
+ CRAFT_STACK = loader.loadClass(packageName + ".inventory.CraftItemStack");
+ CRAFT_HANDLE = getField(null, CRAFT_STACK, "handle");
+ STACK_TAG = getField(null, CRAFT_HANDLE.getType(), "tag");
+
+ // Loading/saving
+ String nmsPackage = BASE_CLASS.getPackage().getName();
+ initializeNMS(loader, nmsPackage);
+
+ LOAD_COMPOUND = READ_LIMITER_CLASS != null ?
+ new LoadMethodSkinUpdate(STREAM_TOOLS, READ_LIMITER_CLASS) :
+ new LoadMethodWorldUpdate(STREAM_TOOLS);
+ SAVE_COMPOUND = getMethod(Modifier.STATIC, 0, STREAM_TOOLS, null, BASE_CLASS, DataOutput.class);
+
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Unable to find offline player.", e);
+ }
+ }
+ }
+
+ private void initializeNMS(ClassLoader loader, String nmsPackage) {
+ try {
+ STREAM_TOOLS = loader.loadClass(nmsPackage + ".NBTCompressedStreamTools");
+ READ_LIMITER_CLASS = loader.loadClass(nmsPackage + ".NBTReadLimiter");
+ } catch (ClassNotFoundException e) {
+ // Ignore - we will detect this later
+ }
+ }
+
+ private String getPackageName() {
+ Server server = Bukkit.getServer();
+ String name = server != null ? server.getClass().getPackage().getName() : null;
+
+ if (name != null && name.contains("craftbukkit")) {
+ return name;
+ } else {
+ // Fallback
+ return "org.bukkit.craftbukkit.v1_7_R3";
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map getDataMap(Object handle) {
+ return (Map) getFieldValue(
+ getDataField(NbtType.TAG_COMPOUND, handle), handle);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getDataList(Object handle) {
+ return (List) getFieldValue(
+ getDataField(NbtType.TAG_LIST, handle), handle);
+ }
+
+ /**
+ * Construct a new NBT list of an unspecified type.
+ *
+ * @return The NBT list.
+ */
+ public static NbtList createList(Object... content) {
+ return createList(Arrays.asList(content));
+ }
+
+ /**
+ * Construct a new NBT list of an unspecified type.
+ *
+ * @return The NBT list.
+ */
+ public static NbtList createList(Iterable extends Object> iterable) {
+ NbtList list = get().new NbtList(
+ INSTANCE.createNbtTag(NbtType.TAG_LIST, null)
+ );
+
+ // Add the content as well
+ for (Object obj : iterable)
+ list.add(obj);
+ return list;
+ }
+
+ /**
+ * Construct a new NBT compound.
+ *
+ * @return The NBT compound.
+ */
+ public static NbtCompound createCompound() {
+ return get().new NbtCompound(
+ INSTANCE.createNbtTag(NbtType.TAG_COMPOUND, null)
+ );
+ }
+
+ /**
+ * Construct a new NBT wrapper from a list.
+ *
+ * @param nmsList - the NBT list.
+ * @return The wrapper.
+ */
+ public static NbtList fromList(Object nmsList) {
+ return get().new NbtList(nmsList);
+ }
+
+ /**
+ * Load the content of a file from a stream.
+ *
+ * Use {@link Files#newInputStreamSupplier(java.io.File)} to provide a stream from a file.
+ *
+ * @param stream - the stream supplier.
+ * @param option - whether or not to decompress the input stream.
+ * @return The decoded NBT compound.
+ * @throws IOException If anything went wrong.
+ */
+ public static NbtCompound fromStream(InputSupplier extends InputStream> stream, StreamOptions option) throws IOException {
+ InputStream input = null;
+ DataInputStream data = null;
+ boolean suppress = true;
+
+ try {
+ input = stream.getInput();
+ data = new DataInputStream(new BufferedInputStream(
+ option == StreamOptions.GZIP_COMPRESSION ? new GZIPInputStream(input) : input
+ ));
+
+ NbtCompound result = fromCompound(get().LOAD_COMPOUND.loadNbt(data));
+ suppress = false;
+ return result;
+
+ } finally {
+ if (data != null)
+ Closeables.close(data, suppress);
+ else if (input != null)
+ Closeables.close(input, suppress);
+ }
+ }
+
+ /**
+ * Save the content of a NBT compound to a stream.
+ *
+ * Use {@link Files#newOutputStreamSupplier(java.io.File)} to provide a stream supplier to a file.
+ *
+ * @param source - the NBT compound to save.
+ * @param stream - the stream.
+ * @param option - whether or not to compress the output.
+ * @throws IOException If anything went wrong.
+ */
+ public static void saveStream(NbtCompound source, OutputSupplier extends OutputStream> stream, StreamOptions option) throws IOException {
+ OutputStream output = null;
+ DataOutputStream data = null;
+ boolean suppress = true;
+
+ try {
+ output = stream.getOutput();
+ data = new DataOutputStream(
+ option == StreamOptions.GZIP_COMPRESSION ? new GZIPOutputStream(output) : output
+ );
+
+ invokeMethod(get().SAVE_COMPOUND, null, source.getHandle(), data);
+ suppress = false;
+
+ } finally {
+ if (data != null)
+ Closeables.close(data, suppress);
+ else if (output != null)
+ Closeables.close(output, suppress);
+ }
+ }
+
+ /**
+ * Construct a new NBT wrapper from a compound.
+ *
+ * @param nmsCompound - the NBT compund.
+ * @return The wrapper.
+ */
+ public static NbtCompound fromCompound(Object nmsCompound) {
+ return get().new NbtCompound(nmsCompound);
+ }
+
+ /**
+ * Set the NBT compound tag of a given item stack.
+ *
+ * The item stack must be a wrapper for a CraftItemStack.
+ *
+ * @param stack - the item stack, cannot be air.
+ * @param compound - the new NBT compound, or NULL to remove it.
+ * @throws IllegalArgumentException If the stack is not a CraftItemStack, or it represents air.
+ */
+ public static void setItemTag(ItemStack stack, NbtCompound compound) {
+ checkItemStack(stack);
+ Object nms = getFieldValue(get().CRAFT_HANDLE, stack);
+
+ // Now update the tag compound
+ setFieldValue(get().STACK_TAG, nms, compound.getHandle());
+ }
+
+ /**
+ * Construct a wrapper for an NBT tag stored (in memory) in an item stack. This is where
+ * auxillary data such as enchanting, name and lore is stored. It does not include items
+ * material, damage value or count.
+ *
+ * The item stack must be a wrapper for a CraftItemStack.
+ *
+ * @param stack - the item stack.
+ * @return A wrapper for its NBT tag.
+ */
+ public static NbtCompound fromItemTag(ItemStack stack) {
+ checkItemStack(stack);
+ Object nms = getFieldValue(get().CRAFT_HANDLE, stack);
+ Object tag = getFieldValue(get().STACK_TAG, nms);
+
+ // Create the tag if it doesn't exist
+ if (tag == null) {
+ NbtCompound compound = createCompound();
+ setItemTag(stack, compound);
+ return compound;
+ }
+ return fromCompound(tag);
+ }
+
+ /**
+ * Retrieve a CraftItemStack version of the stack.
+ *
+ * @param stack - the stack to convert.
+ * @return The CraftItemStack version.
+ */
+ public static ItemStack getCraftItemStack(ItemStack stack) {
+ // Any need to convert?
+ if (stack == null || get().CRAFT_STACK.isAssignableFrom(stack.getClass()))
+ return stack;
+ try {
+ // Call the private constructor
+ Constructor> caller = INSTANCE.CRAFT_STACK.getDeclaredConstructor(ItemStack.class);
+ caller.setAccessible(true);
+ return (ItemStack) caller.newInstance(stack);
+ } catch (Exception e) {
+ throw new IllegalStateException("Unable to convert " + stack + " + to a CraftItemStack.");
+ }
+ }
+
+ /**
+ * Ensure that the given stack can store arbitrary NBT information.
+ *
+ * @param stack - the stack to check.
+ */
+ private static void checkItemStack(ItemStack stack) {
+ if (stack == null)
+ throw new IllegalArgumentException("Stack cannot be NULL.");
+ if (!get().CRAFT_STACK.isAssignableFrom(stack.getClass()))
+ throw new IllegalArgumentException("Stack must be a CraftItemStack.");
+ if (stack.getType() == Material.AIR)
+ throw new IllegalArgumentException("ItemStacks representing air cannot store NMS information.");
+ }
+
+ /**
+ * Convert wrapped List and Map objects into their respective NBT counterparts.
+ *
+ * @param value - the value of the element to create. Can be a List or a Map.
+ * @return The NBT element.
+ */
+ private Object unwrapValue(Object value) {
+ if (value == null)
+ return null;
+
+ if (value instanceof Wrapper) {
+ return ((Wrapper) value).getHandle();
+
+ } else if (value instanceof List) {
+ throw new IllegalArgumentException("Can only insert a WrappedList.");
+ } else if (value instanceof Map) {
+ throw new IllegalArgumentException("Can only insert a WrappedCompound.");
+
+ } else {
+ return createNbtTag(getPrimitiveType(value), value);
+ }
+ }
+
+ /**
+ * Convert a given NBT element to a primitive wrapper or List/Map equivalent.
+ *
+ * All changes to any mutable objects will be reflected in the underlying NBT element(s).
+ *
+ * @param nms - the NBT element.
+ * @return The wrapper equivalent.
+ */
+ private Object wrapNative(Object nms) {
+ if (nms == null)
+ return null;
+
+ if (BASE_CLASS.isAssignableFrom(nms.getClass())) {
+ final NbtType type = getNbtType(nms);
+
+ // Handle the different types
+ switch (type) {
+ case TAG_COMPOUND:
+ return new NbtCompound(nms);
+ case TAG_LIST:
+ return new NbtList(nms);
+ default:
+ return getFieldValue(getDataField(type, nms), nms);
+ }
+ }
+ throw new IllegalArgumentException("Unexpected type: " + nms);
+ }
+
+ /**
+ * Construct a new NMS NBT tag initialized with the given value.
+ *
+ * @param type - the NBT type.
+ * @param value - the value, or NULL to keep the original value.
+ * @return The created tag.
+ */
+ private Object createNbtTag(NbtType type, Object value) {
+ Object tag = invokeMethod(NBT_CREATE_TAG, null, (byte) type.id);
+
+ if (value != null) {
+ setFieldValue(getDataField(type, tag), tag, value);
+ }
+ return tag;
+ }
+
+ /**
+ * Retrieve the field where the NBT class stores its value.
+ *
+ * @param type - the NBT type.
+ * @param nms - the NBT class instance.
+ * @return The corresponding field.
+ */
+ private Field getDataField(NbtType type, Object nms) {
+ if (DATA_FIELD[type.id] == null)
+ DATA_FIELD[type.id] = getField(nms, null, type.getFieldName());
+ return DATA_FIELD[type.id];
+ }
+
+ /**
+ * Retrieve the NBT type from a given NMS NBT tag.
+ *
+ * @param nms - the native NBT tag.
+ * @return The corresponding type.
+ */
+ private NbtType getNbtType(Object nms) {
+ int type = (Byte) invokeMethod(NBT_GET_TYPE, nms);
+ return NBT_ENUM.get(type);
+ }
+
+ /**
+ * Retrieve the nearest NBT type for a given primitive type.
+ *
+ * @param primitive - the primitive type.
+ * @return The corresponding type.
+ */
+ private NbtType getPrimitiveType(Object primitive) {
+ NbtType type = NBT_ENUM.get(NBT_CLASS.inverse().get(
+ Primitives.unwrap(primitive.getClass())
+ ));
+
+ // Display the illegal value at least
+ if (type == null)
+ throw new IllegalArgumentException(String.format(
+ "Illegal type: %s (%s)", primitive.getClass(), primitive));
+ return type;
+ }
+
+ /**
+ * Invoke a method on the given target instance using the provided parameters.
+ *
+ * @param method - the method to invoke.
+ * @param target - the target.
+ * @param params - the parameters to supply.
+ * @return The result of the method.
+ */
+ private static Object invokeMethod(Method method, Object target, Object... params) {
+ try {
+ return method.invoke(target, params);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to invoke method " + method + " for " + target, e);
+ }
+ }
+
+ private static void setFieldValue(Field field, Object target, Object value) {
+ try {
+ field.set(target, value);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to set " + field + " for " + target, e);
+ }
+ }
+
+ private static Object getFieldValue(Field field, Object target) {
+ try {
+ return field.get(target);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to retrieve " + field + " for " + target, e);
+ }
+ }
+
+ /**
+ * Search for the first publically and privately defined method of the given name and parameter count.
+ *
+ * @param requireMod - modifiers that are required.
+ * @param bannedMod - modifiers that are banned.
+ * @param clazz - a class to start with.
+ * @param methodName - the method name, or NULL to skip.
+ * @param params - the expected parameters.
+ * @return The first method by this name.
+ * @throws IllegalStateException If we cannot find this method.
+ */
+ private static Method getMethod(int requireMod, int bannedMod, Class> clazz, String methodName, Class>... params) {
+ for (Method method : clazz.getDeclaredMethods()) {
+ // Limitation: Doesn't handle overloads
+ if ((method.getModifiers() & requireMod) == requireMod &&
+ (method.getModifiers() & bannedMod) == 0 &&
+ (methodName == null || method.getName().equals(methodName)) &&
+ Arrays.equals(method.getParameterTypes(), params)) {
+
+ method.setAccessible(true);
+ return method;
+ }
+ }
+ // Search in every superclass
+ if (clazz.getSuperclass() != null)
+ return getMethod(requireMod, bannedMod, clazz.getSuperclass(), methodName, params);
+ throw new IllegalStateException(String.format(
+ "Unable to find method %s (%s).", methodName, Arrays.asList(params)));
+ }
+
+ /**
+ * Search for the first publically and privately defined field of the given name.
+ *
+ * @param instance - an instance of the class with the field.
+ * @param clazz - an optional class to start with, or NULL to deduce it from instance.
+ * @param fieldName - the field name.
+ * @return The first field by this name.
+ * @throws IllegalStateException If we cannot find this field.
+ */
+ private static Field getField(Object instance, Class> clazz, String fieldName) {
+ if (clazz == null)
+ clazz = instance.getClass();
+ // Ignore access rules
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.getName().equals(fieldName)) {
+ field.setAccessible(true);
+ return field;
+ }
+ }
+ // Recursively fild the correct field
+ if (clazz.getSuperclass() != null)
+ return getField(instance, clazz.getSuperclass(), fieldName);
+ throw new IllegalStateException("Unable to find field " + fieldName + " in " + instance);
+ }
+
+ /**
+ * Represents a class for caching wrappers.
+ *
+ * @author Kristian
+ */
+ private final class CachedNativeWrapper {
+ // Don't recreate wrapper objects
+ private final ConcurrentMap cache = new MapMaker().weakKeys().makeMap();
+
+ public Object wrap(Object value) {
+ Object current = cache.get(value);
+
+ if (current == null) {
+ current = wrapNative(value);
+
+ // Only cache composite objects
+ if (current instanceof ConvertedMap ||
+ current instanceof ConvertedList) {
+ cache.put(value, current);
+ }
+ }
+ return current;
+ }
+ }
+
+ /**
+ * Represents a map that wraps another map and automatically
+ * converts entries of its type and another exposed type.
+ *
+ * @author Kristian
+ */
+ private class ConvertedMap extends AbstractMap implements Wrapper {
+ private final Object handle;
+ private final Map original;
+
+ private final CachedNativeWrapper cache = new CachedNativeWrapper();
+
+ public ConvertedMap(Object handle, Map original) {
+ this.handle = handle;
+ this.original = original;
+ }
+
+ // For converting back and forth
+ protected Object wrapOutgoing(Object value) {
+ return cache.wrap(value);
+ }
+
+ protected Object unwrapIncoming(Object wrapped) {
+ return unwrapValue(wrapped);
+ }
+
+ // Modification
+ @Override
+ public Object put(String key, Object value) {
+ return wrapOutgoing(original.put(
+ (String) key,
+ unwrapIncoming(value)
+ ));
+ }
+
+ // Performance
+ @Override
+ public Object get(Object key) {
+ return wrapOutgoing(original.get(key));
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return wrapOutgoing(original.remove(key));
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return original.containsKey(key);
+ }
+
+ @Override
+ public Set> entrySet() {
+ return new AbstractSet>() {
+ @Override
+ public boolean add(Entry e) {
+ String key = e.getKey();
+ Object value = e.getValue();
+
+ original.put(key, unwrapIncoming(value));
+ return true;
+ }
+
+ @Override
+ public int size() {
+ return original.size();
+ }
+
+ @Override
+ public Iterator> iterator() {
+ return ConvertedMap.this.iterator();
+ }
+ };
+ }
+
+ private Iterator> iterator() {
+ final Iterator> proxy = original.entrySet().iterator();
+
+ return new Iterator>() {
+ @Override
+ public boolean hasNext() {
+ return proxy.hasNext();
+ }
+
+ @Override
+ public Entry next() {
+ Entry entry = proxy.next();
+
+ return new SimpleEntry(
+ entry.getKey(), wrapOutgoing(entry.getValue())
+ );
+ }
+
+ @Override
+ public void remove() {
+ proxy.remove();
+ }
+ };
+ }
+
+ @Override
+ public Object getHandle() {
+ return handle;
+ }
+ }
+
+ /**
+ * Represents a list that wraps another list and converts elements
+ * of its type and another exposed type.
+ *
+ * @author Kristian
+ */
+ private class ConvertedList extends AbstractList implements Wrapper {
+ private final Object handle;
+
+ private final List original;
+ private final CachedNativeWrapper cache = new CachedNativeWrapper();
+
+ public ConvertedList(Object handle, List original) {
+ if (NBT_LIST_TYPE == null)
+ NBT_LIST_TYPE = getField(handle, null, "type");
+ this.handle = handle;
+ this.original = original;
+ }
+
+ protected Object wrapOutgoing(Object value) {
+ return cache.wrap(value);
+ }
+
+ protected Object unwrapIncoming(Object wrapped) {
+ return unwrapValue(wrapped);
+ }
+
+ @Override
+ public Object get(int index) {
+ return wrapOutgoing(original.get(index));
+ }
+
+ @Override
+ public int size() {
+ return original.size();
+ }
+
+ @Override
+ public Object set(int index, Object element) {
+ return wrapOutgoing(
+ original.set(index, unwrapIncoming(element))
+ );
+ }
+
+ @Override
+ public void add(int index, Object element) {
+ Object nbt = unwrapIncoming(element);
+
+ // Set the list type if its the first element
+ if (size() == 0)
+ setFieldValue(NBT_LIST_TYPE, handle, (byte) getNbtType(nbt).id);
+ original.add(index, nbt);
+ }
+
+ @Override
+ public Object remove(int index) {
+ return wrapOutgoing(original.remove(index));
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return original.remove(unwrapIncoming(o));
+ }
+
+ @Override
+ public Object getHandle() {
+ return handle;
+ }
+ }
+
+ /**
+ * Represents a method for loading an NBT compound.
+ *
+ * @author Kristian
+ */
+ private static abstract class LoadCompoundMethod {
+ protected Method staticMethod;
+
+ protected void setMethod(Method method) {
+ this.staticMethod = method;
+ this.staticMethod.setAccessible(true);
+ }
+
+ /**
+ * Load an NBT compound from a given stream.
+ *
+ * @param input - the input stream.
+ * @return The loaded NBT compound.
+ */
+ public abstract Object loadNbt(DataInput input);
+ }
+
+ /**
+ * Load an NBT compound from the NBTCompressedStreamTools static method in 1.7.2 - 1.7.5
+ */
+ private static class LoadMethodWorldUpdate extends LoadCompoundMethod {
+ public LoadMethodWorldUpdate(Class> streamClass) {
+ setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class));
+ }
+
+ @Override
+ public Object loadNbt(DataInput input) {
+ return invokeMethod(staticMethod, null, input);
+ }
+ }
+
+ /**
+ * Load an NBT compound from the NBTCompressedStreamTools static method in 1.7.8
+ */
+ private static class LoadMethodSkinUpdate extends LoadCompoundMethod {
+ private Object readLimiter;
+
+ public LoadMethodSkinUpdate(Class> streamClass, Class> readLimiterClass) {
+ setMethod(getMethod(Modifier.STATIC, 0, streamClass, null, DataInput.class, readLimiterClass));
+
+ // Find the unlimited read limiter
+ for (Field field : readLimiterClass.getDeclaredFields()) {
+ if (readLimiterClass.isAssignableFrom(field.getType())) {
+ try {
+ readLimiter = field.get(null);
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot retrieve read limiter.", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Object loadNbt(DataInput input) {
+ return invokeMethod(staticMethod, null, input, readLimiter);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/faris/kingkits/KingKits.java b/src/main/java/com/faris/kingkits/KingKits.java
index e64f158..c9f4d4a 100644
--- a/src/main/java/com/faris/kingkits/KingKits.java
+++ b/src/main/java/com/faris/kingkits/KingKits.java
@@ -1,5 +1,7 @@
package com.faris.kingkits;
+import com.comphenix.attributes.Attributes;
+import com.comphenix.attributes.Attributes.Attribute;
import com.faris.easysql.mysql.MySQLDetails;
import com.faris.kingkits.controller.*;
import com.faris.kingkits.helper.util.BukkitUtilities;
@@ -15,7 +17,6 @@
import com.faris.kingkits.storage.FlatFileStorage;
import com.faris.kingkits.updater.BukkitUpdater;
import com.faris.kingkits.updater.SpigotUpdater;
-import nl.arfie.bukkit.attributes.Attribute;
import org.bukkit.ChatColor;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.entity.Player;
@@ -42,6 +43,8 @@ public class KingKits extends JavaPlugin {
@Override
public void onEnable() {
+ Attributes.AttributeType.initialiseNameMap();
+
final boolean isSpigot = this.getServer().getVersion().contains("Spigot");
try {
@@ -70,7 +73,7 @@ public void onEnable() {
ConfigurationSerialization.registerClass(Attribute.class);
ConfigurationSerialization.registerClass(MySQLDetails.class);
- if (new File(this.getDataFolder(), "config.yml").exists() && !ConfigController.getInstance().getConfig().getString("Version").equals(ConfigController.CURRENT_CONFIG_VERSION))
+ if (new File(this.getDataFolder(), "config.yml").exists() && (!ConfigController.getInstance().getConfig().contains("Version") || !ConfigController.getInstance().getConfig().getString("Version").equals(ConfigController.CURRENT_CONFIG_VERSION)))
ConfigController.getInstance().migrateOldConfigs();
else ConfigController.getInstance().loadConfiguration();
try {
@@ -261,7 +264,7 @@ public void onDisable() {
this.getServer().getScheduler().cancelTasks(this);
- GuiController.getInstance().shutdownController();
+ if (GuiController.hasInstance()) GuiController.getInstance().shutdownController();
for (KitPlayer kitPlayer : PlayerController.getInstance().getAllPlayers()) {
Player player = kitPlayer.getBukkitPlayer();
diff --git a/src/main/java/com/faris/kingkits/controller/ConfigController.java b/src/main/java/com/faris/kingkits/controller/ConfigController.java
index 5ad612b..e68cba0 100644
--- a/src/main/java/com/faris/kingkits/controller/ConfigController.java
+++ b/src/main/java/com/faris/kingkits/controller/ConfigController.java
@@ -1,5 +1,6 @@
package com.faris.kingkits.controller;
+import com.comphenix.attributes.Attributes;
import com.faris.easysql.mysql.MySQLDetails;
import com.faris.kingkits.KingKits;
import com.faris.kingkits.Kit;
@@ -26,7 +27,7 @@
public class ConfigController implements Controller {
private static ConfigController instance = null;
- public static final String CURRENT_CONFIG_VERSION = "3.3";
+ public static final String CURRENT_CONFIG_VERSION = "3.4";
private MySQLDetails sqlDetails = null;
@@ -76,7 +77,7 @@ public class ConfigController implements Controller {
private boolean allowItemDropping = false;
private boolean allowItemPicking = false;
private boolean allowItemDroppingOnDeath = false;
- private boolean allowOpBypass = true;
+ private boolean allowAdminBypass = true;
private boolean allowQuickSoup = true;
private boolean allowRightClickPreview = true;
private boolean economyEnabled = false;
@@ -138,7 +139,7 @@ private void saveDefaultConfig() {
this.getConfig().addDefault("Updater.Enabled", true, "Set to 'false' if you want to disable the checking of new updates.");
this.getConfig().addDefault("Updater.Update", true, "Set to 'true' if you want to auto-update the plugin if a new version has been found.", "This only works for Bukkit.");
this.getConfig().addDefault("MySQL", new MySQLDetails().serialize(), "MySQL authentication information and details.");
- this.getConfig().addDefault("OP bypass", true, "Set to 'true' if you want OPs to be able to drop/pickup items and do other activities even if disabled in the config.");
+ this.getConfig().addDefault("Admin bypass", true, "Set to 'true' if you want OPs or players with 'kingkits.admin' node to be able to drop/pickup items and do other activities even if disabled in the config.");
this.getConfig().addDefault("Auto-save player data", -1D, "Every time the set number of minutes passes, player data is saved asynchronously.", "Set to -1 to disable auto-save.");
if (!this.getConfig().contains("Allow"))
this.getConfig().createSection("Allow", "Allow/disallow (enable/disable) various things.");
@@ -239,7 +240,7 @@ public void loadConfiguration() {
this.autoSavePlayerData = this.getConfig().getDouble("Auto-save player data", -1D);
this.sqlDetails = MySQLDetails.deserialize(ObjectUtilities.getMap(this.getConfig().get("MySQL")));
- this.allowOpBypass = this.getConfig().getBoolean("OP bypass", true);
+ this.allowAdminBypass = this.getConfig().getBoolean("Admin bypass", true);
this.allowBlockPlacingAndBreaking = this.getConfig().getBoolean("Allow.Block modification", true);
this.allowDeathMessages = this.getConfig().getBoolean("Allow.Death messages", true);
this.allowItemDropping = this.getConfig().getBoolean("Allow.Item dropping", false);
@@ -434,8 +435,8 @@ public boolean canModifyBlocks(World world) {
return !this.worldSettingsMap.containsKey(lowerCaseWorld) ? this.allowBlockPlacingAndBreaking : this.worldSettingsMap.get(lowerCaseWorld).allowBlockPlacingAndBreaking;
}
- public boolean canOpsBypass() {
- return this.allowOpBypass;
+ public boolean canAdminsBypass() {
+ return this.allowAdminBypass;
}
public boolean canPickupItems(World world) {
@@ -1458,19 +1459,6 @@ else if (strArmourType.endsWith("boots"))
this.getConfig().set("Version", "3.2");
this.saveConfig();
- this.reloadConfigs();
- this.loadConfiguration();
- try {
- if (ConfigController.getInstance().getSQLDetails().isEnabled()) {
- SQLController.getInstance();
- DataStorage.setInstance(DataStorage.DataStorageType.SQL);
- } else {
- DataStorage.setInstance(DataStorage.DataStorageType.FILE);
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- }
-
try {
File kitsFolder = new File(KingKits.getInstance().getDataFolder(), "kits");
if (kitsFolder.exists()) {
@@ -1618,13 +1606,6 @@ else if (strArmourType.endsWith("boots"))
} catch (Exception ex) {
ex.printStackTrace();
}
- }
- if (this.getConfig().getString("Version", "").equals("3.2")) {
- // 1.9 changes
- plugin.getLogger().log(Level.INFO, "Converting config v3.2 to v3.3...");
-
- this.getConfig().set("Version", "3.3");
- this.saveConfig();
this.reloadConfigs();
this.loadConfiguration();
@@ -1638,6 +1619,13 @@ else if (strArmourType.endsWith("boots"))
} catch (Exception ex) {
ex.printStackTrace();
}
+ }
+ if (this.getConfig().getString("Version", "").equals("3.2")) {
+ // 1.9 changes
+ plugin.getLogger().log(Level.INFO, "Converting config v3.2 to v3.3...");
+
+ this.getConfig().set("Version", "3.3");
+ this.saveConfig();
try {
File kitsFolder = new File(KingKits.getInstance().getDataFolder(), "kits");
@@ -1787,6 +1775,107 @@ else if (strArmourType.endsWith("boots"))
} catch (Exception ex) {
ex.printStackTrace();
}
+
+ this.reloadConfigs();
+ this.loadConfiguration();
+ try {
+ if (ConfigController.getInstance().getSQLDetails().isEnabled()) {
+ SQLController.getInstance();
+ DataStorage.setInstance(DataStorage.DataStorageType.SQL);
+ } else {
+ DataStorage.setInstance(DataStorage.DataStorageType.FILE);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ if (this.getConfig().getString("Version", "").equals("3.3")) {
+ plugin.getLogger().log(Level.INFO, "Converting config v3.3 to v3.4...");
+
+ this.getConfig().set("Version", "3.4");
+ this.saveConfig();
+
+ try {
+ if (this.getConfig().contains("OP bypass")) {
+ this.getConfig().set("Admin bypass", this.getConfig().getBoolean("OP bypass"));
+ this.getConfig().set("OP bypass", null);
+ this.saveConfig();
+ }
+
+ File kitsFolder = new File(KingKits.getInstance().getDataFolder(), "kits");
+ if (kitsFolder.exists()) {
+ File[] kitFiles = FileUtilities.getFiles(kitsFolder);
+ if (kitFiles.length > 0) {
+ File oldFolder = new File(dataFolder, "old3.3");
+ try {
+ if (!oldFolder.exists()) oldFolder.mkdirs();
+ } catch (Exception ex) {
+ plugin.getLogger().log(Level.WARNING, "Could not create 'old' folder", ex);
+ oldFolder = null;
+ }
+
+ for (File kitFile : kitFiles) {
+ if (kitFile.getName().endsWith(".yml")) {
+ CustomConfiguration kitConfig = CustomConfiguration.loadConfiguration(kitFile);
+ kitConfig.setNewLineAfterHeader(true);
+ kitConfig.setNewLinePerKey(true);
+
+ boolean save = false;
+ if (kitConfig.contains("Items")) {
+ Map itemsMap = ObjectUtilities.getMap(kitConfig.get("Items"));
+ for (Map.Entry serializedItemEntry : new LinkedHashMap<>(itemsMap).entrySet()) {
+ Map serializedItem = ObjectUtilities.getMap(serializedItemEntry.getValue());
+ if (!serializedItem.isEmpty()) {
+ if (serializedItem.containsKey("Attributes")) {
+ Map serializedAttributes = ObjectUtilities.getMap(serializedItem.get("Attributes"));
+ for (Map.Entry serializedAttributesEntry : serializedAttributes.entrySet()) {
+ Map serializedAttribute = ObjectUtilities.getMap(serializedAttributesEntry.getValue());
+ if (serializedAttribute.containsKey("Type")) {
+ String strKeyPrefix = "Items." + serializedItemEntry.getKey() + ".Attributes." + serializedAttributesEntry.getKey();
+ String strAttrType = ObjectUtilities.getObject(serializedAttribute, String.class, "Type", "");
+ save = true;
+ kitConfig.set(strKeyPrefix + ".Name", strAttrType.replace(' ', '_').toUpperCase());
+ Attributes.AttributeType deserializedAttrType = Attributes.AttributeType.valueOf(strAttrType);
+ if (deserializedAttrType != null) {
+ kitConfig.set(strKeyPrefix + ".Type", deserializedAttrType.getMinecraftId());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (save) {
+ if (oldFolder == null) {
+ kitConfig.save(kitFile);
+ continue;
+ }
+ FileUtil.copy(kitFile, new File(oldFolder, kitFile.getName()));
+ FileUtilities.delete(kitFile);
+ kitConfig.save(kitFile);
+ }
+ }
+ }
+
+ if (FileUtilities.getFiles(oldFolder).length == 0) FileUtilities.delete(oldFolder);
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ this.reloadConfigs();
+ this.loadConfiguration();
+ try {
+ if (ConfigController.getInstance().getSQLDetails().isEnabled()) {
+ SQLController.getInstance();
+ DataStorage.setInstance(DataStorage.DataStorageType.SQL);
+ } else {
+ DataStorage.setInstance(DataStorage.DataStorageType.FILE);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
}
}
}
diff --git a/src/main/java/com/faris/kingkits/controller/GuiController.java b/src/main/java/com/faris/kingkits/controller/GuiController.java
index d923b46..d081af0 100644
--- a/src/main/java/com/faris/kingkits/controller/GuiController.java
+++ b/src/main/java/com/faris/kingkits/controller/GuiController.java
@@ -3,6 +3,7 @@
import com.faris.kingkits.KingKits;
import com.faris.kingkits.Kit;
import com.faris.kingkits.Messages;
+import com.faris.kingkits.Permissions;
import com.faris.kingkits.api.event.PlayerKitEvent;
import com.faris.kingkits.api.event.PlayerPreKitEvent;
import com.faris.kingkits.helper.util.*;
@@ -376,7 +377,7 @@ private void setKit(Kit selectedKit, final Player player, final KitPlayer kitPla
} else {
selectedKit = preEvent.getKit();
}
- long kitTimestamp = selectedKit.isUserKit() || (player.isOp() && ConfigController.getInstance().canOpsBypass()) ? -1L : kitPlayer.getKitTimestamp(selectedKit);
+ long kitTimestamp = selectedKit.isUserKit() || (player.hasPermission(Permissions.ADMIN) && ConfigController.getInstance().canAdminsBypass()) ? -1L : kitPlayer.getKitTimestamp(selectedKit);
if (kitTimestamp != -1L) {
if (selectedKit.hasCooldown()) {
if (System.currentTimeMillis() - kitTimestamp > (long) (selectedKit.getCooldown() * 1_000D)) {
@@ -386,7 +387,7 @@ private void setKit(Kit selectedKit, final Player player, final KitPlayer kitPla
}
}
if (kitTimestamp == -1L) {
- if (selectedKit.getCost() > 0D && (!player.isOp() || !ConfigController.getInstance().canOpsBypass())) {
+ if (selectedKit.getCost() > 0D && (!player.hasPermission(Permissions.ADMIN) || !ConfigController.getInstance().canAdminsBypass())) {
double playerBalance = PlayerUtilities.getBalance(player);
if (playerBalance >= selectedKit.getCost()) {
playerBalance -= selectedKit.getCost();
@@ -492,6 +493,10 @@ public static GuiController getInstance() {
return instance;
}
+ public static boolean hasInstance() {
+ return instance != null;
+ }
+
public enum GuiType {
GUI_KITS_MENU(),
GUI_KITS(),
diff --git a/src/main/java/com/faris/kingkits/helper/util/ItemUtilities.java b/src/main/java/com/faris/kingkits/helper/util/ItemUtilities.java
index b331cd6..a944f98 100644
--- a/src/main/java/com/faris/kingkits/helper/util/ItemUtilities.java
+++ b/src/main/java/com/faris/kingkits/helper/util/ItemUtilities.java
@@ -1,7 +1,7 @@
package com.faris.kingkits.helper.util;
-import nl.arfie.bukkit.attributes.Attribute;
-import nl.arfie.bukkit.attributes.Attributes;
+import com.comphenix.attributes.Attributes;
+import com.comphenix.attributes.Attributes.Attribute;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.Material;
@@ -99,12 +99,18 @@ public static ItemStack deserializeItem(Map serializedItem, Item
if (serializedItem.get("Attributes") != null) {
Map attributesMap = ObjectUtilities.getMap(serializedItem.get("Attributes"));
- List attributes = new ArrayList<>();
+ List attributesList = new ArrayList<>();
for (Object serializedAttribute : attributesMap.values()) {
Attribute deserializedAttribute = Attribute.deserialize(ObjectUtilities.getMap(serializedAttribute));
- if (deserializedAttribute != null) attributes.add(deserializedAttribute);
+ if (deserializedAttribute != null) attributesList.add(deserializedAttribute);
+ }
+ if (!attributesList.isEmpty()) {
+ Attributes itemAttributes = new Attributes(deserializedItem);
+ for (Attribute attribute : attributesList) {
+ itemAttributes.add(attribute);
+ }
+ deserializedItem = itemAttributes.getStack();
}
- if (!attributes.isEmpty()) Attributes.apply(deserializedItem, attributes, true);
}
if (serializedItem.get("Enchantments") != null) {
Map enchantmentsMap = ObjectUtilities.getMap(serializedItem.get("Enchantments"));
@@ -190,12 +196,13 @@ public static ItemStack deserializeItem(Map serializedItem, Item
Map serializedBanner = ObjectUtilities.getMap(serializedItem.get("Banner"));
if (serializedBanner.containsKey("Base")) {
Color deserializedBaseColor = Utilities.deserializeColor(ObjectUtilities.getMap(serializedBanner.get("Base")));
- if (deserializedBaseColor != null)
+ if (deserializedBaseColor != null) {
bannerMeta.setBaseColor(DyeColor.getByColor(deserializedBaseColor));
+ }
}
if (serializedBanner.containsKey("Patterns")) {
List patterns = new ArrayList<>();
- Map serializedPatterns = ObjectUtilities.getMap(serializedItem.get("Patterns"));
+ Map serializedPatterns = ObjectUtilities.getMap(serializedBanner.get("Patterns"));
for (Object objSerializedPattern : serializedPatterns.values()) {
Map serializedPattern = ObjectUtilities.getMap(objSerializedPattern);
Pattern pattern = null;
@@ -203,7 +210,7 @@ public static ItemStack deserializeItem(Map serializedItem, Item
if (serializedPattern.get("Pattern") != null) {
String strPatternType = ObjectUtilities.toString(serializedPattern.get("Pattern"));
patternType = PatternType.getByIdentifier(strPatternType);
- if (patternType != null) {
+ if (patternType == null) {
for (PatternType aPatternType : PatternType.values()) {
if (aPatternType.name().replace('_', ' ').equalsIgnoreCase(strPatternType)) {
patternType = aPatternType;
@@ -214,8 +221,9 @@ public static ItemStack deserializeItem(Map serializedItem, Item
}
if (patternType != null && serializedPattern.get("Color") != null) {
Color deserializedPatternColor = Utilities.deserializeColor(ObjectUtilities.getMap(serializedPattern.get("Color")));
- if (deserializedPatternColor != null)
+ if (deserializedPatternColor != null) {
pattern = new Pattern(DyeColor.getByColor(deserializedPatternColor), patternType);
+ }
}
if (pattern != null) patterns.add(pattern);
}
@@ -235,7 +243,7 @@ public static ItemStack deserializeItem(Map serializedItem, Item
}
if (serializedBanner.containsKey("Patterns")) {
List patterns = new ArrayList<>();
- Map serializedPatterns = ObjectUtilities.getMap(serializedItem.get("Patterns"));
+ Map serializedPatterns = ObjectUtilities.getMap(serializedBanner.get("Patterns"));
for (Object objSerializedPattern : serializedPatterns.values()) {
Map serializedPattern = ObjectUtilities.getMap(objSerializedPattern);
Pattern pattern = null;
@@ -243,7 +251,7 @@ public static ItemStack deserializeItem(Map serializedItem, Item
if (serializedPattern.get("Pattern") != null) {
String strPatternType = ObjectUtilities.toString(serializedPattern.get("Pattern"));
patternType = PatternType.getByIdentifier(strPatternType);
- if (patternType != null) {
+ if (patternType == null) {
for (PatternType aPatternType : PatternType.values()) {
if (aPatternType.name().replace('_', ' ').equalsIgnoreCase(strPatternType)) {
patternType = aPatternType;
@@ -254,8 +262,9 @@ public static ItemStack deserializeItem(Map serializedItem, Item
}
if (patternType != null && serializedPattern.get("Color") != null) {
Color deserializedPatternColor = Utilities.deserializeColor(ObjectUtilities.getMap(serializedPattern.get("Color")));
- if (deserializedPatternColor != null)
+ if (deserializedPatternColor != null) {
pattern = new Pattern(DyeColor.getByColor(deserializedPatternColor), patternType);
+ }
}
if (pattern != null) patterns.add(pattern);
}
@@ -518,7 +527,7 @@ public static Map serializeItem(final ItemStack itemStack) {
}
}
- final List itemAttributes = Attributes.fromStack(itemStack);
+ final List itemAttributes = new Attributes(itemStack).getAll();
if (!itemAttributes.isEmpty()) {
Map> serializedAttributes = new LinkedHashMap<>();
for (int i = 0; i < itemAttributes.size(); i++)
diff --git a/src/main/java/com/faris/kingkits/helper/util/KitUtilities.java b/src/main/java/com/faris/kingkits/helper/util/KitUtilities.java
index 2221698..724432b 100644
--- a/src/main/java/com/faris/kingkits/helper/util/KitUtilities.java
+++ b/src/main/java/com/faris/kingkits/helper/util/KitUtilities.java
@@ -2,6 +2,7 @@
import com.faris.kingkits.Kit;
import com.faris.kingkits.Messages;
+import com.faris.kingkits.Permissions;
import com.faris.kingkits.api.event.PlayerKitEvent;
import com.faris.kingkits.api.event.PlayerPreKitEvent;
import com.faris.kingkits.controller.ConfigController;
@@ -131,7 +132,7 @@ public static void listKits(CommandSender sender) {
}
public static boolean setKit(final Player player, Kit kit) {
- return setKit(player, kit, false, player != null && player.isOp() && ConfigController.getInstance().canOpsBypass(), player != null && player.isOp() && ConfigController.getInstance().canOpsBypass());
+ return setKit(player, kit, false, player != null && player.hasPermission(Permissions.ADMIN) && ConfigController.getInstance().canAdminsBypass(), player != null && player.isOp() && ConfigController.getInstance().canAdminsBypass());
}
public static boolean setKit(final Player player, Kit kit, boolean ignoreOneKitPerLife, boolean ignoreCooldown, boolean ignoreCost) {
diff --git a/src/main/java/com/faris/kingkits/listener/EventListener.java b/src/main/java/com/faris/kingkits/listener/EventListener.java
index 5b4231f..3c1c99b 100644
--- a/src/main/java/com/faris/kingkits/listener/EventListener.java
+++ b/src/main/java/com/faris/kingkits/listener/EventListener.java
@@ -459,7 +459,7 @@ public void onPlayerBreakBlock(BlockBreakEvent event) {
final Player player = event.getPlayer();
if (!ConfigController.getInstance().canModifyBlocks(event.getBlock().getWorld())) {
if (Utilities.isPvPWorld(player.getWorld())) {
- if (!ConfigController.getInstance().canOpsBypass() || !player.isOp()) {
+ if (!ConfigController.getInstance().canAdminsBypass() || !player.hasPermission(Permissions.ADMIN)) {
event.setCancelled(true);
Messages.sendMessage(player, Messages.EVENT_BLOCK_BREAK);
}
@@ -476,7 +476,7 @@ public void onPlayerPlaceBlock(BlockPlaceEvent event) {
final Player player = event.getPlayer();
if (!ConfigController.getInstance().canModifyBlocks(event.getBlock().getWorld())) {
if (Utilities.isPvPWorld(player.getWorld())) {
- if (!ConfigController.getInstance().canOpsBypass() || !player.isOp()) {
+ if (!ConfigController.getInstance().canAdminsBypass() || !player.hasPermission(Permissions.ADMIN)) {
event.setCancelled(true);
Messages.sendMessage(player, Messages.EVENT_BLOCK_PLACE);
}
@@ -493,7 +493,7 @@ public void onPlayerDropItem(PlayerDropItemEvent event) {
final Player player = event.getPlayer();
final KitPlayer kitPlayer = PlayerController.getInstance().getPlayer(player);
if (Utilities.isPvPWorld(player.getWorld()) || (kitPlayer != null && kitPlayer.hasKit())) {
- if (!ConfigController.getInstance().canDropItems(player.getWorld()) && (!player.isOp() || ConfigController.getInstance().canOpsBypass())) {
+ if (!ConfigController.getInstance().canDropItems(player.getWorld()) && (!player.hasPermission(Permissions.ADMIN) || ConfigController.getInstance().canAdminsBypass())) {
if (!ConfigController.getInstance().getDropAnimationItems(player.getWorld()).contains(event.getItemDrop().getItemStack().getTypeId()))
event.setCancelled(true);
else event.getItemDrop().remove();
@@ -510,7 +510,7 @@ public void onPlayerPickupItem(PlayerPickupItemEvent event) {
final Player player = event.getPlayer();
final KitPlayer kitPlayer = PlayerController.getInstance().getPlayer(player);
if (Utilities.isPvPWorld(player.getWorld()) || (kitPlayer != null && kitPlayer.hasKit())) {
- if (!ConfigController.getInstance().canPickupItems(player.getWorld()) && (!player.isOp() || ConfigController.getInstance().canOpsBypass())) {
+ if (!ConfigController.getInstance().canPickupItems(player.getWorld()) && (!player.hasPermission(Permissions.ADMIN) || ConfigController.getInstance().canAdminsBypass())) {
event.setCancelled(true);
}
}
@@ -679,7 +679,7 @@ public void onPlayerChangeGamemode(PlayerGameModeChangeEvent event) {
final Player player = event.getPlayer();
if (ConfigController.getInstance().shouldPreventCreative()) {
if (event.getNewGameMode() == GameMode.CREATIVE) {
- if (!ConfigController.getInstance().canOpsBypass() || !player.isOp()) {
+ if (!ConfigController.getInstance().canAdminsBypass() || !player.hasPermission(Permissions.ADMIN)) {
if (Utilities.isPvPWorld(player.getWorld())) {
event.setCancelled(true);
}
diff --git a/src/main/java/com/faris/kingkits/listener/commands/CommandPvPKit.java b/src/main/java/com/faris/kingkits/listener/commands/CommandPvPKit.java
index 580a828..6a1b0e1 100644
--- a/src/main/java/com/faris/kingkits/listener/commands/CommandPvPKit.java
+++ b/src/main/java/com/faris/kingkits/listener/commands/CommandPvPKit.java
@@ -133,7 +133,7 @@ private void setKit(CommandSender sender, Player player, String strKit, boolean
} else {
kit = preEvent.getKit();
}
- long kitTimestamp = player.isOp() && ConfigController.getInstance().canOpsBypass() ? -1L : kitPlayer.getKitTimestamp(kit);
+ long kitTimestamp = player.hasPermission(Permissions.ADMIN) && ConfigController.getInstance().canAdminsBypass() ? -1L : kitPlayer.getKitTimestamp(kit);
if (kit.hasCooldown()) {
if (kitTimestamp != -1L) {
if (System.currentTimeMillis() - kitTimestamp > (long) (kit.getCooldown() * 1_000D)) {
@@ -143,7 +143,7 @@ private void setKit(CommandSender sender, Player player, String strKit, boolean
}
}
if (kitTimestamp == -1L) {
- if (kit.getCost() > 0D && (!player.isOp() || !ConfigController.getInstance().canOpsBypass())) {
+ if (kit.getCost() > 0D && (!player.hasPermission(Permissions.ADMIN) || !ConfigController.getInstance().canAdminsBypass())) {
double playerBalance = PlayerUtilities.getBalance(player);
if (playerBalance >= kit.getCost()) {
playerBalance -= kit.getCost();
diff --git a/src/main/java/mkremins/fanciful/FancyMessage.java b/src/main/java/mkremins/fanciful/FancyMessage.java
index 1ed4125..8c9b4ed 100644
--- a/src/main/java/mkremins/fanciful/FancyMessage.java
+++ b/src/main/java/mkremins/fanciful/FancyMessage.java
@@ -30,7 +30,7 @@
*
* This class follows the builder pattern, allowing for method chaining.
* It is set up such that invocations of property-setting methods will affect the current editing component,
- * and a call to {@link #then()} or {@link #then(Object)} will append a new editing component to the end of the message,
+ * and a call to {@link #then()} or {@link #then(String)} will append a new editing component to the end of the message,
* optionally initializing it with text. Further property-setting method calls will affect that editing component.
*
*/
diff --git a/src/main/java/mkremins/fanciful/TextualComponent.java b/src/main/java/mkremins/fanciful/TextualComponent.java
index 3d06cc4..c80792c 100644
--- a/src/main/java/mkremins/fanciful/TextualComponent.java
+++ b/src/main/java/mkremins/fanciful/TextualComponent.java
@@ -19,8 +19,8 @@
public abstract class TextualComponent implements Cloneable {
static {
- ConfigurationSerialization.registerClass(TextualComponent.ArbitraryTextTypeComponent.class);
- ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class);
+ ConfigurationSerialization.registerClass(ArbitraryTextTypeComponent.class);
+ ConfigurationSerialization.registerClass(ComplexTextTypeComponent.class);
}
@Override
@@ -187,7 +187,7 @@ public void writeJson(JsonWriter writer) throws IOException {
@SuppressWarnings("serial")
public Map serialize() {
- return new java.util.HashMap() {{
+ return new HashMap() {{
put("key", getKey());
for (Map.Entry valEntry : getValue().entrySet()) {
put("value." + valEntry.getKey(), valEntry.getValue());
diff --git a/src/main/java/net/amoebaman/util/ArrayWrapper.java b/src/main/java/net/amoebaman/util/ArrayWrapper.java
index f610f8d..d080c24 100644
--- a/src/main/java/net/amoebaman/util/ArrayWrapper.java
+++ b/src/main/java/net/amoebaman/util/ArrayWrapper.java
@@ -57,10 +57,7 @@ public void setArray(E[] array) {
@SuppressWarnings("rawtypes")
@Override
public boolean equals(Object other) {
- if (!(other instanceof ArrayWrapper)) {
- return false;
- }
- return Arrays.equals(_array, ((ArrayWrapper) other)._array);
+ return other instanceof ArrayWrapper && Arrays.equals(_array, ((ArrayWrapper) other)._array);
}
/**
@@ -107,4 +104,5 @@ public static T[] toArray(Iterable extends T> list, Class c) {
}
return result;
}
+
}
diff --git a/src/main/java/net/amoebaman/util/Reflection.java b/src/main/java/net/amoebaman/util/Reflection.java
index 6b8da23..2a3d30f 100644
--- a/src/main/java/net/amoebaman/util/Reflection.java
+++ b/src/main/java/net/amoebaman/util/Reflection.java
@@ -17,7 +17,6 @@ public final class Reflection {
private static String _versionString;
private Reflection() {
-
}
/**
@@ -42,11 +41,11 @@ public synchronized static String getVersion() {
/**
* Stores loaded classes from the {@code net.minecraft.server} package.
*/
- private static final Map> _loadedNMSClasses = new HashMap>();
+ private static final Map> _loadedNMSClasses = new HashMap<>();
/**
* Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages).
*/
- private static final Map> _loadedOBCClasses = new HashMap>();
+ private static final Map> _loadedOBCClasses = new HashMap<>();
/**
* Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package.
@@ -116,7 +115,7 @@ public synchronized static Object getHandle(Object obj) {
}
}
- private static final Map, Map> _loadedFields = new HashMap, Map>();
+ private static final Map, Map> _loadedFields = new HashMap<>();
/**
* Retrieves a {@link Field} instance declared by the specified class with the specified name.
@@ -139,7 +138,7 @@ public synchronized static Object getHandle(Object obj) {
public synchronized static Field getField(Class> clazz, String name) {
Map loaded;
if (!_loadedFields.containsKey(clazz)) {
- loaded = new HashMap();
+ loaded = new HashMap<>();
_loadedFields.put(clazz, loaded);
} else {
loaded = _loadedFields.get(clazz);
@@ -166,7 +165,7 @@ public synchronized static Field getField(Class> clazz, String name) {
* 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, Map>, Method>>> _loadedMethods = new HashMap, Map>, Method>>>();
+ private static final Map, Map>, Method>>> _loadedMethods = new HashMap<>();
/**
* Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types.
@@ -189,8 +188,7 @@ public synchronized static Field getField(Class> clazz, String name) {
* @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) {
+ public synchronized static Method getMethod(Class> clazz, String name, Class>... args) {
if (!_loadedMethods.containsKey(clazz)) {
_loadedMethods.put(clazz, new HashMap>, Method>>());
}
@@ -201,7 +199,7 @@ public synchronized static Method getMethod(Class> clazz, String name,
}
Map>, Method> loadedSignatures = loadedMethodNames.get(name);
- ArrayWrapper> wrappedArg = new ArrayWrapper>(args);
+ ArrayWrapper> wrappedArg = new ArrayWrapper<>(args);
if (loadedSignatures.containsKey(wrappedArg)) {
return loadedSignatures.get(wrappedArg);
}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/Attribute.java b/src/main/java/nl/arfie/bukkit/attributes/Attribute.java
deleted file mode 100644
index 449696e..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/Attribute.java
+++ /dev/null
@@ -1,271 +0,0 @@
-package nl.arfie.bukkit.attributes;
-
-import com.faris.kingkits.helper.util.ObjectUtilities;
-import com.faris.kingkits.helper.util.Utilities;
-import com.google.common.base.Preconditions;
-import nl.arfie.bukkit.attributes.wrapper.NBTTagCompound;
-import org.bukkit.configuration.serialization.ConfigurationSerializable;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.UUID;
-
-/**
- * Represents a single Attribute that can be applied to ItemStacks.
- *
- * @author Ruud Verbeek
- * @see AttributeType, Operation
- */
-public class Attribute implements ConfigurationSerializable {
-
- UUID uuid;
- AttributeType type;
- Operation operation;
- double amount;
-
- /**
- * Constructs an Attribute with the given
- * {@link AttributeType}, {@link Operation}, amount and {@link UUID}.
- *
- * @param type The type of this Attribute.
- * @param operation The operation this Attribute uses to apply its amount to
- * the final value.
- * @param amount The amount of this Attribute.
- * @param uuid This Attribute's {@link UUID}. Must be unique.
- */
- public Attribute(AttributeType type, Operation operation, double amount, UUID uuid) {
- this.type = type;
- this.operation = operation == null ? Operation.ADD_NUMBER : operation;
- this.amount = amount;
- this.uuid = uuid;
- }
-
- /**
- * Constructs an Attribute using the given {@link AttributeType}, amount and
- * {@link UUID}. {@link Operation#ADD_NUMBER} will be used as
- * {@link Operation}.
- *
- * @param type The type of this Attribute.
- * @param amount The amount of this Attribute.
- * @param uuid This Attribute's {@link UUID}. Must be unique.
- */
- public Attribute(AttributeType type, double amount, UUID uuid) {
- this(type, Operation.ADD_NUMBER, amount, uuid);
- }
-
- /**
- * Constructs an Attribute using the given
- * {@link AttributeType}, {@link Operation} and amount. A random
- * {@link UUID} will be used.
- *
- * @param type The type of this Attribute.
- * @param operation The operation this Attribute uses to apply its amount to
- * the final value.
- * @param amount The amount of this Attribute
- */
- public Attribute(AttributeType type, Operation operation, double amount) {
- this(type, operation, amount, UUID.randomUUID());
- }
-
- /**
- * Constructs an Attribute using the give {@link AttributeType} and amount.
- * {@link Operation#ADD_NUMBER} will be used as {@link Operation} and a
- * random {@link UUID} will be used.
- *
- * @param type The type of this Attribute.
- * @param amount The amount of this Attribute.
- */
- public Attribute(AttributeType type, double amount) {
- this(type, Operation.ADD_NUMBER, amount, UUID.randomUUID());
- }
-
- /**
- * Constructs an Attribute with {@link Operation#ADD_NUMBER} as
- * {@link Operation}, 0.0 as amount and a random {@link UUID}. The
- * {@link AttributeType} must still be set using {@link #setType}.
- */
- public Attribute() {
- this(null, Operation.ADD_NUMBER, 0.0, UUID.randomUUID());
- }
-
- /**
- * Sets the {@link AttributeType} of this Attribute.
- *
- * @param type The {@link AttributeType}
- * @return This Attribute
- */
- public Attribute setType(AttributeType type) {
- this.type = type;
- return this;
- }
-
- /**
- * Sets the {@link Operation} of this Attribute.
- *
- * @param operation The {@link Operation}
- * @return This Attribute
- */
- public Attribute setOperation(Operation operation) {
- this.operation = operation;
- return this;
- }
-
- /**
- * Sets the amount of this Attribute.
- *
- * @param amount The amount
- * @return This Attribute
- */
- public Attribute setAmount(double amount) {
- this.amount = amount;
- return this;
- }
-
- /**
- * Sets the {@link UUID} of this Attribute.
- *
- * @param uuid The {@link UUID}
- * @return This Attribute
- */
- public Attribute setUUID(UUID uuid) {
- this.uuid = uuid;
- return this;
- }
-
- /**
- * Returns this Attribute's {@link AttributeType}
- *
- * @return The {@link AttributeType}
- */
- public AttributeType getType() {
- return type;
- }
-
- /**
- * Returns this Attribute's {@link Operation}
- *
- * @return The {@link Operation}
- */
- public Operation getOperation() {
- return operation;
- }
-
- /**
- * Returns this Attribute's amount
- *
- * @return The amount
- */
- public double getAmount() {
- return amount;
- }
-
- /**
- * Returns this Attribute's {@link UUID}
- *
- * @return The {@link UUID}
- */
- public UUID getUUID() {
- return this.uuid;
- }
-
- NBTTagCompound write() throws InstantiationException, IllegalAccessException {
- Preconditions.checkNotNull(type, "Type cannot be null.");
- if (this.operation == null) operation = Operation.ADD_NUMBER;
- if (this.uuid == null) this.uuid = UUID.randomUUID();
-
- NBTTagCompound tag = new NBTTagCompound();
- tag.setString("AttributeName", type.minecraftID);
- tag.setString("Name", type.minecraftID);
- tag.setInt("Operation", operation.id);
- tag.setDouble("Amount", amount);
- tag.setLong("UUIDMost", uuid.getMostSignificantBits());
- tag.setLong("UUIDLeast", uuid.getLeastSignificantBits());
- return tag;
- }
-
- /**
- * Returns whether or not this attribute is equal to o.
- */
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Attribute)) {
- return false;
- }
- Attribute a = (Attribute) o;
- return (uuid.equals(a.uuid) || (type == a.type && operation == a.operation && amount == a.amount));
- }
-
- static Attribute fromTag(NBTTagCompound c) throws IllegalArgumentException {
- Attribute a = new Attribute();
- if (c.hasKey("AttributeName")) {
- a.setType(AttributeType.fromMinecraftID(c.getString("AttributeName")));
- } else {
- throw new IllegalArgumentException("No AttributeName specified.");
- }
- if (c.hasKey("Operation")) {
- a.setOperation(Operation.fromID(c.getInt("Operation")));
- } else {
- throw new IllegalArgumentException("No Operation specified.");
- }
- if (c.hasKey("Amount")) {
- a.setAmount(c.getDouble("Amount"));
- } else {
- throw new IllegalArgumentException("No Amount specified.");
- }
- if (c.hasKey("UUIDMost") && c.hasKey("UUIDLeast")) {
- a.setUUID(new UUID(c.getLong("UUIDLeast"), c.getLong("UUIDMost")));
- } else {
- a.setUUID(UUID.randomUUID());
- }
- return a;
- }
-
- /**
- * Shortcut to {@link Attributes#apply}.
- *
- * @param is ItemStack to apply this attribute to
- * @param replace Whether or not to replace existing attributes on the
- * ItemStack
- * @return the new ItemStack containing this Attribute
- */
- public ItemStack apply(ItemStack is, boolean replace) {
- return Attributes.apply(is, this, replace);
- }
-
- @Override
- public Map serialize() {
- Map serializedAttribute = new LinkedHashMap<>();
- serializedAttribute.put("UUID", this.getUUID().toString());
- serializedAttribute.put("Type", this.getType().name());
- serializedAttribute.put("Amount", this.getAmount());
- if (this.operation != null) serializedAttribute.put("Operation", this.getOperation().name());
- return serializedAttribute;
- }
-
- public static Attribute deserialize(Map serializedAttribute) {
- Attribute deserializedAttribute = null;
- if (serializedAttribute != null && serializedAttribute.containsKey("Type")) {
- AttributeType attributeType = null;
- try {
- attributeType = AttributeType.valueOf(ObjectUtilities.getObject(serializedAttribute, String.class, "Type"));
- } catch (Exception ignored) {
- }
- if (attributeType != null) {
- UUID attributeUUID = Utilities.isUUID(serializedAttribute.get("UUID")) ? UUID.fromString(serializedAttribute.get("UUID").toString()) : null;
- double attributeAmount = ObjectUtilities.getObject(serializedAttribute, Number.class, "Amount", 0D).doubleValue();
- Operation operation = null;
- try {
- operation = Operation.valueOf(ObjectUtilities.getObject(serializedAttribute, String.class, "Operation"));
- } catch (Exception ignored) {
- }
- if (operation == null) operation = Operation.ADD_NUMBER;
- if (attributeUUID == null)
- deserializedAttribute = new Attribute(attributeType, operation, attributeAmount);
- else deserializedAttribute = new Attribute(attributeType, operation, attributeAmount, attributeUUID);
- }
- }
- return deserializedAttribute;
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/AttributeType.java b/src/main/java/nl/arfie/bukkit/attributes/AttributeType.java
deleted file mode 100644
index eb37f42..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/AttributeType.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package nl.arfie.bukkit.attributes;
-
-/**
- * An AttributeType is the type of effect an {@link Attribute} will have on its
- * user.
- *
- * @author Ruud Verbeek
- * @see Attribute
- */
-public enum AttributeType {
-
- /**
- * Will set the user's maximum health to the given number of life points.
- * One life point equals half a heart.
- */
- MAX_HEALTH("generic.maxHealth"),
- /**
- * Will set the user's number of blocks in which he can find and track other
- * entities.
- */
- FOLLOW_RANGE("generic.followRange"),
- /**
- * Will set the movement speed of the user. Default is 0.7.
- */
- MOVEMENT_SPEED("generic.movementSpeed"),
- /**
- * Will set how resistive the user is to knockbacks. 0.0 = no knockback
- * resistance, 1.0 = full knockback resistance.
- */
- KNOCKBACK_RESISTANCE("generic.knockbackResistance"),
- /**
- * Will set the user's armour defense points. 0.0 = no defense
- * 0.0 = no defense, 30.0 = max defense.
- */
- ARMOUR_DEFENSE("generic.armor"),
- /**
- * Will set the number of life points the user's attacks will normally take
- * off when hitting another Damageable.
- */
- ATTACK_DAMAGE("generic.attackDamage"),
- /**
- * Determines speed at which attack strength recharges. Value is the number of full-strength attacks per second.
- */
- ATTACK_SPEED("generic.attackSpeed"),
- /**
- * Affects the results of loot tables (e.g. when opening chests or chest minecarts, fishing, and killing mobs).
- */
- LUCK("generic.luck"),
- /**
- * Will set a horse's jumping strength. Default is 0.7.
- */
- JUMP_STRENGTH("horse.jumpStrength"),
- /**
- * Will set if a zombie should spawn other "reinforcing" zombies when hit.
- * 0.0 = don't spawn reinforcements, 1.0 = spawn reinforcements.
- */
- SPAWN_REINFORCEMENTS("zombie.spawnReinforcements");
-
- public String minecraftID;
-
- AttributeType(String minecraftID) {
- this.minecraftID = minecraftID;
- }
-
- public static AttributeType fromMinecraftID(String id) {
- for (AttributeType t : values()) {
- if (t.minecraftID.equalsIgnoreCase(id)) {
- return t;
- }
- }
- return null;
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/Attributes.java b/src/main/java/nl/arfie/bukkit/attributes/Attributes.java
deleted file mode 100644
index c80ec2b..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/Attributes.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package nl.arfie.bukkit.attributes;
-
-import com.faris.kingkits.KingKits;
-import nl.arfie.bukkit.attributes.wrapper.CraftItemStack;
-import nl.arfie.bukkit.attributes.wrapper.MinecraftItemStack;
-import nl.arfie.bukkit.attributes.wrapper.NBTTagCompound;
-import nl.arfie.bukkit.attributes.wrapper.NBTTagList;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.logging.Level;
-
-/**
- * Class to apply {@link Attribute}s or {@link Collection}s containing
- * Attributes to ItemStacks.
- *
- * Example code:
- *
- * // Instantiate some Attributes
- * Attribute a1 = new Attribute(AttributeType.ATTACK_DAMAGE,Operation.ADD_NUMBER,20.0),
- * a2 = new Attribute().setType(AttributeType.KNOCKBACK_RESISTANCE).setOperation(Operation.ADD_PERCENTAGE).setAmount(0.75);
- *
- * // Create an ItemStack with these Attributes
- * ItemStack is = new ItemStack(Material.NETHER_STAR);
- *
- * // Apply the attributes to said ItemStack
- * List list = new ArrayList<>();
- * list.add(a1);
- * list.add(a2);
- * Attributes.apply(is, list, true);
- *
- *
- * @author Ruud Verbeek
- * @see Attribute
- */
-public class Attributes {
-
- /**
- * Applies the given attribute to the given ItemStack
- *
- * @param original The original ItemStack to apply the attribute to
- * @param attribute The Attribute to apply.
- * @param replace Whether or not to remove the attributes that were already
- * on the ItemStack
- * @return A new ItemStack containing the attribute
- */
- public static ItemStack apply(ItemStack original, Attribute attribute, boolean replace) {
- try {
- MinecraftItemStack stack = CraftItemStack.asNMSCopy(original);
- NBTTagCompound tag = stack.getTag();
- NBTTagList list = replace ? new NBTTagList() : tag.getList("AttributeModifiers", 10);
- list.add(attribute.write());
- tag.set("AttributeModifiers", list);
- stack.setTag(tag);
- return CraftItemStack.asCraftMirror(stack).getStack();
- } catch (InstantiationException | IllegalAccessException ex) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to apply attribute " + attribute.toString() + " to item stack!", ex);
- return original;
- }
- }
-
- /**
- * Applies the given attributes to the given ItemStack
- *
- * @param original The original ItemStack to apply the attribute to
- * @param attributes The Attributes to apply.
- * @param replace Whether or not to remove the attributes that were already
- * on the ItemStack
- * @return A new ItemStack containing the attributes
- */
- public static ItemStack apply(ItemStack original, Collection extends Attribute> attributes, boolean replace) {
- try {
- MinecraftItemStack stack = CraftItemStack.asNMSCopy(original);
- NBTTagCompound tag = stack.getTag();
- NBTTagList list = replace ? new NBTTagList() : tag.getList("AttributeModifiers", 10);
- for (Attribute attribute : attributes) {
- list.add(attribute.write());
- }
- tag.set("AttributeModifiers", list);
- stack.setTag(tag);
- return CraftItemStack.asCraftMirror(stack).getStack();
- } catch (InstantiationException | IllegalAccessException ex) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to aplly attributes " + attributes.toString() + " to item stack!", ex);
- return original;
- }
- }
-
- /**
- * Returns a {@link List} containing the {@link Attribute}s on the given
- * {@link ItemStack}.
- *
- * @param is the ItemStack to take the Attributes from
- * @return a List containing the Attributes, or an empty list if there
- * weren't any Attributes on the ItemStack or an error occurred.
- */
- public static List fromStack(ItemStack is) {
- try {
- MinecraftItemStack mcis = CraftItemStack.asNMSCopy(is);
- NBTTagCompound tag = mcis.getTag();
- NBTTagList attributes;
- if ((attributes = tag.getList("AttributeModifiers", 10)) == null) {
- return new ArrayList<>();
- }
- List list = new ArrayList<>();
- for (int i = 0; i < attributes.size(); ++i) {
- NBTTagCompound attribute = attributes.get(i);
- list.add(Attribute.fromTag(attribute));
- }
- return list;
- } catch (InstantiationException | IllegalAccessException | IllegalArgumentException ex) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to load attributes from " + is.toString(), ex);
- return new ArrayList<>();
- }
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/Operation.java b/src/main/java/nl/arfie/bukkit/attributes/Operation.java
deleted file mode 100644
index 84b0e6f..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/Operation.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package nl.arfie.bukkit.attributes;
-
-/**
- * An Operation will indicate the way that an Attribute's amount value changes
- * the user's base value of the given {@link AttributeType}. Default is
- * {@link #ADD_NUMBER}.
- *
- * When applying operations, there are three variables: amount, base and output.
- *
- * amount indicates the amount of this {@link Attribute}
- * base indicates the base value of this {@link AttributeType}. For
- * example: 0.7 for a Player's MOVEMENT_SPEED.
- * ouput is the final value of this attribute.
- *
- *
- * @author Ruud Verbeek
- * @see AttributeType, Attribute
- */
-public enum Operation {
-
- /**
- * Will add amount to output . Will be applied before any
- * other operation.
- */
- ADD_NUMBER(0),
- /**
- * Will add amount * base to output after applying all
- * {@link #ADD_NUMBER} operations and before applying any
- * {@link #ADD_PERCENTAGE} operations.
- */
- MULTIPLY_PERCENTAGE(1),
- /**
- * Will add output * (1+amount) to the output, after applying all
- * other operations.
- */
- ADD_PERCENTAGE(2);
- public int id;
-
- Operation(int id) {
- this.id = id;
- }
-
- public static Operation fromID(int id) {
- for (Operation o : values()) {
- if (o.id == id) {
- return o;
- }
- }
- return null;
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/wrapper/CraftItemStack.java b/src/main/java/nl/arfie/bukkit/attributes/wrapper/CraftItemStack.java
deleted file mode 100644
index 604d1e9..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/wrapper/CraftItemStack.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package nl.arfie.bukkit.attributes.wrapper;
-
-import org.bukkit.inventory.ItemStack;
-
-public class CraftItemStack extends SourceWrapper {
-
- private final static Class> clazz = loadClass("org.bukkit.craftbukkit", "inventory.CraftItemStack");
-
- static {
- declareMethod(clazz, "asNMSCopy", ItemStack.class);
- declareMethod(clazz, "asCraftMirror", loadClass("net.minecraft.server", "ItemStack"));
- }
-
- public CraftItemStack() throws InstantiationException, IllegalAccessException {
- super(clazz.newInstance());
- }
-
- public CraftItemStack(Object instance) {
- super(instance);
- }
-
- public static MinecraftItemStack asNMSCopy(ItemStack stack) {
- return new MinecraftItemStack(invokeStaticMethod("asNMSCopy", stack));
- }
-
- public static CraftItemStack asCraftMirror(MinecraftItemStack stack) {
- return new CraftItemStack(invokeStaticMethod("asCraftMirror", stack.instance));
- }
-
- public ItemStack getStack() {
- return (ItemStack) instance;
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/wrapper/MinecraftItemStack.java b/src/main/java/nl/arfie/bukkit/attributes/wrapper/MinecraftItemStack.java
deleted file mode 100644
index a705ec8..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/wrapper/MinecraftItemStack.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package nl.arfie.bukkit.attributes.wrapper;
-
-import com.faris.kingkits.KingKits;
-
-import java.lang.reflect.Field;
-import java.util.logging.Level;
-
-public class MinecraftItemStack extends SourceWrapper {
-
- private final static Class> clazz = loadClass("net.minecraft.server", "ItemStack");
- private static Field tagField;
-
- static {
- try {
- tagField = clazz.getDeclaredField("tag");
- tagField.setAccessible(true);
- } catch (NoSuchFieldException | SecurityException ex) {
- KingKits.getInstance().getLogger().info("Failed to set \"Tag\" accessible!");
- }
- }
-
- public MinecraftItemStack() throws InstantiationException, IllegalAccessException {
- super(clazz.newInstance());
- }
-
- public MinecraftItemStack(Object instance) {
- super(instance);
- }
-
- public void setTag(NBTTagCompound tag) {
- try {
- tagField.set(instance, tag.instance);
- } catch (IllegalArgumentException | IllegalAccessException | SecurityException ex) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to set tag for " + instance.getClass().getName() + "!", ex);
- }
- }
-
- public NBTTagCompound getTag() {
- try {
- return new NBTTagCompound(tagField.get(instance));
- } catch (IllegalArgumentException | IllegalAccessException | SecurityException | InstantiationException ex) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to get tag for " + instance.getClass().getName() + "!", ex);
- return null;
- }
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTBase.java b/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTBase.java
deleted file mode 100644
index cf920e4..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTBase.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package nl.arfie.bukkit.attributes.wrapper;
-
-public class NBTBase extends SourceWrapper {
-
- private final static Class> clazz = loadClass("net.minecraft.server", "NBTBase");
-
- public NBTBase() throws InstantiationException, IllegalAccessException {
- super(clazz.newInstance());
- }
-
- public NBTBase(Object instance) {
- super(instance);
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTTagCompound.java b/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTTagCompound.java
deleted file mode 100644
index dbc12de..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTTagCompound.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package nl.arfie.bukkit.attributes.wrapper;
-
-import com.faris.kingkits.KingKits;
-
-import java.util.logging.Level;
-
-public class NBTTagCompound extends NBTBase {
-
- private final static Class> clazz = loadClass("net.minecraft.server", "NBTTagCompound");
-
- static {
- declareMethod(clazz, "setDouble", String.class, double.class);
- declareMethod(clazz, "getDouble", String.class);
- declareMethod(clazz, "setInt", String.class, int.class);
- declareMethod(clazz, "getInt", String.class);
- declareMethod(clazz, "setString", String.class, String.class);
- declareMethod(clazz, "getString", String.class);
- declareMethod(clazz, "setLong", String.class, long.class);
- declareMethod(clazz, "getLong", String.class);
- declareMethod(clazz, "set", String.class, loadClass("net.minecraft.server", "NBTBase"));
- declareMethod(clazz, "getList", String.class, int.class);
- declareMethod(clazz, "hasKey", String.class);
- }
-
- public NBTTagCompound() throws InstantiationException, IllegalAccessException {
- super(clazz.newInstance());
- }
-
- public NBTTagCompound(Object instance) throws InstantiationException, IllegalAccessException {
- super(instance == null ? clazz.newInstance() : instance);
- }
-
- public void setDouble(String key, double value) {
- invokeMethod("setDouble", key, value);
- }
-
- public double getDouble(String key) {
- return (double) invokeMethod("getDouble", key);
- }
-
- public void setInt(String key, int value) {
- invokeMethod("setInt", key, value);
- }
-
- public int getInt(String key) {
- return (int) invokeMethod("getInt", key);
- }
-
- public void setString(String key, String value) {
- invokeMethod("setString", key, value);
- }
-
- public String getString(String key) {
- return (String) invokeMethod("getString", key);
- }
-
- public void setLong(String key, long value) {
- invokeMethod("setLong", key, value);
- }
-
- public long getLong(String key) {
- return (long) invokeMethod("getLong", key);
- }
-
- public void set(String key, NBTBase value) {
- invokeMethod("set", key, value.instance);
- }
-
- public void set(String key, NBTTagList value) {
- invokeMethod("set", key, value.instance);
- }
-
- public NBTTagList getList(String key, int paramInt) {
- try {
- return new NBTTagList(invokeMethod("getList", key, paramInt));
- } catch (InstantiationException | IllegalAccessException ex) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to get List for " + instance.getClass().getName() + "!", ex);
- return null;
- }
- }
-
- public boolean hasKey(String key) {
- return (boolean) invokeMethod("hasKey", key);
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTTagList.java b/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTTagList.java
deleted file mode 100644
index a5bef5e..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/wrapper/NBTTagList.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package nl.arfie.bukkit.attributes.wrapper;
-
-public class NBTTagList extends NBTBase {
-
- private final static Class> clazz = loadClass("net.minecraft.server", "NBTTagList");
-
- static {
- declareMethod(clazz, "size");
- declareMethod(clazz, "get", int.class);
- declareMethod(clazz, "add", loadClass("net.minecraft.server", "NBTBase"));
- }
-
- public NBTTagList() throws InstantiationException, IllegalAccessException {
- super(clazz.newInstance());
- }
-
- public NBTTagList(Object instance) throws InstantiationException, IllegalAccessException {
- super(instance == null ? clazz.newInstance() : instance);
- }
-
- public int size() {
- return (int) invokeMethod("size");
- }
-
- public NBTTagCompound get(int index) throws InstantiationException, IllegalAccessException {
- return new NBTTagCompound(invokeMethod("get", index));
- }
-
- public void add(NBTBase base) {
- invokeMethod("add", base.instance);
- }
-
-}
diff --git a/src/main/java/nl/arfie/bukkit/attributes/wrapper/SourceWrapper.java b/src/main/java/nl/arfie/bukkit/attributes/wrapper/SourceWrapper.java
deleted file mode 100644
index 5b2f0a9..0000000
--- a/src/main/java/nl/arfie/bukkit/attributes/wrapper/SourceWrapper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package nl.arfie.bukkit.attributes.wrapper;
-
-import com.faris.kingkits.KingKits;
-import org.bukkit.Bukkit;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.logging.Level;
-
-abstract class SourceWrapper {
-
- protected Object instance;
-
- private static final HashMap methods = new HashMap<>();
-
- protected static String v;
-
- static {
- String pkgName = Bukkit.getServer().getClass().getPackage().getName();
- v = "." + pkgName.substring(pkgName.lastIndexOf('.') + 1) + ".";
- }
-
- public SourceWrapper(Object instance) {
- this.instance = instance;
- }
-
- protected static Class> loadClass(String start, String end) {
- try {
- return Bukkit.class.getClassLoader().loadClass(start + v + end);
- } catch (ClassNotFoundException ex) {
- return null;
- }
- }
-
- protected static void declareMethod(Class> clazz, String name, Class>... parameterTypes) {
- try {
- methods.put(name, clazz.getMethod(name, parameterTypes));
- } catch (NoSuchMethodException | SecurityException ex) {
- if (parameterTypes != null && parameterTypes.length > 0) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to get declared method " + name + " with parameters " + Arrays.deepToString(parameterTypes) + " for " + clazz.getClass().getName() + "!", ex);
- } else {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to get declared method " + name + " for " + clazz.getClass().getName() + "!", ex);
- }
- }
- }
-
- protected Object invokeMethod(String name, Object... args) {
- try {
- return methods.get(name).invoke(instance, args);
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
- if (args != null && args.length > 0) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to invoke method " + name + " with parameters " + Arrays.deepToString(args) + " for " + instance.getClass().getName() + "!", ex);
- } else {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to invoke method " + name + " for " + instance.getClass().getName() + "!", ex);
- }
- return null;
- }
- }
-
- protected static Object invokeStaticMethod(String name, Object... args) {
- try {
- return methods.get(name).invoke(null, args);
- } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
- if (args != null && args.length > 0) {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to invoke static metod " + name + " with parameters " + Arrays.deepToString(args) + "!", ex);
- } else {
- KingKits.getInstance().getLogger().log(Level.SEVERE, "Failed to invoke static metod " + name + "!", ex);
- }
- return null;
- }
- }
-
-}