diff --git a/.gitignore b/.gitignore index 61b3b58..56102af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +################# +## Eclipse +################# +.src/test/ + ################# ## Eclipse ################# diff --git a/pom.xml b/pom.xml index 035a9cf..7d008b9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.faris KingKits - 5.2.6 + 5.2.7 jar @@ -144,7 +144,7 @@ org.bukkit bukkit - 1.9.2-R0.1-SNAPSHOT + 1.10.2-R0.1-SNAPSHOT com.google.code.gson diff --git a/src/main/java/com/comphenix/attributes/Attributes.java b/src/main/java/com/comphenix/attributes/Attributes.java new file mode 100644 index 0000000..cc54e1b --- /dev/null +++ b/src/main/java/com/comphenix/attributes/Attributes.java @@ -0,0 +1,457 @@ +// 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.comphenix.attributes.NbtFactory.NbtCompound; +import com.comphenix.attributes.NbtFactory.NbtList; +import com.faris.kingkits.helper.util.ObjectUtilities; +import com.faris.kingkits.helper.util.Utilities; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterators; +import com.google.common.collect.Maps; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentMap; + +public class Attributes { + public enum Operation { + ADD_NUMBER(0), + MULTIPLY_PERCENTAGE(1), + ADD_PERCENTAGE(2); + private int id; + + private Operation(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + public static Operation fromId(int id) { + // Linear scan is very fast for small N + for (Operation op : values()) { + if (op.getId() == id) { + return op; + } + } + throw new IllegalArgumentException("Corrupt operation ID " + id + " detected."); + } + } + + public static class AttributeType { + private static ConcurrentMap LOOKUP = Maps.newConcurrentMap(); + public static final AttributeType GENERIC_MAX_HEALTH = new AttributeType("generic.maxHealth").register(); + public static final AttributeType GENERIC_FOLLOW_RANGE = new AttributeType("generic.followRange").register(); + public static final AttributeType GENERIC_ATTACK_DAMAGE = new AttributeType("generic.attackDamage").register(); + public static final AttributeType GENERIC_MOVEMENT_SPEED = new AttributeType("generic.movementSpeed").register(); + public static final AttributeType GENERIC_KNOCKBACK_RESISTANCE = new AttributeType("generic.knockbackResistance").register(); + public static final AttributeType GENERIC_ARMOUR_DEFENSE = new AttributeType("generic.armor").register(); + public static final AttributeType GENERIC_ATTACK_SPEED = new AttributeType("generic.attackSpeed").register(); + public static final AttributeType GENERIC_LUCK = new AttributeType("generic.luck").register(); + public static final AttributeType HORSE_JUMP_STRENGTH = new AttributeType("horse.jumpStrength").register(); + public static final AttributeType ZOMBIE_SPAWN_REINFORCEMENTS = new AttributeType("zombie.spawnReinforcements").register(); + + private static Map 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 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 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 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 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 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 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; - } - } - -}