Browse Source

Repair rewrite continues

nossr50 6 năm trước cách đây
mục cha
commit
b41a30fa26
25 tập tin đã thay đổi với 511 bổ sung155 xóa
  1. 8 3
      pom.xml
  2. 0 1
      src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
  3. 19 0
      src/main/java/com/gmail/nossr50/bukkit/BukkitFactory.java
  4. 2 2
      src/main/java/com/gmail/nossr50/config/ConfigManager.java
  5. 6 6
      src/main/java/com/gmail/nossr50/config/hocon/serializers/RepairWildcardSerializer.java
  6. 3 3
      src/main/java/com/gmail/nossr50/config/hocon/serializers/RepairableSerializer.java
  7. 6 6
      src/main/java/com/gmail/nossr50/config/hocon/skills/repair/ConfigRepair.java
  8. 61 0
      src/main/java/com/gmail/nossr50/datatypes/items/BukkitMMOItem.java
  9. 13 0
      src/main/java/com/gmail/nossr50/datatypes/items/CustomItemMatching.java
  10. 62 0
      src/main/java/com/gmail/nossr50/datatypes/items/CustomItemTarget.java
  11. 33 0
      src/main/java/com/gmail/nossr50/datatypes/items/ItemMatchProperty.java
  12. 61 0
      src/main/java/com/gmail/nossr50/datatypes/items/ItemWildcards.java
  13. 40 0
      src/main/java/com/gmail/nossr50/datatypes/items/MMOItem.java
  14. 13 0
      src/main/java/com/gmail/nossr50/datatypes/nbt/MMOEntity.java
  15. 26 0
      src/main/java/com/gmail/nossr50/datatypes/nbt/NBTHolder.java
  16. 8 2
      src/main/java/com/gmail/nossr50/skills/repair/RepairCost.java
  17. 0 51
      src/main/java/com/gmail/nossr50/skills/repair/RepairCostItem.java
  18. 21 15
      src/main/java/com/gmail/nossr50/skills/repair/RepairCostWildcard.java
  19. 12 4
      src/main/java/com/gmail/nossr50/skills/repair/RepairTransaction.java
  20. 0 43
      src/main/java/com/gmail/nossr50/skills/repair/RepairWildcard.java
  21. 66 0
      src/main/java/com/gmail/nossr50/skills/repair/SimpleRepairCost.java
  22. 10 10
      src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java
  23. 6 6
      src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableBuilder.java
  24. 20 0
      src/main/java/com/gmail/nossr50/util/nbt/NBTUtils.java
  25. 15 3
      src/main/java/com/gmail/nossr50/util/nbt/RawNBT.java

+ 8 - 3
pom.xml

@@ -216,10 +216,15 @@
         </dependency>
         <dependency>
             <groupId>org.spigotmc</groupId>
-            <artifactId>spigot-api</artifactId>
-            <version>1.14.2-R0.1-SNAPSHOT</version>
-            <scope>provided</scope>
+            <artifactId>spigot</artifactId>
+            <version>1.13.2-R0.1-SNAPSHOT</version>
         </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.spigotmc</groupId>-->
+<!--            <artifactId>spigot-api</artifactId>-->
+<!--            <version>1.14.2-R0.1-SNAPSHOT</version>-->
+<!--            <scope>provided</scope>-->
+<!--        </dependency>-->
         <dependency>
             <groupId>com.sk89q.worldguard</groupId>
             <artifactId>worldguard-core</artifactId>

+ 0 - 1
src/main/java/com/gmail/nossr50/api/ExperienceAPI.java

@@ -629,7 +629,6 @@ public final class ExperienceAPI {
      * @param skillType The skill to get the level for
      * @return the level of a given skill
      * @throws InvalidSkillException if the given skill is not valid
-     * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead
      */
     @Deprecated
     public static int getLevel(Player player, String skillType) {

+ 19 - 0
src/main/java/com/gmail/nossr50/bukkit/BukkitFactory.java

@@ -0,0 +1,19 @@
+package com.gmail.nossr50.bukkit;
+
+import com.gmail.nossr50.datatypes.items.BukkitMMOItem;
+import com.gmail.nossr50.util.nbt.RawNBT;
+
+/**
+ * Used to convert or construct platform independent types into Bukkit types
+ */
+public class BukkitFactory {
+
+    /**
+     * Creates a BukkitMMOItem which contains Bukkit implementations for the type MMOItem
+     * @return a new BukkitMMOItem
+     */
+    public static BukkitMMOItem createBukkitMMOItem(String namespaceKey, int amount, RawNBT rawNBT) {
+        return new BukkitMMOItem(namespaceKey, amount, rawNBT);
+    }
+
+}

+ 2 - 2
src/main/java/com/gmail/nossr50/config/ConfigManager.java

@@ -39,7 +39,7 @@ import com.gmail.nossr50.config.hocon.skills.ranks.SkillRankProperty;
 import com.gmail.nossr50.config.hocon.skills.repair.ConfigRepair;
 import com.gmail.nossr50.skills.repair.RepairCost;
 import com.gmail.nossr50.skills.repair.RepairTransaction;
-import com.gmail.nossr50.skills.repair.RepairWildcard;
+import com.gmail.nossr50.datatypes.items.ItemWildcards;
 import com.gmail.nossr50.config.hocon.skills.salvage.ConfigSalvage;
 import com.gmail.nossr50.config.hocon.skills.smelting.ConfigSmelting;
 import com.gmail.nossr50.config.hocon.skills.swords.ConfigSwords;
@@ -280,7 +280,7 @@ public final class ConfigManager {
         customSerializers.registerType(TypeToken.of(PlayerNotificationSettings.class), new PlayerNotificationSerializer());
         customSerializers.registerType(TypeToken.of(SoundSetting.class), new SoundSettingSerializer());
         customSerializers.registerType(TypeToken.of(ItemStack.class), new ItemStackSerializer());
-        customSerializers.registerType(TypeToken.of(RepairWildcard.class), new RepairWildcardSerializer());
+        customSerializers.registerType(TypeToken.of(ItemWildcards.class), new RepairWildcardSerializer());
         customSerializers.registerType(TypeToken.of(RepairCost.class), new RepairCostSerializer());
         customSerializers.registerType(TypeToken.of(RepairTransaction.class), new RepairTransactionSerializer());
     }

+ 6 - 6
src/main/java/com/gmail/nossr50/config/hocon/serializers/RepairWildcardSerializer.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config.hocon.serializers;
 
-import com.gmail.nossr50.skills.repair.RepairWildcard;
+import com.gmail.nossr50.datatypes.items.ItemWildcards;
 import com.google.common.reflect.TypeToken;
 import ninja.leaping.configurate.ConfigurationNode;
 import ninja.leaping.configurate.ValueType;
@@ -12,30 +12,30 @@ import org.checkerframework.checker.nullness.qual.Nullable;
 
 import java.util.Set;
 
-public class RepairWildcardSerializer implements TypeSerializer<RepairWildcard> {
+public class RepairWildcardSerializer implements TypeSerializer<ItemWildcards> {
 
     private static final String WILDCARD_IDENTIFIER_NAME = "Wildcard-Identifier-Name";
     private static final String MATCHING_ITEMS = "Matching-Items";
 
     @Nullable
     @Override
-    public RepairWildcard deserialize(@NonNull TypeToken<?> type, @NonNull ConfigurationNode value) throws ObjectMappingException {
+    public ItemWildcards deserialize(@NonNull TypeToken<?> type, @NonNull ConfigurationNode value) throws ObjectMappingException {
 
         String wildCardName = value.getNode(WILDCARD_IDENTIFIER_NAME).getValue(TypeToken.of(String.class));
 
         if(value.getNode(WILDCARD_IDENTIFIER_NAME).getNode(MATCHING_ITEMS).getValueType() != ValueType.NULL) {
             Set<ItemStack> matchCandidates = value.getNode(WILDCARD_IDENTIFIER_NAME).getNode(MATCHING_ITEMS).getValue(new TypeToken<Set<ItemStack>>() {});
 
-            return new RepairWildcard(wildCardName, matchCandidates);
+            return new ItemWildcards(wildCardName, matchCandidates);
         }
 
         return null;
     }
 
     @Override
-    public void serialize(@NonNull TypeToken<?> type, @Nullable RepairWildcard obj, @NonNull ConfigurationNode value) throws ObjectMappingException {
+    public void serialize(@NonNull TypeToken<?> type, @Nullable ItemWildcards obj, @NonNull ConfigurationNode value) throws ObjectMappingException {
         value.getNode(WILDCARD_IDENTIFIER_NAME).setValue(obj.getWildcardName());
-        value.getNode(WILDCARD_IDENTIFIER_NAME).getNode(MATCHING_ITEMS).setValue(obj.getMatchingItems());
+        value.getNode(WILDCARD_IDENTIFIER_NAME).getNode(MATCHING_ITEMS).setValue(obj.getItemTargets());
     }
 
 }

+ 3 - 3
src/main/java/com/gmail/nossr50/config/hocon/serializers/RepairableSerializer.java

@@ -24,7 +24,7 @@ public class RepairableSerializer implements TypeSerializer<Repairable> {
     private static final String STRICT_MATCH_ITEM = "Strict-Match-Item";
     private static final String STRICT_MATCHING_REPAIR_TRANSACTION = "Strict-Matching-Repair-Transaction";
     private static final String REPAIR_COUNT = "Repair-Count";
-    private static final String NBT = "NBT";
+//    private static final String NBT = "NBT";
     private static final String PERMISSION = "Permission";
     private static final String MINIMUM_LEVEL = "Minimum-Level";
 
@@ -34,7 +34,7 @@ public class RepairableSerializer implements TypeSerializer<Repairable> {
         RepairableBuilder builder = new RepairableBuilder(itemStack)
                 .repairTransaction(value.getNode(REPAIR_TRANSACTION).getValue(TypeToken.of(RepairTransaction.class)))
                 .strictMatchingItem(value.getNode(STRICT_MATCH_ITEM).getValue(TypeToken.of(Boolean.class)))
-                .strictMatchingRepairTransaction(value.getNode(STRICT_MATCHING_REPAIR_TRANSACTION).getValue(TypeToken.of(Boolean.class)))
+//                .strictMatchingRepairTransaction(value.getNode(STRICT_MATCHING_REPAIR_TRANSACTION).getValue(TypeToken.of(Boolean.class)))
                 .baseXP(value.getNode(BASE_XP).getValue(TypeToken.of(Integer.class)))
                 .repairCount(value.getNode(REPAIR_COUNT).getValue(TypeToken.of(Integer.class)));
 
@@ -58,7 +58,7 @@ public class RepairableSerializer implements TypeSerializer<Repairable> {
         value.getNode(ITEM).setValue(obj.getItem());
         value.getNode(REPAIR_TRANSACTION).setValue(obj.getRepairTransaction());
         value.getNode(STRICT_MATCH_ITEM).setValue(obj.isStrictMatchingItem());
-        value.getNode(STRICT_MATCHING_REPAIR_TRANSACTION).setValue(obj.isStrictMatchingRepairTransaction());
+//        value.getNode(STRICT_MATCHING_REPAIR_TRANSACTION).setValue(obj.isStrictMatchingRepairTransaction());
         value.getNode(BASE_XP).setValue(obj.getBaseXP());
         value.getNode(REPAIR_COUNT).setValue(obj.getRepairCount());
 

+ 6 - 6
src/main/java/com/gmail/nossr50/config/hocon/skills/repair/ConfigRepair.java

@@ -4,7 +4,7 @@ import com.gmail.nossr50.config.ConfigConstants;
 import com.gmail.nossr50.config.hocon.skills.repair.general.ConfigRepairGeneral;
 import com.gmail.nossr50.config.hocon.skills.repair.repairmastery.ConfigRepairRepairMastery;
 import com.gmail.nossr50.config.hocon.skills.repair.subskills.ConfigRepairSubSkills;
-import com.gmail.nossr50.skills.repair.RepairWildcard;
+import com.gmail.nossr50.datatypes.items.ItemWildcards;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
 import ninja.leaping.configurate.objectmapping.Setting;
 import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@@ -18,7 +18,7 @@ import static org.bukkit.Material.*;
 public class ConfigRepair {
 
     public static final ArrayList<Repairable> CONFIG_REPAIRABLES_DEFAULTS;
-    public static final HashSet<RepairWildcard> REPAIR_WILDCARDS_DEFAULTS;
+    public static final HashSet<ItemWildcards> REPAIR_WILDCARDS_DEFAULTS;
 //    public static final Material[] PLANKS = new Material[]{OAK_PLANKS, BIRCH_PLANKS, DARK_OAK_PLANKS, ACACIA_PLANKS, JUNGLE_PLANKS, SPRUCE_PLANKS};
 
     static {
@@ -28,7 +28,7 @@ public class ConfigRepair {
                 new ItemStack(BIRCH_PLANKS, 1), new ItemStack(DARK_OAK_PLANKS, 1),
                 new ItemStack(ACACIA_PLANKS, 1), new ItemStack(JUNGLE_PLANKS, 1),
                 new ItemStack(SPRUCE_PLANKS, 1)});
-        RepairWildcard planksWildCard = new RepairWildcard("Planks", new HashSet<>(planksList));
+        ItemWildcards planksWildCard = new ItemWildcards("Planks", new HashSet<>(planksList));
         REPAIR_WILDCARDS_DEFAULTS.add(planksWildCard);
 
         CONFIG_REPAIRABLES_DEFAULTS = new ArrayList<>();
@@ -102,7 +102,7 @@ public class ConfigRepair {
     private ArrayList<Repairable> configRepairablesList = CONFIG_REPAIRABLES_DEFAULTS;
 
     @Setting(value = "Z-Repairables-Wildcards", comment = "Used to define an alias that can be matched to several materials.")
-    private HashSet<RepairWildcard> repairWildcards = new HashSet<>();
+    private HashSet<ItemWildcards> itemWildcards = new HashSet<>();
 
     public ConfigRepairGeneral getRepairGeneral() {
         return repairGeneral;
@@ -128,7 +128,7 @@ public class ConfigRepair {
         return configRepairablesList;
     }
 
-    public HashSet<RepairWildcard> getRepairWildcards() {
-        return repairWildcards;
+    public HashSet<ItemWildcards> getItemWildcards() {
+        return itemWildcards;
     }
 }

+ 61 - 0
src/main/java/com/gmail/nossr50/datatypes/items/BukkitMMOItem.java

@@ -0,0 +1,61 @@
+package com.gmail.nossr50.datatypes.items;
+
+import com.gmail.nossr50.util.nbt.RawNBT;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+public class BukkitMMOItem implements MMOItem<ItemStack> {
+
+    private ItemStack itemImplementation;
+    private RawNBT rawNBT;
+
+    public BukkitMMOItem(String namespaceKey, int amount, RawNBT rawNBT) throws NullPointerException {
+        ItemStack itemStack;
+        Material material = Material.matchMaterial(namespaceKey);
+
+        if(material == null) {
+            throw new NullPointerException("Material for user defined item could not be found in the server software.");
+        }
+
+        itemStack = new ItemStack(material);
+
+        //Get default item meta
+        ItemMeta itemMeta = Bukkit.getItemFactory().getItemMeta(itemStack.getType());
+
+        //Set default item meta
+        itemStack.setItemMeta(itemMeta);
+
+        //Set amount
+        itemStack.setAmount(amount);
+
+        //Set item implementation
+        this.itemImplementation = itemStack;
+
+        //Set raw NBT
+        if(rawNBT != null)
+            this.rawNBT = rawNBT;
+    }
+
+    @Override
+    public ItemStack getItemImplementation() {
+        return itemImplementation;
+    }
+
+    @Override
+    public String getNamespaceKey() {
+        return itemImplementation.getType().getKey().toString();
+    }
+
+    @Override
+    public int getItemAmount() {
+        return itemImplementation.getAmount();
+    }
+
+    @Override
+    public RawNBT getRawNBT() {
+        return rawNBT;
+    }
+
+}

+ 13 - 0
src/main/java/com/gmail/nossr50/datatypes/items/CustomItemMatching.java

@@ -0,0 +1,13 @@
+package com.gmail.nossr50.datatypes.items;
+
+public interface CustomItemMatching {
+
+    /**
+     * Determines whether or not an item matches this one
+     * Behaviours for matching can vary based on the implementation
+     * @param otherItem target item to compare itself to
+     * @return true if this item matches the target item
+     */
+    boolean isMatch(MMOItem otherItem);
+
+}

+ 62 - 0
src/main/java/com/gmail/nossr50/datatypes/items/CustomItemTarget.java

@@ -0,0 +1,62 @@
+package com.gmail.nossr50.datatypes.items;
+
+import java.util.HashSet;
+
+/**
+ * This type contains data and rules which govern equating equivalency between one item and another in Minecraft.
+ *
+ * In mcMMO it is sometimes needed to match one item to another, but items contain a lot of metadata
+ * Some of this metadata is important, some of it isn't, and whether something is important or not when
+ * considering two items to be similar enough to be considered matching items is not strictly defined and is in fact different from server to server.
+ *
+ * mcMMO employs a flexible system where users can define which properties of an items metadata (often its NBT)
+ * are important for matching and mcMMO will respect those properties when comparing one item to another.
+ *
+ * If a user does not define a property as being important for matching mcMMO will ignore that property when matching
+ * two or more items, even if that property is not equivalent between the items. This type will contain information
+ * on which properties are to be considered important for matching purposes.
+ *
+ * The main goal of this system is accommodate for the vast majority of custom item modifications a server can employ,
+ * these custom items are often defined in irregular ways server to server, thus why this type was made.
+ *
+ * In summary, this type serves several purposes...
+ * 1) Abstract away platform specific implementations of MC Items
+ * 2) Contain information about an item and which properties of said item that are considered important and thus will be used to equate equivalency to another item when doing comparisons
+ */
+public class CustomItemTarget implements CustomItemMatching {
+
+    private MMOItem item; //Abstract representation of the item
+    private HashSet<ItemMatchProperty> itemMatchProperties; //Item properties used for matching
+
+    public CustomItemTarget(MMOItem item) {
+        this.item = item;
+        itemMatchProperties = new HashSet<>();
+    }
+
+    public CustomItemTarget(MMOItem item, HashSet<ItemMatchProperty> itemMatchProperties) {
+        this.item = item;
+        this.itemMatchProperties = itemMatchProperties;
+    }
+
+    public MMOItem getItem() {
+        return item;
+    }
+
+    public HashSet<ItemMatchProperty> getItemMatchProperties() {
+        return itemMatchProperties;
+    }
+
+    /**
+     * Determines whether or not an item matches this one
+     * Behaviours for matching can vary based on the implementation
+     * @param otherItem target item to compare itself to
+     * @return true if this item matches the target item
+     */
+    @Override
+    public boolean isMatch(MMOItem otherItem) {
+        //First compare the basic things that need to match between each item
+        if(item.equals(otherItem)) {
+
+        }
+    }
+}

+ 33 - 0
src/main/java/com/gmail/nossr50/datatypes/items/ItemMatchProperty.java

@@ -0,0 +1,33 @@
+package com.gmail.nossr50.datatypes.items;
+
+/**
+ * Represents a property of an item which is used in strict matching
+ * Typically this represents and NBT field and its value
+ * All NBT entries have an ID and a value, this value can be one of many types
+ */
+public class ItemMatchProperty {
+
+    final private Object propertyValue;
+    final private String nbtID;
+
+    public ItemMatchProperty(Object propertyValue, String nbtID) {
+        this.propertyValue = propertyValue;
+        this.nbtID = nbtID;
+    }
+
+    /**
+     * The expected value for this NBT entry
+     * @return the expected value for this NBT entry
+     */
+    public Object getPropertyValue() {
+        return propertyValue;
+    }
+
+    /**
+     * The ID (name) of this NBT entry
+     * @return the ID (name) of this NBT entry
+     */
+    public String getID() {
+        return nbtID;
+    }
+}

+ 61 - 0
src/main/java/com/gmail/nossr50/datatypes/items/ItemWildcards.java

@@ -0,0 +1,61 @@
+package com.gmail.nossr50.datatypes.items;
+
+import org.bukkit.inventory.ItemStack;
+
+import java.util.HashSet;
+import java.util.Objects;
+
+/**
+ * Represents a series of items that are all acceptable inputs for a behaviour
+ * Wildcards have a unique name that defines them, no two wildcards should share the same name.
+ * The name is important as it is used to identify the wildcard to the player.
+ *
+ * One example of the purpose of this Datatype:
+ *
+ * As an example, in Repair users are allowed to define a repair cost that can specify wildcards
+ * One such example is wood planks, many variants exist in Minecraft and they can all be used to repair Wooden tools
+ *
+ * ItemWildcards is a flexible datatype and won't be used just for Repair, but at the time of writing it was created
+ *  to solve a problem with Repair. Given its flexible nature it can be used for many purposes.
+ *
+ */
+public class ItemWildcards {
+
+    private String wildcardName;
+    private HashSet<CustomItemTarget> itemTargets;
+
+    public ItemWildcards(String wildcardName, HashSet<CustomItemTarget> itemTargets) {
+        this.wildcardName = wildcardName;
+        this.itemTargets = itemTargets;
+    }
+
+    public int getItemCount() {
+        return itemTargets.size();
+    }
+
+    public HashSet<ItemStack> getItemTargets() {
+        return itemTargets;
+    }
+
+    public void setItemTargets(HashSet<CustomItemTarget> itemTargets) {
+        this.itemTargets = itemTargets;
+    }
+
+    public String getWildcardName() {
+        return wildcardName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ItemWildcards)) return false;
+        ItemWildcards that = (ItemWildcards) o;
+        return getWildcardName().equals(that.getWildcardName()) &&
+                getItemTargets().equals(that.getItemTargets());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getWildcardName(), getItemTargets());
+    }
+}

+ 40 - 0
src/main/java/com/gmail/nossr50/datatypes/items/MMOItem.java

@@ -0,0 +1,40 @@
+package com.gmail.nossr50.datatypes.items;
+
+import com.gmail.nossr50.util.nbt.RawNBT;
+
+/**
+ * Represents the abstracted form of an item in Minecraft which can be used to construct an item implementation per platform
+ * Return types of this object are not platform specific
+ * Only requires a namespace key to be defined, all other properties will be default initialized
+ */
+public interface MMOItem<T> {
+
+    /**
+     * Gets the item implementation of this type for this object
+     * @return the item implementation
+     */
+    T getItemImplementation();
+
+    /**
+     * Get the Minecraft fully qualified namespace (FQN) key for this item
+     * Typically the FQN will read like this 'minecraft:name_here'
+     * @return the fully qualified namespace key for this item
+     */
+    String getNamespaceKey();
+
+    /**
+     * Get the amount of this Item
+     * Items in Minecraft are technically stacks of items with the minimum amount being 1 in most cases
+     * The amount is used for matching purposes, and should default to 1 if undefined
+     * @return the amount for this Item
+     */
+    int getItemAmount();
+
+    /**
+     * Get the RawNBT for this item if it has any
+     * This can be null
+     * @return the raw NBT if it exists, null otherwise
+     */
+    RawNBT getRawNBT();
+
+}

+ 13 - 0
src/main/java/com/gmail/nossr50/datatypes/nbt/MMOEntity.java

@@ -0,0 +1,13 @@
+package com.gmail.nossr50.datatypes.nbt;
+
+/**
+ * Platform independent representation of a Entity in Minecraft
+ * @param <T> the platform specific type of this Entity
+ */
+public interface MMOEntity<T> {
+    /**
+     * Get the platform specific implementation of this entity
+     * @return the platform specific implementation of this entity
+     */
+    T getImplementation();
+}

+ 26 - 0
src/main/java/com/gmail/nossr50/datatypes/nbt/NBTHolder.java

@@ -0,0 +1,26 @@
+package com.gmail.nossr50.datatypes.nbt;
+
+import com.gmail.nossr50.util.nbt.RawNBT;
+
+/**
+ * Many things in Minecraft make use of the NBT System
+ * You can read about the NBT System here - https://wiki.vg/NBT
+ *
+ * Types that support NBT will implement this interface
+ */
+public interface NBTHolder {
+
+    /**
+     * Get the RawNBT for this object
+     * @return the RawNBT for this object
+     */
+    RawNBT getRawNBT();
+
+    /**
+     * Determine whether or not this object has the specific NBT entry and matching value
+     * @param id the ID fof the NBT entry
+     * @param value the value of the NBT entry
+     * @return returns true if the NBT of id exists and its value matches
+     */
+    boolean hasNBTValue(String id, Object value);
+}

+ 8 - 2
src/main/java/com/gmail/nossr50/skills/repair/RepairCost.java

@@ -11,9 +11,15 @@ public interface RepairCost {
     /**
      * Searches a player inventory for a matching ItemStack that can be used to pay for the repair transaction
      * @param playerInventory inventory of player attempting to pay the cost
-     * @param strictMatching whether or not to match repair cost items strictly with items in a players inventory
      * @return any compatible payment items if found
      */
-    ItemStack findPayment(PlayerInventory playerInventory, boolean strictMatching);
+    ItemStack findPayment(PlayerInventory playerInventory);
+
+    /**
+     * Whether or not this repair cost is strictly matched
+     * Strict matching compares Items by using metadata and material type
+     * @return true if the RepairCost uses strict matching
+     */
+    boolean hasStrictMatching();
 
 }

+ 0 - 51
src/main/java/com/gmail/nossr50/skills/repair/RepairCostItem.java

@@ -1,51 +0,0 @@
-package com.gmail.nossr50.skills.repair;
-
-import org.bukkit.Material;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.PlayerInventory;
-
-import java.util.Objects;
-
-public class RepairCostItem implements RepairCost {
-
-    private ItemStack repairCostItem;
-
-    public RepairCostItem(ItemStack repairCostItem) {
-        this.repairCostItem = repairCostItem;
-    }
-
-    @Override
-    public ItemStack findPayment(PlayerInventory playerInventory, boolean strictMatching) {
-        for(ItemStack itemStack : playerInventory.getContents()) {
-            if(itemStack == null || itemStack.getType() == Material.AIR) {
-                continue;
-            }
-
-            //Attempt to match the item in the inventory to any of the compatible repair items
-            if(strictMatching) {
-                //TODO: Replace with strict matching code
-                if(itemStack.isSimilar(repairCostItem))
-                    return itemStack;
-            } else {
-                if(itemStack.getType() == repairCostItem.getType()) {
-                    return itemStack;
-                }
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(repairCostItem);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof RepairCostItem)) return false;
-        RepairCostItem that = (RepairCostItem) o;
-        return repairCostItem.equals(that.repairCostItem);
-    }
-}

+ 21 - 15
src/main/java/com/gmail/nossr50/skills/repair/RepairCostWildcard.java

@@ -1,9 +1,12 @@
 package com.gmail.nossr50.skills.repair;
 
+import com.gmail.nossr50.datatypes.items.ItemWildcards;
 import org.bukkit.Material;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.PlayerInventory;
 
+import java.util.HashSet;
+
 /**
  * Represents a piece of a RepairTransaction
  * Multiple RepairCost pieces are used to pay for a RepairTransaction
@@ -12,25 +15,28 @@ import org.bukkit.inventory.PlayerInventory;
  */
 public class RepairCostWildcard implements RepairCost {
 
-    private RepairWildcard repairWildcard;
+    private HashSet<SimpleRepairCost> simpleRepairCosts;
+    private ItemWildcards itemWildcards;
+
+
+    public RepairCostWildcard(ItemWildcards itemWildcards) {
+        this.itemWildcards = itemWildcards;
+        simpleRepairCosts = new HashSet<>();
+
+        for(ItemStack itemStack : )
+    }
 
     @Override
-    public ItemStack findPayment(PlayerInventory playerInventory, boolean strictMatching) {
+    public ItemStack findPayment(PlayerInventory playerInventory) {
         for(ItemStack itemStack : playerInventory.getContents()) {
             if(itemStack == null || itemStack.getType() == Material.AIR) {
                 continue;
             }
 
-            for(ItemStack wildCardItem : repairWildcard.getMatchingItems()) {
+            for(SimpleRepairCost simpleRepairCost : simpleRepairCosts) {
                 //Attempt to match the item in the inventory to any of the compatible repair items
-                if(strictMatching) {
-                    //TODO: Replace with strict matching code
-                    if(itemStack.isSimilar(wildCardItem))
-                        return itemStack;
-                } else {
-                    if(itemStack.getType() == wildCardItem.getType()) {
-                        return itemStack;
-                    }
+                if(simpleRepairCost.findPayment(playerInventory) != null) {
+                    return simpleRepairCost.findPayment(playerInventory);
                 }
             }
         }
@@ -38,12 +44,12 @@ public class RepairCostWildcard implements RepairCost {
         return null;
     }
 
-    public RepairWildcard getRepairWildcard() {
-        return repairWildcard;
+    public ItemWildcards getItemWildcards() {
+        return itemWildcards;
     }
 
-    public void setRepairWildcard(RepairWildcard repairWildcard) {
-        this.repairWildcard = repairWildcard;
+    public void setItemWildcards(ItemWildcards itemWildcards) {
+        this.itemWildcards = itemWildcards;
     }
 
 }

+ 12 - 4
src/main/java/com/gmail/nossr50/skills/repair/RepairTransaction.java

@@ -4,10 +4,18 @@ package com.gmail.nossr50.skills.repair;
 import java.util.HashSet;
 
 /**
- * Represents a complete repair transaction
- * A repair transaction is made up of a multiple RepairCost objects
- * A RepairCost object is used to find a matching ItemStack in a players inventory if one exists
- * A RepairCost object can be a single item or it can be multiple items representing a range of compatible items to pay that part of the RepairTransaction
+ * Represents a complete "repair transaction"
+ *
+ * I will define a "repair transaction" as such
+ * - The items used to pay the cost of repairing an item in mcMMO via the Repair Skill
+ *
+ * A single "RepairTransaction" is made up of a multiple RepairCost objects
+ * No two RepairCosts contained within this type can be exact duplicates
+ *
+ * A RepairCost is used to find a matching ItemStack in a players inventory if one exists to pay its cost
+ *
+ * A RepairCost can be a single item or it can be multiple items representing a range of compatible items
+ *  to pay that part of the RepairTransaction
  */
 public class RepairTransaction {
     private HashSet<RepairCost> repairItems;

+ 0 - 43
src/main/java/com/gmail/nossr50/skills/repair/RepairWildcard.java

@@ -1,43 +0,0 @@
-package com.gmail.nossr50.skills.repair;
-
-import org.bukkit.inventory.ItemStack;
-
-import java.util.Objects;
-import java.util.Set;
-
-public class RepairWildcard {
-
-    private String wildcardName;
-    private Set<ItemStack> matchingItems;
-
-    public RepairWildcard(String wildcardName, Set<ItemStack> matchingItems) {
-        this.wildcardName = wildcardName;
-        this.matchingItems = matchingItems;
-    }
-
-    public Set<ItemStack> getMatchingItems() {
-        return matchingItems;
-    }
-
-    public void setMatchingItems(Set<ItemStack> matchingItems) {
-        this.matchingItems = matchingItems;
-    }
-
-    public String getWildcardName() {
-        return wildcardName;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof RepairWildcard)) return false;
-        RepairWildcard that = (RepairWildcard) o;
-        return getWildcardName().equals(that.getWildcardName()) &&
-                getMatchingItems().equals(that.getMatchingItems());
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(getWildcardName(), getMatchingItems());
-    }
-}

+ 66 - 0
src/main/java/com/gmail/nossr50/skills/repair/SimpleRepairCost.java

@@ -0,0 +1,66 @@
+package com.gmail.nossr50.skills.repair;
+
+import com.gmail.nossr50.datatypes.items.ItemMatchProperty;
+import org.bukkit.Material;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
+
+import java.util.Objects;
+
+/**
+ * Implementation of RepairCost
+ * <p>
+ * A SimpleRepairCost can be one or more items, any one of which can be used to pay for a RepairTransaction
+ * If a SimpleRepairCost is more than one item, then only one of the items are required to represent its cost.
+ *
+ * This type is strictly for use with RepairTransaction, which represents the full cost of a Repair.
+ * @see com.gmail.nossr50.skills.repair.RepairTransaction for more details
+ */
+public class SimpleRepairCost implements RepairCost {
+
+    private ItemMatchProperty itemMatchProperty;
+
+    public SimpleRepairCost(ItemMatchProperty itemMatchProperty) {
+        this.itemMatchProperty = itemMatchProperty;
+    }
+
+    @Override
+    public ItemStack findPayment(PlayerInventory playerInventory) {
+        for(ItemStack itemStack : playerInventory.getContents()) {
+            if(itemStack == null || itemStack.getType() == Material.AIR) {
+                continue;
+            }
+
+            //Attempt to match the item in the inventory to any of the compatible repair items
+            if(hasStrictMatching()) {
+                //TODO: Replace with strict matching code
+                if(item)
+                    return itemStack;
+            } else {
+                if(itemStack.getType() == itemMatchProperty.getType()) {
+                    return itemStack;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(itemMatchProperty);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SimpleRepairCost)) return false;
+        SimpleRepairCost that = (SimpleRepairCost) o;
+        return itemMatchProperty.equals(that.itemMatchProperty);
+    }
+
+    @Override
+    public boolean hasStrictMatching() {
+        return strictMatching;
+    }
+}

+ 10 - 10
src/main/java/com/gmail/nossr50/skills/repair/repairables/Repairable.java

@@ -12,7 +12,7 @@ public class Repairable {
     private short maximumDurability;
     private RepairTransaction repairTransaction;
     private boolean strictMatchingItem = false;
-    private boolean strictMatchingRepairTransaction = false;
+//    private boolean strictMatchingRepairTransaction = false;
     private int baseXP = 0;
     private RawNBT rawNBT;
     private int repairCount = 1;
@@ -20,13 +20,13 @@ public class Repairable {
     private boolean hasPermission = false;
     private boolean hasNBT = false;
 
-    public Repairable(ItemStack item, int minimumLevel, short maximumDurability, RepairTransaction repairTransaction, boolean strictMatchingItem, boolean strictMatchingRepairTransaction, int baseXP, int repairCount) {
+    public Repairable(ItemStack item, int minimumLevel, short maximumDurability, RepairTransaction repairTransaction, boolean strictMatchingItem, int baseXP, int repairCount) {
         this.item = item;
         this.minimumLevel = minimumLevel;
         this.maximumDurability = maximumDurability;
         this.repairTransaction = repairTransaction;
         this.strictMatchingItem = strictMatchingItem;
-        this.strictMatchingRepairTransaction = strictMatchingRepairTransaction;
+//        this.strictMatchingRepairTransaction = strictMatchingRepairTransaction;
         this.baseXP = baseXP;
         this.repairCount = repairCount;
     }
@@ -67,13 +67,13 @@ public class Repairable {
         this.strictMatchingItem = strictMatchingItem;
     }
 
-    public boolean isStrictMatchingRepairTransaction() {
-        return strictMatchingRepairTransaction;
-    }
-
-    public void setStrictMatchingRepairTransaction(boolean strictMatchingRepairTransaction) {
-        this.strictMatchingRepairTransaction = strictMatchingRepairTransaction;
-    }
+//    public boolean isStrictMatchingRepairTransaction() {
+//        return strictMatchingRepairTransaction;
+//    }
+//
+//    public void setStrictMatchingRepairTransaction(boolean strictMatchingRepairTransaction) {
+//        this.strictMatchingRepairTransaction = strictMatchingRepairTransaction;
+//    }
 
     public int getBaseXP() {
         return baseXP;

+ 6 - 6
src/main/java/com/gmail/nossr50/skills/repair/repairables/RepairableBuilder.java

@@ -12,7 +12,7 @@ public class RepairableBuilder {
     private short maximumDurability;
     private RepairTransaction repairTransaction;
     private boolean strictMatchingItem = false;
-    private boolean strictMatchingRepairTransaction = false;
+//    private boolean strictMatchingRepairTransaction = false;
     private int baseXP = 0;
     private RawNBT rawNBT;
     private int repairCount = 1;
@@ -43,10 +43,10 @@ public class RepairableBuilder {
         return this;
     }
 
-    public RepairableBuilder strictMatchingRepairTransaction(Boolean strictMatchingRepairTransaction) {
-        this.strictMatchingRepairTransaction = strictMatchingRepairTransaction;
-        return this;
-    }
+//    public RepairableBuilder strictMatchingRepairTransaction(Boolean strictMatchingRepairTransaction) {
+//        this.strictMatchingRepairTransaction = strictMatchingRepairTransaction;
+//        return this;
+//    }
 
     public RepairableBuilder baseXP(Integer baseXP) {
         this.baseXP = baseXP;
@@ -74,7 +74,7 @@ public class RepairableBuilder {
 
     private Repairable makeRepairable() {
         Repairable repairable = new Repairable(item, minimumLevel, maximumDurability, repairTransaction,
-                strictMatchingItem, strictMatchingRepairTransaction, baseXP, repairCount);
+                strictMatchingItem, baseXP, repairCount);
 
         if(permissionWrapper != null) {
             repairable.setPermissionWrapper(permissionWrapper);

+ 20 - 0
src/main/java/com/gmail/nossr50/util/nbt/NBTUtils.java

@@ -1,6 +1,26 @@
 package com.gmail.nossr50.util.nbt;
 
 
+import com.gmail.nossr50.mcMMO;
+import net.minecraft.server.v1_13_R2.NBTBase;
+import org.bukkit.craftbukkit.v1_13_R2.entity.CraftItem;
+import org.bukkit.craftbukkit.v1_13_R2.util.CraftNBTTagConfigSerializer;
+import org.bukkit.inventory.ItemStack;
+
 public class NBTUtils {
 
+    public RawNBT<?> constructNBT(String nbtString) {
+        try {
+            return new RawNBT<NBTBase>(nbtString, CraftNBTTagConfigSerializer.deserialize(nbtString));
+        } catch (Exception e) {
+            e.printStackTrace();
+            mcMMO.p.getLogger().severe("mcMMO was unable parse the NBT string from your config! Double check that it is proper NBT!");
+            return null;
+        }
+    }
+
+    public boolean hasNBT(ItemStack itemStack) {
+        if(CraftItem)
+    }
+
 }

+ 15 - 3
src/main/java/com/gmail/nossr50/util/nbt/RawNBT.java

@@ -1,10 +1,22 @@
 package com.gmail.nossr50.util.nbt;
 
-public class RawNBT {
-    String nbtContents;
+/**
+ * A simple class that acts as a container for raw NBT data
+ * NBT data will be constructed from the raw NBT string using server internals
+ * This type is mostly used to take a raw string of NBT and transform it into the NBT data type used by internals
+ *  the transformed data can then be used to check NBT data of entities in Minecraft
+ *
+ *  One use of this type is as follows
+ *  1) Read partial or complete NBT from the config file for an item
+ *  2) Check an items NBT tree for this NBT data during runtime once transformed
+ */
+public class RawNBT<T> {
+    private String nbtContents;
+    private T nbtTree; //Will be constructed using server internals to make matching NBT easier
 
-    public RawNBT(String nbtContents) {
+    public RawNBT(String nbtContents, T nbtTree) {
         this.nbtContents = nbtContents;
+        NBTUtils
     }
 
     public String getNbtContents() {