From 30cb6f45f8f5f34076be443c28dde83560b75977 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Fri, 1 Feb 2019 23:08:23 -0800 Subject: [PATCH 001/108] Add the first framework for an ItemExpression API The goal of this new API is to be able to have a unified syntax for matching the various elements that make up an ItemStack. Think ItemStack.isSimilar() on steroids. In other words, a regular expression-like syntax for ItemStacks. --- .../itemExpression/ItemExpression.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java new file mode 100644 index 00000000..c71a330e --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -0,0 +1,46 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + +/** + * A unified syntax for matching any ItemStack for things like the material, amount, lore contents, and more. + * + * While mostly designed to be used in a .yaml config file, this can also be used from java. + */ +public class ItemExpression { + /** + * Creates an ItemExpression from a section of bukkit configuration format. + * @param configurationSection The subsection of config that should be parsed. + */ + public ItemExpression(ConfigurationSection configurationSection) { + parseConfig(configurationSection); + } + + /** + * Mutate this ItemExpression, overriding the existing options set for this with the options given in the + * ConfigurationSection. + * @param configurationSection The config that options will be taken from. + */ + public void parseConfig(ConfigurationSection configurationSection) { + } + + /** + * Creates the default ItemExpression. + * + * By default, it will match any ItemStack. + */ + public ItemExpression() { + } + + /** + * Runs this ItemExpression on a given ItemStack. + * + * This will not mutate the ItemStack nor this ItemExpression. + * @param item The ItemStack to be matched upon. + * @return If the given item matches. + */ + public boolean matches(ItemStack item) { + return true; + } +} From cb3df58f820dd3340efe0e95cc88e0953d020db8 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Fri, 1 Feb 2019 23:25:53 -0800 Subject: [PATCH 002/108] Add material matching to ItemExpression --- .../itemExpression/ItemExpression.java | 30 +++++++++++++++++-- .../itemExpression/material/AnyMaterial.java | 10 +++++++ .../material/ExactlyMaterial.java | 16 ++++++++++ .../material/MaterialMatcher.java | 7 +++++ .../material/RegexMaterial.java | 18 +++++++++++ 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index c71a330e..c39e60f2 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,7 +1,14 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; +import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.AnyMaterial; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; + +import java.util.regex.Pattern; /** * A unified syntax for matching any ItemStack for things like the material, amount, lore contents, and more. @@ -23,6 +30,15 @@ public ItemExpression(ConfigurationSection configurationSection) { * @param configurationSection The config that options will be taken from. */ public void parseConfig(ConfigurationSection configurationSection) { + String materialString = configurationSection.getString("material", "any"); + if (materialString.equals("any")) + setMaterial(new AnyMaterial()); + else if (materialString.startsWith("regex ")) { + String regex = materialString.replaceFirst("^regex ", ""); + Pattern pattern = Pattern.compile(regex); + setMaterial(new RegexMaterial(pattern)); + } else + setMaterial(new ExactlyMaterial(Material.getMaterial(materialString))); } /** @@ -30,8 +46,7 @@ public void parseConfig(ConfigurationSection configurationSection) { * * By default, it will match any ItemStack. */ - public ItemExpression() { - } + public ItemExpression() {} /** * Runs this ItemExpression on a given ItemStack. @@ -41,6 +56,15 @@ public ItemExpression() { * @return If the given item matches. */ public boolean matches(ItemStack item) { - return true; + if (!materialMatcher.matches(item.getType())) + return false; + else + return true; + } + + private MaterialMatcher materialMatcher = new AnyMaterial(); + + public void setMaterial(MaterialMatcher materialMatcher) { + this.materialMatcher = materialMatcher; } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java new file mode 100644 index 00000000..b7015fda --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; + +import org.bukkit.Material; + +public class AnyMaterial implements MaterialMatcher { + @Override + public boolean matches(Material material) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java new file mode 100644 index 00000000..df780ddd --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java @@ -0,0 +1,16 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; + +import org.bukkit.Material; + +public class ExactlyMaterial implements MaterialMatcher { + public ExactlyMaterial(Material material) { + this.material = material; + } + + public Material material; + + @Override + public boolean matches(Material material) { + return this.material == material; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java new file mode 100644 index 00000000..50171227 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java @@ -0,0 +1,7 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; + +import org.bukkit.Material; + +public interface MaterialMatcher { + boolean matches(Material material); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java new file mode 100644 index 00000000..1dedc0cc --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java @@ -0,0 +1,18 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; + +import org.bukkit.Material; + +import java.util.regex.Pattern; + +public class RegexMaterial implements MaterialMatcher { + public RegexMaterial(Pattern regex) { + this.regex = regex; + } + + public Pattern regex; + + @Override + public boolean matches(Material material) { + return regex.matcher(material.toString()).matches(); + } +} From 58b4e5ae390352cd33a0e3520e823efdca13dc97 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Fri, 1 Feb 2019 23:54:50 -0800 Subject: [PATCH 003/108] Redo material parsing Now it used more yaml and less parsing the syntax out of a string. --- .../itemExpression/ItemExpression.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index c39e60f2..8d79e4cc 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -27,18 +27,16 @@ public ItemExpression(ConfigurationSection configurationSection) { /** * Mutate this ItemExpression, overriding the existing options set for this with the options given in the * ConfigurationSection. - * @param configurationSection The config that options will be taken from. + * @param config The config that options will be taken from. */ - public void parseConfig(ConfigurationSection configurationSection) { - String materialString = configurationSection.getString("material", "any"); - if (materialString.equals("any")) + public void parseConfig(ConfigurationSection config) { + if (config.contains("material.exactly")) + setMaterial(new ExactlyMaterial(Material.getMaterial(config.getString("material.exactly")))); + else if (config.contains("material.regex")) + setMaterial(new RegexMaterial(Pattern.compile(config.getString("material.regex")))); + else if ("any".equals(config.getString("material"))) + // yoda order because config.getString is null if doesn't exist setMaterial(new AnyMaterial()); - else if (materialString.startsWith("regex ")) { - String regex = materialString.replaceFirst("^regex ", ""); - Pattern pattern = Pattern.compile(regex); - setMaterial(new RegexMaterial(pattern)); - } else - setMaterial(new ExactlyMaterial(Material.getMaterial(materialString))); } /** From e0cd36771ae247ccadc4f6102101ffa529ae1563 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:09:58 -0800 Subject: [PATCH 004/108] Add amount matching --- .../itemExpression/ItemExpression.java | 56 +++++++++++++++++++ .../itemExpression/amount/AmountMatcher.java | 5 ++ .../itemExpression/amount/AnyAmount.java | 8 +++ .../itemExpression/amount/ExactlyAmount.java | 14 +++++ .../itemExpression/amount/RangeAmount.java | 54 ++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 8d79e4cc..52719832 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -2,12 +2,20 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.ExactlyAmount; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.RangeAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.AnyMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.regex.Pattern; /** @@ -30,6 +38,11 @@ public ItemExpression(ConfigurationSection configurationSection) { * @param config The config that options will be taken from. */ public void parseConfig(ConfigurationSection config) { + parseMaterial(config); + parseAmount(config); + } + + private void parseMaterial(ConfigurationSection config) { if (config.contains("material.exactly")) setMaterial(new ExactlyMaterial(Material.getMaterial(config.getString("material.exactly")))); else if (config.contains("material.regex")) @@ -39,6 +52,39 @@ else if ("any".equals(config.getString("material"))) setMaterial(new AnyMaterial()); } + private void parseAmount(ConfigurationSection config) { + if (config.contains("amount.range")) + setAmount(new RangeAmount( + config.getInt("amount.range.low", 0), + config.getInt("amount.range.high"), + config.getBoolean("amount.range.inclusiveLow", true), + config.getBoolean("amount.range.inclusiveHigh", true))); + else if ("any".equals(config.getString("amount"))) + setAmount(new AnyAmount()); + else if (config.contains("amount")) + setAmount(new ExactlyAmount(config.getInt("amount"))); + } + + @SuppressWarnings("unchecked") // fix your warnings, java + private List getConfigList(ConfigurationSection config, String path) + { + if (!config.isList(path)) return null; + + List list = new ArrayList<>(); + + for (Object object : config.getList(path)) { + if (object instanceof Map) { + MemoryConfiguration mc = new MemoryConfiguration(); + + mc.addDefaults((Map) object); + + list.add(mc); + } + } + + return list; + } + /** * Creates the default ItemExpression. * @@ -65,4 +111,14 @@ public boolean matches(ItemStack item) { public void setMaterial(MaterialMatcher materialMatcher) { this.materialMatcher = materialMatcher; } + + private AmountMatcher amountMatcher = new AnyAmount(); + + public AmountMatcher getAmount() { + return amountMatcher; + } + + public void setAmount(AmountMatcher amountMatcher) { + this.amountMatcher = amountMatcher; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java new file mode 100644 index 00000000..1e6de63c --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -0,0 +1,5 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; + +public interface AmountMatcher { + boolean matches(int amount); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java new file mode 100644 index 00000000..33586546 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java @@ -0,0 +1,8 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; + +public class AnyAmount implements AmountMatcher { + @Override + public boolean matches(int amount) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java new file mode 100644 index 00000000..31a080b8 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java @@ -0,0 +1,14 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; + +public class ExactlyAmount implements AmountMatcher { + public ExactlyAmount(int amount) { + this.amount = amount; + } + + public int amount; + + @Override + public boolean matches(int amount) { + return this.amount == amount; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java new file mode 100644 index 00000000..db0c044f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java @@ -0,0 +1,54 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; + +public class RangeAmount implements AmountMatcher { + public RangeAmount(int low, int high, boolean lowInclusive, boolean highInclusive) { + set(low, high); + this.highInclusive = highInclusive; + this.lowInclusive = lowInclusive; + } + + private int low; + private int high; + public boolean highInclusive; + public boolean lowInclusive; + + public void set(int low, int high) { + if (low <= high) { + // expected situation, do as normal + this.low = low; + this.high = high; + } else { + // accidentally reversed, fix it silently + this.low = high; + this.high = low; + } + } + + public int getLow() { + return low; + } + + public int getHigh() { + return high; + } + + @Override + public boolean matches(int amount) { + if (lowInclusive) { + if (amount < low) + return false; + } else { + if (amount <= low) + return false; + } + if (highInclusive) { + if (amount > high) + return false; + } else { + if (amount >= high) + return false; + } + + return true; + } +} From 108dc3c5e71e27666131298a9c188a4d1d27b354 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:11:08 -0800 Subject: [PATCH 005/108] Add intelij files to .gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index f0380db4..e9f18c1c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,8 @@ .classpath .project .settings/** + +/.idea/ +/*.iml +/*.ipr +/*.iws From 2e28aa0a59dd2a6903a8ad57a3d47edec68a5fca Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:14:37 -0800 Subject: [PATCH 006/108] Remove unused function from development Was going to have a complicated or function for amount but it was complicated and I don't want to hvae to implement config parsing for that right now. This was used in the complicated config parsing. --- .../itemExpression/ItemExpression.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 52719832..fd95f07b 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -65,26 +65,6 @@ else if (config.contains("amount")) setAmount(new ExactlyAmount(config.getInt("amount"))); } - @SuppressWarnings("unchecked") // fix your warnings, java - private List getConfigList(ConfigurationSection config, String path) - { - if (!config.isList(path)) return null; - - List list = new ArrayList<>(); - - for (Object object : config.getList(path)) { - if (object instanceof Map) { - MemoryConfiguration mc = new MemoryConfiguration(); - - mc.addDefaults((Map) object); - - list.add(mc); - } - } - - return list; - } - /** * Creates the default ItemExpression. * From 91b015a75c2921de404d1ad2a3236b32c4ebcf30 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:15:28 -0800 Subject: [PATCH 007/108] Refactor material parsing again Now instead of material.exactly: STONE it's material: STONE --- .../itemHandling/itemExpression/ItemExpression.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index fd95f07b..efd236cf 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -43,13 +43,13 @@ public void parseConfig(ConfigurationSection config) { } private void parseMaterial(ConfigurationSection config) { - if (config.contains("material.exactly")) - setMaterial(new ExactlyMaterial(Material.getMaterial(config.getString("material.exactly")))); - else if (config.contains("material.regex")) + if (config.contains("material.regex")) setMaterial(new RegexMaterial(Pattern.compile(config.getString("material.regex")))); else if ("any".equals(config.getString("material"))) // yoda order because config.getString is null if doesn't exist setMaterial(new AnyMaterial()); + else if (config.contains("material")) + setMaterial(new ExactlyMaterial(Material.getMaterial(config.getString("material")))); } private void parseAmount(ConfigurationSection config) { From e1c485db35707ab3024597043c9c17211b29a00a Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:16:00 -0800 Subject: [PATCH 008/108] Remove unused exports --- .../itemHandling/itemExpression/ItemExpression.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index efd236cf..23ab6e1c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -2,7 +2,6 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; @@ -13,9 +12,6 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.util.regex.Pattern; /** From e35fd8529b3eb069a685ab72746db6a3dd19db7a Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:20:29 -0800 Subject: [PATCH 009/108] Add @author Ameliorate to ItemExpression and related classes --- pom.xml | 10 ---------- .../itemHandling/itemExpression/ItemExpression.java | 2 ++ .../itemExpression/amount/AmountMatcher.java | 3 +++ .../itemHandling/itemExpression/amount/AnyAmount.java | 3 +++ .../itemExpression/amount/ExactlyAmount.java | 3 +++ .../itemExpression/amount/RangeAmount.java | 3 +++ .../itemExpression/material/AnyMaterial.java | 3 +++ .../itemExpression/material/ExactlyMaterial.java | 3 +++ .../itemExpression/material/MaterialMatcher.java | 3 +++ .../itemExpression/material/RegexMaterial.java | 3 +++ 10 files changed, 26 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index e7647401..142db421 100644 --- a/pom.xml +++ b/pom.xml @@ -105,14 +105,4 @@ - - - - - org.codehaus.mojo - findbugs-maven-plugin - 3.0.4 - - - diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 23ab6e1c..8693e50f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -18,6 +18,8 @@ * A unified syntax for matching any ItemStack for things like the material, amount, lore contents, and more. * * While mostly designed to be used in a .yaml config file, this can also be used from java. + * + * @author Ameliorate */ public class ItemExpression { /** diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index 1e6de63c..162816ab 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -1,5 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; +/** + * @author Ameliorate + */ public interface AmountMatcher { boolean matches(int amount); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java index 33586546..dd239e89 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java @@ -1,5 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; +/** + * @author Ameliorate + */ public class AnyAmount implements AmountMatcher { @Override public boolean matches(int amount) { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java index 31a080b8..6db4d00a 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java @@ -1,5 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; +/** + * @author Ameliorate + */ public class ExactlyAmount implements AmountMatcher { public ExactlyAmount(int amount) { this.amount = amount; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java index db0c044f..32f3d2fd 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java @@ -1,5 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; +/** + * @author Ameliorate + */ public class RangeAmount implements AmountMatcher { public RangeAmount(int low, int high, boolean lowInclusive, boolean highInclusive) { set(low, high); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java index b7015fda..013824cd 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java @@ -2,6 +2,9 @@ import org.bukkit.Material; +/** + * @author Ameliorate + */ public class AnyMaterial implements MaterialMatcher { @Override public boolean matches(Material material) { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java index df780ddd..5dfc4194 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java @@ -2,6 +2,9 @@ import org.bukkit.Material; +/** + * @author Ameliorate + */ public class ExactlyMaterial implements MaterialMatcher { public ExactlyMaterial(Material material) { this.material = material; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java index 50171227..ab2243ce 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java @@ -2,6 +2,9 @@ import org.bukkit.Material; +/** + * @author Ameliorate + */ public interface MaterialMatcher { boolean matches(Material material); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java index 1dedc0cc..7a1d35b7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java @@ -4,6 +4,9 @@ import java.util.regex.Pattern; +/** + * @author Ameliorate + */ public class RegexMaterial implements MaterialMatcher { public RegexMaterial(Pattern regex) { this.regex = regex; From 256be1586c3542c15c85477c2720b49953d7fdfd Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:51:30 -0800 Subject: [PATCH 010/108] Add lore matching --- .../itemExpression/ItemExpression.java | 33 +++++++++++++++++ .../itemExpression/lore/AnyLore.java | 13 +++++++ .../itemExpression/lore/ExactlyLore.java | 19 ++++++++++ .../itemExpression/lore/LoreMatcher.java | 10 ++++++ .../itemExpression/lore/RegexLore.java | 35 +++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 8693e50f..22f8a9c8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -7,11 +7,17 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.ExactlyAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.RangeAmount; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.AnyLore; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.ExactlyLore; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.LoreMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.RegexLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.AnyMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; +import java.util.ArrayList; +import java.util.List; import java.util.regex.Pattern; /** @@ -38,6 +44,7 @@ public ItemExpression(ConfigurationSection configurationSection) { public void parseConfig(ConfigurationSection config) { parseMaterial(config); parseAmount(config); + parseLore(config); } private void parseMaterial(ConfigurationSection config) { @@ -63,6 +70,22 @@ else if (config.contains("amount")) setAmount(new ExactlyAmount(config.getInt("amount"))); } + private void parseLore(ConfigurationSection config) { + if (config.contains("lore.regex")) { + List patternsStr = config.getStringList("lore.regex"); + List patterns = new ArrayList<>(); + boolean multiline = config.getBoolean("lore.regexMultiline", true); + + for (String patternStr : patternsStr) { + patterns.add(Pattern.compile(patternStr, multiline ? Pattern.MULTILINE : 0)); + } + setLore(new RegexLore(patterns)); + } else if ("any".equals(config.getString("lore"))) + setLore(new AnyLore()); + else if (config.contains("lore")) + setLore(new ExactlyLore(config.getStringList("lore"))); + } + /** * Creates the default ItemExpression. * @@ -99,4 +122,14 @@ public AmountMatcher getAmount() { public void setAmount(AmountMatcher amountMatcher) { this.amountMatcher = amountMatcher; } + + private LoreMatcher loreMatcher = new AnyLore(); + + public LoreMatcher getLore() { + return loreMatcher; + } + + public void setLore(LoreMatcher loreMatcher) { + this.loreMatcher = loreMatcher; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java new file mode 100644 index 00000000..879b4e45 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java @@ -0,0 +1,13 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class AnyLore implements LoreMatcher { + @Override + public boolean matches(List lore) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java new file mode 100644 index 00000000..5e27465f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java @@ -0,0 +1,19 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ExactlyLore implements LoreMatcher { + public ExactlyLore(List lore) { + this.lore = lore; + } + + public List lore; + + @Override + public boolean matches(List lore) { + return this.lore.equals(lore); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java new file mode 100644 index 00000000..b6dac746 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; + +import java.util.List; + +/** + * @author Ameliorate + */ +public interface LoreMatcher { + boolean matches(List lore); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java new file mode 100644 index 00000000..1d977766 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java @@ -0,0 +1,35 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; + +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author Ameliorate + */ +public class RegexLore implements LoreMatcher { + public RegexLore(List patterns) { + this.patterns = patterns; + } + + public RegexLore(Pattern... patterns) { + this(Arrays.asList(patterns)); + } + + public List patterns; + + @Override + public boolean matches(List lore) { + StringBuilder loreStr = new StringBuilder(); + for (String line : lore) { + loreStr.append(line); + loreStr.append('\n'); + } + + for (Pattern pattern : patterns) { + if (pattern.matcher(loreStr).matches()) + return true; + } + return false; + } +} From d5fcc89d55ade215e97ed78e9465e520560d9843 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:52:49 -0800 Subject: [PATCH 011/108] Add a getMaterial like all the other matchers --- .../itemExpression/ItemExpression.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 22f8a9c8..a53ca235 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -28,6 +28,13 @@ * @author Ameliorate */ public class ItemExpression { + /** + * Creates the default ItemExpression. + * + * By default, it will match any ItemStack. + */ + public ItemExpression() {} + /** * Creates an ItemExpression from a section of bukkit configuration format. * @param configurationSection The subsection of config that should be parsed. @@ -86,13 +93,6 @@ else if (config.contains("lore")) setLore(new ExactlyLore(config.getStringList("lore"))); } - /** - * Creates the default ItemExpression. - * - * By default, it will match any ItemStack. - */ - public ItemExpression() {} - /** * Runs this ItemExpression on a given ItemStack. * @@ -109,6 +109,10 @@ public boolean matches(ItemStack item) { private MaterialMatcher materialMatcher = new AnyMaterial(); + public MaterialMatcher getMaterial() { + return materialMatcher; + } + public void setMaterial(MaterialMatcher materialMatcher) { this.materialMatcher = materialMatcher; } From 6bfc0d648c81c5b43f36b774af5c1088a07731ae Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 00:54:49 -0800 Subject: [PATCH 012/108] Add the new matchers to ItemExpression.matches() Forgot to do that when adding them. --- .../itemHandling/itemExpression/ItemExpression.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index a53ca235..d5b677a6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -103,8 +103,11 @@ else if (config.contains("lore")) public boolean matches(ItemStack item) { if (!materialMatcher.matches(item.getType())) return false; - else - return true; + else if (!amountMatcher.matches(item.getAmount())) + return false; + else if (!loreMatcher.matches(item.getItemMeta().getLore())) + return false; + return true; } private MaterialMatcher materialMatcher = new AnyMaterial(); From a5110a2738101a2fdb21415683ac51d067dd9a71 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 01:11:39 -0800 Subject: [PATCH 013/108] Add name matching --- .../itemExpression/ItemExpression.java | 30 +++++++++++++++++++ .../itemExpression/name/AnyName.java | 11 +++++++ .../itemExpression/name/ExactlyName.java | 17 +++++++++++ .../itemExpression/name/NameMatcher.java | 8 +++++ .../itemExpression/name/RegexName.java | 19 ++++++++++++ .../itemExpression/name/VanillaName.java | 15 ++++++++++ 6 files changed, 100 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index d5b677a6..41f29657 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -15,6 +15,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; import java.util.ArrayList; import java.util.List; @@ -52,6 +53,7 @@ public void parseConfig(ConfigurationSection config) { parseMaterial(config); parseAmount(config); parseLore(config); + parseName(config); } private void parseMaterial(ConfigurationSection config) { @@ -93,6 +95,17 @@ else if (config.contains("lore")) setLore(new ExactlyLore(config.getStringList("lore"))); } + private void parseName(ConfigurationSection config) { + if (config.contains("name.regex")) + setName(new RegexName(Pattern.compile(config.getString("name.regex")))); + else if ("any".equals(config.getString("name"))) + setName(new AnyName()); + else if ("vanilla".equals(config.getString("name"))) + setName(new VanillaName()); + else if (config.contains("name")) + setName(new ExactlyName(config.getString("name"))); + } + /** * Runs this ItemExpression on a given ItemStack. * @@ -105,8 +118,15 @@ public boolean matches(ItemStack item) { return false; else if (!amountMatcher.matches(item.getAmount())) return false; + else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyLore)) + // slightly gross, but passing in null if !hasItemMeta is also kinda gross + // the code here wouldn't look nice either + // java null chaining operator when?. + return false; else if (!loreMatcher.matches(item.getItemMeta().getLore())) return false; + else if (!nameMatcher.matches(item.getItemMeta().getDisplayName())) + return false; return true; } @@ -139,4 +159,14 @@ public LoreMatcher getLore() { public void setLore(LoreMatcher loreMatcher) { this.loreMatcher = loreMatcher; } + + private NameMatcher nameMatcher; + + public NameMatcher getName() { + return nameMatcher; + } + + public void setName(NameMatcher nameMatcher) { + this.nameMatcher = nameMatcher; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java new file mode 100644 index 00000000..771308c0 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java @@ -0,0 +1,11 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +/** + * @author Ameliorate + */ +public class AnyName implements NameMatcher { + @Override + public boolean matches(String name) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java new file mode 100644 index 00000000..bdaebb87 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java @@ -0,0 +1,17 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +/** + * @author Ameliorate + */ +public class ExactlyName implements NameMatcher { + public ExactlyName(String name) { + this.name = name; + } + + public String name; + + @Override + public boolean matches(String name) { + return this.name.equals(name); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java new file mode 100644 index 00000000..865d3d0e --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java @@ -0,0 +1,8 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +/** + * @author Ameliorate + */ +public interface NameMatcher { + boolean matches(String name); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java new file mode 100644 index 00000000..f9dc9ada --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java @@ -0,0 +1,19 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +import java.util.regex.Pattern; + +/** + * @author Ameliorate + */ +public class RegexName implements NameMatcher { + public RegexName(Pattern regex) { + this.regex = regex; + } + + public Pattern regex; + + @Override + public boolean matches(String name) { + return regex.matcher(name).matches(); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java new file mode 100644 index 00000000..a262e488 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java @@ -0,0 +1,15 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +/** + * Makes sure the name is what shows up when you have not renamed the item. + * + * Actually just checks for null. + * + * @author Ameliorate + */ +public class VanillaName implements NameMatcher { + @Override + public boolean matches(String name) { + return name == null; + } +} From 21336dbac882a3fb8bffc28382569d564e2fc2d3 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 01:28:24 -0800 Subject: [PATCH 014/108] Fix typo of AnyLore -> AnyName in the gross part of ItemExpression.matches --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 41f29657..158e35cd 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -118,7 +118,7 @@ public boolean matches(ItemStack item) { return false; else if (!amountMatcher.matches(item.getAmount())) return false; - else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyLore)) + else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName)) // slightly gross, but passing in null if !hasItemMeta is also kinda gross // the code here wouldn't look nice either // java null chaining operator when?. From cfd99f6d2fb878123d839b3cd8268f4c94617f71 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 17:05:14 -0800 Subject: [PATCH 015/108] Add ItemExpression.getItemExpression() It gets an ItemExpression from a config. --- .../itemExpression/ItemExpression.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 158e35cd..d7fb4d5d 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -56,6 +56,20 @@ public void parseConfig(ConfigurationSection config) { parseName(config); } + /** + * Gets a ItemExpression from the given path in the config + * @param configurationSection The config to get the ItemExpression from + * @param path The path to the ItemExpression + * @return The ItemExpression in the config that path points to, or null if there was not an ItemExpression at path. + */ + public static ItemExpression getItemExpression(ConfigurationSection configurationSection, String path) { + if (configurationSection == null) + return null; + if (!configurationSection.contains(path)) + return null; + return new ItemExpression(configurationSection.getConfigurationSection(path)); + } + private void parseMaterial(ConfigurationSection config) { if (config.contains("material.regex")) setMaterial(new RegexMaterial(Pattern.compile(config.getString("material.regex")))); From e5e41337dac2a8fe50fdc1f2c6a633361a203fab Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 17:58:44 -0800 Subject: [PATCH 016/108] Make the private parse*() functions in ItemExpression take a path argument Now you can reuse them to refer to identical but duplicated options. --- .../itemExpression/ItemExpression.java | 104 ++++++++++-------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index d7fb4d5d..644700e8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -50,10 +50,10 @@ public ItemExpression(ConfigurationSection configurationSection) { * @param config The config that options will be taken from. */ public void parseConfig(ConfigurationSection config) { - parseMaterial(config); - parseAmount(config); - parseLore(config); - parseName(config); + setMaterial(parseMaterial(config, "material")); + setAmount(parseAmount(config, "amount")); + setLore(parseLore(config, "lore")); + setName(parseName(config, "name")); } /** @@ -70,54 +70,58 @@ public static ItemExpression getItemExpression(ConfigurationSection configuratio return new ItemExpression(configurationSection.getConfigurationSection(path)); } - private void parseMaterial(ConfigurationSection config) { - if (config.contains("material.regex")) - setMaterial(new RegexMaterial(Pattern.compile(config.getString("material.regex")))); - else if ("any".equals(config.getString("material"))) + private MaterialMatcher parseMaterial(ConfigurationSection config, String path) { + if (config.contains(path + ".regex")) + return(new RegexMaterial(Pattern.compile(config.getString(path + ".regex")))); + else if ("any".equals(config.getString(path))) // yoda order because config.getString is null if doesn't exist - setMaterial(new AnyMaterial()); - else if (config.contains("material")) - setMaterial(new ExactlyMaterial(Material.getMaterial(config.getString("material")))); - } - - private void parseAmount(ConfigurationSection config) { - if (config.contains("amount.range")) - setAmount(new RangeAmount( - config.getInt("amount.range.low", 0), - config.getInt("amount.range.high"), - config.getBoolean("amount.range.inclusiveLow", true), - config.getBoolean("amount.range.inclusiveHigh", true))); - else if ("any".equals(config.getString("amount"))) - setAmount(new AnyAmount()); - else if (config.contains("amount")) - setAmount(new ExactlyAmount(config.getInt("amount"))); - } - - private void parseLore(ConfigurationSection config) { - if (config.contains("lore.regex")) { - List patternsStr = config.getStringList("lore.regex"); + return(new AnyMaterial()); + else if (config.contains(path)) + return(new ExactlyMaterial(Material.getMaterial(config.getString(path)))); + return null; + } + + private AmountMatcher parseAmount(ConfigurationSection config, String path) { + if (config.contains(path + ".range")) + return(new RangeAmount( + config.getInt(path + ".range.low", 0), + config.getInt(path + ".range.high"), + config.getBoolean(path + ".range.inclusiveLow", true), + config.getBoolean(path + ".range.inclusiveHigh", true))); + else if ("any".equals(config.getString(path))) + return(new AnyAmount()); + else if (config.contains(path)) + return(new ExactlyAmount(config.getInt(path))); + return null; + } + + private LoreMatcher parseLore(ConfigurationSection config, String path) { + if (config.contains(path + ".regex")) { + List patternsStr = config.getStringList(path + ".regex"); List patterns = new ArrayList<>(); - boolean multiline = config.getBoolean("lore.regexMultiline", true); + boolean multiline = config.getBoolean(path + ".regexMultiline", true); for (String patternStr : patternsStr) { patterns.add(Pattern.compile(patternStr, multiline ? Pattern.MULTILINE : 0)); } - setLore(new RegexLore(patterns)); - } else if ("any".equals(config.getString("lore"))) - setLore(new AnyLore()); - else if (config.contains("lore")) - setLore(new ExactlyLore(config.getStringList("lore"))); - } - - private void parseName(ConfigurationSection config) { - if (config.contains("name.regex")) - setName(new RegexName(Pattern.compile(config.getString("name.regex")))); - else if ("any".equals(config.getString("name"))) - setName(new AnyName()); - else if ("vanilla".equals(config.getString("name"))) - setName(new VanillaName()); - else if (config.contains("name")) - setName(new ExactlyName(config.getString("name"))); + return(new RegexLore(patterns)); + } else if ("any".equals(config.getString(path))) + return(new AnyLore()); + else if (config.contains(path)) + return(new ExactlyLore(config.getStringList(path))); + return null; + } + + private NameMatcher parseName(ConfigurationSection config, String path) { + if (config.contains(path + ".regex")) + return(new RegexName(Pattern.compile(config.getString(path + ".regex")))); + else if ("any".equals(config.getString(path))) + return(new AnyName()); + else if ("vanilla".equals(config.getString(path))) + return(new VanillaName()); + else if (config.contains(path)) + return(new ExactlyName(config.getString(path))); + return null; } /** @@ -151,6 +155,8 @@ public MaterialMatcher getMaterial() { } public void setMaterial(MaterialMatcher materialMatcher) { + if (materialMatcher == null) + return; this.materialMatcher = materialMatcher; } @@ -161,6 +167,8 @@ public AmountMatcher getAmount() { } public void setAmount(AmountMatcher amountMatcher) { + if (amountMatcher == null) + return; this.amountMatcher = amountMatcher; } @@ -171,6 +179,8 @@ public LoreMatcher getLore() { } public void setLore(LoreMatcher loreMatcher) { + if (loreMatcher == null) + return; this.loreMatcher = loreMatcher; } @@ -181,6 +191,8 @@ public NameMatcher getName() { } public void setName(NameMatcher nameMatcher) { + if (nameMatcher == null) + return; this.nameMatcher = nameMatcher; } } From 0e7223c9146260f0b1e242154283b71a06aa9725 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 22:23:02 -0800 Subject: [PATCH 017/108] Add enchantment matching --- .../itemExpression/ItemExpression.java | 94 ++++++++++++++++++- .../itemExpression/amount/AmountMatcher.java | 2 + .../enchantment/AnyEnchantment.java | 13 +++ .../enchantment/EnchantmentMatcher.java | 10 ++ .../enchantment/ExactlyEnchantment.java | 24 +++++ 5 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 644700e8..cb5d9df0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -2,11 +2,15 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.ExactlyAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.RangeAmount; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.AnyEnchantment; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.ExactlyEnchantment; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.AnyLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.ExactlyLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.LoreMatcher; @@ -17,8 +21,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.regex.Pattern; /** @@ -54,6 +57,8 @@ public void parseConfig(ConfigurationSection config) { setAmount(parseAmount(config, "amount")); setLore(parseLore(config, "lore")); setName(parseName(config, "name")); + setEnchantmentAny(parseEnchantment(config, "enchantmentsAny")); + setEnchantmentAll(parseEnchantment(config, "enchantmentsAll")); } /** @@ -124,6 +129,26 @@ else if (config.contains(path)) return null; } + private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, String path) { + ConfigurationSection enchantments = config.getConfigurationSection(path); + ArrayList enchantmentMatcher = new ArrayList<>(); + for (String enchantName : enchantments.getKeys(false)) { + if (enchantName.equals("mode")) + continue; + + if (config.getString(path + "." + enchantName).equals("any")) + // don't think too much about enchantmentsAll: any + // it works out + enchantmentMatcher.add(new AnyEnchantment()); + else + enchantmentMatcher.add( + new ExactlyEnchantment(Enchantment.getByName(enchantName), + parseAmount(config, path + "." + enchantName))); + } + + return new EnchantmentSetMatcher(enchantmentMatcher); + } + /** * Runs this ItemExpression on a given ItemStack. * @@ -145,6 +170,10 @@ else if (!loreMatcher.matches(item.getItemMeta().getLore())) return false; else if (!nameMatcher.matches(item.getItemMeta().getDisplayName())) return false; + else if (!enchantmentMatcherAny.matches(item.getEnchantments(), true)) + return false; + else if (!enchantmentMatcherAll.matches(item.getEnchantments(), false)) + return false; return true; } @@ -195,4 +224,65 @@ public void setName(NameMatcher nameMatcher) { return; this.nameMatcher = nameMatcher; } + + private EnchantmentSetMatcher enchantmentMatcherAny = + new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); + + public EnchantmentSetMatcher getEnchantmentAny() { + return enchantmentMatcherAny; + } + + public void setEnchantmentAny(EnchantmentSetMatcher enchantmentMatcher) { + if (enchantmentMatcher == null) + return; + this.enchantmentMatcherAny = enchantmentMatcher; + } + + private EnchantmentSetMatcher enchantmentMatcherAll = + new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); + + public EnchantmentSetMatcher getEnchantmentAll() { + return enchantmentMatcherAll; + } + + public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { + this.enchantmentMatcherAll = enchantmentMatcherAll; + } + + + public class EnchantmentSetMatcher { + public EnchantmentSetMatcher(List enchantmentMatchers) { + this.enchantmentMatchers = enchantmentMatchers; + } + + public List enchantmentMatchers; + + public boolean matches(Map enchantments, boolean isAny) { + if (enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment && enchantments.size() == 0) + return true; + + for (EnchantmentMatcher matcher : enchantmentMatchers) { + boolean matchedOne = false; + + for (Map.Entry entry : enchantments.entrySet()) { + Enchantment enchantment = entry.getKey(); + int level = entry.getValue(); + + if (matcher.matches(enchantment, level)) { + matchedOne = true; + if (isAny) + return true; + } + } + + if (!isAny && !matchedOne) + return false; + } + + if (!isAny) + return true; + else + return false; + } + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index 162816ab..94bae9e0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -2,6 +2,8 @@ /** * @author Ameliorate + * + * Also used to match the level on an enchantment. */ public interface AmountMatcher { boolean matches(int amount); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java new file mode 100644 index 00000000..3e239065 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java @@ -0,0 +1,13 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; + +/** + * @author Ameliorate + */ +public class AnyEnchantment implements EnchantmentMatcher { + @Override + public boolean matches(Enchantment enchantment, int level) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java new file mode 100644 index 00000000..c7b0599b --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; + +/** + * @author Ameliorate + */ +public interface EnchantmentMatcher { + boolean matches(Enchantment enchantment, int level); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java new file mode 100644 index 00000000..e4cadf5e --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ExactlyEnchantment implements EnchantmentMatcher { + public ExactlyEnchantment(Enchantment enchantment, AmountMatcher level) { + this.enchantment = enchantment; + this.level = level; + } + + public Enchantment enchantment; + public AmountMatcher level; + + @Override + public boolean matches(Enchantment enchantment, int level) { + if (!this.enchantment.equals(enchantment)) + return false; + return this.level.matches(level); + } +} From f7b43c8afbb7b87e648cbd7ea3ba894db60be4b1 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 22:27:06 -0800 Subject: [PATCH 018/108] Add durability matching --- .../itemExpression/ItemExpression.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index cb5d9df0..4278ac55 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -55,6 +55,7 @@ public ItemExpression(ConfigurationSection configurationSection) { public void parseConfig(ConfigurationSection config) { setMaterial(parseMaterial(config, "material")); setAmount(parseAmount(config, "amount")); + setDurability(parseAmount(config, "durability")); setLore(parseLore(config, "lore")); setName(parseName(config, "name")); setEnchantmentAny(parseEnchantment(config, "enchantmentsAny")); @@ -161,6 +162,8 @@ public boolean matches(ItemStack item) { return false; else if (!amountMatcher.matches(item.getAmount())) return false; + else if (!durabilityMatcher.matches(item.getDurability())) + return false; else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName)) // slightly gross, but passing in null if !hasItemMeta is also kinda gross // the code here wouldn't look nice either @@ -249,6 +252,18 @@ public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { this.enchantmentMatcherAll = enchantmentMatcherAll; } + private AmountMatcher durabilityMatcher = new AnyAmount(); + + public AmountMatcher getDurability() { + return durabilityMatcher; + } + + public void setDurability(AmountMatcher durabilityMatcher) { + if (durabilityMatcher == null) + return; + this.durabilityMatcher = durabilityMatcher; + } + public class EnchantmentSetMatcher { public EnchantmentSetMatcher(List enchantmentMatchers) { From d0b9bbe7568714361cfaedbaaea3c5ab0a450584 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 22:28:29 -0800 Subject: [PATCH 019/108] Add null checking to enchantment matching --- .../itemHandling/itemExpression/ItemExpression.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 4278ac55..bceb19b7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -132,6 +132,9 @@ else if (config.contains(path)) private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, String path) { ConfigurationSection enchantments = config.getConfigurationSection(path); + if (enchantments == null) + return null; + ArrayList enchantmentMatcher = new ArrayList<>(); for (String enchantName : enchantments.getKeys(false)) { if (enchantName.equals("mode")) @@ -249,6 +252,8 @@ public EnchantmentSetMatcher getEnchantmentAll() { } public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { + if (materialMatcher == null) + return; this.enchantmentMatcherAll = enchantmentMatcherAll; } From e10347190a7b212a49691f121b3ce6b0f074e56a Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 22:29:47 -0800 Subject: [PATCH 020/108] Remove minor double empty line I have my font set so small I can barely see when I have a double enter --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index bceb19b7..c49483da 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -269,7 +269,6 @@ public void setDurability(AmountMatcher durabilityMatcher) { this.durabilityMatcher = durabilityMatcher; } - public class EnchantmentSetMatcher { public EnchantmentSetMatcher(List enchantmentMatchers) { this.enchantmentMatchers = enchantmentMatchers; From 25e6114c9df7473ef0512576cfef2fdab27d1a9e Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 22:42:27 -0800 Subject: [PATCH 021/108] Add matching if an item is unbreakable --- .../itemExpression/ItemExpression.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index c49483da..0ad1ec50 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -60,6 +60,8 @@ public void parseConfig(ConfigurationSection config) { setName(parseName(config, "name")); setEnchantmentAny(parseEnchantment(config, "enchantmentsAny")); setEnchantmentAll(parseEnchantment(config, "enchantmentsAll")); + + unbreakable = config.getBoolean("unbreakable", false); } /** @@ -167,7 +169,8 @@ else if (!amountMatcher.matches(item.getAmount())) return false; else if (!durabilityMatcher.matches(item.getDurability())) return false; - else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName)) + else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName) && + !enchantmentMatcherAll.matchesAny() && !enchantmentMatcherAny.matchesAny() && unbreakable != null) // slightly gross, but passing in null if !hasItemMeta is also kinda gross // the code here wouldn't look nice either // java null chaining operator when?. @@ -180,9 +183,16 @@ else if (!enchantmentMatcherAny.matches(item.getEnchantments(), true)) return false; else if (!enchantmentMatcherAll.matches(item.getEnchantments(), false)) return false; + else if (unbreakable != null && item.getItemMeta().isUnbreakable() != unbreakable) + return false; return true; } + /** + * null if matches unbreakable == true and unbreakable == false + */ + public Boolean unbreakable = null; + private MaterialMatcher materialMatcher = new AnyMaterial(); public MaterialMatcher getMaterial() { @@ -277,7 +287,7 @@ public EnchantmentSetMatcher(List enchantmentMatchers) { public List enchantmentMatchers; public boolean matches(Map enchantments, boolean isAny) { - if (enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment && enchantments.size() == 0) + if (matchesAny() && enchantments.size() == 0) return true; for (EnchantmentMatcher matcher : enchantmentMatchers) { @@ -303,5 +313,9 @@ public boolean matches(Map enchantments, boolean isAny) { else return false; } + + public boolean matchesAny() { + return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment; + } } } From ae8249ab7cdf2714193a203295bcb4cfd419f4d9 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 22:48:33 -0800 Subject: [PATCH 022/108] Add negative matching enchantments It only matches if none of the listed enchantments are on the item --- .../itemExpression/ItemExpression.java | 16 ++++++++++++++++ .../enchantment/NoEnchantment.java | 13 +++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 0ad1ec50..4da292b8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -11,6 +11,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.AnyEnchantment; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.ExactlyEnchantment; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.NoEnchantment; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.AnyLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.ExactlyLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.LoreMatcher; @@ -183,6 +184,8 @@ else if (!enchantmentMatcherAny.matches(item.getEnchantments(), true)) return false; else if (!enchantmentMatcherAll.matches(item.getEnchantments(), false)) return false; + else if (getEnchantmentMatcherNone.matches(item.getEnchantments(), false)) + return false; else if (unbreakable != null && item.getItemMeta().isUnbreakable() != unbreakable) return false; return true; @@ -267,6 +270,19 @@ public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { this.enchantmentMatcherAll = enchantmentMatcherAll; } + private EnchantmentSetMatcher getEnchantmentMatcherNone = + new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment())); + + public EnchantmentSetMatcher getGetEnchantmentNone() { + return getEnchantmentMatcherNone; + } + + public void setGetEnchantmentNone(EnchantmentSetMatcher getEnchantmentMatcherNone) { + if (getEnchantmentMatcherNone == null) + return; + this.getEnchantmentMatcherNone = getEnchantmentMatcherNone; + } + private AmountMatcher durabilityMatcher = new AnyAmount(); public AmountMatcher getDurability() { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java new file mode 100644 index 00000000..24ff0c10 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java @@ -0,0 +1,13 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; + +/** + * @author Ameliorate + */ +public class NoEnchantment implements EnchantmentMatcher { + @Override + public boolean matches(Enchantment enchantment, int level) { + return false; + } +} From fdf5c968af61c379afbb0e98f327e3f3cf5e60f9 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 23:02:19 -0800 Subject: [PATCH 023/108] Fix matches none with no itemmeta --- .../itemHandling/itemExpression/ItemExpression.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 4da292b8..e024c118 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -171,7 +171,8 @@ else if (!amountMatcher.matches(item.getAmount())) else if (!durabilityMatcher.matches(item.getDurability())) return false; else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName) && - !enchantmentMatcherAll.matchesAny() && !enchantmentMatcherAny.matchesAny() && unbreakable != null) + !enchantmentMatcherAll.matchesAny() && !enchantmentMatcherAny.matchesAny() && !getEnchantmentMatcherNone.matchesNone() && + unbreakable != null) // slightly gross, but passing in null if !hasItemMeta is also kinda gross // the code here wouldn't look nice either // java null chaining operator when?. @@ -333,5 +334,9 @@ public boolean matches(Map enchantments, boolean isAny) { public boolean matchesAny() { return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment; } + + public boolean matchesNone() { + return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof NoEnchantment; + } } } From 615780c28a63a0313253fa6ab8737c17fb626539 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 2 Feb 2019 23:04:03 -0800 Subject: [PATCH 024/108] Parse enchantmentsNone from config --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index e024c118..504233c5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -61,6 +61,7 @@ public void parseConfig(ConfigurationSection config) { setName(parseName(config, "name")); setEnchantmentAny(parseEnchantment(config, "enchantmentsAny")); setEnchantmentAll(parseEnchantment(config, "enchantmentsAll")); + setEnchantmentNone(parseEnchantment(config, "enchantmentsNone")); unbreakable = config.getBoolean("unbreakable", false); } @@ -278,7 +279,7 @@ public EnchantmentSetMatcher getGetEnchantmentNone() { return getEnchantmentMatcherNone; } - public void setGetEnchantmentNone(EnchantmentSetMatcher getEnchantmentMatcherNone) { + public void setEnchantmentNone(EnchantmentSetMatcher getEnchantmentMatcherNone) { if (getEnchantmentMatcherNone == null) return; this.getEnchantmentMatcherNone = getEnchantmentMatcherNone; From 2148980f94b1725f490b72bec2954e348ecbe9d6 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 15:59:53 -0800 Subject: [PATCH 025/108] Fix variable name getEnchantmentMatcherNone -> enchantmentMatcherNone --- .../itemHandling/itemExpression/ItemExpression.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 504233c5..7e3735bb 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -172,7 +172,7 @@ else if (!amountMatcher.matches(item.getAmount())) else if (!durabilityMatcher.matches(item.getDurability())) return false; else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName) && - !enchantmentMatcherAll.matchesAny() && !enchantmentMatcherAny.matchesAny() && !getEnchantmentMatcherNone.matchesNone() && + !enchantmentMatcherAll.matchesAny() && !enchantmentMatcherAny.matchesAny() && !enchantmentMatcherNone.matchesNone() && unbreakable != null) // slightly gross, but passing in null if !hasItemMeta is also kinda gross // the code here wouldn't look nice either @@ -186,7 +186,7 @@ else if (!enchantmentMatcherAny.matches(item.getEnchantments(), true)) return false; else if (!enchantmentMatcherAll.matches(item.getEnchantments(), false)) return false; - else if (getEnchantmentMatcherNone.matches(item.getEnchantments(), false)) + else if (enchantmentMatcherNone.matches(item.getEnchantments(), false)) return false; else if (unbreakable != null && item.getItemMeta().isUnbreakable() != unbreakable) return false; @@ -272,17 +272,17 @@ public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { this.enchantmentMatcherAll = enchantmentMatcherAll; } - private EnchantmentSetMatcher getEnchantmentMatcherNone = + private EnchantmentSetMatcher enchantmentMatcherNone = new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment())); public EnchantmentSetMatcher getGetEnchantmentNone() { - return getEnchantmentMatcherNone; + return enchantmentMatcherNone; } public void setEnchantmentNone(EnchantmentSetMatcher getEnchantmentMatcherNone) { if (getEnchantmentMatcherNone == null) return; - this.getEnchantmentMatcherNone = getEnchantmentMatcherNone; + this.enchantmentMatcherNone = getEnchantmentMatcherNone; } private AmountMatcher durabilityMatcher = new AnyAmount(); From 01952880b1c84995e766e78dd3a8995e767eed72 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 16:03:00 -0800 Subject: [PATCH 026/108] Fix getGetEnchantmentNone -> getEnchantmentNone --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 7e3735bb..5f9a30f5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -275,7 +275,7 @@ public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { private EnchantmentSetMatcher enchantmentMatcherNone = new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment())); - public EnchantmentSetMatcher getGetEnchantmentNone() { + public EnchantmentSetMatcher getEnchantmentNone() { return enchantmentMatcherNone; } From 41ba0025bb4e88a0022bde561825d5ab7d45ec2b Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 16:10:39 -0800 Subject: [PATCH 027/108] Add matching EnchantmentStorageMeta Like enchanted books and things --- .../itemExpression/ItemExpression.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 5f9a30f5..b25d0898 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -4,6 +4,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.ExactlyAmount; @@ -62,6 +63,9 @@ public void parseConfig(ConfigurationSection config) { setEnchantmentAny(parseEnchantment(config, "enchantmentsAny")); setEnchantmentAll(parseEnchantment(config, "enchantmentsAll")); setEnchantmentNone(parseEnchantment(config, "enchantmentsNone")); + setEnchantmentHeldAny(parseEnchantment(config, "enchantmentsHeldAny")); + setEnchantmentHeldAll(parseEnchantment(config, "enchantmentsHeldAll")); + setEnchantmentHeldNone(parseEnchantment(config, "enchantmentsHeldNone")); unbreakable = config.getBoolean("unbreakable", false); } @@ -190,6 +194,15 @@ else if (enchantmentMatcherNone.matches(item.getEnchantments(), false)) return false; else if (unbreakable != null && item.getItemMeta().isUnbreakable() != unbreakable) return false; + else if (!(item.getItemMeta() instanceof EnchantmentStorageMeta) && !enchantmentMatcherHeldAll.matchesAny() && + !enchantmentMatcherHeldAny.matchesAny() && !enchantmentMatcherHeldNone.matchesNone()) + return false; + else if (!enchantmentMatcherHeldAny.matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), true)) + return false; + else if (!enchantmentMatcherHeldAll.matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), false)) + return false; + else if (enchantmentMatcherHeldNone.matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), false)) + return false; return true; } @@ -285,6 +298,45 @@ public void setEnchantmentNone(EnchantmentSetMatcher getEnchantmentMatcherNone) this.enchantmentMatcherNone = getEnchantmentMatcherNone; } + public EnchantmentSetMatcher getEnchantmentHeldAny() { + return enchantmentMatcherHeldAny; + } + + public void setEnchantmentHeldAny(EnchantmentSetMatcher enchantmentMatcherHeldAny) { + if (enchantmentMatcherHeldAny == null) + return; + this.enchantmentMatcherHeldAny = enchantmentMatcherHeldAny; + } + + public EnchantmentSetMatcher getEnchantmentHeldAll() { + return enchantmentMatcherHeldAll; + } + + public void setEnchantmentHeldAll(EnchantmentSetMatcher enchantmentMatcherHeldAll) { + if (enchantmentMatcherHeldAll == null) + return; + this.enchantmentMatcherHeldAll = enchantmentMatcherHeldAll; + } + + public EnchantmentSetMatcher getEnchantmentHeldNone() { + return enchantmentMatcherHeldNone; + } + + public void setEnchantmentHeldNone(EnchantmentSetMatcher enchantmentMatcherHeldNone) { + if (enchantmentMatcherHeldNone == null) + return; + this.enchantmentMatcherHeldNone = enchantmentMatcherHeldNone; + } + + private EnchantmentSetMatcher enchantmentMatcherHeldAny = + new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); + + private EnchantmentSetMatcher enchantmentMatcherHeldAll = + new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); + + private EnchantmentSetMatcher enchantmentMatcherHeldNone = + new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment())); + private AmountMatcher durabilityMatcher = new AnyAmount(); public AmountMatcher getDurability() { From c352c9f0342bd34b59d3fd8bebcb1d51f761a500 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 17:41:17 -0800 Subject: [PATCH 028/108] Fix unbreakable parsing from config --- .../itemHandling/itemExpression/ItemExpression.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index b25d0898..cf143500 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -67,7 +67,10 @@ public void parseConfig(ConfigurationSection config) { setEnchantmentHeldAll(parseEnchantment(config, "enchantmentsHeldAll")); setEnchantmentHeldNone(parseEnchantment(config, "enchantmentsHeldNone")); - unbreakable = config.getBoolean("unbreakable", false); + if (config.contains("unbreakable")) + unbreakable = config.getBoolean("unbreakable"); + else + unbreakable = null; } /** From b9c71e5f13693c4a1bb5407da898a95f2c5a8ad1 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 19:40:14 -0800 Subject: [PATCH 029/108] Fix all the NPEs and wrong logic I wrote a simple command that tests ItemExpression with the item in your hand and found all the bugs. --- .../itemExpression/ItemExpression.java | 37 ++++++++++--------- .../itemExpression/name/VanillaName.java | 4 +- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index cf143500..33311230 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -5,6 +5,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.ExactlyAmount; @@ -148,17 +149,9 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri ArrayList enchantmentMatcher = new ArrayList<>(); for (String enchantName : enchantments.getKeys(false)) { - if (enchantName.equals("mode")) - continue; - - if (config.getString(path + "." + enchantName).equals("any")) - // don't think too much about enchantmentsAll: any - // it works out - enchantmentMatcher.add(new AnyEnchantment()); - else - enchantmentMatcher.add( - new ExactlyEnchantment(Enchantment.getByName(enchantName), - parseAmount(config, path + "." + enchantName))); + enchantmentMatcher.add( + new ExactlyEnchantment(Enchantment.getByName(enchantName), + parseAmount(config, path + "." + enchantName))); } return new EnchantmentSetMatcher(enchantmentMatcher); @@ -172,6 +165,8 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri * @return If the given item matches. */ public boolean matches(ItemStack item) { + System.out.println(item.getItemMeta().getDisplayName().length()); + if (!materialMatcher.matches(item.getType())) return false; else if (!amountMatcher.matches(item.getAmount())) @@ -179,7 +174,7 @@ else if (!amountMatcher.matches(item.getAmount())) else if (!durabilityMatcher.matches(item.getDurability())) return false; else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName) && - !enchantmentMatcherAll.matchesAny() && !enchantmentMatcherAny.matchesAny() && !enchantmentMatcherNone.matchesNone() && + enchantmentMatcherAll.matchesAny() && enchantmentMatcherAny.matchesAny() && enchantmentMatcherNone.matchesNone() && unbreakable != null) // slightly gross, but passing in null if !hasItemMeta is also kinda gross // the code here wouldn't look nice either @@ -200,15 +195,23 @@ else if (unbreakable != null && item.getItemMeta().isUnbreakable() != unbreakabl else if (!(item.getItemMeta() instanceof EnchantmentStorageMeta) && !enchantmentMatcherHeldAll.matchesAny() && !enchantmentMatcherHeldAny.matchesAny() && !enchantmentMatcherHeldNone.matchesNone()) return false; - else if (!enchantmentMatcherHeldAny.matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), true)) + else if (!enchantmentMatcherHeldAny.matches(castOrNull(item.getItemMeta()), true)) return false; - else if (!enchantmentMatcherHeldAll.matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), false)) + else if (!enchantmentMatcherHeldAll.matches(castOrNull(item.getItemMeta()), false)) return false; - else if (enchantmentMatcherHeldNone.matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), false)) + else if (enchantmentMatcherHeldNone.matches(castOrNull(item.getItemMeta()), false)) return false; return true; } + private Map castOrNull(ItemMeta itemMeta) { + Map result = (itemMeta instanceof EnchantmentStorageMeta) ? + ((EnchantmentStorageMeta) itemMeta).getStoredEnchants() : null; + if (result == null) + result = new HashMap<>(); + return result; + } + /** * null if matches unbreakable == true and unbreakable == false */ @@ -250,7 +253,7 @@ public void setLore(LoreMatcher loreMatcher) { this.loreMatcher = loreMatcher; } - private NameMatcher nameMatcher; + private NameMatcher nameMatcher = new AnyName(); public NameMatcher getName() { return nameMatcher; @@ -283,7 +286,7 @@ public EnchantmentSetMatcher getEnchantmentAll() { } public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { - if (materialMatcher == null) + if (enchantmentMatcherAll == null) return; this.enchantmentMatcherAll = enchantmentMatcherAll; } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java index a262e488..725208fe 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java @@ -3,13 +3,13 @@ /** * Makes sure the name is what shows up when you have not renamed the item. * - * Actually just checks for null. + * Actually just checks for empty string. * * @author Ameliorate */ public class VanillaName implements NameMatcher { @Override public boolean matches(String name) { - return name == null; + return name.isEmpty(); } } From 026bf2ca866e0cc704d994ceb04f3197fb6f166b Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 19:45:15 -0800 Subject: [PATCH 030/108] Make lore regexes just one regex I couldn't figure out the whole list of regexes thing. --- .../itemExpression/ItemExpression.java | 9 +++------ .../itemExpression/lore/RegexLore.java | 17 +++++------------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 33311230..6ca69bb0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -115,14 +115,11 @@ else if (config.contains(path)) private LoreMatcher parseLore(ConfigurationSection config, String path) { if (config.contains(path + ".regex")) { - List patternsStr = config.getStringList(path + ".regex"); - List patterns = new ArrayList<>(); + String patternStr = config.getString(path + ".regex"); boolean multiline = config.getBoolean(path + ".regexMultiline", true); + Pattern pattern = Pattern.compile(patternStr, multiline ? Pattern.MULTILINE : 0); - for (String patternStr : patternsStr) { - patterns.add(Pattern.compile(patternStr, multiline ? Pattern.MULTILINE : 0)); - } - return(new RegexLore(patterns)); + return(new RegexLore(pattern)); } else if ("any".equals(config.getString(path))) return(new AnyLore()); else if (config.contains(path)) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java index 1d977766..33530435 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java @@ -1,6 +1,5 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; -import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; @@ -8,15 +7,11 @@ * @author Ameliorate */ public class RegexLore implements LoreMatcher { - public RegexLore(List patterns) { - this.patterns = patterns; + public RegexLore(Pattern pattern) { + this.pattern = pattern; } - public RegexLore(Pattern... patterns) { - this(Arrays.asList(patterns)); - } - - public List patterns; + public Pattern pattern; @Override public boolean matches(List lore) { @@ -26,10 +21,8 @@ public boolean matches(List lore) { loreStr.append('\n'); } - for (Pattern pattern : patterns) { - if (pattern.matcher(loreStr).matches()) - return true; - } + if (pattern.matcher(loreStr).matches()) + return true; return false; } } From 80c4d8afff33de6063d0469f2538c4140ab49d3e Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 19:51:04 -0800 Subject: [PATCH 031/108] Remove debug println --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 6ca69bb0..ee438776 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -162,8 +162,6 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri * @return If the given item matches. */ public boolean matches(ItemStack item) { - System.out.println(item.getItemMeta().getDisplayName().length()); - if (!materialMatcher.matches(item.getType())) return false; else if (!amountMatcher.matches(item.getAmount())) From 9b5d6edbe1debde633356e61bbba3b0976076652 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 23:08:32 -0800 Subject: [PATCH 032/108] Fix the whole thing instanceof AnyName stuff Although matchers need to check for null. It's worth it because now there's no NPE when matching an air itemstack. --- .../itemExpression/ItemExpression.java | 40 ++++++------------- .../itemExpression/lore/RegexLore.java | 12 ++---- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index ee438776..6f71c6bf 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -162,22 +162,22 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri * @return If the given item matches. */ public boolean matches(ItemStack item) { + ItemMeta meta; + if (item.hasItemMeta()) { + meta = item.getItemMeta(); + } else { + meta = new ItemStack(Material.IRON_AXE, 1).getItemMeta(); // clever hack + } + if (!materialMatcher.matches(item.getType())) return false; else if (!amountMatcher.matches(item.getAmount())) return false; else if (!durabilityMatcher.matches(item.getDurability())) return false; - else if (!item.hasItemMeta() && !(loreMatcher instanceof AnyLore) && !(nameMatcher instanceof AnyName) && - enchantmentMatcherAll.matchesAny() && enchantmentMatcherAny.matchesAny() && enchantmentMatcherNone.matchesNone() && - unbreakable != null) - // slightly gross, but passing in null if !hasItemMeta is also kinda gross - // the code here wouldn't look nice either - // java null chaining operator when?. - return false; - else if (!loreMatcher.matches(item.getItemMeta().getLore())) + else if (!loreMatcher.matches(meta.getLore())) return false; - else if (!nameMatcher.matches(item.getItemMeta().getDisplayName())) + else if (!nameMatcher.matches(meta.getDisplayName())) return false; else if (!enchantmentMatcherAny.matches(item.getEnchantments(), true)) return false; @@ -185,16 +185,13 @@ else if (!enchantmentMatcherAll.matches(item.getEnchantments(), false)) return false; else if (enchantmentMatcherNone.matches(item.getEnchantments(), false)) return false; - else if (unbreakable != null && item.getItemMeta().isUnbreakable() != unbreakable) + else if (unbreakable != null && meta.isUnbreakable() != unbreakable) return false; - else if (!(item.getItemMeta() instanceof EnchantmentStorageMeta) && !enchantmentMatcherHeldAll.matchesAny() && - !enchantmentMatcherHeldAny.matchesAny() && !enchantmentMatcherHeldNone.matchesNone()) + else if (!enchantmentMatcherHeldAny.matches(castOrNull(meta), true)) return false; - else if (!enchantmentMatcherHeldAny.matches(castOrNull(item.getItemMeta()), true)) + else if (!enchantmentMatcherHeldAll.matches(castOrNull(meta), false)) return false; - else if (!enchantmentMatcherHeldAll.matches(castOrNull(item.getItemMeta()), false)) - return false; - else if (enchantmentMatcherHeldNone.matches(castOrNull(item.getItemMeta()), false)) + else if (enchantmentMatcherHeldNone.matches(castOrNull(meta), false)) return false; return true; } @@ -358,9 +355,6 @@ public EnchantmentSetMatcher(List enchantmentMatchers) { public List enchantmentMatchers; public boolean matches(Map enchantments, boolean isAny) { - if (matchesAny() && enchantments.size() == 0) - return true; - for (EnchantmentMatcher matcher : enchantmentMatchers) { boolean matchedOne = false; @@ -384,13 +378,5 @@ public boolean matches(Map enchantments, boolean isAny) { else return false; } - - public boolean matchesAny() { - return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment; - } - - public boolean matchesNone() { - return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof NoEnchantment; - } } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java index 33530435..8a8e89b8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java @@ -15,14 +15,8 @@ public RegexLore(Pattern pattern) { @Override public boolean matches(List lore) { - StringBuilder loreStr = new StringBuilder(); - for (String line : lore) { - loreStr.append(line); - loreStr.append('\n'); - } - - if (pattern.matcher(loreStr).matches()) - return true; - return false; + if (lore == null) + return false; + return pattern.matcher(String.join("\n", lore)).find(); } } From e1e06cfbbc4038fe14adbc13cb2a527ab95946c2 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 23:29:27 -0800 Subject: [PATCH 033/108] Remove the "material: any" and sorts part of the config parser You can just say the same thing by leaving out material:. It's still in for amount, since that logic is also used for matching the level of an an enchant, and saying any level is useful. --- .../itemHandling/itemExpression/ItemExpression.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 6f71c6bf..1044df2f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -91,9 +91,6 @@ public static ItemExpression getItemExpression(ConfigurationSection configuratio private MaterialMatcher parseMaterial(ConfigurationSection config, String path) { if (config.contains(path + ".regex")) return(new RegexMaterial(Pattern.compile(config.getString(path + ".regex")))); - else if ("any".equals(config.getString(path))) - // yoda order because config.getString is null if doesn't exist - return(new AnyMaterial()); else if (config.contains(path)) return(new ExactlyMaterial(Material.getMaterial(config.getString(path)))); return null; @@ -120,9 +117,7 @@ private LoreMatcher parseLore(ConfigurationSection config, String path) { Pattern pattern = Pattern.compile(patternStr, multiline ? Pattern.MULTILINE : 0); return(new RegexLore(pattern)); - } else if ("any".equals(config.getString(path))) - return(new AnyLore()); - else if (config.contains(path)) + } else if (config.contains(path)) return(new ExactlyLore(config.getStringList(path))); return null; } @@ -130,8 +125,6 @@ else if (config.contains(path)) private NameMatcher parseName(ConfigurationSection config, String path) { if (config.contains(path + ".regex")) return(new RegexName(Pattern.compile(config.getString(path + ".regex")))); - else if ("any".equals(config.getString(path))) - return(new AnyName()); else if ("vanilla".equals(config.getString(path))) return(new VanillaName()); else if (config.contains(path)) From e3a5952b34dbd09e30e03a39e9693ba32099af7a Mon Sep 17 00:00:00 2001 From: Amelorate Date: Mon, 4 Feb 2019 23:32:30 -0800 Subject: [PATCH 034/108] Optimize imports --- .../itemExpression/ItemExpression.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 1044df2f..1e1c5558 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -6,22 +6,10 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AnyAmount; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.ExactlyAmount; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.RangeAmount; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.AnyEnchantment; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.ExactlyEnchantment; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.NoEnchantment; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.AnyLore; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.ExactlyLore; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.LoreMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.RegexLore; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.AnyMaterial; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; import java.util.*; From 7f908263fe0e93206497a4d69a275920bc9f3edf Mon Sep 17 00:00:00 2001 From: Amelorate Date: Tue, 5 Feb 2019 21:00:39 -0800 Subject: [PATCH 035/108] Fix nothing being matched Seems some stuff did need the whole instanceof thing --- .../itemHandling/itemExpression/ItemExpression.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 1e1c5558..b2c482ad 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -336,6 +336,9 @@ public EnchantmentSetMatcher(List enchantmentMatchers) { public List enchantmentMatchers; public boolean matches(Map enchantments, boolean isAny) { + if (matchesAny() && enchantments.size() == 0) + return true; + for (EnchantmentMatcher matcher : enchantmentMatchers) { boolean matchedOne = false; @@ -359,5 +362,9 @@ public boolean matches(Map enchantments, boolean isAny) { else return false; } + + public boolean matchesAny() { + return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment; + } } } From 168d77bb08687bba381ab599398850ceb966d19c Mon Sep 17 00:00:00 2001 From: Amelorate Date: Fri, 8 Feb 2019 19:12:00 -0800 Subject: [PATCH 036/108] Add a function to remove an amount of matching items from an inventory It can also infer the amount from the ItemExpression's amount field, including using randomness if the amount is a range. --- .../itemExpression/ItemExpression.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index b2c482ad..34f20147 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -3,6 +3,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; @@ -13,6 +14,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import java.util.regex.Pattern; /** @@ -185,6 +187,98 @@ private Map castOrNull(ItemMeta itemMeta) { return result; } + /** + * Removes amount items that match this ItemExpression from tne inventory. + * + * This function correctly handles situations where the inventory has two or more ItemStacks that do not satisfy + * .isSimilar() but do match this ItemExpression. + * @param inventory The inventory items will be removed from. + * @param amount The number of items to remove. If this is -1, all items that match will be removed. + * @return If there were enough items to remove. If this is false, no items have been removed from the inventory. + */ + public boolean removeFromInventory(Inventory inventory, int amount) { + // store the amount matcher, because it'll mess with things later + // for exacple, what happens when amount=1 was passed into this function but amount: 64 is in the config? + AmountMatcher amountMatcher1 = getAmount(); + setAmount(new AnyAmount()); + + try { + int runningAmount = amount; + boolean infinite = false; + if (runningAmount == -1) { + runningAmount = Integer.MAX_VALUE; + infinite = true; + } + + ItemStack[] contents = inventory.getStorageContents(); + contents = Arrays.stream(contents).map(item -> item != null ? item.clone() : null).toArray(ItemStack[]::new); + for (ItemStack item : contents) { + if (item == null) + continue; + if (item.getType() == Material.AIR) + continue; + + if (matches(item)) { + if (item.getAmount() >= runningAmount) { + int itemOldAmount = item.getAmount(); + item.setAmount(item.getAmount() - runningAmount); + runningAmount -= itemOldAmount - item.getAmount(); + break; + } else if (item.getAmount() < runningAmount) { + runningAmount -= item.getAmount(); + item.setAmount(0); + } + } + } + + if (runningAmount == 0 || infinite) { + inventory.setStorageContents(contents); + return true; + } else if (runningAmount < 0) { + // big trouble, this isn't supposed to happen + throw new AssertionError("runningAmount is less than 0, there's a bug somewhere. runningAmount: " + runningAmount); + } else { + // items remaining + return false; + } + } finally { + // restore the amount matcher now we're done + setAmount(amountMatcher1); + } + } + + /** + * Removes the items that match this ItemExpression. The amount to remove is infered from the amount of this + * ItemExpression. + * + * If amount is `any`, all items that match this ItemExpression will be removed. + * If amount is a range and random is true, a random number of items within the range will be removed. + * If amount is a range and random is false, the lower bound of the range will be used. + * @param inventory The inventory items will be removed from. + * @param random To select a random number within amount. This only applies if amount is a range. + * @return If there were enough items to remove. If this is false, no items have been removed from the inventory. + */ + public boolean removeFromInventory(Inventory inventory, boolean random) { + int amount; + if (amountMatcher instanceof ExactlyAmount) { + amount = ((ExactlyAmount) amountMatcher).amount; + } else if (amountMatcher instanceof AnyAmount) { + amount = -1; + } else if (amountMatcher instanceof RangeAmount && !random) { + RangeAmount rangeAmount = (RangeAmount) amountMatcher; + amount = rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : 1); + } else if (amountMatcher instanceof RangeAmount && random) { + RangeAmount rangeAmount = (RangeAmount) amountMatcher; + amount = ThreadLocalRandom.current() + .nextInt(rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : -1), + rangeAmount.getHigh() + (rangeAmount.highInclusive ? 1 : 0)); + } else { + throw new IllegalArgumentException("removeFromInventory(Inventory, boolean) does not work with custom AmountMatchers"); + } + + return removeFromInventory(inventory, amount); + } + /** * null if matches unbreakable == true and unbreakable == false */ From 37aaf6739e54506d6f913b978ed7626817b8fa88 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sat, 9 Feb 2019 00:05:23 -0800 Subject: [PATCH 037/108] Use vanilla enchantment keys instead of the bukkit enchantment names The bukkit naming was nonsense, although it's a little harder to get vanilla enchantments by key. --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 34f20147..340741df 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; @@ -130,7 +131,7 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri ArrayList enchantmentMatcher = new ArrayList<>(); for (String enchantName : enchantments.getKeys(false)) { enchantmentMatcher.add( - new ExactlyEnchantment(Enchantment.getByName(enchantName), + new ExactlyEnchantment(Enchantment.getByKey(NamespacedKey.minecraft(enchantName.toLowerCase())), parseAmount(config, path + "." + enchantName))); } From 9b39851a57ad2f79210365e40bb2746a705d2f4b Mon Sep 17 00:00:00 2001 From: Amelorate Date: Tue, 19 Feb 2019 14:21:21 -0800 Subject: [PATCH 038/108] Add basic matching on player heads Not done yet, but switching computers for a while and need some place to put this changeset. --- .../itemExpression/ItemExpression.java | 47 +++++++++++++++++++ .../itemExpression/uuid/AnyUUID.java | 10 ++++ .../itemExpression/uuid/ExactlyUUID.java | 16 +++++++ .../itemExpression/uuid/PlayerNameUUID.java | 23 +++++++++ .../itemExpression/uuid/UUIDMatcher.java | 7 +++ 5 files changed, 103 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 340741df..8f56453f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -8,11 +8,13 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.*; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -58,6 +60,7 @@ public void parseConfig(ConfigurationSection config) { setEnchantmentHeldAny(parseEnchantment(config, "enchantmentsHeldAny")); setEnchantmentHeldAll(parseEnchantment(config, "enchantmentsHeldAll")); setEnchantmentHeldNone(parseEnchantment(config, "enchantmentsHeldNone")); + setSkullMatchers(parseSkull(config, "skull")); if (config.contains("unbreakable")) unbreakable = config.getBoolean("unbreakable"); @@ -138,6 +141,28 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri return new EnchantmentSetMatcher(enchantmentMatcher); } + private List parseSkull(ConfigurationSection config, String path) { + List matchers = new ArrayList<>(); + ConfigurationSection skull = config.getConfigurationSection(path); + if (skull == null) + return Collections.emptyList(); + + for (String name : skull.getStringList("names")) { + matchers.add(new PlayerNameUUID(name)); + } + + for (String uuid : skull.getStringList("uuids")) { + matchers.add(new ExactlyUUID(UUID.fromString(uuid))); + } + + if (skull.contains("name")) + matchers.add(new PlayerNameUUID(skull.getString("name"))); + if (skull.contains("uuid")) + matchers.add(new ExactlyUUID(UUID.fromString(skull.getString("name")))); + + return matchers; + } + /** * Runs this ItemExpression on a given ItemStack. * @@ -153,6 +178,8 @@ public boolean matches(ItemStack item) { meta = new ItemStack(Material.IRON_AXE, 1).getItemMeta(); // clever hack } + System.out.println(item.getItemMeta() instanceof SkullMeta); + if (!materialMatcher.matches(item.getType())) return false; else if (!amountMatcher.matches(item.getAmount())) @@ -177,6 +204,8 @@ else if (!enchantmentMatcherHeldAll.matches(castOrNull(meta), false)) return false; else if (enchantmentMatcherHeldNone.matches(castOrNull(meta), false)) return false; + else if (!skullMatches(meta)) + return false; return true; } @@ -188,6 +217,16 @@ private Map castOrNull(ItemMeta itemMeta) { return result; } + private boolean skullMatches(ItemMeta meta) { + UUID uuid; + if (!(meta instanceof SkullMeta) || !((SkullMeta) meta).hasOwner()) + uuid = new UUID(0, 0); + else + uuid = ((SkullMeta) meta).getOwningPlayer().getUniqueId(); + + return skullMatchers.stream().anyMatch((matcher) -> matcher.matches(uuid)); + } + /** * Removes amount items that match this ItemExpression from tne inventory. * @@ -423,6 +462,14 @@ public void setDurability(AmountMatcher durabilityMatcher) { this.durabilityMatcher = durabilityMatcher; } + public List skullMatchers = Collections.singletonList(new AnyUUID()); + + public void setSkullMatchers(List matchers) { + if (matchers == null || matchers.isEmpty()) + return; + skullMatchers = matchers; + } + public class EnchantmentSetMatcher { public EnchantmentSetMatcher(List enchantmentMatchers) { this.enchantmentMatchers = enchantmentMatchers; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java new file mode 100644 index 00000000..d5dfe5b1 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; + +import java.util.UUID; + +public class AnyUUID implements UUIDMatcher { + @Override + public boolean matches(UUID uuid) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java new file mode 100644 index 00000000..2f36822f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java @@ -0,0 +1,16 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; + +import java.util.UUID; + +public class ExactlyUUID implements UUIDMatcher { + public ExactlyUUID(UUID uuid) { + this.uuid = uuid; + } + + public UUID uuid; + + @Override + public boolean matches(UUID uuid) { + return this.uuid.equals(uuid); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java new file mode 100644 index 00000000..b37597a4 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java @@ -0,0 +1,23 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +import java.util.UUID; + +public class PlayerNameUUID implements UUIDMatcher { + public PlayerNameUUID(String name) { + this.name = name; + } + + public String name; + + @Override + public boolean matches(UUID uuid) { + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + if (player.getName() != null) + return player.getName().equals(name); + else + return false; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java new file mode 100644 index 00000000..e750066f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java @@ -0,0 +1,7 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; + +import java.util.UUID; + +public interface UUIDMatcher { + boolean matches(UUID uuid); +} From ed0bf5e75f7d32cbc1813ad0da20d4aeb5f622cb Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 23 Feb 2019 16:12:50 -0800 Subject: [PATCH 039/108] Bump version Not that it's done, but I want to start using the ItemExpression API in civspellapi. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 142db421..b0ae9097 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ vg.civcraft.mc.civmodcore CivModCore - 1.7.0 + 1.8.0 CivModCore https://github.com/DevotedMC/CivModCore/ From fbd9e5a5b8f29cd297a510430b78965fcb393144 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 23 Feb 2019 21:17:50 -0800 Subject: [PATCH 040/108] Add a constructor for ItemExpression to match exactly an ItemStack It also can act like ItemStack.isSimilar(). --- .../itemExpression/ItemExpression.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 8f56453f..07710654 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -19,6 +19,7 @@ import java.util.*; import java.util.concurrent.ThreadLocalRandom; import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * A unified syntax for matching any ItemStack for things like the material, amount, lore contents, and more. @@ -43,6 +44,63 @@ public ItemExpression(ConfigurationSection configurationSection) { parseConfig(configurationSection); } + /** + * Creates an ItemExpression that matches exactly the passed ItemStack, and no other item. + * + * Note that because of how ItemExpression is implemented, if ItemExpression does not support matching an element + * of an item, this will accept any item with that element. For example, if ItemExpression did not support + * matching the player on a player skull (it supports it), this constructor would return an ItemExpression + * that matched any player head even when passed a player head with a specific name. + * @param item The ItemStack that this ItemExpression would exactly match. + */ + public ItemExpression(ItemStack item) { + this(item, false); + } + + /** + * Creates an ItemExpression that matches exactly the passed ItemStack, or acts equilivent to ItemStack.isSimilar(). + * + * See also ItemExpression(ItemStack). + * @param item The item that this ItemExpression would match. + * @param acceptSimilar If this ItemExpression should act similar to ItemStack.isSimilar(). + */ + public ItemExpression(ItemStack item, boolean acceptSimilar) { + setMaterial(new ExactlyMaterial(item.getType())); + if (acceptSimilar) + setAmount(new AnyAmount()); + else + setAmount(new ExactlyAmount(item.getAmount())); + setDurability(new ExactlyAmount(item.getDurability())); + if (item.hasItemMeta() && item.getItemMeta().hasLore()) + setLore(new ExactlyLore(item.getItemMeta().getLore())); + else + setLore(new ExactlyLore(new ArrayList<>())); + if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) + setName(new ExactlyName(item.getItemMeta().getDisplayName())); + else + setName(new VanillaName()); + if (item.hasItemMeta() && item.getItemMeta().hasEnchants()) + setEnchantmentAll(exactlyEnchantments(item.getEnchantments())); + else + setEnchantmentAll(new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment()))); + if (item.getItemMeta() instanceof EnchantmentStorageMeta) + setEnchantmentHeldAll(exactlyEnchantments(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants())); + else + setEnchantmentHeldAll(new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment()))); + if (item.getItemMeta() instanceof SkullMeta) + setSkullMatchers(Collections.singletonList(new ExactlyUUID(((SkullMeta) item.getItemMeta()).getOwningPlayer().getUniqueId()))); + else + setSkullMatchers(Collections.singletonList(new ExactlyUUID(new UUID(0, 0)))); + } + + private EnchantmentSetMatcher exactlyEnchantments(Map enchantments) { + return new EnchantmentSetMatcher(enchantments.entrySet().stream().map((kv) -> { + Enchantment enchantment = kv.getKey(); + int level = kv.getValue(); + return new ExactlyEnchantment(enchantment, new ExactlyAmount(level)); + }).collect(Collectors.toList())); + } + /** * Mutate this ItemExpression, overriding the existing options set for this with the options given in the * ConfigurationSection. From db12a76be3e41b0b3836c277505d42e1b6bf72d1 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 23 Feb 2019 21:50:28 -0800 Subject: [PATCH 041/108] Remove minor debug statement --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 07710654..d04f2afa 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -236,8 +236,6 @@ public boolean matches(ItemStack item) { meta = new ItemStack(Material.IRON_AXE, 1).getItemMeta(); // clever hack } - System.out.println(item.getItemMeta() instanceof SkullMeta); - if (!materialMatcher.matches(item.getType())) return false; else if (!amountMatcher.matches(item.getAmount())) From 4f4d397a8f4224f020deb4f09a82a0f055d4d71e Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 24 Feb 2019 21:58:36 -0800 Subject: [PATCH 042/108] Refactor ItemExpression to use less boilerplate Instead of a bunch of individual fields for each property of the item to be checked, there is now a set of ItemMatchers, where ItemExpression.matches(ItemStack) will return false if any one of the ItemMatchers return false. This design is much more extendable, since it avoids the boolean hell the previous design suffered from. One downside of this design is that the .yaml config format doesn't at all reflect the API, and making the config format reflect the API would make the config format nearly unusable. Another downside is that stages of matching are not automatically tested on every single item, however this is more of an advantage because not every stage possible is ran on every item. --- .../itemExpression/ItemExpression.java | 388 +++++------------- .../itemExpression/ItemMatcher.java | 14 + .../amount/ItemAmountMatcher.java | 20 + .../amount/ItemDurabilityMatcher.java | 26 ++ .../enchantment/AnyEnchantment.java | 13 - .../enchantment/EnchantmentsSource.java | 18 + .../enchantment/ItemEnchantmentsMatcher.java | 70 ++++ .../ItemExactlyEnchantmentsMatcher.java | 46 +++ .../enchantment/ItemZeroEnchantsMatcher.java | 50 +++ .../enchantment/NoEnchantment.java | 13 - .../itemExpression/lore/AnyLore.java | 13 - .../itemExpression/lore/ItemLoreMatcher.java | 20 + .../itemExpression/material/AnyMaterial.java | 13 - .../material/ItemMaterialMatcher.java | 20 + .../itemExpression/misc/ItemSkullMatcher.java | 33 ++ .../misc/ItemUnbreakableMatcher.java | 22 + .../itemExpression/name/AnyName.java | 11 - .../itemExpression/name/ItemNameMatcher.java | 25 ++ .../itemExpression/uuid/AnyUUID.java | 10 - 19 files changed, 459 insertions(+), 366 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index d04f2afa..220cab19 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -6,14 +6,16 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemUnbreakableMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemSkullMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.*; import java.util.*; @@ -21,6 +23,10 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.HELD; +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.ITEM; +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.ItemEnchantmentsMatcher.Mode.*; + /** * A unified syntax for matching any ItemStack for things like the material, amount, lore contents, and more. * @@ -65,40 +71,47 @@ public ItemExpression(ItemStack item) { * @param acceptSimilar If this ItemExpression should act similar to ItemStack.isSimilar(). */ public ItemExpression(ItemStack item, boolean acceptSimilar) { - setMaterial(new ExactlyMaterial(item.getType())); - if (acceptSimilar) - setAmount(new AnyAmount()); - else - setAmount(new ExactlyAmount(item.getAmount())); - setDurability(new ExactlyAmount(item.getDurability())); - if (item.hasItemMeta() && item.getItemMeta().hasLore()) - setLore(new ExactlyLore(item.getItemMeta().getLore())); - else - setLore(new ExactlyLore(new ArrayList<>())); - if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) - setName(new ExactlyName(item.getItemMeta().getDisplayName())); - else - setName(new VanillaName()); - if (item.hasItemMeta() && item.getItemMeta().hasEnchants()) - setEnchantmentAll(exactlyEnchantments(item.getEnchantments())); + // material + addMatcher(new ItemMaterialMatcher(new ExactlyMaterial(item.getType()))); + + // amount + if (!acceptSimilar) + addMatcher(new ItemAmountMatcher(new ExactlyAmount(item.getAmount()))); + + // stop here if there isn't any itemmeta, so not every other matcher needs to check + if (!item.hasItemMeta()) + return; + + // durability + if (item.getItemMeta() instanceof Damageable) + addMatcher(new ItemDurabilityMatcher(new ExactlyAmount(((Damageable) item.getItemMeta()).getDamage()))); + + // lore + addMatcher(new ItemLoreMatcher(new ExactlyLore(item.getItemMeta().getLore()))); + + // name + if (item.getItemMeta().hasDisplayName()) + addMatcher(new ItemNameMatcher(new ExactlyName(item.getItemMeta().getDisplayName()))); else - setEnchantmentAll(new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment()))); + addMatcher(new ItemNameMatcher(new VanillaName())); + + // enchantments + addMatcher(new ItemExactlyEnchantmentsMatcher(item.getEnchantments(), ITEM)); + + // enchantments held like an enchanted book if (item.getItemMeta() instanceof EnchantmentStorageMeta) - setEnchantmentHeldAll(exactlyEnchantments(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants())); + addMatcher(new ItemExactlyEnchantmentsMatcher(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), HELD)); else - setEnchantmentHeldAll(new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment()))); - if (item.getItemMeta() instanceof SkullMeta) - setSkullMatchers(Collections.singletonList(new ExactlyUUID(((SkullMeta) item.getItemMeta()).getOwningPlayer().getUniqueId()))); - else - setSkullMatchers(Collections.singletonList(new ExactlyUUID(new UUID(0, 0)))); - } + addMatcher(new ItemZeroEnchantsMatcher(HELD)); + + // skulls + if (item.getItemMeta() instanceof SkullMeta && ((SkullMeta) item.getItemMeta()).hasOwner()) + addMatcher(new ItemSkullMatcher(Collections.singletonList(new ExactlyUUID(((SkullMeta) item.getItemMeta()).getOwningPlayer().getUniqueId())))); + else if (item.getItemMeta() instanceof SkullMeta && !((SkullMeta) item.getItemMeta()).hasOwner()) + addMatcher(new ItemSkullMatcher(Collections.singletonList(new ExactlyUUID(new UUID(0, 0))))); - private EnchantmentSetMatcher exactlyEnchantments(Map enchantments) { - return new EnchantmentSetMatcher(enchantments.entrySet().stream().map((kv) -> { - Enchantment enchantment = kv.getKey(); - int level = kv.getValue(); - return new ExactlyEnchantment(enchantment, new ExactlyAmount(level)); - }).collect(Collectors.toList())); + // unbreakable + addMatcher(new ItemUnbreakableMatcher(item.getItemMeta().isUnbreakable())); } /** @@ -107,23 +120,18 @@ private EnchantmentSetMatcher exactlyEnchantments(Map ench * @param config The config that options will be taken from. */ public void parseConfig(ConfigurationSection config) { - setMaterial(parseMaterial(config, "material")); - setAmount(parseAmount(config, "amount")); - setDurability(parseAmount(config, "durability")); - setLore(parseLore(config, "lore")); - setName(parseName(config, "name")); - setEnchantmentAny(parseEnchantment(config, "enchantmentsAny")); - setEnchantmentAll(parseEnchantment(config, "enchantmentsAll")); - setEnchantmentNone(parseEnchantment(config, "enchantmentsNone")); - setEnchantmentHeldAny(parseEnchantment(config, "enchantmentsHeldAny")); - setEnchantmentHeldAll(parseEnchantment(config, "enchantmentsHeldAll")); - setEnchantmentHeldNone(parseEnchantment(config, "enchantmentsHeldNone")); - setSkullMatchers(parseSkull(config, "skull")); - - if (config.contains("unbreakable")) - unbreakable = config.getBoolean("unbreakable"); - else - unbreakable = null; + addMatcher(new ItemMaterialMatcher(parseMaterial(config, "material"))); + addMatcher(new ItemAmountMatcher(parseAmount(config, "amound"))); + addMatcher(new ItemDurabilityMatcher(parseAmount(config, "durability"))); + addMatcher(new ItemLoreMatcher(parseLore(config, "lore"))); + addMatcher(new ItemNameMatcher(parseName(config, "name"))); + addMatcher(parseEnchantment(config, "enchantmentsAny", ANY, ITEM)); + addMatcher(parseEnchantment(config, "enchantmentsAll", ALL, ITEM)); + addMatcher(parseEnchantment(config, "enchantmentsNone", NONE, ITEM)); + addMatcher(parseEnchantment(config, "enchantmentsHeldAny", ANY, HELD)); + addMatcher(parseEnchantment(config, "enchantmentsHeldAll", ALL, HELD)); + addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); + addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); } /** @@ -184,7 +192,9 @@ else if (config.contains(path)) return null; } - private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, String path) { + private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, String path, + ItemEnchantmentsMatcher.Mode mode, + EnchantmentsSource source) { ConfigurationSection enchantments = config.getConfigurationSection(path); if (enchantments == null) return null; @@ -196,7 +206,7 @@ private EnchantmentSetMatcher parseEnchantment(ConfigurationSection config, Stri parseAmount(config, path + "." + enchantName))); } - return new EnchantmentSetMatcher(enchantmentMatcher); + return new ItemEnchantmentsMatcher(enchantmentMatcher, mode, source); } private List parseSkull(ConfigurationSection config, String path) { @@ -229,58 +239,7 @@ private List parseSkull(ConfigurationSection config, String path) { * @return If the given item matches. */ public boolean matches(ItemStack item) { - ItemMeta meta; - if (item.hasItemMeta()) { - meta = item.getItemMeta(); - } else { - meta = new ItemStack(Material.IRON_AXE, 1).getItemMeta(); // clever hack - } - - if (!materialMatcher.matches(item.getType())) - return false; - else if (!amountMatcher.matches(item.getAmount())) - return false; - else if (!durabilityMatcher.matches(item.getDurability())) - return false; - else if (!loreMatcher.matches(meta.getLore())) - return false; - else if (!nameMatcher.matches(meta.getDisplayName())) - return false; - else if (!enchantmentMatcherAny.matches(item.getEnchantments(), true)) - return false; - else if (!enchantmentMatcherAll.matches(item.getEnchantments(), false)) - return false; - else if (enchantmentMatcherNone.matches(item.getEnchantments(), false)) - return false; - else if (unbreakable != null && meta.isUnbreakable() != unbreakable) - return false; - else if (!enchantmentMatcherHeldAny.matches(castOrNull(meta), true)) - return false; - else if (!enchantmentMatcherHeldAll.matches(castOrNull(meta), false)) - return false; - else if (enchantmentMatcherHeldNone.matches(castOrNull(meta), false)) - return false; - else if (!skullMatches(meta)) - return false; - return true; - } - - private Map castOrNull(ItemMeta itemMeta) { - Map result = (itemMeta instanceof EnchantmentStorageMeta) ? - ((EnchantmentStorageMeta) itemMeta).getStoredEnchants() : null; - if (result == null) - result = new HashMap<>(); - return result; - } - - private boolean skullMatches(ItemMeta meta) { - UUID uuid; - if (!(meta instanceof SkullMeta) || !((SkullMeta) meta).hasOwner()) - uuid = new UUID(0, 0); - else - uuid = ((SkullMeta) meta).getOwningPlayer().getUniqueId(); - - return skullMatchers.stream().anyMatch((matcher) -> matcher.matches(uuid)); + return matchers.stream().allMatch((matcher) -> matcher.matches(item)); } /** @@ -293,10 +252,12 @@ private boolean skullMatches(ItemMeta meta) { * @return If there were enough items to remove. If this is false, no items have been removed from the inventory. */ public boolean removeFromInventory(Inventory inventory, int amount) { - // store the amount matcher, because it'll mess with things later + // store the amount matchers, because it'll mess with things later // for exacple, what happens when amount=1 was passed into this function but amount: 64 is in the config? - AmountMatcher amountMatcher1 = getAmount(); - setAmount(new AnyAmount()); + List amountMatchers = matchers.stream().filter((m) -> m instanceof ItemAmountMatcher).collect(Collectors.toList()); + for (ItemMatcher m : amountMatchers) { + matchers.remove(m); + } try { int runningAmount = amount; @@ -338,8 +299,8 @@ public boolean removeFromInventory(Inventory inventory, int amount) { return false; } } finally { - // restore the amount matcher now we're done - setAmount(amountMatcher1); + // restore the amount matchers now we're done + amountMatchers.forEach(this::addMatcher); } } @@ -356,6 +317,21 @@ public boolean removeFromInventory(Inventory inventory, int amount) { */ public boolean removeFromInventory(Inventory inventory, boolean random) { int amount; + List amountMatchers = matchers.stream() + .filter((m) -> m instanceof ItemAmountMatcher) + .map((m) -> (ItemAmountMatcher) m) + .collect(Collectors.toList()); + + AmountMatcher amountMatcher; + if (amountMatchers.size() > 1) + throw new IllegalStateException("Can't infer the amount from an ItemExpression with multiple " + + "ItemAmountMatchers."); + else if (amountMatchers.size() == 1) + amountMatcher = amountMatchers.get(0).matcher; + else { + amountMatcher = new AnyAmount(); + } + if (amountMatcher instanceof ExactlyAmount) { amount = ((ExactlyAmount) amountMatcher).amount; } else if (amountMatcher instanceof AnyAmount) { @@ -376,193 +352,19 @@ public boolean removeFromInventory(Inventory inventory, boolean random) { } /** - * null if matches unbreakable == true and unbreakable == false + * Add a property of the item to be checked, using an ItemMatcher. + * @param matcher The ItemMatcher to be added to the list that will be checked aganst each item inside + * ItemExpression.matches(ItemStack). If this is null, this function will do nothing. */ - public Boolean unbreakable = null; - - private MaterialMatcher materialMatcher = new AnyMaterial(); - - public MaterialMatcher getMaterial() { - return materialMatcher; - } - - public void setMaterial(MaterialMatcher materialMatcher) { - if (materialMatcher == null) - return; - this.materialMatcher = materialMatcher; + public void addMatcher(ItemMatcher matcher) { + if (matcher != null) + matchers.add(matcher); } - private AmountMatcher amountMatcher = new AnyAmount(); - - public AmountMatcher getAmount() { - return amountMatcher; - } - - public void setAmount(AmountMatcher amountMatcher) { - if (amountMatcher == null) - return; - this.amountMatcher = amountMatcher; - } - - private LoreMatcher loreMatcher = new AnyLore(); - - public LoreMatcher getLore() { - return loreMatcher; - } - - public void setLore(LoreMatcher loreMatcher) { - if (loreMatcher == null) - return; - this.loreMatcher = loreMatcher; - } - - private NameMatcher nameMatcher = new AnyName(); - - public NameMatcher getName() { - return nameMatcher; - } - - public void setName(NameMatcher nameMatcher) { - if (nameMatcher == null) - return; - this.nameMatcher = nameMatcher; - } - - private EnchantmentSetMatcher enchantmentMatcherAny = - new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); - - public EnchantmentSetMatcher getEnchantmentAny() { - return enchantmentMatcherAny; - } - - public void setEnchantmentAny(EnchantmentSetMatcher enchantmentMatcher) { - if (enchantmentMatcher == null) - return; - this.enchantmentMatcherAny = enchantmentMatcher; - } - - private EnchantmentSetMatcher enchantmentMatcherAll = - new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); - - public EnchantmentSetMatcher getEnchantmentAll() { - return enchantmentMatcherAll; - } - - public void setEnchantmentAll(EnchantmentSetMatcher enchantmentMatcherAll) { - if (enchantmentMatcherAll == null) - return; - this.enchantmentMatcherAll = enchantmentMatcherAll; - } - - private EnchantmentSetMatcher enchantmentMatcherNone = - new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment())); - - public EnchantmentSetMatcher getEnchantmentNone() { - return enchantmentMatcherNone; - } - - public void setEnchantmentNone(EnchantmentSetMatcher getEnchantmentMatcherNone) { - if (getEnchantmentMatcherNone == null) - return; - this.enchantmentMatcherNone = getEnchantmentMatcherNone; - } - - public EnchantmentSetMatcher getEnchantmentHeldAny() { - return enchantmentMatcherHeldAny; - } - - public void setEnchantmentHeldAny(EnchantmentSetMatcher enchantmentMatcherHeldAny) { - if (enchantmentMatcherHeldAny == null) - return; - this.enchantmentMatcherHeldAny = enchantmentMatcherHeldAny; - } - - public EnchantmentSetMatcher getEnchantmentHeldAll() { - return enchantmentMatcherHeldAll; - } - - public void setEnchantmentHeldAll(EnchantmentSetMatcher enchantmentMatcherHeldAll) { - if (enchantmentMatcherHeldAll == null) - return; - this.enchantmentMatcherHeldAll = enchantmentMatcherHeldAll; - } - - public EnchantmentSetMatcher getEnchantmentHeldNone() { - return enchantmentMatcherHeldNone; - } - - public void setEnchantmentHeldNone(EnchantmentSetMatcher enchantmentMatcherHeldNone) { - if (enchantmentMatcherHeldNone == null) - return; - this.enchantmentMatcherHeldNone = enchantmentMatcherHeldNone; - } - - private EnchantmentSetMatcher enchantmentMatcherHeldAny = - new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); - - private EnchantmentSetMatcher enchantmentMatcherHeldAll = - new EnchantmentSetMatcher(Collections.singletonList(new AnyEnchantment())); - - private EnchantmentSetMatcher enchantmentMatcherHeldNone = - new EnchantmentSetMatcher(Collections.singletonList(new NoEnchantment())); - - private AmountMatcher durabilityMatcher = new AnyAmount(); - - public AmountMatcher getDurability() { - return durabilityMatcher; - } - - public void setDurability(AmountMatcher durabilityMatcher) { - if (durabilityMatcher == null) - return; - this.durabilityMatcher = durabilityMatcher; - } - - public List skullMatchers = Collections.singletonList(new AnyUUID()); - - public void setSkullMatchers(List matchers) { - if (matchers == null || matchers.isEmpty()) - return; - skullMatchers = matchers; - } - - public class EnchantmentSetMatcher { - public EnchantmentSetMatcher(List enchantmentMatchers) { - this.enchantmentMatchers = enchantmentMatchers; - } - - public List enchantmentMatchers; - - public boolean matches(Map enchantments, boolean isAny) { - if (matchesAny() && enchantments.size() == 0) - return true; - - for (EnchantmentMatcher matcher : enchantmentMatchers) { - boolean matchedOne = false; - - for (Map.Entry entry : enchantments.entrySet()) { - Enchantment enchantment = entry.getKey(); - int level = entry.getValue(); - - if (matcher.matches(enchantment, level)) { - matchedOne = true; - if (isAny) - return true; - } - } - - if (!isAny && !matchedOne) - return false; - } - - if (!isAny) - return true; - else - return false; - } - - public boolean matchesAny() { - return enchantmentMatchers.size() == 1 && enchantmentMatchers.get(0) instanceof AnyEnchantment; - } - } + /** + * All of the matchers in this set must return true in order for this ItemExpression to match a given item. + * + * This is the only data structure holding ItemMatchers in this ItemExpression, so it is fine to mutate this field. + */ + public HashSet matchers = new HashSet<>(); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java new file mode 100644 index 00000000..4ca31def --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java @@ -0,0 +1,14 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; + +import org.bukkit.inventory.ItemStack; + +/** + * Represents a single property of an item that should be checked. + * + * If any one of these reject an item by returning false, ItemExpression.matches(ItemStack) will return false. + * + * @author Ameliorate + */ +public interface ItemMatcher { + boolean matches(ItemStack item); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java new file mode 100644 index 00000000..68f16f3f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java @@ -0,0 +1,20 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemAmountMatcher implements ItemMatcher { + public ItemAmountMatcher(AmountMatcher matcher) { + this.matcher = matcher; + } + + public AmountMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + return matcher.matches(item.getAmount()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java new file mode 100644 index 00000000..21413c43 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java @@ -0,0 +1,26 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemDurabilityMatcher implements ItemMatcher { + public ItemDurabilityMatcher(AmountMatcher matcher) { + this.matcher = matcher; + } + + public AmountMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + int durability; + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof Damageable)) + durability = -1; + else + durability = ((Damageable) item.getItemMeta()).getDamage(); + return matcher.matches(durability); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java deleted file mode 100644 index 3e239065..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java +++ /dev/null @@ -1,13 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; - -import org.bukkit.enchantments.Enchantment; - -/** - * @author Ameliorate - */ -public class AnyEnchantment implements EnchantmentMatcher { - @Override - public boolean matches(Enchantment enchantment, int level) { - return true; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java new file mode 100644 index 00000000..714cebc2 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java @@ -0,0 +1,18 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +/** + * Represents the different holders of enchantments an item can have. + * + * @author Ameliorate + */ +public enum EnchantmentsSource { + /** + * The normal enchantments on the item that take effect. For example a diamond sword with Sharpness 5. + */ + ITEM, + + /** + * For example from the enchantments held inside an enchanted book + */ + HELD, +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java new file mode 100644 index 00000000..1da6a9db --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java @@ -0,0 +1,70 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * @author Ameliorate + */ +public class ItemEnchantmentsMatcher implements ItemMatcher { + public enum Mode { + ANY, + ALL, + NONE, + } + + public ItemEnchantmentsMatcher(List enchantmentMatchers, Mode mode, EnchantmentsSource source) { + this.enchantmentMatchers = enchantmentMatchers; + this.mode = mode; + this.source = source; + } + + public List enchantmentMatchers; + public Mode mode; + public EnchantmentsSource source; + + @Override + public boolean matches(ItemStack item) { + switch (source) { + case ITEM: + return matches(item.getEnchantments()); + case HELD: + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + return false; + return matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants()); + } + throw new AssertionError("not reachable"); + // see the below function for the coy remarks + } + + public boolean matches(Map enchantments) { + Stream enchantmentMatcherStream = enchantmentMatchers.stream(); + Predicate predicate = (enchantmentMatcher) -> enchantments.entrySet().stream().anyMatch((e) -> { + Enchantment enchantment = e.getKey(); + int level = e.getValue(); + return enchantmentMatcher.matches(enchantment, level); + }); + + switch (mode) { + // Normally there'd be a break statement after each of the return's, but java complains because the break's + // are technically unreachable. + case ANY: + return enchantmentMatcherStream.anyMatch(predicate); + case ALL: + return enchantmentMatcherStream.allMatch(predicate); + case NONE: + return enchantmentMatcherStream.noneMatch(predicate); + } + + throw new AssertionError("not reachable"); + // naturally, it complains here because it can't figure out that the switch above always returns, so we don't + // need a return statement here. + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java new file mode 100644 index 00000000..2e7dd184 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java @@ -0,0 +1,46 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.Collections; +import java.util.Map; + +/** + * Returns true when the item has exactly the list of enchantments, no fewer and no more. + * + * This is unlike ItemEnchantmentsMatcher with a bunch of ExactlyEnchantment's and mode: ALL, because + * that will accept an item with extra enchantments. This will deny items with extra enchantments. + * + * @author Ameliorate + */ +public class ItemExactlyEnchantmentsMatcher implements ItemMatcher { + public ItemExactlyEnchantmentsMatcher(Map enchantments, + EnchantmentsSource source) { + this.enchantments = enchantments; + this.source = source; + } + + public Map enchantments; + public EnchantmentsSource source; + + @Override + public boolean matches(ItemStack item) { + Map itemEnchantments; + switch (source) { + case ITEM: + itemEnchantments = item.getEnchantments(); + break; + case HELD: + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + itemEnchantments = Collections.emptyMap(); + else + itemEnchantments = ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(); + break; + } + + return item.getEnchantments().equals(enchantments); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java new file mode 100644 index 00000000..74039fde --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java @@ -0,0 +1,50 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.Collections; +import java.util.Map; + +/** + * Returns false if the item has any enchantments in the specified field. + * + * @author Ameliorate + */ +public class ItemZeroEnchantsMatcher implements ItemMatcher { + /** + * Defaults the source to EnchantmentSource.ITEM. + */ + public ItemZeroEnchantsMatcher() { + this(EnchantmentsSource.ITEM); + } + + public ItemZeroEnchantsMatcher(EnchantmentsSource source) { + this.source = source; + } + + public EnchantmentsSource source; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta()) + return true; + + Map enchantments = Collections.emptyMap(); + switch (source) { + case ITEM: + enchantments = item.getEnchantments(); + break; + case HELD: + if (!(item.getItemMeta() instanceof EnchantmentStorageMeta)) + enchantments = Collections.emptyMap(); + else + enchantments = ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(); + break; + } + + return enchantments.isEmpty(); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java deleted file mode 100644 index 24ff0c10..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/NoEnchantment.java +++ /dev/null @@ -1,13 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; - -import org.bukkit.enchantments.Enchantment; - -/** - * @author Ameliorate - */ -public class NoEnchantment implements EnchantmentMatcher { - @Override - public boolean matches(Enchantment enchantment, int level) { - return false; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java deleted file mode 100644 index 879b4e45..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/AnyLore.java +++ /dev/null @@ -1,13 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; - -import java.util.List; - -/** - * @author Ameliorate - */ -public class AnyLore implements LoreMatcher { - @Override - public boolean matches(List lore) { - return true; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java new file mode 100644 index 00000000..b16d8ff8 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java @@ -0,0 +1,20 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemLoreMatcher implements ItemMatcher { + public ItemLoreMatcher(LoreMatcher matcher) { + this.matcher = matcher; + } + + public LoreMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + return item.hasItemMeta() && matcher.matches(item.getItemMeta().getLore()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java deleted file mode 100644 index 013824cd..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/AnyMaterial.java +++ /dev/null @@ -1,13 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; - -import org.bukkit.Material; - -/** - * @author Ameliorate - */ -public class AnyMaterial implements MaterialMatcher { - @Override - public boolean matches(Material material) { - return true; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java new file mode 100644 index 00000000..4b2606a5 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java @@ -0,0 +1,20 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemMaterialMatcher implements ItemMatcher { + public ItemMaterialMatcher(MaterialMatcher matcher) { + this.matcher = matcher; + } + + public MaterialMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + return matcher.matches(item.getType()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java new file mode 100644 index 00000000..a40c6b5a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java @@ -0,0 +1,33 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.UUIDMatcher; + +import java.util.List; +import java.util.UUID; + +/** + * @author Ameliorate + */ +public class ItemSkullMatcher implements ItemMatcher { + public ItemSkullMatcher(List ownerMatcher) { + this.ownerMatcher = ownerMatcher; + } + + public List ownerMatcher; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof SkullMeta)) + return false; + UUID owner; + SkullMeta meta = (SkullMeta) item.getItemMeta(); + if (!meta.hasOwner()) + owner = new UUID(0, 0); + else + owner = meta.getOwningPlayer().getUniqueId(); + return ownerMatcher.stream().anyMatch((matcher) -> matcher.matches(owner)); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java new file mode 100644 index 00000000..0036fe5d --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java @@ -0,0 +1,22 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemUnbreakableMatcher implements ItemMatcher { + public ItemUnbreakableMatcher(boolean unbreakable) { + this.unbreakable = unbreakable; + } + + boolean unbreakable; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta()) + return false; + return item.getItemMeta().isUnbreakable() == unbreakable; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java deleted file mode 100644 index 771308c0..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java +++ /dev/null @@ -1,11 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; - -/** - * @author Ameliorate - */ -public class AnyName implements NameMatcher { - @Override - public boolean matches(String name) { - return true; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java new file mode 100644 index 00000000..e5f50416 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemNameMatcher implements ItemMatcher { + public ItemNameMatcher(NameMatcher matcher) { + this.matcher = matcher; + } + + public NameMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + String name; + if (!item.hasItemMeta() || !item.getItemMeta().hasDisplayName()) + name = ""; + else + name = item.getItemMeta().getDisplayName(); + return matcher.matches(name); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java deleted file mode 100644 index d5dfe5b1..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java +++ /dev/null @@ -1,10 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; - -import java.util.UUID; - -public class AnyUUID implements UUIDMatcher { - @Override - public boolean matches(UUID uuid) { - return true; - } -} From 6e42ffbce2800b5c3672767f9b42403665afa6d2 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 25 Feb 2019 17:25:53 -0800 Subject: [PATCH 043/108] Add some documentation to stuff I guess I wrote this last night when I wanted to document all the classes but now I don't want to document all the classes. --- .../itemHandling/itemExpression/amount/AmountMatcher.java | 3 ++- .../itemHandling/itemExpression/amount/AnyAmount.java | 2 ++ .../itemHandling/itemExpression/amount/ExactlyAmount.java | 2 ++ .../itemHandling/itemExpression/amount/RangeAmount.java | 8 ++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index 94bae9e0..e3d0d1f8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -3,7 +3,8 @@ /** * @author Ameliorate * - * Also used to match the level on an enchantment. + * In addition to the amount of items in an ItemStack, these are also used for the durability of an item, and + * the level of an enchantment. */ public interface AmountMatcher { boolean matches(int amount); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java index dd239e89..eb88a30f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; /** + * Accepts any amount. + * * @author Ameliorate */ public class AnyAmount implements AmountMatcher { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java index 6db4d00a..2d8440ae 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; /** + * Accepts an amount exactly equal to the amount passed in. + * * @author Ameliorate */ public class ExactlyAmount implements AmountMatcher { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java index 32f3d2fd..fcf0237d 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java @@ -1,9 +1,17 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; /** + * Accepts an amount between high and low. Also allows selecting if the range should include high and low. + * * @author Ameliorate */ public class RangeAmount implements AmountMatcher { + /** + * @param low The lowest number that this range should accept. + * @param high The highest number that this range should accpet. + * @param lowInclusive If this range should accept values equal to low. + * @param highInclusive If this range should accept values equal to high. + */ public RangeAmount(int low, int high, boolean lowInclusive, boolean highInclusive) { set(low, high); this.highInclusive = highInclusive; From 2e465f00975af30dfc80014635b354c9ddded013 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 25 Feb 2019 19:38:32 -0800 Subject: [PATCH 044/108] Fix a NPE in ExactlyLore when creating an exact ItemExpression Fixes both the entire class of errors in ExactlyLore and the specific error in new ItemExpression(ItemStack). --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 3 ++- .../itemHandling/itemExpression/lore/ExactlyLore.java | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 220cab19..516cdb7b 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -87,7 +87,8 @@ public ItemExpression(ItemStack item, boolean acceptSimilar) { addMatcher(new ItemDurabilityMatcher(new ExactlyAmount(((Damageable) item.getItemMeta()).getDamage()))); // lore - addMatcher(new ItemLoreMatcher(new ExactlyLore(item.getItemMeta().getLore()))); + addMatcher(new ItemLoreMatcher(new ExactlyLore(item.getItemMeta().hasLore() ? + item.getItemMeta().getLore() : Collections.emptyList()))); // name if (item.getItemMeta().hasDisplayName()) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java index 5e27465f..508ad8e4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; +import java.util.Collections; import java.util.List; /** @@ -7,6 +8,8 @@ */ public class ExactlyLore implements LoreMatcher { public ExactlyLore(List lore) { + if (lore == null) + lore = Collections.emptyList(); this.lore = lore; } From a998749dfb58ad044076be7b511e652a8481b642 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 25 Feb 2019 19:51:27 -0800 Subject: [PATCH 045/108] Fix a class of errors with implementors of ItemMatcher Multiple ItemMatchers would return false if !item.hasItemMeta(), which is often incorrect. This is replaced with checking if the item does not have an ItemMeta, and using a "empty" value if it does not have one --- .../enchantment/ItemEnchantmentsMatcher.java | 3 +++ .../itemExpression/lore/ItemLoreMatcher.java | 11 ++++++++++- .../itemExpression/misc/ItemUnbreakableMatcher.java | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java index 1da6a9db..5a50a448 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java @@ -21,6 +21,9 @@ public enum Mode { } public ItemEnchantmentsMatcher(List enchantmentMatchers, Mode mode, EnchantmentsSource source) { + if (enchantmentMatchers.isEmpty()) + throw new IllegalArgumentException("enchanmentMatchers can not be empty. If an empty enchantmentMatchers " + + "was allowed, it would cause many subtle logic errors."); this.enchantmentMatchers = enchantmentMatchers; this.mode = mode; this.source = source; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java index b16d8ff8..2e66b3ef 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java @@ -3,6 +3,9 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Collections; +import java.util.List; + /** * @author Ameliorate */ @@ -15,6 +18,12 @@ public ItemLoreMatcher(LoreMatcher matcher) { @Override public boolean matches(ItemStack item) { - return item.hasItemMeta() && matcher.matches(item.getItemMeta().getLore()); + List itemLore; + if (!item.hasItemMeta() || !item.getItemMeta().hasLore()) + itemLore = Collections.emptyList(); + else + itemLore = item.getItemMeta().getLore(); + + return matcher.matches(itemLore); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java index 0036fe5d..61349063 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java @@ -15,7 +15,8 @@ public ItemUnbreakableMatcher(boolean unbreakable) { @Override public boolean matches(ItemStack item) { - if (!item.hasItemMeta()) + if (!item.hasItemMeta() && unbreakable) + // an item without metadata can not be unbreakable return false; return item.getItemMeta().isUnbreakable() == unbreakable; } From 36528a3494bc52b3452f9347bdc843cf99779110 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 17:50:09 -0800 Subject: [PATCH 046/108] Add a function to remove from the main hand or off hand Also abstract some stuff into their own functions to support the new feature --- .../itemExpression/ItemExpression.java | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 516cdb7b..e719a8c3 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -6,6 +6,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.SkullMeta; @@ -253,6 +254,17 @@ public boolean matches(ItemStack item) { * @return If there were enough items to remove. If this is false, no items have been removed from the inventory. */ public boolean removeFromInventory(Inventory inventory, int amount) { + ItemStack[] contents = inventory.getStorageContents(); + + ItemStack[] result = removeFromItemArray(contents, amount); + if (result == null) + return false; + + inventory.setStorageContents(result); + return true; + } + + private ItemStack[] removeFromItemArray(ItemStack[] contents, int amount) { // store the amount matchers, because it'll mess with things later // for exacple, what happens when amount=1 was passed into this function but amount: 64 is in the config? List amountMatchers = matchers.stream().filter((m) -> m instanceof ItemAmountMatcher).collect(Collectors.toList()); @@ -268,7 +280,6 @@ public boolean removeFromInventory(Inventory inventory, int amount) { infinite = true; } - ItemStack[] contents = inventory.getStorageContents(); contents = Arrays.stream(contents).map(item -> item != null ? item.clone() : null).toArray(ItemStack[]::new); for (ItemStack item : contents) { if (item == null) @@ -290,14 +301,13 @@ public boolean removeFromInventory(Inventory inventory, int amount) { } if (runningAmount == 0 || infinite) { - inventory.setStorageContents(contents); - return true; + return contents; } else if (runningAmount < 0) { // big trouble, this isn't supposed to happen throw new AssertionError("runningAmount is less than 0, there's a bug somewhere. runningAmount: " + runningAmount); } else { // items remaining - return false; + return null; } } finally { // restore the amount matchers now we're done @@ -317,7 +327,15 @@ public boolean removeFromInventory(Inventory inventory, int amount) { * @return If there were enough items to remove. If this is false, no items have been removed from the inventory. */ public boolean removeFromInventory(Inventory inventory, boolean random) { - int amount; + return removeFromInventory(inventory, getAmount(random)); + } + + /** + * Abstraction for the algorithm defined in removeFromInventory's javadoc. + * @param random To select a random number within amount. This only applies if amount is a range. + * @return The amount field of the config format. This is extracted from the structure of this ItemStack, not the config. + */ + private int getAmount(boolean random) { List amountMatchers = matchers.stream() .filter((m) -> m instanceof ItemAmountMatcher) .map((m) -> (ItemAmountMatcher) m) @@ -334,22 +352,55 @@ else if (amountMatchers.size() == 1) } if (amountMatcher instanceof ExactlyAmount) { - amount = ((ExactlyAmount) amountMatcher).amount; + return ((ExactlyAmount) amountMatcher).amount; } else if (amountMatcher instanceof AnyAmount) { - amount = -1; + return -1; } else if (amountMatcher instanceof RangeAmount && !random) { RangeAmount rangeAmount = (RangeAmount) amountMatcher; - amount = rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : 1); + return rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : 1); } else if (amountMatcher instanceof RangeAmount && random) { RangeAmount rangeAmount = (RangeAmount) amountMatcher; - amount = ThreadLocalRandom.current() + return ThreadLocalRandom.current() .nextInt(rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : -1), rangeAmount.getHigh() + (rangeAmount.highInclusive ? 1 : 0)); } else { throw new IllegalArgumentException("removeFromInventory(Inventory, boolean) does not work with custom AmountMatchers"); } + } + + /** + * Removes amount items that match this ItemExpression from the main hand or the off hand, prefeing the main hand. + * @param inventory The player's inventory to remove the items from. + * @param amount The number of items to remove. All ItemStacks that match will be removed if this is -1. + * @return If there were enough items to remove. If this is false, no items were removed. + */ + public boolean removeFromMainHandOrOffHand(PlayerInventory inventory, int amount) { + ItemStack[] items = new ItemStack[2]; + items[0] = inventory.getItemInMainHand(); + items[1] = inventory.getItemInOffHand(); + + ItemStack[] result = removeFromItemArray(items, amount); + if (result == null) + return false; + + inventory.setItemInMainHand(result[0]); + inventory.setItemInOffHand(result[1]); + return true; + } - return removeFromInventory(inventory, amount); + /** + * Removes the items that match this ItemExpression from either the main hand or the oof hand of the player. + * The amount to remove is infered from the amount of this ItemExpression. + * + * If amount is `any`, all items that match this ItemExpression will be removed. + * If amount is a range and random is true, a random number of items within the range will be removed. + * If amount is a range and random is false, the lower bound of the range will be used. + * @param inventory The player inventory to remove the items from. + * @param random To select a random number within amount. This only applies if amount is a range. + * @return If there were enough items to remove. If this is false, no items have been removed from the inventory. + */ + public boolean removeFromMainHandOrOffHand(PlayerInventory inventory, boolean random) { + return removeFromMainHandOrOffHand(inventory, getAmount(random)); } /** From c4ae41c2faec202aa98960ea5f53dcb9bce16116 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 18:01:05 -0800 Subject: [PATCH 047/108] Revert changes to pom.xml --- pom.xml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b0ae9097..e7647401 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ vg.civcraft.mc.civmodcore CivModCore - 1.8.0 + 1.7.0 CivModCore https://github.com/DevotedMC/CivModCore/ @@ -105,4 +105,14 @@ + + + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.4 + + + From 0d96b1789c8834f518fa0cd92d21f9b85d4e7b45 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 18:18:16 -0800 Subject: [PATCH 048/108] s/amound/amount in ItemExpression config parsing I accidentally when doing the big refactor --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index e719a8c3..a47cea21 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -123,7 +123,7 @@ else if (item.getItemMeta() instanceof SkullMeta && !((SkullMeta) item.getItemMe */ public void parseConfig(ConfigurationSection config) { addMatcher(new ItemMaterialMatcher(parseMaterial(config, "material"))); - addMatcher(new ItemAmountMatcher(parseAmount(config, "amound"))); + addMatcher(new ItemAmountMatcher(parseAmount(config, "amount"))); addMatcher(new ItemDurabilityMatcher(parseAmount(config, "durability"))); addMatcher(new ItemLoreMatcher(parseLore(config, "lore"))); addMatcher(new ItemNameMatcher(parseName(config, "name"))); From dbb1ba99944eb86f0e3a8a9d5ee5d64d5de73961 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 19:19:38 -0800 Subject: [PATCH 049/108] Add regex player skulls --- .../itemExpression/ItemExpression.java | 3 +++ .../uuid/PlayerNameRegexUUID.java | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index a47cea21..635d3f2f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -230,6 +230,9 @@ private List parseSkull(ConfigurationSection config, String path) { if (skull.contains("uuid")) matchers.add(new ExactlyUUID(UUID.fromString(skull.getString("name")))); + if (skull.contains("regex")) + matchers.add(new PlayerNameRegexUUID(Pattern.compile(skull.getString("regex")))); + return matchers; } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java new file mode 100644 index 00000000..9554307a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; + +import java.util.UUID; +import java.util.regex.Pattern; + +public class PlayerNameRegexUUID implements UUIDMatcher { + public PlayerNameRegexUUID(Pattern pattern) { + this.pattern = pattern; + } + + public Pattern pattern; + + @Override + public boolean matches(UUID uuid) { + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + if (player.getName() != null) { + String name = player.getName(); + return pattern.matcher(name).matches(); + } else + return false; + } +} From 538c97a274ce4ef9dbfc1d7311fd6d08d58d270d Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 19:29:59 -0800 Subject: [PATCH 050/108] Add a few forgotten @author tags --- .../itemHandling/itemExpression/uuid/ExactlyUUID.java | 3 +++ .../itemExpression/uuid/PlayerNameRegexUUID.java | 3 +++ .../itemHandling/itemExpression/uuid/PlayerNameUUID.java | 3 +++ .../itemHandling/itemExpression/uuid/UUIDMatcher.java | 5 +++++ 4 files changed, 14 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java index 2f36822f..22ed1f36 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java @@ -2,6 +2,9 @@ import java.util.UUID; +/** + * @author Ameliorate + */ public class ExactlyUUID implements UUIDMatcher { public ExactlyUUID(UUID uuid) { this.uuid = uuid; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java index 9554307a..87886b66 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java @@ -6,6 +6,9 @@ import java.util.UUID; import java.util.regex.Pattern; +/** + * @author Ameliorate + */ public class PlayerNameRegexUUID implements UUIDMatcher { public PlayerNameRegexUUID(Pattern pattern) { this.pattern = pattern; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java index b37597a4..193e457b 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java @@ -5,6 +5,9 @@ import java.util.UUID; +/** + * @author Ameliorate + */ public class PlayerNameUUID implements UUIDMatcher { public PlayerNameUUID(String name) { this.name = name; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java index e750066f..2890f5d5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java @@ -2,6 +2,11 @@ import java.util.UUID; +/** + * @author Ameliorate + * + * These classes are generally used for matching player heads. + */ public interface UUIDMatcher { boolean matches(UUID uuid); } From e955865b44cb69b72677f8e008a406f92428c1c0 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 20:03:33 -0800 Subject: [PATCH 051/108] Fix ItemExactlyEnchantmentsMatcher ignoring held enchantments Also items with no enchantments and stuff --- .../enchantment/ItemExactlyEnchantmentsMatcher.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java index 2e7dd184..5ed2ed45 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java @@ -39,8 +39,10 @@ public boolean matches(ItemStack item) { else itemEnchantments = ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(); break; + default: + throw new AssertionError("not reachable"); } - return item.getEnchantments().equals(enchantments); + return itemEnchantments.equals(enchantments); } } From c37a0886ca2cbf5851b3399cdd739bf996e8d465 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 21:18:05 -0800 Subject: [PATCH 052/108] Add ItemFlag to the things that can be matched by ItemExpression --- .../itemExpression/ItemExpression.java | 32 +++++++++++++++++++ .../itemExpression/misc/ItemFlagMatcher.java | 28 ++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 635d3f2f..ba6c365c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -5,6 +5,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.Damageable; @@ -14,6 +15,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemFlagMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemUnbreakableMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemSkullMatcher; @@ -114,6 +116,18 @@ else if (item.getItemMeta() instanceof SkullMeta && !((SkullMeta) item.getItemMe // unbreakable addMatcher(new ItemUnbreakableMatcher(item.getItemMeta().isUnbreakable())); + + // flags + HashSet flagsNotSet = new HashSet<>(Arrays.asList(ItemFlag.values())); + + for (ItemFlag flag : item.getItemMeta().getItemFlags()) { + addMatcher(new ItemFlagMatcher(flag, true)); + flagsNotSet.remove(flag); + } + + for (ItemFlag flag : flagsNotSet) { + addMatcher(new ItemFlagMatcher(flag, false)); + } } /** @@ -134,6 +148,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseEnchantment(config, "enchantmentsHeldAll", ALL, HELD)); addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); + parseFlags(config, "flags").forEach(this::addMatcher); } /** @@ -236,6 +251,23 @@ private List parseSkull(ConfigurationSection config, String path) { return matchers; } + private List parseFlags(ConfigurationSection config, String path) { + List matchers = new ArrayList<>(); + + ConfigurationSection flags = config.getConfigurationSection(path); + if (flags == null) + return Collections.emptyList(); + + for (String flagKey : flags.getKeys(false)) { + ItemFlag flag = ItemFlag.valueOf(flagKey.toUpperCase()); + boolean setting = flags.getBoolean(flagKey); + + matchers.add(new ItemFlagMatcher(flag, setting)); + } + + return matchers; + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java new file mode 100644 index 00000000..b47b305b --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java @@ -0,0 +1,28 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +public class ItemFlagMatcher implements ItemMatcher { + public ItemFlagMatcher(ItemFlag flag, boolean setting) { + this.flag = flag; + this.setting = setting; + } + + public ItemFlag flag; + public boolean setting; + + @Override + public boolean matches(ItemStack item) { + boolean setting; + if (item.hasItemMeta()) { + setting = item.getItemMeta().hasItemFlag(flag); + } else { + setting = false; + // this is okay because all the flags default to false. + } + + return this.setting == setting; + } +} From 74fed799c0635824d4e471213b7d38001259e3d4 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 21:21:47 -0800 Subject: [PATCH 053/108] Add matching on unbreakable to the config The capability was there, I just forgot to expose it in the config interface. --- .../itemHandling/itemExpression/ItemExpression.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index ba6c365c..3120166e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -149,6 +149,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); parseFlags(config, "flags").forEach(this::addMatcher); + addMatcher(parseUnbreakable(config, "unbreakable")); } /** @@ -268,6 +269,13 @@ private List parseFlags(ConfigurationSection config, String pat return matchers; } + private ItemUnbreakableMatcher parseUnbreakable(ConfigurationSection config, String path) { + if (!config.contains(path)) + return null; + boolean unbreakable = config.getBoolean(path); + return new ItemUnbreakableMatcher(unbreakable); + } + /** * Runs this ItemExpression on a given ItemStack. * From 772905812ca058ecc0916fc7518f660a6e3191ea Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 27 Feb 2019 21:44:26 -0800 Subject: [PATCH 054/108] Document private ItemStack.removeFromItemArray(ItemStack[], int) --- .../itemHandling/itemExpression/ItemExpression.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 3120166e..7fff7193 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -307,6 +307,13 @@ public boolean removeFromInventory(Inventory inventory, int amount) { return true; } + /** + * Removes amount items that match this ItemExpression from contents, returning the modified version of contents. + * @param contents The list of items to be matched and possibly removed. This may contain nulls. + * The array and the ItemStacks inside will not be mutated. + * @param amount The number of items to remove. + * @return The new list of items will amount removed. If there were not enough items to remove, null will be returned. + */ private ItemStack[] removeFromItemArray(ItemStack[] contents, int amount) { // store the amount matchers, because it'll mess with things later // for exacple, what happens when amount=1 was passed into this function but amount: 64 is in the config? From 9e72d642e245b3d5e565be61a3dc230716f3e995 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 1 Mar 2019 13:27:27 -0800 Subject: [PATCH 055/108] Add matching over ItemMaps to ItemExpression --- .../mc/civmodcore/itemHandling/ItemMap.java | 53 ++++++++++++++++--- .../itemExpression/ItemExpression.java | 49 +++++++++++++++++ .../itemExpression/ItemMapMatcher.java | 8 +++ .../amount/ItemAmountMatcher.java | 9 +++- 4 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/ItemMap.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/ItemMap.java index 310d55d2..56993405 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/ItemMap.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/ItemMap.java @@ -1,13 +1,11 @@ package vg.civcraft.mc.civmodcore.itemHandling; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; +import java.util.function.Predicate; import java.util.logging.Logger; + +import com.google.common.collect.Lists; import net.minecraft.server.v1_13_R2.NBTTagCompound; import net.minecraft.server.v1_13_R2.NBTTagList; import org.bukkit.Bukkit; @@ -18,6 +16,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemExpression; /** * Allows the storage and comparison of itemstacks while ignoring their maximum possible stack sizes. This offers @@ -562,6 +561,48 @@ public boolean removeSafelyFrom(Inventory i) { return true; } + /** + * Matches a number of ItemExpression on this ItemMap, trying to match each ItemExpression to a ItemStack 1:1. + * + * This works similar to, but not exactly like ItemMap.getEntries().steam().allMatch(). + * + * For example, if this is an ItemMap of a diamond sword and a stack of dirt, passing this function a + * ItemExpression that matches any sword will return true, but passing it a collection of + * ItemExpressions [Matches diamond sword, Matches any sword] will return false, because it can't match each + * ItemExpression to an ItemStack. + * @param itemExpressions The collection of ItemExpression that will match over this ItemMap. + * @return true if all if all of the ItemExpressions matched an item in this ItemMap in a 1:1 fashion, otherwise false. + */ + public boolean itemExpressionsMatchItems(Collection itemExpressions) { + // clone so we can remove elements as needed. + ArrayList itemExpressions1 = new ArrayList<>(itemExpressions); + ItemMap clone = clone(); + + // The list is reversed so we can remove the current ItemExpression without shifting over the list. + for (ItemExpression e : Lists.reverse(itemExpressions1)) { + Predicate> iePredicate = e.getMatchesItemMapPredicate(clone); + boolean matched = false; + + for (Entry entry : clone.getEntrySet()) { + if (iePredicate.test(entry)) { + // Make sure that each ItemExpression can match one ItemStack, + // and that each ItemStack can only be matched by one ItemExpression + clone.removeItemStack(entry.getKey()); + itemExpressions1.remove(e); + matched = true; + break; + } + } + + if (!matched) { + // slight optimization to return early instead of needing to check every single ItemExpression + return false; + } + } + + return itemExpressions1.isEmpty(); + } + @Override public boolean equals(Object o) { if (o instanceof ItemMap) { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 7fff7193..8ae44eb5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -11,6 +11,7 @@ import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.SkullMeta; +import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; @@ -23,6 +24,7 @@ import java.util.*; import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -287,6 +289,53 @@ public boolean matches(ItemStack item) { return matchers.stream().allMatch((matcher) -> matcher.matches(item)); } + /** + * Returns a lambda with the ItemMap bound into its environment. This is an instance of currying in java. + * + * If you wanted to call this function directly you'd say `getMatchesItemMapPredicate(itemMap)(entry)`. + * + * This function is implemented in this way in order to be able to reuse the predicate inside multiple functions + * while still being able to have the ItemMap usable inside the lambda. + * + * This function is mostly used to implement ItemMap advanced matching. It is not recommended to be used. + * @param itemMap The curried ItemMap value + * @return The curried function. + */ + public Predicate> getMatchesItemMapPredicate(ItemMap itemMap) { + // currying in java 2019 + return (kv) -> { + ItemStack item = kv.getKey(); + //Integer amount = kv.getValue(); + return matchers.stream().allMatch((matcher) -> { + if (matcher instanceof ItemMapMatcher) { + return ((ItemMapMatcher) matcher).matches(itemMap, item); + } else { + return matcher.matches(item); + } + }); + }; + } + + /** + * Runs this ItemExpression on a given ItemMap, and returns true if the ItemExpression matched any one of the + * ItemStacks contained within the ItemMap. + * @param itemMap The ItemMap this ItemExpression will match over. + * @return If this ItemExpression matched at least one of the ItemStacks within the ItemMap. + */ + public boolean matchesAnyItemMap(ItemMap itemMap) { + return itemMap.getEntrySet().stream().anyMatch(getMatchesItemMapPredicate(itemMap)); + } + + /** + * Runs this ItemExpression on a given ItemMap, and returns true if the ItemExpression matched all of the + * ItemStacks contained within the ItemMap. + * @param itemMap The ItemMap this ItemExpression will match over. + * @return If this ItemExpression matched every one of the ItemStacks within the ItemMap. + */ + public boolean matchesAllItemMap(ItemMap itemMap) { + return itemMap.getEntrySet().stream().allMatch(getMatchesItemMapPredicate(itemMap)); + } + /** * Removes amount items that match this ItemExpression from tne inventory. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java new file mode 100644 index 00000000..1867288a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java @@ -0,0 +1,8 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; + +public interface ItemMapMatcher extends ItemMatcher { + boolean matches(ItemMap itemMap, ItemStack item); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java index 68f16f3f..01517e50 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java @@ -1,12 +1,14 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMapMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; /** * @author Ameliorate */ -public class ItemAmountMatcher implements ItemMatcher { +public class ItemAmountMatcher implements ItemMatcher, ItemMapMatcher { public ItemAmountMatcher(AmountMatcher matcher) { this.matcher = matcher; } @@ -17,4 +19,9 @@ public ItemAmountMatcher(AmountMatcher matcher) { public boolean matches(ItemStack item) { return matcher.matches(item.getAmount()); } + + @Override + public boolean matches(ItemMap itemMap, ItemStack item) { + return matcher.matches(itemMap.getAmount(item)); + } } From 359dd8326b98747db9274dd5db796414dedf42db Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 1 Mar 2019 13:28:08 -0800 Subject: [PATCH 056/108] Add a function to parse a List from a config To aid in the ItemMap API using a list of ItemExpressions. --- .../itemExpression/ItemExpression.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 8ae44eb5..55428dc7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -3,6 +3,7 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemFlag; @@ -168,6 +169,41 @@ public static ItemExpression getItemExpression(ConfigurationSection configuratio return new ItemExpression(configurationSection.getConfigurationSection(path)); } + public static List getItemExpressionList(ConfigurationSection config, String path) { + if (!config.contains(path)) + return Collections.emptyList(); + + List itemExpressionsConfig = getConfigList(config, path); + List itemExpressions = new ArrayList<>(); + + for (ConfigurationSection itemExConfig : itemExpressionsConfig) { + itemExpressions.add(new ItemExpression(itemExConfig)); + } + + return itemExpressions; + } + + @SuppressWarnings("unchecked") // fix your warnings, java + private static List getConfigList(ConfigurationSection config, String path) + { + if (!config.isList(path)) + return Collections.emptyList(); + + List list = new ArrayList<>(); + + for (Object object : config.getList(path)) { + if (object instanceof Map) { + MemoryConfiguration mc = new MemoryConfiguration(); + + mc.addDefaults((Map) object); + + list.add(mc); + } + } + + return list; + } + private MaterialMatcher parseMaterial(ConfigurationSection config, String path) { if (config.contains(path + ".regex")) return(new RegexMaterial(Pattern.compile(config.getString(path + ".regex")))); From 935349ba2b4453fe662f127cd9b21005c8ec853b Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 1 Mar 2019 13:52:09 -0800 Subject: [PATCH 057/108] Add matching by any enchantment of a specific level enchantmentsAll: any: any or a more reasonable example enchantmentsAll: any: 5 --- .../itemExpression/ItemExpression.java | 12 +++++++--- .../enchantment/AnyEnchantment.java | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 55428dc7..9c584157 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -257,9 +257,15 @@ private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, St ArrayList enchantmentMatcher = new ArrayList<>(); for (String enchantName : enchantments.getKeys(false)) { - enchantmentMatcher.add( - new ExactlyEnchantment(Enchantment.getByKey(NamespacedKey.minecraft(enchantName.toLowerCase())), - parseAmount(config, path + "." + enchantName))); + EnchantmentMatcher matcher; + AmountMatcher amountMatcher = parseAmount(config, path + "." + enchantName); + if (enchantName.equals("any")) { + matcher = new AnyEnchantment(amountMatcher); + } else { + matcher = new AnyEnchantment(amountMatcher); + } + + enchantmentMatcher.add(matcher); } return new ItemEnchantmentsMatcher(enchantmentMatcher, mode, source); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java new file mode 100644 index 00000000..6750130e --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java @@ -0,0 +1,22 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.enchantments.Enchantment; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * Matches any enchantment type, as long as the level matches the level matcher. + * + * @author Ameliorate + */ +public class AnyEnchantment implements EnchantmentMatcher { + public AnyEnchantment(AmountMatcher level) { + this.level = level; + } + + public AmountMatcher level; + + @Override + public boolean matches(Enchantment enchantment, int level) { + return this.level.matches(level); + } +} From 8a16e3e0be9b548e39578a9bbd5d492128754f87 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 1 Mar 2019 18:00:26 -0800 Subject: [PATCH 058/108] Better document getMatchesItemMapPredicate. --- .../itemHandling/itemExpression/ItemExpression.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 9c584157..dbcdc9b5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -334,6 +334,11 @@ public boolean matches(ItemStack item) { /** * Returns a lambda with the ItemMap bound into its environment. This is an instance of currying in java. * + * The lambda returned uses the Entry it is passed to match on the ItemStack key. If the matcher implements + * ItemMapMatcher, it'll use that interface instead of the normal ItemMatcher. The reason it used an Entry instead + * of directly the ItemStack contained within is that it's designed to be used to be used as + * ItemMap.getEntries().stream().anyMatch(getMatchesItemMapPredicate(ItemMap)). + * * If you wanted to call this function directly you'd say `getMatchesItemMapPredicate(itemMap)(entry)`. * * This function is implemented in this way in order to be able to reuse the predicate inside multiple functions From a2c045652125bb4034110094c6f2297c962fdd95 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 1 Mar 2019 20:06:24 -0800 Subject: [PATCH 059/108] Add matching over item held inventories Like shulker boxes. This is done using a list of ItemExpressions, using the ItemMap API that was added last (major) commit --- .../itemExpression/ItemExpression.java | 32 +++++++++++--- .../inventory/ItemEmptyInventoryMatcher.java | 16 +++++++ .../ItemExactlyInventoryMatcher.java | 44 +++++++++++++++++++ 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index dbcdc9b5..21df130f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,26 +1,26 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; import org.bukkit.Material; -import org.bukkit.NamespacedKey; +import org.bukkit.block.Container; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.BlockStateMeta; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.SkullMeta; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemEmptyInventoryMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemFlagMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemUnbreakableMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemSkullMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.*; import java.util.*; @@ -131,6 +131,19 @@ else if (item.getItemMeta() instanceof SkullMeta && !((SkullMeta) item.getItemMe for (ItemFlag flag : flagsNotSet) { addMatcher(new ItemFlagMatcher(flag, false)); } + + // inventory + Inventory itemInventory; + if (item.getItemMeta() instanceof BlockStateMeta && ((BlockStateMeta) item.getItemMeta()).hasBlockState() && + ((BlockStateMeta) item.getItemMeta()).getBlockState() instanceof Container) { + itemInventory = ((Container) ((BlockStateMeta) item.getItemMeta()).getBlockState()).getInventory(); + addMatcher(new ItemExactlyInventoryMatcher( + Arrays.stream(itemInventory.getContents()) + .map(ItemExpression::new) + .collect(Collectors.toList()))); + } else { + addMatcher(new ItemEmptyInventoryMatcher()); + } } /** @@ -153,6 +166,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); parseFlags(config, "flags").forEach(this::addMatcher); addMatcher(parseUnbreakable(config, "unbreakable")); + addMatcher(parseInventory(config, "inventory")); } /** @@ -320,6 +334,14 @@ private ItemUnbreakableMatcher parseUnbreakable(ConfigurationSection config, Str return new ItemUnbreakableMatcher(unbreakable); } + private ItemExactlyInventoryMatcher parseInventory(ConfigurationSection config, String path) { + List itemExpressions = getItemExpressionList(config, path); + if (itemExpressions.isEmpty()) + return null; + + return new ItemExactlyInventoryMatcher(itemExpressions); + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java new file mode 100644 index 00000000..22ef3e91 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java @@ -0,0 +1,16 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * Matches an item that has an empty inventory, or no inventory at all. + * + * @author Ameliorate + */ +public class ItemEmptyInventoryMatcher implements ItemMatcher { + @Override + public boolean matches(ItemStack item) { + return ItemExactlyInventoryMatcher.getItemHeldInventory(item).getTotalItemAmount() == 0; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java new file mode 100644 index 00000000..795d6c9d --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java @@ -0,0 +1,44 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory; + +import org.bukkit.block.Container; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; +import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemExpression; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; + +/** + * Matches an item if all of the ItemExpressions match the items within the inventory in a 1:1 fashion. + * + * See also ItemMap.itemExpressionsMatchItems(). + * + * @author Ameliorate + */ +public class ItemExactlyInventoryMatcher implements ItemMatcher { + public ItemExactlyInventoryMatcher(List itemExpressions) { + this.itemExpressions = itemExpressions; + } + + public List itemExpressions; + + @Override + public boolean matches(ItemStack item) { + return getItemHeldInventory(item).itemExpressionsMatchItems(itemExpressions); + } + + /** + * @param item The item to get the inventory of. + * @return An ItemMap of the item's inventory. + * If the item does not have an inventory or has an empty inventory, returns an empty ItemMap. + */ + public static ItemMap getItemHeldInventory(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BlockStateMeta) || + !((BlockStateMeta) item.getItemMeta()).hasBlockState() || + !(((BlockStateMeta) item.getItemMeta()).getBlockState() instanceof Container)) + return new ItemMap(); + else + return new ItemMap(((Container) ((BlockStateMeta) item.getItemMeta()).getBlockState()).getInventory()); + } +} From eb12f9219d0fa01d1a7ba2bbd9c68208cd7789b8 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 1 Mar 2019 21:55:30 -0800 Subject: [PATCH 060/108] Remove useless null check in RegexLore --- .../civmodcore/itemHandling/itemExpression/lore/RegexLore.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java index 8a8e89b8..b117db1b 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java @@ -15,8 +15,6 @@ public RegexLore(Pattern pattern) { @Override public boolean matches(List lore) { - if (lore == null) - return false; return pattern.matcher(String.join("\n", lore)).find(); } } From 6454e5c904c3b7ab2f9e1820f32a0d057e3a4061 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 3 Mar 2019 13:47:16 -0800 Subject: [PATCH 061/108] Add matching over a book's metadata The author, generation, and title. I'm not 100% sure on what I'll do for the pages, but I'll figure that one out later. --- .../itemExpression/ItemExpression.java | 61 +++++++++++++++++-- .../book/ItemBookAuthorMatcher.java | 27 ++++++++ .../book/ItemBookGenerationMatcher.java | 28 +++++++++ .../book/ItemBookNoGenerationMatcher.java | 17 ++++++ .../book/ItemBookTitleMatcher.java | 32 ++++++++++ .../misc/ItemMetaNotInstanceOfMatcher.java | 29 +++++++++ 6 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 21df130f..63107ff6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -8,12 +8,13 @@ import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; -import org.bukkit.inventory.meta.BlockStateMeta; -import org.bukkit.inventory.meta.Damageable; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.inventory.meta.*; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookAuthorMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookGenerationMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookNoGenerationMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookTitleMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemEmptyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemExactlyInventoryMatcher; @@ -144,6 +145,19 @@ else if (item.getItemMeta() instanceof SkullMeta && !((SkullMeta) item.getItemMe } else { addMatcher(new ItemEmptyInventoryMatcher()); } + + // books + if (item.getItemMeta() instanceof BookMeta) { + addMatcher(new ItemBookTitleMatcher(new ExactlyName(((BookMeta) item.getItemMeta()).getTitle()))); + addMatcher(new ItemBookAuthorMatcher(new ExactlyName(((BookMeta) item.getItemMeta()).getAuthor()))); + + if (((BookMeta) item.getItemMeta()).hasGeneration()) + addMatcher(new ItemBookGenerationMatcher(Collections.singletonList(((BookMeta) item.getItemMeta()).getGeneration()))); + else + addMatcher(new ItemBookNoGenerationMatcher()); + } else { + addMatcher(new ItemMetaNotInstanceOfMatcher(BookMeta.class)); + } } /** @@ -167,6 +181,7 @@ public void parseConfig(ConfigurationSection config) { parseFlags(config, "flags").forEach(this::addMatcher); addMatcher(parseUnbreakable(config, "unbreakable")); addMatcher(parseInventory(config, "inventory")); + parseBook(config, "book").forEach(this::addMatcher); } /** @@ -342,6 +357,44 @@ private ItemExactlyInventoryMatcher parseInventory(ConfigurationSection config, return new ItemExactlyInventoryMatcher(itemExpressions); } + private List parseBook(ConfigurationSection config, String path) { + if (!config.contains(path)) + return Collections.emptyList(); + + ConfigurationSection book = config.getConfigurationSection(path); + ArrayList matchers = new ArrayList<>(); + + // author + if (book.contains("author")) { + matchers.add(new ItemBookAuthorMatcher(parseName(book, "author"))); + } + + // generation + ArrayList generations = new ArrayList<>(); + + if (book.contains("generation") && !book.isList("generation")) { + BookMeta.Generation generation = BookMeta.Generation.valueOf(book.getString("generation").toUpperCase()); + generations.add(generation); + } else if (book.isList("generation")) { + for (String generationS : book.getStringList("generation")) { + BookMeta.Generation generation = BookMeta.Generation.valueOf(generationS.toUpperCase()); + generations.add(generation); + } + } + + matchers.add(new ItemBookGenerationMatcher(generations)); + + // title + if (book.contains("title")) { + matchers.add(new ItemBookTitleMatcher(parseName(book, "title"))); + } + + // pages + // TODO: Implement matching on the pages of a book + + return matchers; + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java new file mode 100644 index 00000000..5fa3a83a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java @@ -0,0 +1,27 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +/** + * @author Ameliorate + */ +public class ItemBookAuthorMatcher implements ItemMatcher { + public ItemBookAuthorMatcher(NameMatcher author) { + this.author = author; + } + + public NameMatcher author; + + @Override + public boolean matches(ItemStack item) { + String author = ""; + if (item.hasItemMeta() && item.getItemMeta() instanceof BookMeta && ((BookMeta) item.getItemMeta()).hasAuthor()) { + author = ((BookMeta) item.getItemMeta()).getAuthor(); + } + + return this.author.matches(author); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java new file mode 100644 index 00000000..3b2abcf3 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java @@ -0,0 +1,28 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemBookGenerationMatcher implements ItemMatcher { + public ItemBookGenerationMatcher(List generations) { + this.generations = generations; + } + + public List generations; + + @Override + public boolean matches(ItemStack item) { + BookMeta.Generation generation = BookMeta.Generation.ORIGINAL; + + if (item.hasItemMeta() && item.getItemMeta() instanceof BookMeta && ((BookMeta) item.getItemMeta()).hasGeneration()) + generation = ((BookMeta) item.getItemMeta()).getGeneration(); + + return generations.contains(generation); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java new file mode 100644 index 00000000..64fa155f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java @@ -0,0 +1,17 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemBookNoGenerationMatcher implements ItemMatcher { + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta)) + return false; + return ((BookMeta) item.getItemMeta()).hasGeneration(); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java new file mode 100644 index 00000000..65f3a882 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java @@ -0,0 +1,32 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +/** + * @author Ameliorate + */ +public class ItemBookTitleMatcher implements ItemMatcher { + public ItemBookTitleMatcher(NameMatcher title) { + this.title = title; + } + + public NameMatcher title; + + @Override + public boolean matches(ItemStack item) { + String title = ""; + + if (item.hasItemMeta()) { + if (item.getItemMeta() instanceof BookMeta && ((BookMeta) item.getItemMeta()).hasTitle()) { + title = ((BookMeta) item.getItemMeta()).getTitle(); + } else { + title = item.getItemMeta().getDisplayName(); // is this a good? + } + } + + return this.title.matches(title); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java new file mode 100644 index 00000000..f887b8bd --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java @@ -0,0 +1,29 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * Matches an item if the item's meta is not of a specific type. + * + * For example, if itemMetaInterface=EnchantmentStorageMeta, this will match any item whose ItemMeta does not implement + * EnchantmentStorageMeta. + * + * @author Ameliorate + */ +public class ItemMetaNotInstanceOfMatcher implements ItemMatcher { + public ItemMetaNotInstanceOfMatcher(Class itemMetaInterface) { + this.itemMetaInterface = itemMetaInterface; + } + + public Class itemMetaInterface; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta()) + // an item with no meta has a meta that does not implement itemMetaInterface. + return true; + return !itemMetaInterface.isAssignableFrom(item.getItemMeta().getClass()); + } +} From 785874416de9247e35547d1799ea5471e596f1b6 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 3 Mar 2019 14:10:59 -0800 Subject: [PATCH 062/108] Refractor exact ItemExpressions Now it just stores the ItemStack to be matched. The API is also now exposed from the config. A few classes that were only used from the exactly API is also removed. --- .../itemExpression/ItemExpression.java | 103 +++--------------- .../book/ItemBookNoGenerationMatcher.java | 17 --- .../misc/ItemExactlyStackMatcher.java | 26 +++++ .../misc/ItemMetaNotInstanceOfMatcher.java | 29 ----- 4 files changed, 41 insertions(+), 134 deletions(-) delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 63107ff6..d28d2a8f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,7 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; import org.bukkit.Material; -import org.bukkit.block.Container; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.inventory.Inventory; @@ -13,10 +12,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookAuthorMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookGenerationMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookNoGenerationMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookTitleMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemEmptyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; @@ -60,10 +57,9 @@ public ItemExpression(ConfigurationSection configurationSection) { /** * Creates an ItemExpression that matches exactly the passed ItemStack, and no other item. * - * Note that because of how ItemExpression is implemented, if ItemExpression does not support matching an element - * of an item, this will accept any item with that element. For example, if ItemExpression did not support - * matching the player on a player skull (it supports it), this constructor would return an ItemExpression - * that matched any player head even when passed a player head with a specific name. + * This constructor uses ItemStack.equals() directly, so this supports all aspects of an item, even those that are + * not supported by ItemExpression. + * * @param item The ItemStack that this ItemExpression would exactly match. */ public ItemExpression(ItemStack item) { @@ -75,89 +71,10 @@ public ItemExpression(ItemStack item) { * * See also ItemExpression(ItemStack). * @param item The item that this ItemExpression would match. - * @param acceptSimilar If this ItemExpression should act similar to ItemStack.isSimilar(). + * @param acceptSimilar If this ItemExpression should use ItemStack.isSimilar() instead of .equals(). */ public ItemExpression(ItemStack item, boolean acceptSimilar) { - // material - addMatcher(new ItemMaterialMatcher(new ExactlyMaterial(item.getType()))); - - // amount - if (!acceptSimilar) - addMatcher(new ItemAmountMatcher(new ExactlyAmount(item.getAmount()))); - - // stop here if there isn't any itemmeta, so not every other matcher needs to check - if (!item.hasItemMeta()) - return; - - // durability - if (item.getItemMeta() instanceof Damageable) - addMatcher(new ItemDurabilityMatcher(new ExactlyAmount(((Damageable) item.getItemMeta()).getDamage()))); - - // lore - addMatcher(new ItemLoreMatcher(new ExactlyLore(item.getItemMeta().hasLore() ? - item.getItemMeta().getLore() : Collections.emptyList()))); - - // name - if (item.getItemMeta().hasDisplayName()) - addMatcher(new ItemNameMatcher(new ExactlyName(item.getItemMeta().getDisplayName()))); - else - addMatcher(new ItemNameMatcher(new VanillaName())); - - // enchantments - addMatcher(new ItemExactlyEnchantmentsMatcher(item.getEnchantments(), ITEM)); - - // enchantments held like an enchanted book - if (item.getItemMeta() instanceof EnchantmentStorageMeta) - addMatcher(new ItemExactlyEnchantmentsMatcher(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(), HELD)); - else - addMatcher(new ItemZeroEnchantsMatcher(HELD)); - - // skulls - if (item.getItemMeta() instanceof SkullMeta && ((SkullMeta) item.getItemMeta()).hasOwner()) - addMatcher(new ItemSkullMatcher(Collections.singletonList(new ExactlyUUID(((SkullMeta) item.getItemMeta()).getOwningPlayer().getUniqueId())))); - else if (item.getItemMeta() instanceof SkullMeta && !((SkullMeta) item.getItemMeta()).hasOwner()) - addMatcher(new ItemSkullMatcher(Collections.singletonList(new ExactlyUUID(new UUID(0, 0))))); - - // unbreakable - addMatcher(new ItemUnbreakableMatcher(item.getItemMeta().isUnbreakable())); - - // flags - HashSet flagsNotSet = new HashSet<>(Arrays.asList(ItemFlag.values())); - - for (ItemFlag flag : item.getItemMeta().getItemFlags()) { - addMatcher(new ItemFlagMatcher(flag, true)); - flagsNotSet.remove(flag); - } - - for (ItemFlag flag : flagsNotSet) { - addMatcher(new ItemFlagMatcher(flag, false)); - } - - // inventory - Inventory itemInventory; - if (item.getItemMeta() instanceof BlockStateMeta && ((BlockStateMeta) item.getItemMeta()).hasBlockState() && - ((BlockStateMeta) item.getItemMeta()).getBlockState() instanceof Container) { - itemInventory = ((Container) ((BlockStateMeta) item.getItemMeta()).getBlockState()).getInventory(); - addMatcher(new ItemExactlyInventoryMatcher( - Arrays.stream(itemInventory.getContents()) - .map(ItemExpression::new) - .collect(Collectors.toList()))); - } else { - addMatcher(new ItemEmptyInventoryMatcher()); - } - - // books - if (item.getItemMeta() instanceof BookMeta) { - addMatcher(new ItemBookTitleMatcher(new ExactlyName(((BookMeta) item.getItemMeta()).getTitle()))); - addMatcher(new ItemBookAuthorMatcher(new ExactlyName(((BookMeta) item.getItemMeta()).getAuthor()))); - - if (((BookMeta) item.getItemMeta()).hasGeneration()) - addMatcher(new ItemBookGenerationMatcher(Collections.singletonList(((BookMeta) item.getItemMeta()).getGeneration()))); - else - addMatcher(new ItemBookNoGenerationMatcher()); - } else { - addMatcher(new ItemMetaNotInstanceOfMatcher(BookMeta.class)); - } + addMatcher(new ItemExactlyStackMatcher(item, acceptSimilar)); } /** @@ -182,6 +99,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseUnbreakable(config, "unbreakable")); addMatcher(parseInventory(config, "inventory")); parseBook(config, "book").forEach(this::addMatcher); + addMatcher(parseExactly(config, "exactly")); } /** @@ -395,6 +313,15 @@ private List parseBook(ConfigurationSection config, String path) { return matchers; } + private ItemExactlyStackMatcher parseExactly(ConfigurationSection config, String path) { + if (!config.contains(path)) + return null; + + boolean acceptBoolean = config.getBoolean(path + ".acceptSimilar"); + + return new ItemExactlyStackMatcher(config.getItemStack(path), acceptBoolean); + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java deleted file mode 100644 index 64fa155f..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookNoGenerationMatcher.java +++ /dev/null @@ -1,17 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; - -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BookMeta; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -/** - * @author Ameliorate - */ -public class ItemBookNoGenerationMatcher implements ItemMatcher { - @Override - public boolean matches(ItemStack item) { - if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta)) - return false; - return ((BookMeta) item.getItemMeta()).hasGeneration(); - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java new file mode 100644 index 00000000..ca1365d9 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java @@ -0,0 +1,26 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +public class ItemExactlyStackMatcher implements ItemMatcher { + public ItemExactlyStackMatcher(ItemStack itemStack) { + this(itemStack, false); + } + + public ItemExactlyStackMatcher(ItemStack itemStack, boolean acceptSimilar) { + this.itemStack = itemStack; + this.acceptSimilar = acceptSimilar; + } + + public ItemStack itemStack; + public boolean acceptSimilar; + + @Override + public boolean matches(ItemStack item) { + if (!acceptSimilar) + return itemStack.equals(item); + else + return itemStack.isSimilar(item); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java deleted file mode 100644 index f887b8bd..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMetaNotInstanceOfMatcher.java +++ /dev/null @@ -1,29 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; - -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -/** - * Matches an item if the item's meta is not of a specific type. - * - * For example, if itemMetaInterface=EnchantmentStorageMeta, this will match any item whose ItemMeta does not implement - * EnchantmentStorageMeta. - * - * @author Ameliorate - */ -public class ItemMetaNotInstanceOfMatcher implements ItemMatcher { - public ItemMetaNotInstanceOfMatcher(Class itemMetaInterface) { - this.itemMetaInterface = itemMetaInterface; - } - - public Class itemMetaInterface; - - @Override - public boolean matches(ItemStack item) { - if (!item.hasItemMeta()) - // an item with no meta has a meta that does not implement itemMetaInterface. - return true; - return !itemMetaInterface.isAssignableFrom(item.getItemMeta().getClass()); - } -} From a8d11a7159dae7c0e6c5ae61656e54119b2e29cf Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 3 Mar 2019 14:24:38 -0800 Subject: [PATCH 063/108] Refactor book generation matching Now it'll return false if it isn't a book with a generation --- .../itemExpression/book/ItemBookGenerationMatcher.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java index 3b2abcf3..8feade22 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java @@ -18,11 +18,10 @@ public ItemBookGenerationMatcher(List generations) { @Override public boolean matches(ItemStack item) { - BookMeta.Generation generation = BookMeta.Generation.ORIGINAL; + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta) || !((BookMeta) item.getItemMeta()).hasGeneration()) { + return false; + } - if (item.hasItemMeta() && item.getItemMeta() instanceof BookMeta && ((BookMeta) item.getItemMeta()).hasGeneration()) - generation = ((BookMeta) item.getItemMeta()).getGeneration(); - - return generations.contains(generation); + return generations.contains(((BookMeta) item.getItemMeta()).getGeneration()); } } From fabd4c1b53b308457df52e5014ebf628350c233e Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 3 Mar 2019 14:29:46 -0800 Subject: [PATCH 064/108] Continue removing unused classes after exactly ItemExpression refactor Also move ItemExactlyInventoryMatcher into misc because it was alone in inventory. --- .../itemExpression/ItemExpression.java | 2 +- .../ItemExactlyEnchantmentsMatcher.java | 48 ------------------ .../enchantment/ItemZeroEnchantsMatcher.java | 50 ------------------- .../inventory/ItemEmptyInventoryMatcher.java | 16 ------ .../ItemExactlyInventoryMatcher.java | 2 +- 5 files changed, 2 insertions(+), 116 deletions(-) delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java rename src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/{inventory => misc}/ItemExactlyInventoryMatcher.java (95%) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index d28d2a8f..5f6c28ff 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -14,7 +14,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookGenerationMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookTitleMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory.ItemExactlyInventoryMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java deleted file mode 100644 index 5ed2ed45..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemExactlyEnchantmentsMatcher.java +++ /dev/null @@ -1,48 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; - -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.Collections; -import java.util.Map; - -/** - * Returns true when the item has exactly the list of enchantments, no fewer and no more. - * - * This is unlike ItemEnchantmentsMatcher with a bunch of ExactlyEnchantment's and mode: ALL, because - * that will accept an item with extra enchantments. This will deny items with extra enchantments. - * - * @author Ameliorate - */ -public class ItemExactlyEnchantmentsMatcher implements ItemMatcher { - public ItemExactlyEnchantmentsMatcher(Map enchantments, - EnchantmentsSource source) { - this.enchantments = enchantments; - this.source = source; - } - - public Map enchantments; - public EnchantmentsSource source; - - @Override - public boolean matches(ItemStack item) { - Map itemEnchantments; - switch (source) { - case ITEM: - itemEnchantments = item.getEnchantments(); - break; - case HELD: - if (!item.hasItemMeta() || !(item.getItemMeta() instanceof EnchantmentStorageMeta)) - itemEnchantments = Collections.emptyMap(); - else - itemEnchantments = ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(); - break; - default: - throw new AssertionError("not reachable"); - } - - return itemEnchantments.equals(enchantments); - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java deleted file mode 100644 index 74039fde..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemZeroEnchantsMatcher.java +++ /dev/null @@ -1,50 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; - -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.Collections; -import java.util.Map; - -/** - * Returns false if the item has any enchantments in the specified field. - * - * @author Ameliorate - */ -public class ItemZeroEnchantsMatcher implements ItemMatcher { - /** - * Defaults the source to EnchantmentSource.ITEM. - */ - public ItemZeroEnchantsMatcher() { - this(EnchantmentsSource.ITEM); - } - - public ItemZeroEnchantsMatcher(EnchantmentsSource source) { - this.source = source; - } - - public EnchantmentsSource source; - - @Override - public boolean matches(ItemStack item) { - if (!item.hasItemMeta()) - return true; - - Map enchantments = Collections.emptyMap(); - switch (source) { - case ITEM: - enchantments = item.getEnchantments(); - break; - case HELD: - if (!(item.getItemMeta() instanceof EnchantmentStorageMeta)) - enchantments = Collections.emptyMap(); - else - enchantments = ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(); - break; - } - - return enchantments.isEmpty(); - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java deleted file mode 100644 index 22ef3e91..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemEmptyInventoryMatcher.java +++ /dev/null @@ -1,16 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory; - -import org.bukkit.inventory.ItemStack; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -/** - * Matches an item that has an empty inventory, or no inventory at all. - * - * @author Ameliorate - */ -public class ItemEmptyInventoryMatcher implements ItemMatcher { - @Override - public boolean matches(ItemStack item) { - return ItemExactlyInventoryMatcher.getItemHeldInventory(item).getTotalItemAmount() == 0; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java similarity index 95% rename from src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java rename to src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java index 795d6c9d..bccf92df 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/inventory/ItemExactlyInventoryMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java @@ -1,4 +1,4 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.inventory; +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; import org.bukkit.block.Container; import org.bukkit.inventory.ItemStack; From ebdaf150449d2fdbc64cabaab333d88df2cb70f3 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 4 Mar 2019 20:03:18 -0800 Subject: [PATCH 065/108] Remove some code that was only used by exactly ItemExpressions Now instead of matchers using the notion of a default value for items that do not have the property, they'll return false. --- .../itemExpression/amount/ItemDurabilityMatcher.java | 8 +++----- .../itemExpression/lore/ItemLoreMatcher.java | 10 ++-------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java index 21413c43..1cd6a378 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java @@ -16,11 +16,9 @@ public ItemDurabilityMatcher(AmountMatcher matcher) { @Override public boolean matches(ItemStack item) { - int durability; if (!item.hasItemMeta() || !(item.getItemMeta() instanceof Damageable)) - durability = -1; - else - durability = ((Damageable) item.getItemMeta()).getDamage(); - return matcher.matches(durability); + return false; + + return matcher.matches(((Damageable) item.getItemMeta()).getDamage()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java index 2e66b3ef..7049ea35 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java @@ -3,9 +3,6 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; -import java.util.Collections; -import java.util.List; - /** * @author Ameliorate */ @@ -18,12 +15,9 @@ public ItemLoreMatcher(LoreMatcher matcher) { @Override public boolean matches(ItemStack item) { - List itemLore; if (!item.hasItemMeta() || !item.getItemMeta().hasLore()) - itemLore = Collections.emptyList(); - else - itemLore = item.getItemMeta().getLore(); + return false; - return matcher.matches(itemLore); + return matcher.matches(item.getItemMeta().getLore()); } } From 873a765d996987ada1fc692a987b28f4d2671bbd Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 4 Mar 2019 20:05:44 -0800 Subject: [PATCH 066/108] Fix bug in ItemUnbreakableMatcher It'll now use a default value instead of the questionable logic used before. The default is a good thing because items without an itemmeta are always breakable. --- .../itemExpression/misc/ItemUnbreakableMatcher.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java index 61349063..366b23a0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java @@ -11,13 +11,14 @@ public ItemUnbreakableMatcher(boolean unbreakable) { this.unbreakable = unbreakable; } - boolean unbreakable; + public boolean unbreakable; @Override public boolean matches(ItemStack item) { - if (!item.hasItemMeta() && unbreakable) + boolean isUnbreakable = false; + if (item.hasItemMeta()) // an item without metadata can not be unbreakable - return false; - return item.getItemMeta().isUnbreakable() == unbreakable; + isUnbreakable = item.getItemMeta().isUnbreakable(); + return isUnbreakable == unbreakable; } } From 5e40eba919da8c3f52264d23699d71a053bba3e4 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 4 Mar 2019 21:59:31 -0800 Subject: [PATCH 067/108] Add matching over the pages of a book It does horrible clever things with unicode private areas in order to do regexes over the pages, but it's basically okay. --- .../itemExpression/ItemExpression.java | 14 ++++++--- .../itemExpression/book/BookPageMatcher.java | 15 ++++++++++ .../itemExpression/book/ExactlyBookPages.java | 19 ++++++++++++ .../book/ItemBookPagesMatcher.java | 30 +++++++++++++++++++ .../itemExpression/book/RegexBookPages.java | 28 +++++++++++++++++ 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 5f6c28ff..188ebe6f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -10,9 +10,7 @@ import org.bukkit.inventory.meta.*; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookAuthorMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookGenerationMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.ItemBookTitleMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; @@ -308,7 +306,15 @@ private List parseBook(ConfigurationSection config, String path) { } // pages - // TODO: Implement matching on the pages of a book + if (book.contains("pages.regex")) { + boolean isMultiline = book.getBoolean("pages.regexMultiline", true); + Pattern pattern = Pattern.compile(book.getString("pages.regex"),isMultiline ? Pattern.MULTILINE : 0); + + matchers.add(new ItemBookPagesMatcher(new RegexBookPages(pattern))); + } else if (book.isList("pages")) { + List pages = book.getStringList("pages"); + matchers.add(new ItemBookPagesMatcher(new ExactlyBookPages(pages))); + } return matchers; } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java new file mode 100644 index 00000000..c4715d54 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java @@ -0,0 +1,15 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import java.util.List; + +/** + * @author Ameliorate + */ +public interface BookPageMatcher { + /** + * @param pages A list of multi-line strings that represent the pages of a written book. Colours left intact in the + * section character format. + * @return If the pages matched. + */ + boolean matches(List pages); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java new file mode 100644 index 00000000..d39703df --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java @@ -0,0 +1,19 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ExactlyBookPages implements BookPageMatcher { + public ExactlyBookPages(List pages) { + this.pages = pages; + } + + public List pages; + + @Override + public boolean matches(List pages) { + return this.pages.equals(pages); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java new file mode 100644 index 00000000..fad303c2 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java @@ -0,0 +1,30 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.Collections; +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemBookPagesMatcher implements ItemMatcher { + public ItemBookPagesMatcher(BookPageMatcher matcher) { + this.matcher = matcher; + } + + public BookPageMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + List pages = Collections.emptyList(); + + if (item.hasItemMeta() && item.getItemMeta() instanceof BookMeta && ((BookMeta) item.getItemMeta()).hasPages()) { + pages = ((BookMeta) item.getItemMeta()).getPages(); + } + + return matcher.matches(pages); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java new file mode 100644 index 00000000..2fbb92a6 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java @@ -0,0 +1,28 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author Ameliorate + */ +public class RegexBookPages implements BookPageMatcher { + public RegexBookPages(Pattern regex) { + this.regex = regex; + } + + public Pattern regex; + + @Override + public boolean matches(List pages) { + StringBuilder pageBuilder = new StringBuilder(); + for (String page : pages) { + pageBuilder.append("\ueB0F"); + pageBuilder.append(page); + pageBuilder.append('\ueE0F'); + } + + String formattedPages = pageBuilder.toString(); + return regex.matcher(formattedPages).find(); + } +} From 96c30dbf2581598595041305652447ebf0508e22 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 4 Mar 2019 22:24:14 -0800 Subject: [PATCH 068/108] Add matching over the color of a shulkerbox --- .../itemExpression/ItemExpression.java | 18 ++++++++ .../misc/ItemShulkerBoxColorMatcher.java | 42 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 188ebe6f..100576b7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; +import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; @@ -98,6 +99,9 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseInventory(config, "inventory")); parseBook(config, "book").forEach(this::addMatcher); addMatcher(parseExactly(config, "exactly")); + addMatcher(parseShulkerBoxColor(config, "shulkerbox.color", false)); + addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorAny", false)); + addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorNone", true)); } /** @@ -328,6 +332,20 @@ private ItemExactlyStackMatcher parseExactly(ConfigurationSection config, String return new ItemExactlyStackMatcher(config.getItemStack(path), acceptBoolean); } + private ItemShulkerBoxColorMatcher parseShulkerBoxColor(ConfigurationSection config, String path, boolean notInList) { + if (!config.contains(path)) + return null; + + if (config.isList(path)) { + ArrayList colors = new ArrayList<>(); + config.getStringList(path).stream().map((c) -> DyeColor.valueOf(c.toUpperCase())).forEach(colors::add); + return new ItemShulkerBoxColorMatcher(colors, notInList); + } else { + return new ItemShulkerBoxColorMatcher( + Collections.singletonList(DyeColor.valueOf(config.getString(path).toUpperCase())), notInList); + } + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java new file mode 100644 index 00000000..9a58b0c0 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java @@ -0,0 +1,42 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.DyeColor; +import org.bukkit.block.ShulkerBox; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemShulkerBoxColorMatcher implements ItemMatcher { + public ItemShulkerBoxColorMatcher(List color, boolean notInList) { + this.color = color; + this.notInList = notInList; + } + + public ItemShulkerBoxColorMatcher(List color) { + this(color, false); + } + + public List color; + public boolean notInList; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BlockStateMeta) || + !((BlockStateMeta) item.getItemMeta()).hasBlockState() || + !(((BlockStateMeta) item.getItemMeta()).getBlockState() instanceof ShulkerBox)) + return false; + + DyeColor colour = ((ShulkerBox) ((BlockStateMeta) item.getItemMeta()).getBlockState()).getColor(); + + if (notInList) { + return !this.color.contains(colour); + } else { + return this.color.contains(colour); + } + } +} From 856901d49c01d4f305cb01f6349e70afa25695f9 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 4 Mar 2019 22:44:27 -0800 Subject: [PATCH 069/108] Add matching over knowlege books That wasn't as bad as I was expecting. --- .../itemExpression/ItemExpression.java | 9 ++++ .../misc/ItemKnowledgeBookMatcher.java | 45 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 100576b7..8cf09bad 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -102,6 +102,8 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseShulkerBoxColor(config, "shulkerbox.color", false)); addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorAny", false)); addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorNone", true)); + addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); + addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); } /** @@ -346,6 +348,13 @@ private ItemShulkerBoxColorMatcher parseShulkerBoxColor(ConfigurationSection con } } + private ItemKnowledgeBookMatcher parseKnowlegeBook(ConfigurationSection config, String path, boolean requireAll) { + if (!config.contains(path)) + return null; + + return new ItemKnowledgeBookMatcher(parseName(config, path), requireAll); + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java new file mode 100644 index 00000000..7b22fff2 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java @@ -0,0 +1,45 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.KnowledgeBookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Ameliorate + */ +public class ItemKnowledgeBookMatcher implements ItemMatcher { + public ItemKnowledgeBookMatcher(NameMatcher recipeMatcher, boolean requireAllMatch) { + this.recipeMatcher = recipeMatcher; + this.requireAllMatch = requireAllMatch; + } + + public ItemKnowledgeBookMatcher(NameMatcher recipeMatcher) { + this(recipeMatcher, false); + } + + public NameMatcher recipeMatcher; + public boolean requireAllMatch; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof KnowledgeBookMeta) || + !((KnowledgeBookMeta) item.getItemMeta()).hasRecipes()) + return false; + + List recipes = ((KnowledgeBookMeta) item.getItemMeta()).getRecipes().stream() + .map(NamespacedKey::toString).collect(Collectors.toList()); + + Stream recipesStream = recipes.stream(); + + if (requireAllMatch) + return recipesStream.allMatch(recipeMatcher::matches); + else + return recipesStream.anyMatch(recipeMatcher::matches); + } +} From 807c2b91096a2443a6a53660792f1d8fced8fd66 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 5 Mar 2019 17:20:51 -0800 Subject: [PATCH 070/108] Add matching over the custom effects of a potion Basically the same as enchantments. The base effect will be harder, though. --- .../itemExpression/ItemExpression.java | 46 +++++++++++++- .../enchantment/ItemEnchantmentsMatcher.java | 10 +-- .../itemExpression/misc/ListMatchingMode.java | 23 +++++++ .../potion/AnyPotionEffect.java | 24 +++++++ .../potion/ExactlyPotionEffect.java | 27 ++++++++ .../potion/ItemPotionEffectsMatcher.java | 62 +++++++++++++++++++ .../potion/PotionEffectMatcher.java | 10 +++ 7 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 8cf09bad..9026527c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -9,6 +9,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.*; +import org.bukkit.potion.PotionEffectType; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.*; @@ -18,6 +19,10 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.AnyPotionEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.ExactlyPotionEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.ItemPotionEffectsMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.PotionEffectMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.*; import java.util.*; @@ -28,7 +33,7 @@ import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.HELD; import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.ITEM; -import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.ItemEnchantmentsMatcher.Mode.*; +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode.*; /** * A unified syntax for matching any ItemStack for things like the material, amount, lore contents, and more. @@ -104,6 +109,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorNone", true)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); + parsePotion(config, "potion").forEach(this::addMatcher); } /** @@ -200,7 +206,7 @@ else if (config.contains(path)) } private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, String path, - ItemEnchantmentsMatcher.Mode mode, + ListMatchingMode mode, EnchantmentsSource source) { ConfigurationSection enchantments = config.getConfigurationSection(path); if (enchantments == null) @@ -355,6 +361,42 @@ private ItemKnowledgeBookMatcher parseKnowlegeBook(ConfigurationSection config, return new ItemKnowledgeBookMatcher(parseName(config, path), requireAll); } + private List parsePotion(ConfigurationSection config, String path) { + if (!config.contains(path)) + return Collections.emptyList(); + + ArrayList matchers = new ArrayList<>(); + + ConfigurationSection potion = config.getConfigurationSection(path); + + matchers.add(parsePotionEffects(potion, "customEffectsAny", ANY)); + matchers.add(parsePotionEffects(potion, "customEffectsAll", ALL)); + matchers.add(parsePotionEffects(potion, "customEffectsNone", NONE)); + + return matchers; + } + + private ItemPotionEffectsMatcher parsePotionEffects(ConfigurationSection config, String path, ListMatchingMode mode) { + if (!config.isList(path)) + return null; + + ArrayList matchers = new ArrayList<>(); + + for (ConfigurationSection effect : getConfigList(config, path)) { + String type = effect.getString("type"); + AmountMatcher level = parseAmount(effect, "level"); + AmountMatcher duration = parseAmount(effect, "durationTicks"); + + PotionEffectMatcher matcher = type.equals("any") ? + new AnyPotionEffect(level, duration) : + new ExactlyPotionEffect(PotionEffectType.getByName(type), level, duration); + + matchers.add(matcher); + } + + return new ItemPotionEffectsMatcher(matchers, mode); + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java index 5a50a448..09e9a631 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java @@ -4,6 +4,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; import java.util.List; import java.util.Map; @@ -14,13 +15,8 @@ * @author Ameliorate */ public class ItemEnchantmentsMatcher implements ItemMatcher { - public enum Mode { - ANY, - ALL, - NONE, - } - public ItemEnchantmentsMatcher(List enchantmentMatchers, Mode mode, EnchantmentsSource source) { + public ItemEnchantmentsMatcher(List enchantmentMatchers, ListMatchingMode mode, EnchantmentsSource source) { if (enchantmentMatchers.isEmpty()) throw new IllegalArgumentException("enchanmentMatchers can not be empty. If an empty enchantmentMatchers " + "was allowed, it would cause many subtle logic errors."); @@ -30,7 +26,7 @@ public ItemEnchantmentsMatcher(List enchantmentMatchers, Mod } public List enchantmentMatchers; - public Mode mode; + public ListMatchingMode mode; public EnchantmentsSource source; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java new file mode 100644 index 00000000..086b1ee2 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java @@ -0,0 +1,23 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +/** + * Represents the different ways of interpreting a list of things when comparing it to another list. + * + * @author Ameliorate + */ +public enum ListMatchingMode { + /** + * At least one element in the list must match an element in the other list. + */ + ANY, + + /** + * Every one of the elements in the list must match an element in the other list. + */ + ALL, + + /** + * No element in the list may match an element in the other list. + */ + NONE, +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java new file mode 100644 index 00000000..e67167ee --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; + +import org.bukkit.potion.PotionEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * Matches any potion type, as long as the level matches the level matcher. + * + * @author Ameliorate + */ +public class AnyPotionEffect implements PotionEffectMatcher { + public AnyPotionEffect(AmountMatcher level, AmountMatcher duration) { + this.level = level; + this.duration = duration; + } + + public AmountMatcher level; + public AmountMatcher duration; + + @Override + public boolean matches(PotionEffect effect) { + return level.matches(effect.getAmplifier()) && duration.matches(effect.getDuration()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java new file mode 100644 index 00000000..6ccf55de --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java @@ -0,0 +1,27 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; + +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ExactlyPotionEffect implements PotionEffectMatcher { + public ExactlyPotionEffect(PotionEffectType type, AmountMatcher level, AmountMatcher duration) { + this.type = type; + this.level = level; + this.duration = duration; + } + + public PotionEffectType type; + public AmountMatcher level; + public AmountMatcher duration; + + @Override + public boolean matches(PotionEffect effect) { + return type.equals(effect.getType()) && + level.matches(effect.getAmplifier()) && + duration.matches(effect.getDuration()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java new file mode 100644 index 00000000..1c6113bf --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java @@ -0,0 +1,62 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * @author Ameliorate + */ +public class ItemPotionEffectsMatcher implements ItemMatcher { + public ItemPotionEffectsMatcher(List potionMatchers, ListMatchingMode mode) { + if (potionMatchers.isEmpty()) + throw new IllegalArgumentException("potionMatchers can not be empty. If an empty potionMatchers " + + "was allowed, it would cause many subtle logic errors."); + this.potionMatchers = potionMatchers; + this.mode = mode; + } + + public List potionMatchers; + public ListMatchingMode mode; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof PotionMeta)) + return false; + + PotionMeta potion = (PotionMeta) item.getItemMeta(); + + List effects = new ArrayList<>(); + if (potion.hasCustomEffects()) + effects.addAll(potion.getCustomEffects()); + + return matches(effects); + } + + public boolean matches(List effects) { + Stream enchantmentMatcherStream = potionMatchers.stream(); + Predicate predicate = (potionMatcher) -> effects.stream().anyMatch(potionMatcher::matches); + + switch (mode) { + // Normally there'd be a break statement after each of the return's, but java complains because the break's + // are technically unreachable. + case ANY: + return enchantmentMatcherStream.anyMatch(predicate); + case ALL: + return enchantmentMatcherStream.allMatch(predicate); + case NONE: + return enchantmentMatcherStream.noneMatch(predicate); + } + + throw new AssertionError("not reachable"); + // naturally, it complains here because it can't figure out that the switch above always returns, so we don't + // need a return statement here. + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java new file mode 100644 index 00000000..016f4d23 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; + +import org.bukkit.potion.PotionEffect; + +/** + * @author Ameliorate + */ +public interface PotionEffectMatcher { + boolean matches(PotionEffect effect); +} From fc28fe9770ab40267a1fdff6c29c29a7a4f876c8 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 5 Mar 2019 18:02:54 -0800 Subject: [PATCH 071/108] Add matching over the base effect of a potion --- .../itemExpression/ItemExpression.java | 19 +++++-- .../potion/ItemPotionBaseEffectMatcher.java | 57 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 9026527c..1e74acbe 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -19,10 +19,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.AnyPotionEffect; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.ExactlyPotionEffect; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.ItemPotionEffectsMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.PotionEffectMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.*; import java.util.*; @@ -373,6 +370,20 @@ private List parsePotion(ConfigurationSection config, String path) matchers.add(parsePotionEffects(potion, "customEffectsAll", ALL)); matchers.add(parsePotionEffects(potion, "customEffectsNone", NONE)); + if (potion.contains("base")) { + ConfigurationSection base = potion.getConfigurationSection("base"); + + NameMatcher type; + Boolean isExtended = config.contains("extended") ? config.getBoolean("extended") : null; + Boolean isUpgraded = config.contains("upgraded") ? config.getBoolean("upgraded") : null; + + if (base.contains("type")) { + type = parseName(base, "type"); + matchers.add(new ItemPotionBaseEffectMatcher(type, + Optional.ofNullable(isExtended), Optional.ofNullable(isUpgraded))); + } + } + return matchers; } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java new file mode 100644 index 00000000..f412d0ec --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java @@ -0,0 +1,57 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionType; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +import java.util.Optional; + +/** + * Matches the "base" effect of a potion. + * + * A potion obtainable in vanilla survival singleplayer is represented by this class, storing only the type, + * and a boolean of if it's upgraded and if it's extended. + * + * Notably, this class as well as vanilla does not expose a duration. Instead the duration is calculated from the + * type and extended boolean. + * + * @author Ameliorate + */ +public class ItemPotionBaseEffectMatcher implements ItemMatcher { + public ItemPotionBaseEffectMatcher(NameMatcher type, Optional isExtended, Optional isUpgraded) { + this.type = type; + this.isExtended = isExtended; + this.isUpgraded = isUpgraded; + } + + public NameMatcher type; + public Optional isExtended; + public Optional isUpgraded; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof PotionMeta)) + return false; + + PotionData data = ((PotionMeta) item.getItemMeta()).getBasePotionData(); + + PotionType type = data.getType(); + boolean extended = data.isExtended(); + boolean upgraded = data.isUpgraded(); + + if (isExtended.isPresent()) { + if (extended != isExtended.get()) + return false; + } + + if (isUpgraded.isPresent()) { + if (upgraded != isUpgraded.get()) + return false; + } + + return this.type.matches(type.toString()); + } +} From 504f36d44fb3d9a8f0b24f07b2beb8fd4c3937eb Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 8 Mar 2019 15:25:17 -0800 Subject: [PATCH 072/108] Add matching over item attributes rip AmountMatcher being simple Overall the resulting code is simple, but it took tons of studying the minecraft wiki and spigot javadocs to come up with a (semi-)simple solution. --- .../itemExpression/ItemExpression.java | 61 ++++++++++--- .../itemExpression/amount/AmountMatcher.java | 6 +- .../itemExpression/amount/AnyAmount.java | 2 +- .../itemExpression/amount/ExactlyAmount.java | 6 +- .../itemExpression/amount/RangeAmount.java | 14 +-- .../misc/ItemAttributeMatcher.java | 90 +++++++++++++++++++ 6 files changed, 156 insertions(+), 23 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 1e74acbe..7d7f2843 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -4,10 +4,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.*; import org.bukkit.inventory.meta.*; import org.bukkit.potion.PotionEffectType; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; @@ -107,6 +104,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); parsePotion(config, "potion").forEach(this::addMatcher); + parseAllAttributes(config, "attributes").forEach(this::addMatcher); } /** @@ -169,14 +167,14 @@ else if (config.contains(path)) private AmountMatcher parseAmount(ConfigurationSection config, String path) { if (config.contains(path + ".range")) return(new RangeAmount( - config.getInt(path + ".range.low", 0), - config.getInt(path + ".range.high"), + config.getDouble(path + ".range.low", 0), + config.getDouble(path + ".range.high"), config.getBoolean(path + ".range.inclusiveLow", true), config.getBoolean(path + ".range.inclusiveHigh", true))); else if ("any".equals(config.getString(path))) return(new AnyAmount()); else if (config.contains(path)) - return(new ExactlyAmount(config.getInt(path))); + return(new ExactlyAmount(config.getDouble(path))); return null; } @@ -408,6 +406,47 @@ private ItemPotionEffectsMatcher parsePotionEffects(ConfigurationSection config, return new ItemPotionEffectsMatcher(matchers, mode); } + private List parseAllAttributes(ConfigurationSection config, String path) { + ArrayList matchers = new ArrayList<>(); + + for (ListMatchingMode mode : ListMatchingMode.values()) { + for (EquipmentSlot slot : EquipmentSlot.values()) { + String modeString = mode.toString().toLowerCase(); + + matchers.add(parseAttributes(config, path + "." + slot + "." + modeString, slot, mode)); + } + } + + for (ListMatchingMode mode : ListMatchingMode.values()) { + matchers.add(parseAttributes(config, path + ".any." + mode, null, mode)); + } + + return matchers; + } + + private ItemAttributeMatcher parseAttributes(ConfigurationSection config, String path, EquipmentSlot slot, + ListMatchingMode mode) { + if (!(config.isList(path))) + return null; + + List attributeMatchers = new ArrayList<>(); + + for (ConfigurationSection attribute : getConfigList(config, path)) { + NameMatcher attributeM = parseName(attribute, "attribute"); + NameMatcher name = parseName(attribute, "name"); + NameMatcher operation = parseName(attribute, "operation"); + UUIDMatcher uuid = new ExactlyUUID(UUID.fromString(attribute.getString("uuid"))); + AmountMatcher amount = parseAmount(attribute, "amount"); + + ItemAttributeMatcher.AttributeMatcher attributeMatcher = + new ItemAttributeMatcher.AttributeMatcher(attributeM, name, operation, uuid, amount); + + attributeMatchers.add(attributeMatcher); + } + + return new ItemAttributeMatcher(attributeMatchers, slot, mode); + } + /** * Runs this ItemExpression on a given ItemStack. * @@ -586,17 +625,17 @@ else if (amountMatchers.size() == 1) } if (amountMatcher instanceof ExactlyAmount) { - return ((ExactlyAmount) amountMatcher).amount; + return (int) ((ExactlyAmount) amountMatcher).amount; } else if (amountMatcher instanceof AnyAmount) { return -1; } else if (amountMatcher instanceof RangeAmount && !random) { RangeAmount rangeAmount = (RangeAmount) amountMatcher; - return rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : 1); + return (int) (rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : 1)); } else if (amountMatcher instanceof RangeAmount && random) { RangeAmount rangeAmount = (RangeAmount) amountMatcher; return ThreadLocalRandom.current() - .nextInt(rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : -1), - rangeAmount.getHigh() + (rangeAmount.highInclusive ? 1 : 0)); + .nextInt((int) rangeAmount.getLow() + (rangeAmount.lowInclusive ? 0 : -1), + (int) rangeAmount.getHigh() + (rangeAmount.highInclusive ? 1 : 0)); } else { throw new IllegalArgumentException("removeFromInventory(Inventory, boolean) does not work with custom AmountMatchers"); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index e3d0d1f8..256a2f49 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -7,5 +7,9 @@ * the level of an enchantment. */ public interface AmountMatcher { - boolean matches(int amount); + default boolean matches(int amount) { + return matches((double) amount); + } + + boolean matches(double amount); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java index eb88a30f..795a932f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java @@ -7,7 +7,7 @@ */ public class AnyAmount implements AmountMatcher { @Override - public boolean matches(int amount) { + public boolean matches(double amount) { return true; } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java index 2d8440ae..2c8c30d1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java @@ -6,14 +6,14 @@ * @author Ameliorate */ public class ExactlyAmount implements AmountMatcher { - public ExactlyAmount(int amount) { + public ExactlyAmount(double amount) { this.amount = amount; } - public int amount; + public double amount; @Override - public boolean matches(int amount) { + public boolean matches(double amount) { return this.amount == amount; } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java index fcf0237d..4f68d6ee 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java @@ -12,18 +12,18 @@ public class RangeAmount implements AmountMatcher { * @param lowInclusive If this range should accept values equal to low. * @param highInclusive If this range should accept values equal to high. */ - public RangeAmount(int low, int high, boolean lowInclusive, boolean highInclusive) { + public RangeAmount(double low, double high, boolean lowInclusive, boolean highInclusive) { set(low, high); this.highInclusive = highInclusive; this.lowInclusive = lowInclusive; } - private int low; - private int high; + private double low; + private double high; public boolean highInclusive; public boolean lowInclusive; - public void set(int low, int high) { + public void set(double low, double high) { if (low <= high) { // expected situation, do as normal this.low = low; @@ -35,16 +35,16 @@ public void set(int low, int high) { } } - public int getLow() { + public double getLow() { return low; } - public int getHigh() { + public double getHigh() { return high; } @Override - public boolean matches(int amount) { + public boolean matches(double amount) { if (lowInclusive) { if (amount < low) return false; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java new file mode 100644 index 00000000..87ca79d3 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java @@ -0,0 +1,90 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.UUIDMatcher; + +import java.util.List; +import java.util.function.Predicate; + +/** + * Matches over the attributes of an item that apply for a given slot. + * + * @author Ameliorate + */ +public class ItemAttributeMatcher implements ItemMatcher { + /** + * @param slot May be null, for an item that applies no matter what slot it is in. + */ + public ItemAttributeMatcher(List matchers, EquipmentSlot slot, ListMatchingMode mode) { + this.matchers = matchers; + this.slot = slot; + this.mode = mode; + } + + public List matchers; + public EquipmentSlot slot; + public ListMatchingMode mode; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !item.getItemMeta().hasAttributeModifiers()) + return false; + + return item.getItemMeta().getAttributeModifiers(slot).entries().stream().anyMatch((e) -> { + Attribute attribute = e.getKey(); + AttributeModifier modifier = e.getValue(); + + Predicate matcherMatchesPredicate = (matcher) -> matcher.matches(attribute, modifier); + + switch (mode) { + case ANY: + return matchers.stream().anyMatch(matcherMatchesPredicate); + case ALL: + return matchers.stream().allMatch(matcherMatchesPredicate); + case NONE: + return matchers.stream().noneMatch(matcherMatchesPredicate); + } + + throw new AssertionError("not reachable"); + }); + } + + public static class AttributeMatcher { + public AttributeMatcher(NameMatcher attribute, + NameMatcher name, NameMatcher operation, + UUIDMatcher uuid, AmountMatcher amount) { + this.attribute = attribute; + this.name = name; + this.operation = operation; + this.uuid = uuid; + this.amount = amount; + } + + public NameMatcher attribute; + public NameMatcher name; + public NameMatcher operation; + public UUIDMatcher uuid; + public AmountMatcher amount; + + public boolean matches(Attribute attribute, AttributeModifier modifier) { + if (this.attribute != null && !this.attribute.matches(attribute.toString())) + return false; + else if (name != null && !name.matches(modifier.getName())) + return false; + else if (operation != null && !operation.matches(modifier.getOperation().toString())) + return false; + else if (uuid != null && !uuid.matches(modifier.getUniqueId())) + return false; + else if (amount != null && !amount.matches(modifier.getAmount())) + return false; + else + return true; + } + } +} From 529b512180d976d534955278984ab286d6b3dfd1 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 8 Mar 2019 18:44:42 -0800 Subject: [PATCH 073/108] Add matching over buckets of tropical fish Probably never will ever be needed, but it's here now, and it's an item off of the checklist. Also adds a fancy and overcomplicated reflection/generic function for parsing out list of possible enum entires from the config into ItemMatchers. Probably wasn't needed, but we've got it now. --- .../itemExpression/ItemExpression.java | 71 +++++++++++++++++++ .../ItemTropicFishBBodyColorMatcher.java | 38 ++++++++++ .../ItemTropicFishBPatternColorMatcher.java | 38 ++++++++++ .../ItemTropicFishBPatternMatcher.java | 38 ++++++++++ 4 files changed, 185 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 7d7f2843..0b4f57e7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -4,6 +4,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.entity.TropicalFish; import org.bukkit.inventory.*; import org.bukkit.inventory.meta.*; import org.bukkit.potion.PotionEffectType; @@ -17,6 +18,9 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket.ItemTropicFishBBodyColorMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket.ItemTropicFishBPatternColorMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket.ItemTropicFishBPatternMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.*; import java.util.*; @@ -105,6 +109,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); parsePotion(config, "potion").forEach(this::addMatcher); parseAllAttributes(config, "attributes").forEach(this::addMatcher); + parseTropicFishBucket(config, "tropicalFishBucket").forEach(this::addMatcher); } /** @@ -447,6 +452,72 @@ private ItemAttributeMatcher parseAttributes(ConfigurationSection config, String return new ItemAttributeMatcher(attributeMatchers, slot, mode); } + private List parseTropicFishBucket(ConfigurationSection config, String path) { + if (!config.contains(path)) + return Collections.emptyList(); + + ArrayList matchers = new ArrayList<>(); + + ConfigurationSection bucket = config.getConfigurationSection(path); + + matchers.add(parseEnumListMatcher(bucket, "bodyColor.any", + false, + ItemTropicFishBBodyColorMatcher::new, DyeColor.class)); + matchers.add(parseEnumListMatcher(bucket, "bodyColor.none", + true, + ItemTropicFishBBodyColorMatcher::new, DyeColor.class)); + matchers.add(parseEnumListMatcher(bucket, "patternColor.any", + false, + ItemTropicFishBPatternColorMatcher::new, DyeColor.class)); + matchers.add(parseEnumListMatcher(bucket, "patternColor.none", + true, + ItemTropicFishBPatternColorMatcher::new, DyeColor.class)); + matchers.add(parseEnumListMatcher(bucket, "pattern.any", + false, + ItemTropicFishBPatternMatcher::new, TropicalFish.Pattern.class)); + matchers.add(parseEnumListMatcher(bucket, "pattern.none", + true, + ItemTropicFishBPatternMatcher::new, TropicalFish.Pattern.class)); + + return matchers; + } + + /** + * Parses a list of Enums in the config into an ItemMatcher. + * @param matcher The constructor of the ItemMatcher in question. This should usually be (thing implements ItemMatcher)::new. + * @param enumClass The type of the enum that the ItemMatcher has a list of. + * @param The type of the enum that the ItemMatcher has a list of. + */ + private > ItemMatcher parseEnumListMatcher(ConfigurationSection config, String path, + boolean notInList, + EnumItemMatcher matcher, Class enumClass) { + if (!config.contains(path)) + return null; + + ArrayList enumStrings = new ArrayList<>(); + + if (!config.isList(path)) { + enumStrings.add(config.getString(path)); + } else { + enumStrings.addAll(config.getStringList(path)); + } + + List properties = enumStrings.stream() + .map((name) -> matcher.parseEnum(enumClass, name.toUpperCase())) + .collect(Collectors.toList()); + + return matcher.construct(properties, notInList); + } + + @FunctionalInterface + private interface EnumItemMatcher> { + ItemMatcher construct(List properties, boolean notInList); + + default E parseEnum(Class enumClass, String name) { + return E.valueOf(enumClass, name); + } + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java new file mode 100644 index 00000000..5bb91194 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java @@ -0,0 +1,38 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket; + +import org.bukkit.DyeColor; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.TropicalFishBucketMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemTropicFishBBodyColorMatcher implements ItemMatcher { + public ItemTropicFishBBodyColorMatcher(List bodyColor) { + this(bodyColor, false); + } + + public ItemTropicFishBBodyColorMatcher(List bodyColor, boolean notInList) { + this.bodyColor = bodyColor; + this.notInList = notInList; + } + + public List bodyColor; + public boolean notInList; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof TropicalFishBucketMeta) || + !((TropicalFishBucketMeta) item.getItemMeta()).hasVariant()) + return false; + + if (notInList) { + return !bodyColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getBodyColor()); + } else { + return bodyColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getBodyColor()); + } + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java new file mode 100644 index 00000000..fd35e63b --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java @@ -0,0 +1,38 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket; + +import org.bukkit.DyeColor; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.TropicalFishBucketMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemTropicFishBPatternColorMatcher implements ItemMatcher { + public ItemTropicFishBPatternColorMatcher(List patternColor, boolean notInList) { + this.patternColor = patternColor; + this.notInList = notInList; + } + + public ItemTropicFishBPatternColorMatcher(List patternColor) { + this(patternColor, false); + } + + public List patternColor; + public boolean notInList; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof TropicalFishBucketMeta) || + !((TropicalFishBucketMeta) item.getItemMeta()).hasVariant()) + return false; + + if (notInList) { + return !patternColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPatternColor()); + } else { + return patternColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPatternColor()); + } + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java new file mode 100644 index 00000000..1943ec52 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java @@ -0,0 +1,38 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket; + +import org.bukkit.entity.TropicalFish; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.TropicalFishBucketMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemTropicFishBPatternMatcher implements ItemMatcher { + public ItemTropicFishBPatternMatcher(List pattern, boolean notInList) { + this.pattern = pattern; + this.notInList = notInList; + } + + public ItemTropicFishBPatternMatcher(List pattern) { + this(pattern, false); + } + + public List pattern; + public boolean notInList; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof TropicalFishBucketMeta) || + !((TropicalFishBucketMeta) item.getItemMeta()).hasVariant()) + return false; + + if (notInList) { + return !pattern.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPattern()); + } else { + return pattern.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPattern()); + } + } +} From e33a8dd88b06ac90b41b1be82bcd8fab766cd010 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 8 Mar 2019 19:04:59 -0800 Subject: [PATCH 074/108] Further abstract parseEnumListMatcher to match any/none as well Also use it for shulker box coluor. --- .../itemExpression/ItemExpression.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 0b4f57e7..5b524577 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -102,9 +102,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseInventory(config, "inventory")); parseBook(config, "book").forEach(this::addMatcher); addMatcher(parseExactly(config, "exactly")); - addMatcher(parseShulkerBoxColor(config, "shulkerbox.color", false)); - addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorAny", false)); - addMatcher(parseShulkerBoxColor(config, "shulkerbox.colorNone", true)); + parseEnumListMatcherAnyNone(config, "shulkerbox", ItemShulkerBoxColorMatcher::new, DyeColor.class).forEach(this::addMatcher); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); parsePotion(config, "potion").forEach(this::addMatcher); @@ -460,28 +458,35 @@ private List parseTropicFishBucket(ConfigurationSection config, Str ConfigurationSection bucket = config.getConfigurationSection(path); - matchers.add(parseEnumListMatcher(bucket, "bodyColor.any", - false, + matchers.addAll(parseEnumListMatcherAnyNone(bucket, "bodyColor", ItemTropicFishBBodyColorMatcher::new, DyeColor.class)); - matchers.add(parseEnumListMatcher(bucket, "bodyColor.none", - true, - ItemTropicFishBBodyColorMatcher::new, DyeColor.class)); - matchers.add(parseEnumListMatcher(bucket, "patternColor.any", - false, - ItemTropicFishBPatternColorMatcher::new, DyeColor.class)); - matchers.add(parseEnumListMatcher(bucket, "patternColor.none", - true, - ItemTropicFishBPatternColorMatcher::new, DyeColor.class)); - matchers.add(parseEnumListMatcher(bucket, "pattern.any", - false, + matchers.addAll(parseEnumListMatcherAnyNone(bucket, "patternColor", ItemTropicFishBPatternMatcher::new, TropicalFish.Pattern.class)); - matchers.add(parseEnumListMatcher(bucket, "pattern.none", - true, + matchers.addAll(parseEnumListMatcherAnyNone(bucket, "pattern", ItemTropicFishBPatternMatcher::new, TropicalFish.Pattern.class)); return matchers; } + private > List parseEnumListMatcherAnyNone(ConfigurationSection config, String path, + EnumItemMatcher matcher, Class enumClass) { + if (!config.contains(path)) + return Collections.emptyList(); + + ArrayList matchers = new ArrayList<>(); + + if (config.isConfigurationSection(path)) { + matchers.add(parseEnumListMatcher(config, path + ".any", + false, matcher, enumClass)); + matchers.add(parseEnumListMatcher(config, path + ".none", + true, matcher, enumClass)); + } else { + matchers.add(parseEnumListMatcher(config, path, false, matcher, enumClass)); + } + + return matchers; + } + /** * Parses a list of Enums in the config into an ItemMatcher. * @param matcher The constructor of the ItemMatcher in question. This should usually be (thing implements ItemMatcher)::new. From 677600f4ae97b54a44ad5962cb7fe3d3a455a925 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 9 Mar 2019 22:05:41 -0800 Subject: [PATCH 075/108] Refactor the way enums are matched Not there's an EnumMatcher set of classes, and a generic way to parse an EnumMatcher from the config. Also removes that one insane method. --- .../itemExpression/ItemExpression.java | 112 +++++------------- .../book/ItemBookGenerationMatcher.java | 9 +- .../enummatcher/EnumFromListMatcher.java | 33 ++++++ .../enummatcher/EnumIndexMatcher.java | 17 +++ .../enummatcher/EnumMatcher.java | 12 ++ .../enummatcher/ExactlyEnumMatcher.java | 17 +++ .../enummatcher/NameEnumMatcher.java | 19 +++ .../misc/ItemAttributeMatcher.java | 13 +- .../misc/ItemShulkerBoxColorMatcher.java | 19 +-- .../ItemTropicFishBBodyColorMatcher.java | 21 +--- .../ItemTropicFishBPatternColorMatcher.java | 21 +--- .../ItemTropicFishBPatternMatcher.java | 19 +-- 12 files changed, 157 insertions(+), 155 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 5b524577..bb78580e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -2,6 +2,8 @@ import org.bukkit.DyeColor; import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.entity.TropicalFish; @@ -12,6 +14,10 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumFromListMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumIndexMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.NameEnumMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; @@ -102,7 +108,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseInventory(config, "inventory")); parseBook(config, "book").forEach(this::addMatcher); addMatcher(parseExactly(config, "exactly")); - parseEnumListMatcherAnyNone(config, "shulkerbox", ItemShulkerBoxColorMatcher::new, DyeColor.class).forEach(this::addMatcher); + addMatcher(new ItemShulkerBoxColorMatcher(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); parsePotion(config, "potion").forEach(this::addMatcher); @@ -296,19 +302,7 @@ private List parseBook(ConfigurationSection config, String path) { } // generation - ArrayList generations = new ArrayList<>(); - - if (book.contains("generation") && !book.isList("generation")) { - BookMeta.Generation generation = BookMeta.Generation.valueOf(book.getString("generation").toUpperCase()); - generations.add(generation); - } else if (book.isList("generation")) { - for (String generationS : book.getStringList("generation")) { - BookMeta.Generation generation = BookMeta.Generation.valueOf(generationS.toUpperCase()); - generations.add(generation); - } - } - - matchers.add(new ItemBookGenerationMatcher(generations)); + matchers.add(new ItemBookGenerationMatcher(parseEnumMatcher(config, "generation", BookMeta.Generation.class))); // title if (book.contains("title")) { @@ -338,20 +332,6 @@ private ItemExactlyStackMatcher parseExactly(ConfigurationSection config, String return new ItemExactlyStackMatcher(config.getItemStack(path), acceptBoolean); } - private ItemShulkerBoxColorMatcher parseShulkerBoxColor(ConfigurationSection config, String path, boolean notInList) { - if (!config.contains(path)) - return null; - - if (config.isList(path)) { - ArrayList colors = new ArrayList<>(); - config.getStringList(path).stream().map((c) -> DyeColor.valueOf(c.toUpperCase())).forEach(colors::add); - return new ItemShulkerBoxColorMatcher(colors, notInList); - } else { - return new ItemShulkerBoxColorMatcher( - Collections.singletonList(DyeColor.valueOf(config.getString(path).toUpperCase())), notInList); - } - } - private ItemKnowledgeBookMatcher parseKnowlegeBook(ConfigurationSection config, String path, boolean requireAll) { if (!config.contains(path)) return null; @@ -435,9 +415,9 @@ private ItemAttributeMatcher parseAttributes(ConfigurationSection config, String List attributeMatchers = new ArrayList<>(); for (ConfigurationSection attribute : getConfigList(config, path)) { - NameMatcher attributeM = parseName(attribute, "attribute"); + EnumMatcher attributeM = parseEnumMatcher(attribute, "attribute", Attribute.class); + EnumMatcher operation = parseEnumMatcher(attribute, "operation", AttributeModifier.Operation.class); NameMatcher name = parseName(attribute, "name"); - NameMatcher operation = parseName(attribute, "operation"); UUIDMatcher uuid = new ExactlyUUID(UUID.fromString(attribute.getString("uuid"))); AmountMatcher amount = parseAmount(attribute, "amount"); @@ -458,68 +438,36 @@ private List parseTropicFishBucket(ConfigurationSection config, Str ConfigurationSection bucket = config.getConfigurationSection(path); - matchers.addAll(parseEnumListMatcherAnyNone(bucket, "bodyColor", - ItemTropicFishBBodyColorMatcher::new, DyeColor.class)); - matchers.addAll(parseEnumListMatcherAnyNone(bucket, "patternColor", - ItemTropicFishBPatternMatcher::new, TropicalFish.Pattern.class)); - matchers.addAll(parseEnumListMatcherAnyNone(bucket, "pattern", - ItemTropicFishBPatternMatcher::new, TropicalFish.Pattern.class)); + matchers.add(new ItemTropicFishBBodyColorMatcher(parseEnumMatcher(bucket, "bodyColor", DyeColor.class))); + matchers.add(new ItemTropicFishBPatternColorMatcher(parseEnumMatcher(bucket, "patternColor", DyeColor.class))); + matchers.add(new ItemTropicFishBPatternMatcher(parseEnumMatcher(bucket, "pattern", TropicalFish.Pattern.class))); return matchers; } - private > List parseEnumListMatcherAnyNone(ConfigurationSection config, String path, - EnumItemMatcher matcher, Class enumClass) { - if (!config.contains(path)) - return Collections.emptyList(); - - ArrayList matchers = new ArrayList<>(); - - if (config.isConfigurationSection(path)) { - matchers.add(parseEnumListMatcher(config, path + ".any", - false, matcher, enumClass)); - matchers.add(parseEnumListMatcher(config, path + ".none", - true, matcher, enumClass)); - } else { - matchers.add(parseEnumListMatcher(config, path, false, matcher, enumClass)); - } - - return matchers; - } - - /** - * Parses a list of Enums in the config into an ItemMatcher. - * @param matcher The constructor of the ItemMatcher in question. This should usually be (thing implements ItemMatcher)::new. - * @param enumClass The type of the enum that the ItemMatcher has a list of. - * @param The type of the enum that the ItemMatcher has a list of. - */ - private > ItemMatcher parseEnumListMatcher(ConfigurationSection config, String path, - boolean notInList, - EnumItemMatcher matcher, Class enumClass) { + private > EnumMatcher parseEnumMatcher(ConfigurationSection config, String path, + Class enumClass) { if (!config.contains(path)) return null; - ArrayList enumStrings = new ArrayList<>(); - - if (!config.isList(path)) { - enumStrings.add(config.getString(path)); - } else { - enumStrings.addAll(config.getStringList(path)); - } - - List properties = enumStrings.stream() - .map((name) -> matcher.parseEnum(enumClass, name.toUpperCase())) - .collect(Collectors.toList()); + if (config.isList(path)) { + List enumStrings = config.getStringList(path); + boolean notInList = false; - return matcher.construct(properties, notInList); - } + if (enumStrings.get(0).equals("noneOf")) { + notInList = true; + enumStrings.remove(0); + } - @FunctionalInterface - private interface EnumItemMatcher> { - ItemMatcher construct(List properties, boolean notInList); + List properties = enumStrings.stream() + .map((name) -> E.valueOf(enumClass, name.toUpperCase())) + .collect(Collectors.toList()); - default E parseEnum(Class enumClass, String name) { - return E.valueOf(enumClass, name); + return new EnumFromListMatcher<>(properties, notInList); + } if (config.isInt(path + ".index")) { + return new EnumIndexMatcher<>(config.getInt(path + ".index")); + } else { + return new NameEnumMatcher<>(parseName(config, path)); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java index 8feade22..1f0a23f5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java @@ -3,18 +3,17 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.List; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; /** * @author Ameliorate */ public class ItemBookGenerationMatcher implements ItemMatcher { - public ItemBookGenerationMatcher(List generations) { + public ItemBookGenerationMatcher(EnumMatcher generations) { this.generations = generations; } - public List generations; + public EnumMatcher generations; @Override public boolean matches(ItemStack item) { @@ -22,6 +21,6 @@ public boolean matches(ItemStack item) { return false; } - return generations.contains(((BookMeta) item.getItemMeta()).getGeneration()); + return generations.matches(((BookMeta) item.getItemMeta()).getGeneration()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java new file mode 100644 index 00000000..4d6c6917 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java @@ -0,0 +1,33 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class EnumFromListMatcher> implements EnumMatcher { + public EnumFromListMatcher(List enums, boolean notInList) { + this.enums = enums; + this.notInList = notInList; + } + + public EnumFromListMatcher(List enums) { + this(enums, false); + } + + public List enums; + + /** + * If this should do "not in the list of enums" instead of the default of "is in the list of enums". + */ + public boolean notInList; + + @Override + public boolean matches(E enumm) { + if (notInList) { + return !enums.contains(enumm); + } else { + return enums.contains(enumm); + } + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java new file mode 100644 index 00000000..afb5554b --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java @@ -0,0 +1,17 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; + +/** + * @author Ameliorate + */ +public class EnumIndexMatcher> implements EnumMatcher { + public EnumIndexMatcher(int index) { + this.index = index; + } + + int index; + + @Override + public boolean matches(E enumm) { + return enumm.ordinal() == index; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java new file mode 100644 index 00000000..c194fcbd --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java @@ -0,0 +1,12 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; + +/** + * Matches over an Enum in an enum-generic way. + * + * @param The enum being matched over. + * + * @author Ameliorate + */ +public interface EnumMatcher> { + boolean matches(E enumm); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java new file mode 100644 index 00000000..acb8db20 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java @@ -0,0 +1,17 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; + +/** + * @author Ameliorate + */ +public class ExactlyEnumMatcher> implements EnumMatcher { + public ExactlyEnumMatcher(E exactly) { + this.exactly = exactly; + } + + public E exactly; + + @Override + public boolean matches(E enumm) { + return exactly.equals(enumm); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java new file mode 100644 index 00000000..f887dda4 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java @@ -0,0 +1,19 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; + +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +/** + * @author Ameliorate + */ +public class NameEnumMatcher> implements EnumMatcher { + public NameEnumMatcher(NameMatcher nameMatcher) { + this.nameMatcher = nameMatcher; + } + + public NameMatcher nameMatcher; + + @Override + public boolean matches(E enumm) { + return nameMatcher.matches(enumm.toString()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java index 87ca79d3..abff8acb 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java @@ -6,6 +6,7 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.UUIDMatcher; @@ -56,8 +57,8 @@ public boolean matches(ItemStack item) { } public static class AttributeMatcher { - public AttributeMatcher(NameMatcher attribute, - NameMatcher name, NameMatcher operation, + public AttributeMatcher(EnumMatcher attribute, + NameMatcher name, EnumMatcher operation, UUIDMatcher uuid, AmountMatcher amount) { this.attribute = attribute; this.name = name; @@ -66,18 +67,18 @@ public AttributeMatcher(NameMatcher attribute, this.amount = amount; } - public NameMatcher attribute; + public EnumMatcher attribute; + public EnumMatcher operation; public NameMatcher name; - public NameMatcher operation; public UUIDMatcher uuid; public AmountMatcher amount; public boolean matches(Attribute attribute, AttributeModifier modifier) { - if (this.attribute != null && !this.attribute.matches(attribute.toString())) + if (this.attribute != null && !this.attribute.matches(attribute)) return false; else if (name != null && !name.matches(modifier.getName())) return false; - else if (operation != null && !operation.matches(modifier.getOperation().toString())) + else if (operation != null && !operation.matches(modifier.getOperation())) return false; else if (uuid != null && !uuid.matches(modifier.getUniqueId())) return false; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java index 9a58b0c0..0ebd1303 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java @@ -5,24 +5,17 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.List; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; /** * @author Ameliorate */ public class ItemShulkerBoxColorMatcher implements ItemMatcher { - public ItemShulkerBoxColorMatcher(List color, boolean notInList) { + public ItemShulkerBoxColorMatcher(EnumMatcher color) { this.color = color; - this.notInList = notInList; - } - - public ItemShulkerBoxColorMatcher(List color) { - this(color, false); } - public List color; - public boolean notInList; + public EnumMatcher color; @Override public boolean matches(ItemStack item) { @@ -33,10 +26,6 @@ public boolean matches(ItemStack item) { DyeColor colour = ((ShulkerBox) ((BlockStateMeta) item.getItemMeta()).getBlockState()).getColor(); - if (notInList) { - return !this.color.contains(colour); - } else { - return this.color.contains(colour); - } + return this.color.matches(colour); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java index 5bb91194..0e44a0a4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java @@ -4,24 +4,17 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.TropicalFishBucketMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.List; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; /** * @author Ameliorate */ public class ItemTropicFishBBodyColorMatcher implements ItemMatcher { - public ItemTropicFishBBodyColorMatcher(List bodyColor) { - this(bodyColor, false); - } - - public ItemTropicFishBBodyColorMatcher(List bodyColor, boolean notInList) { - this.bodyColor = bodyColor; - this.notInList = notInList; + public ItemTropicFishBBodyColorMatcher(EnumMatcher color) { + this.color = color; } - public List bodyColor; - public boolean notInList; + public EnumMatcher color; @Override public boolean matches(ItemStack item) { @@ -29,10 +22,6 @@ public boolean matches(ItemStack item) { !((TropicalFishBucketMeta) item.getItemMeta()).hasVariant()) return false; - if (notInList) { - return !bodyColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getBodyColor()); - } else { - return bodyColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getBodyColor()); - } + return color.matches(((TropicalFishBucketMeta) item.getItemMeta()).getBodyColor()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java index fd35e63b..909f63ca 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java @@ -4,24 +4,17 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.TropicalFishBucketMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.List; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; /** * @author Ameliorate */ public class ItemTropicFishBPatternColorMatcher implements ItemMatcher { - public ItemTropicFishBPatternColorMatcher(List patternColor, boolean notInList) { - this.patternColor = patternColor; - this.notInList = notInList; - } - - public ItemTropicFishBPatternColorMatcher(List patternColor) { - this(patternColor, false); + public ItemTropicFishBPatternColorMatcher(EnumMatcher color) { + this.color = color; } - public List patternColor; - public boolean notInList; + public EnumMatcher color; @Override public boolean matches(ItemStack item) { @@ -29,10 +22,6 @@ public boolean matches(ItemStack item) { !((TropicalFishBucketMeta) item.getItemMeta()).hasVariant()) return false; - if (notInList) { - return !patternColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPatternColor()); - } else { - return patternColor.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPatternColor()); - } + return color.matches(((TropicalFishBucketMeta) item.getItemMeta()).getPatternColor()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java index 1943ec52..9e2ae430 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java @@ -4,24 +4,17 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.TropicalFishBucketMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; - -import java.util.List; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; /** * @author Ameliorate */ public class ItemTropicFishBPatternMatcher implements ItemMatcher { - public ItemTropicFishBPatternMatcher(List pattern, boolean notInList) { + public ItemTropicFishBPatternMatcher(EnumMatcher pattern) { this.pattern = pattern; - this.notInList = notInList; - } - - public ItemTropicFishBPatternMatcher(List pattern) { - this(pattern, false); } - public List pattern; - public boolean notInList; + public EnumMatcher pattern; @Override public boolean matches(ItemStack item) { @@ -29,10 +22,6 @@ public boolean matches(ItemStack item) { !((TropicalFishBucketMeta) item.getItemMeta()).hasVariant()) return false; - if (notInList) { - return !pattern.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPattern()); - } else { - return pattern.contains(((TropicalFishBucketMeta) item.getItemMeta()).getPattern()); - } + return pattern.matches(((TropicalFishBucketMeta) item.getItemMeta()).getPattern()); } } From 140806662306ddf35ee9423c8fb46b03bfaf3b70 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 9 Mar 2019 22:21:55 -0800 Subject: [PATCH 076/108] Use EnumMatcher for matching on base potion effects Also now they work if you omit the type, for example to match on a extended potion of any type. --- .../itemExpression/ItemExpression.java | 18 +++++++++++------- .../potion/ItemPotionBaseEffectMatcher.java | 8 ++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index bb78580e..cfaefb8a 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -10,6 +10,7 @@ import org.bukkit.inventory.*; import org.bukkit.inventory.meta.*; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.*; @@ -351,18 +352,21 @@ private List parsePotion(ConfigurationSection config, String path) matchers.add(parsePotionEffects(potion, "customEffectsAll", ALL)); matchers.add(parsePotionEffects(potion, "customEffectsNone", NONE)); - if (potion.contains("base")) { + if (potion.isConfigurationSection("base")) { ConfigurationSection base = potion.getConfigurationSection("base"); - NameMatcher type; - Boolean isExtended = config.contains("extended") ? config.getBoolean("extended") : null; - Boolean isUpgraded = config.contains("upgraded") ? config.getBoolean("upgraded") : null; + Boolean isExtended = base.contains("extended") ? base.getBoolean("extended") : null; + Boolean isUpgraded = base.contains("upgraded") ? base.getBoolean("upgraded") : null; + EnumMatcher type; if (base.contains("type")) { - type = parseName(base, "type"); - matchers.add(new ItemPotionBaseEffectMatcher(type, - Optional.ofNullable(isExtended), Optional.ofNullable(isUpgraded))); + type = parseEnumMatcher(base, "type", PotionType.class); + } else { + type = new EnumFromListMatcher<>(Arrays.asList(PotionType.values())); } + + matchers.add(new ItemPotionBaseEffectMatcher(type, + Optional.ofNullable(isExtended), Optional.ofNullable(isUpgraded))); } return matchers; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java index f412d0ec..c2133549 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java @@ -5,7 +5,7 @@ import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionType; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; import java.util.Optional; @@ -21,13 +21,13 @@ * @author Ameliorate */ public class ItemPotionBaseEffectMatcher implements ItemMatcher { - public ItemPotionBaseEffectMatcher(NameMatcher type, Optional isExtended, Optional isUpgraded) { + public ItemPotionBaseEffectMatcher(EnumMatcher type, Optional isExtended, Optional isUpgraded) { this.type = type; this.isExtended = isExtended; this.isUpgraded = isUpgraded; } - public NameMatcher type; + public EnumMatcher type; public Optional isExtended; public Optional isUpgraded; @@ -52,6 +52,6 @@ public boolean matches(ItemStack item) { return false; } - return this.type.matches(type.toString()); + return this.type.matches(type); } } From 928de8b7afabbc45d8a6a3c63a6d8cef9b00f995 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 11 Mar 2019 11:25:50 -0700 Subject: [PATCH 077/108] Add case insensitivity to ExactlyName and RegexName Also uses this in NameEnumMatcher, since all enums are capitalized. --- .../itemHandling/itemExpression/ItemExpression.java | 13 +++++++++---- .../itemExpression/name/ExactlyName.java | 11 ++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index cfaefb8a..fa6685a4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -200,16 +200,21 @@ private LoreMatcher parseLore(ConfigurationSection config, String path) { return null; } - private NameMatcher parseName(ConfigurationSection config, String path) { + private NameMatcher parseName(ConfigurationSection config, String path, boolean caseSensitive) { if (config.contains(path + ".regex")) - return(new RegexName(Pattern.compile(config.getString(path + ".regex")))); + return(new RegexName(Pattern.compile(config.getString(path + ".regex"), + caseSensitive ? 0 : Pattern.CASE_INSENSITIVE))); else if ("vanilla".equals(config.getString(path))) return(new VanillaName()); else if (config.contains(path)) - return(new ExactlyName(config.getString(path))); + return(new ExactlyName(config.getString(path), caseSensitive)); return null; } + private NameMatcher parseName(ConfigurationSection config, String path) { + return parseName(config, path, true); + } + private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, String path, ListMatchingMode mode, EnchantmentsSource source) { @@ -471,7 +476,7 @@ private > EnumMatcher parseEnumMatcher(ConfigurationSection } if (config.isInt(path + ".index")) { return new EnumIndexMatcher<>(config.getInt(path + ".index")); } else { - return new NameEnumMatcher<>(parseName(config, path)); + return new NameEnumMatcher<>(parseName(config, path, false)); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java index bdaebb87..f0ede991 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java @@ -8,10 +8,19 @@ public ExactlyName(String name) { this.name = name; } + public ExactlyName(String name, boolean caseSensitive) { + this.name = name.toLowerCase(); + this.caseSensitive = caseSensitive; + } + public String name; + public boolean caseSensitive = true; @Override public boolean matches(String name) { - return this.name.equals(name); + if (caseSensitive) + return this.name.equals(name); + else + return this.name.equals(name.toLowerCase()); } } From e198b76f0cdb58842806d7769c69c251ca1ac15c Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 11 Mar 2019 11:29:07 -0700 Subject: [PATCH 078/108] Add matching over the number of pages in a book --- .../itemExpression/ItemExpression.java | 5 +++++ .../book/ItemBookPageCountMatcher.java | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index fa6685a4..a76fc987 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -326,6 +326,11 @@ private List parseBook(ConfigurationSection config, String path) { matchers.add(new ItemBookPagesMatcher(new ExactlyBookPages(pages))); } + // page count + if (book.contains("pageCount")) { + matchers.add(new ItemBookPageCountMatcher(parseAmount(book, "pageCount"))); + } + return matchers; } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java new file mode 100644 index 00000000..b31fb387 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java @@ -0,0 +1,22 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +public class ItemBookPageCountMatcher implements ItemMatcher { + public ItemBookPageCountMatcher(AmountMatcher pageCount) { + this.pageCount = pageCount; + } + + public AmountMatcher pageCount; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta)) + return false; + + return pageCount.matches(((BookMeta) item.getItemMeta()).getPageCount()); + } +} From ed6c569ed078cfb415b2e2264b66f787d98450de Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 11 Mar 2019 17:49:48 -0700 Subject: [PATCH 079/108] Add matching over the number of enchantments in an item --- .../itemExpression/ItemExpression.java | 10 +++++ .../ItemEnchantmentCountMatcher.java | 43 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index a76fc987..40ac97f3 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -100,9 +100,11 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseEnchantment(config, "enchantmentsAny", ANY, ITEM)); addMatcher(parseEnchantment(config, "enchantmentsAll", ALL, ITEM)); addMatcher(parseEnchantment(config, "enchantmentsNone", NONE, ITEM)); + addMatcher(parseEnchangmentCount(config, "enchantmentCount", ITEM)); addMatcher(parseEnchantment(config, "enchantmentsHeldAny", ANY, HELD)); addMatcher(parseEnchantment(config, "enchantmentsHeldAll", ALL, HELD)); addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); + addMatcher(parseEnchangmentCount(config, "enchantmentHeldCount", HELD)); addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); parseFlags(config, "flags").forEach(this::addMatcher); addMatcher(parseUnbreakable(config, "unbreakable")); @@ -238,6 +240,14 @@ private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, St return new ItemEnchantmentsMatcher(enchantmentMatcher, mode, source); } + private ItemEnchantmentCountMatcher parseEnchangmentCount(ConfigurationSection config, String path, + EnchantmentsSource source) { + if (!config.contains(path)) + return null; + + return new ItemEnchantmentCountMatcher(parseAmount(config, path), source); + } + private List parseSkull(ConfigurationSection config, String path) { List matchers = new ArrayList<>(); ConfigurationSection skull = config.getConfigurationSection(path); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java new file mode 100644 index 00000000..b54aac9c --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java @@ -0,0 +1,43 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemEnchantmentCountMatcher implements ItemMatcher { + public ItemEnchantmentCountMatcher(AmountMatcher enchantmentCount, EnchantmentsSource source) { + this.enchantmentCount = enchantmentCount; + this.source = source; + } + + public ItemEnchantmentCountMatcher(AmountMatcher enchantmentCount) { + this(enchantmentCount, EnchantmentsSource.ITEM); + } + + public AmountMatcher enchantmentCount; + public EnchantmentsSource source; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta()) + return false; + if (source == EnchantmentsSource.HELD && !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + return false; + + int count = 0; + switch (source) { + case HELD: + count = ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants().size(); + break; + case ITEM: + count = item.getItemMeta().getEnchants().size(); + break; + } + + return enchantmentCount.matches(count); + } +} From cce2510d4e8ce94bb4d74b613d5aa87b5d3352ca Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Mon, 11 Mar 2019 17:50:26 -0700 Subject: [PATCH 080/108] Add forgotten @author javadoc in ItemBookPageCountMatcher --- .../itemExpression/book/ItemBookPageCountMatcher.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java index b31fb387..df3b71b1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java @@ -5,6 +5,9 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +/** + * @author Ameliorate + */ public class ItemBookPageCountMatcher implements ItemMatcher { public ItemBookPageCountMatcher(AmountMatcher pageCount) { this.pageCount = pageCount; From 1ecbb91f363658be4202a47c1599994acb4d9efc Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 19:34:46 -0700 Subject: [PATCH 081/108] Add basic color matching support Nothing uses it yet, and it can't do anything other than exact colours. I've got no clue when it comes to the math behind colors, so I don't know how most people'd like to compare the colours of items. --- .../itemExpression/ItemExpression.java | 75 +++++++++++++++++++ .../itemExpression/color/ColorMatcher.java | 10 +++ .../itemExpression/color/ExactlyColor.java | 67 +++++++++++++++++ .../itemExpression/color/ListColor.java | 32 ++++++++ 4 files changed, 184 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 40ac97f3..22fe2d81 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; +import org.bukkit.Color; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.attribute.Attribute; @@ -14,6 +15,9 @@ import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ColorMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ExactlyColor; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ListColor; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumFromListMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumIndexMatcher; @@ -495,6 +499,77 @@ private > EnumMatcher parseEnumMatcher(ConfigurationSection } } + private ColorMatcher parseColor(ConfigurationSection config, String path) { + if (!config.contains(path)) + return null; + + return parseColor(config.get(path)); + } + + private ColorMatcher parseColor(Object config) { + if (config == null) + return null; + + if (config instanceof String) { + // vanilla dye name + return new ExactlyColor(ExactlyColor.getColorByVanillaName((String) config)); + + } else if (config instanceof Integer) { + // rgb color + return new ExactlyColor(Color.fromRGB((Integer) config)); + + } else if (config instanceof List) { + // any of matchers in list + return parseListColor((List) config); + + } else if (config instanceof Map) { + if (((Map) config).containsKey("rgb")) { + // rgb int or [r, g, b] + Object rgb = ((Map) config).get("rgb"); + + if (rgb instanceof Integer) { + // rgb int + return new ExactlyColor(Color.fromRGB((Integer) rgb)); + } else if (rgb instanceof List) { + // [r, g, b] + int red = (int) ((List) rgb).get(0); + int green = (int) ((List) rgb).get(1); + int blue = (int) ((List) rgb).get(2); + return new ExactlyColor(Color.fromRGB(red, green, blue)); + } + + } else if (((Map) config).containsKey("html")) { + // html color name + String htmlColorName = (String) ((Map) config).get("html"); + return new ExactlyColor(ExactlyColor.getColorByHTMLName(htmlColorName)); + + } else if (((Map) config).containsKey("firework")) { + // firework vanilla dye name + String fireworkDyeColorName = (String) ((Map) config).get("firework"); + return new ExactlyColor(ExactlyColor.getColorByVanillaName(fireworkDyeColorName, true)); + + } else if (((Map) config).containsKey("anyOf")) { + // any of matchers in list + return parseListColor((List) ((Map) config).get("anyOf")); + + } else if (((Map) config).containsKey("noneOf")) { + // none of matchers in list + return parseListColor((List) ((Map) config).get("noneOf")); + } + } + + return null; + } + + private ListColor parseListColor(List config) { + if (config == null) + return null; + + return new ListColor(((List) config).stream() + .map(this::parseColor) + .collect(Collectors.toList()), false); + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java new file mode 100644 index 00000000..79aeaa45 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color; + +import org.bukkit.Color; + +/** + * @author Ameliorate + */ +public interface ColorMatcher { + boolean matches(Color color); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java new file mode 100644 index 00000000..01718985 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java @@ -0,0 +1,67 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color; + +import org.bukkit.Color; +import org.bukkit.DyeColor; + +/** + * @author Ameliorate + */ +public class ExactlyColor implements ColorMatcher { + public ExactlyColor(Color colour) { + this.color = colour; + } + + public Color color; + + @Override + public boolean matches(Color color) { + return this.color.equals(color); + } + + /** + * Maps between HTML colors and org.bukkit.Color. See https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Color.html + * for the full list of colors. + */ + public static Color getColorByHTMLName(String name) { + switch (name.toUpperCase()) { + case "AQUA": return Color.AQUA; + case "BLACK": return Color.BLACK; + case "BLUE": return Color.BLUE; + case "FUCHSIA": return Color.FUCHSIA; + case "GRAY": return Color.GRAY; + case "GREEN": return Color.GREEN; + case "LIME": return Color.LIME; + case "MAROON": return Color.MAROON; + case "NAVY": return Color.NAVY; + case "OLIVE": return Color.ORANGE; + case "PURPLE": return Color.PURPLE; + case "RED": return Color.RED; + case "SILVER": return Color.SILVER; + case "TEAL": return Color.TEAL; + case "WHITE": return Color.WHITE; + case "YELLOW": return Color.YELLOW; + default: + throw new IllegalArgumentException(name + " is not a html color name in org.bukkit.Color."); + } + } + + /** + * Maps between the vanilla dye colors and org.bukkit.Color. See https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html + * for the full list of colors. + * + * @param useFireworkColor Use the colors used for firework crafting instead of the vanilla default colors used for + * wool and other items. + */ + public static Color getColorByVanillaName(String name, boolean useFireworkColor) { + DyeColor color = DyeColor.valueOf(name.toUpperCase()); + return useFireworkColor ? color.getFireworkColor() : color.getColor(); + } + + /** + * Maps between the vanilla dye colors and org.bukkit.Color. See https://hub.spigotmc.org/javadocs/spigot/org/bukkit/DyeColor.html + * for the full list of colors. + */ + public static Color getColorByVanillaName(String name) { + return getColorByVanillaName(name, false); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java new file mode 100644 index 00000000..2d0ca0ab --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java @@ -0,0 +1,32 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color; + +import org.bukkit.Color; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * @author Ameliorate + */ +public class ListColor implements ColorMatcher { + public ListColor(List matchers, boolean noneInList) { + this.matchers = matchers; + this.noneInList = noneInList; + } + + public List matchers; + public boolean noneInList; + + @Override + public boolean matches(Color color) { + Stream stream = matchers.stream(); + Predicate predicate = (matcher) -> matcher.matches(color); + + if (noneInList) { + return stream.noneMatch(predicate); + } else { + return stream.anyMatch(predicate); + } + } +} From 4533670588bd7ba8eb0ef56146128194596833ac Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 20:16:06 -0700 Subject: [PATCH 082/108] Add another forgotten @author in ItemMapMatcher --- .../civmodcore/itemHandling/itemExpression/ItemMapMatcher.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java index 1867288a..c754cf8f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMapMatcher.java @@ -3,6 +3,9 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; +/** + * @author Ameliorate + */ public interface ItemMapMatcher extends ItemMatcher { boolean matches(ItemMap itemMap, ItemStack item); } From cef1b06f610d29e4ebf00c556fa819a9d1328a98 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 20:46:24 -0700 Subject: [PATCH 083/108] Add matching over the color of leather armour Also add to ExactlyColor.getColorByVanillaName a mapping to the default color for leather armor. --- .../itemExpression/ItemExpression.java | 8 ++++++ .../itemExpression/color/ExactlyColor.java | 6 +++++ .../misc/ItemLeatherArmorColorMatcher.java | 27 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 22fe2d81..2c3b500d 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -121,6 +121,7 @@ public void parseConfig(ConfigurationSection config) { parsePotion(config, "potion").forEach(this::addMatcher); parseAllAttributes(config, "attributes").forEach(this::addMatcher); parseTropicFishBucket(config, "tropicalFishBucket").forEach(this::addMatcher); + addMatcher(parseLeatherColor(config, "leatherArmorColor")); } /** @@ -570,6 +571,13 @@ private ListColor parseListColor(List config) { .collect(Collectors.toList()), false); } + private ItemLeatherArmorColorMatcher parseLeatherColor(ConfigurationSection config, String path) { + if (!config.contains(path)) + return null; + + return new ItemLeatherArmorColorMatcher(parseColor(config, path)); + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java index 01718985..6efa84fb 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java @@ -1,7 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color; +import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.DyeColor; +import org.bukkit.inventory.ItemFactory; /** * @author Ameliorate @@ -53,6 +55,10 @@ public static Color getColorByHTMLName(String name) { * wool and other items. */ public static Color getColorByVanillaName(String name, boolean useFireworkColor) { + if ("defaultLeather".equals(name)) { + return Bukkit.getServer().getItemFactory().getDefaultLeatherColor(); + } + DyeColor color = DyeColor.valueOf(name.toUpperCase()); return useFireworkColor ? color.getFireworkColor() : color.getColor(); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java new file mode 100644 index 00000000..f13a9c3f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java @@ -0,0 +1,27 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +import org.bukkit.Color; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ColorMatcher; + +/** + * @author Ameliorate + */ +public class ItemLeatherArmorColorMatcher implements ItemMatcher { + public ItemLeatherArmorColorMatcher(ColorMatcher color) { + this.color = color; + } + + public ColorMatcher color; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof LeatherArmorMeta)) + return false; + + Color leatherColor = ((LeatherArmorMeta) item.getItemMeta()).getColor(); + return color.matches(leatherColor); + } +} From 36e313c4113d205e938b4d597c031e12e937b40e Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 22:23:28 -0700 Subject: [PATCH 084/108] Add matching over the properties of a map Well that wasn't as hard as I expected. It doesn't touch the map render thing, but it works over everything else. --- .../itemExpression/ItemExpression.java | 58 +++++++++++++++++++ .../itemExpression/map/CenterMapView.java | 29 ++++++++++ .../itemExpression/map/IDMapView.java | 21 +++++++ .../map/IsUnlimitedTrackingMapView.java | 19 ++++++ .../itemExpression/map/IsVirtualMapView.java | 19 ++++++ .../map/ItemMapColorMatcher.java | 26 +++++++++ .../map/ItemMapIsScalingMatcher.java | 24 ++++++++ .../map/ItemMapLocationMatcher.java | 27 +++++++++ .../map/ItemMapViewMatcher.java | 25 ++++++++ .../itemExpression/map/MapViewMatcher.java | 10 ++++ .../itemExpression/map/ScaleMapView.java | 20 +++++++ .../itemExpression/map/WorldMapView.java | 23 ++++++++ 12 files changed, 301 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 2c3b500d..dffbf3d6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -10,6 +10,7 @@ import org.bukkit.entity.TropicalFish; import org.bukkit.inventory.*; import org.bukkit.inventory.meta.*; +import org.bukkit.map.MapView; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; @@ -23,6 +24,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumIndexMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.NameEnumMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; @@ -122,6 +124,7 @@ public void parseConfig(ConfigurationSection config) { parseAllAttributes(config, "attributes").forEach(this::addMatcher); parseTropicFishBucket(config, "tropicalFishBucket").forEach(this::addMatcher); addMatcher(parseLeatherColor(config, "leatherArmorColor")); + parseMap(config, "map").forEach(this::addMatcher); } /** @@ -578,6 +581,61 @@ private ItemLeatherArmorColorMatcher parseLeatherColor(ConfigurationSection conf return new ItemLeatherArmorColorMatcher(parseColor(config, path)); } + private List parseMap(ConfigurationSection config, String path) { + if (!config.isConfigurationSection(path)) + return Collections.emptyList(); + + List matchers = new ArrayList<>(); + + ConfigurationSection map = config.getConfigurationSection(path); + + if (map.contains("center.x")) { + matchers.add(new ItemMapViewMatcher(new CenterMapView(parseAmount(map, "center.x"), + CenterMapView.CenterCoordinate.X))); + } + + if (map.contains("center.z")) { + matchers.add(new ItemMapViewMatcher(new CenterMapView(parseAmount(map, "center.z"), + CenterMapView.CenterCoordinate.Z))); + } + + if (map.contains("id")) { + matchers.add(new ItemMapViewMatcher(new IDMapView(parseAmount(map, "id")))); + } + + if (map.isBoolean("isUnlimitedTracking")) { + matchers.add(new ItemMapViewMatcher(new IsUnlimitedTrackingMapView(map.getBoolean("isUnlimitedTracking")))); + } + + if (map.isBoolean("isVirtual")) { + matchers.add(new ItemMapViewMatcher(new IsVirtualMapView(map.getBoolean("isVirtual")))); + } + + if (map.contains("scale")) { + matchers.add(new ItemMapViewMatcher(new ScaleMapView( + parseEnumMatcher(map, "scale", MapView.Scale.class)))); + } + + if (map.contains("world")) { + matchers.add(new ItemMapViewMatcher(new WorldMapView(parseName(map, "world")))); + } + + if (map.contains("color")) { + matchers.add(new ItemMapColorMatcher(parseColor(map, "color"))); + } + + if (map.isBoolean("isScaling")) { + matchers.add(new ItemMapIsScalingMatcher(map.getBoolean("isScaling"))); + } + + if (map.contains("location")) { + matchers.add(new ItemMapLocationMatcher(parseName(map, "location"))); + } + + return matchers; + } + + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java new file mode 100644 index 00000000..64a14b8c --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java @@ -0,0 +1,29 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.map.MapView; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class CenterMapView implements MapViewMatcher { + public CenterMapView(AmountMatcher mapLocation, CenterCoordinate centerCoordinate) { + this.mapLocation = mapLocation; + this.centerCoordinate = centerCoordinate; + } + + public AmountMatcher mapLocation; + public CenterCoordinate centerCoordinate; + + @Override + public boolean matches(MapView map) { + int coordinate = centerCoordinate == CenterCoordinate.X ? map.getCenterX() : map.getCenterZ(); + + return mapLocation.matches(coordinate); + } + + public enum CenterCoordinate { + X, + Z, + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java new file mode 100644 index 00000000..e2c4e6f7 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java @@ -0,0 +1,21 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.map.MapView; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class IDMapView implements MapViewMatcher { + public IDMapView(AmountMatcher id) { + this.id = id; + } + + public AmountMatcher id; + + @Override + public boolean matches(MapView map) { + int id = map.getId(); + return this.id.matches(id); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java new file mode 100644 index 00000000..4bafda0a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java @@ -0,0 +1,19 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.map.MapView; + +/** + * @author Ameliorate + */ +public class IsUnlimitedTrackingMapView implements MapViewMatcher { + public IsUnlimitedTrackingMapView(boolean isUmlimitedTracking) { + this.isUmlimitedTracking = isUmlimitedTracking; + } + + public boolean isUmlimitedTracking; + + @Override + public boolean matches(MapView map) { + return map.isUnlimitedTracking() == isUmlimitedTracking; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java new file mode 100644 index 00000000..a1c8f3ee --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java @@ -0,0 +1,19 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.map.MapView; + +/** + * @author Ameliorate + */ +public class IsVirtualMapView implements MapViewMatcher { + public IsVirtualMapView(boolean isVirtual) { + this.isVirtual = isVirtual; + } + + public boolean isVirtual; + + @Override + public boolean matches(MapView map) { + return map.isVirtual() == isVirtual; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java new file mode 100644 index 00000000..e84e3ad2 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java @@ -0,0 +1,26 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ColorMatcher; + +/** + * @author Ameliorate + */ +public class ItemMapColorMatcher implements ItemMatcher { + public ItemMapColorMatcher(ColorMatcher color) { + this.color = color; + } + + public ColorMatcher color; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta) || + !((MapMeta) item.getItemMeta()).hasColor()) + return false; + + return color.matches(((MapMeta) item.getItemMeta()).getColor()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java new file mode 100644 index 00000000..29a4106c --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemMapIsScalingMatcher implements ItemMatcher { + public ItemMapIsScalingMatcher(boolean isScaling) { + this.isScaling = isScaling; + } + + public boolean isScaling; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || (item.getItemMeta() instanceof MapMeta)) + return false; + + return ((MapMeta) item.getItemMeta()).isScaling() == isScaling; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java new file mode 100644 index 00000000..77619aae --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java @@ -0,0 +1,27 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +/** + * @author Ameliorate + */ +public class ItemMapLocationMatcher implements ItemMatcher { + public ItemMapLocationMatcher(NameMatcher locationName) { + this.locationName = locationName; + } + + public NameMatcher locationName; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta) || + !((MapMeta) item.getItemMeta()).hasLocationName()) + return false; + + String location = ((MapMeta) item.getItemMeta()).getLocationName(); + return locationName.matches(location); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java new file mode 100644 index 00000000..30069bc1 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.MapMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemMapViewMatcher implements ItemMatcher { + public ItemMapViewMatcher(MapViewMatcher matcher) { + this.matcher = matcher; + } + + public MapViewMatcher matcher; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta) || + !((MapMeta) item.getItemMeta()).hasMapView()) + return false; + + return matcher.matches(((MapMeta) item.getItemMeta()).getMapView()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java new file mode 100644 index 00000000..b72fb415 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.map.MapView; + +/** + * @author Ameliorate + */ +public interface MapViewMatcher { + boolean matches(MapView map); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java new file mode 100644 index 00000000..9e161794 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java @@ -0,0 +1,20 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.map.MapView; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; + +/** + * @author Ameliorate + */ +public class ScaleMapView implements MapViewMatcher { + public ScaleMapView(EnumMatcher scale) { + this.scale = scale; + } + + public EnumMatcher scale; + + @Override + public boolean matches(MapView map) { + return scale.matches(map.getScale()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java new file mode 100644 index 00000000..1c00092b --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java @@ -0,0 +1,23 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; + +import org.bukkit.World; +import org.bukkit.map.MapView; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; + +/** + * @author Ameliorate + */ +public class WorldMapView implements MapViewMatcher { + public WorldMapView(NameMatcher world) { + this.world = world; + } + + public NameMatcher world; + + @Override + public boolean matches(MapView map) { + World world = map.getWorld(); + + return this.world.matches(world.getName()); + } +} From 6cfd848792fdc4b9ca636b4d2088c809a3a77823 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 22:38:02 -0700 Subject: [PATCH 085/108] Add ItemExpression.addMatcher(Collection) This allows adding multiple ItemMatcher's, when prevously you'd do collection.forEach(this::addMatcher), which was acceptable but not great. --- .../itemExpression/ItemExpression.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index dffbf3d6..fc5ddb27 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -112,19 +112,19 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); addMatcher(parseEnchangmentCount(config, "enchantmentHeldCount", HELD)); addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); - parseFlags(config, "flags").forEach(this::addMatcher); + addMatcher(parseFlags(config, "flags")); addMatcher(parseUnbreakable(config, "unbreakable")); addMatcher(parseInventory(config, "inventory")); - parseBook(config, "book").forEach(this::addMatcher); + addMatcher(parseBook(config, "book")); addMatcher(parseExactly(config, "exactly")); addMatcher(new ItemShulkerBoxColorMatcher(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); - parsePotion(config, "potion").forEach(this::addMatcher); - parseAllAttributes(config, "attributes").forEach(this::addMatcher); - parseTropicFishBucket(config, "tropicalFishBucket").forEach(this::addMatcher); + addMatcher(parsePotion(config, "potion")); + addMatcher(parseAllAttributes(config, "attributes")); + addMatcher(parseTropicFishBucket(config, "tropicalFishBucket")); addMatcher(parseLeatherColor(config, "leatherArmorColor")); - parseMap(config, "map").forEach(this::addMatcher); + addMatcher(parseMap(config, "map")); } /** @@ -875,6 +875,15 @@ public void addMatcher(ItemMatcher matcher) { matchers.add(matcher); } + /** + * Add a number of properties if the item to be checked, using a number of ItemMatchers. + * @param matchers The list of ItemMatchers that will be added to the list of ItemMatchers to check aganst a given + * item. If this list contains any null elements, those null elements will be ignored. + */ + public void addMatcher(Collection matchers) { + matchers.forEach(this::addMatcher); + } + /** * All of the matchers in this set must return true in order for this ItemExpression to match a given item. * From 9d4ef03a2af33acc5a83a9bc320669decd8c0500 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 22:47:06 -0700 Subject: [PATCH 086/108] Sort ItemExpression.parseConfig() and add comments Also parseLeatherColor is removed and inlined, since it was a one-line function. --- .../itemExpression/ItemExpression.java | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index fc5ddb27..9a8418bd 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -98,32 +98,72 @@ public ItemExpression(ItemStack item, boolean acceptSimilar) { * @param config The config that options will be taken from. */ public void parseConfig(ConfigurationSection config) { + // material addMatcher(new ItemMaterialMatcher(parseMaterial(config, "material"))); + + // amount addMatcher(new ItemAmountMatcher(parseAmount(config, "amount"))); + + // durability addMatcher(new ItemDurabilityMatcher(parseAmount(config, "durability"))); + + // lore addMatcher(new ItemLoreMatcher(parseLore(config, "lore"))); + + // display name addMatcher(new ItemNameMatcher(parseName(config, "name"))); + + // enchantments (example: eff5 diamond pickaxe) addMatcher(parseEnchantment(config, "enchantmentsAny", ANY, ITEM)); addMatcher(parseEnchantment(config, "enchantmentsAll", ALL, ITEM)); addMatcher(parseEnchantment(config, "enchantmentsNone", NONE, ITEM)); addMatcher(parseEnchangmentCount(config, "enchantmentCount", ITEM)); + + // held enchantments (example: enchanted book) addMatcher(parseEnchantment(config, "enchantmentsHeldAny", ANY, HELD)); addMatcher(parseEnchantment(config, "enchantmentsHeldAll", ALL, HELD)); addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); addMatcher(parseEnchangmentCount(config, "enchantmentHeldCount", HELD)); + + // skull addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); + + // item flags (https://hub.spigotmc.org/javadocs/spigot/org/bukkit/inventory/ItemFlag.html) addMatcher(parseFlags(config, "flags")); + + // unbreakable addMatcher(parseUnbreakable(config, "unbreakable")); + + // held inventory (example: shulker box) addMatcher(parseInventory(config, "inventory")); + addMatcher(parseInventory(config, "shulkerbox.inventory")); + + // shulker box color + addMatcher(new ItemShulkerBoxColorMatcher(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); + + // written book addMatcher(parseBook(config, "book")); + + // exact item stack addMatcher(parseExactly(config, "exactly")); - addMatcher(new ItemShulkerBoxColorMatcher(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); + + // knowlege book (creative item that holds recipe unlocks) addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); + + // potion addMatcher(parsePotion(config, "potion")); + + // attributes addMatcher(parseAllAttributes(config, "attributes")); + + // tropical fish bucket (added in 1.13) addMatcher(parseTropicFishBucket(config, "tropicalFishBucket")); - addMatcher(parseLeatherColor(config, "leatherArmorColor")); + + // leather armor color + addMatcher(new ItemLeatherArmorColorMatcher(parseColor(config, "leatherArmorColor"))); + + // map addMatcher(parseMap(config, "map")); } @@ -574,13 +614,6 @@ private ListColor parseListColor(List config) { .collect(Collectors.toList()), false); } - private ItemLeatherArmorColorMatcher parseLeatherColor(ConfigurationSection config, String path) { - if (!config.contains(path)) - return null; - - return new ItemLeatherArmorColorMatcher(parseColor(config, path)); - } - private List parseMap(ConfigurationSection config, String path) { if (!config.isConfigurationSection(path)) return Collections.emptyList(); From 61b0fb53fea41900e1da48586584ade73d2e436f Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 12 Mar 2019 23:16:19 -0700 Subject: [PATCH 087/108] Fix multiple ItemMatchers being initalized with null values Now they have a .contruct() function that checks for null. --- .../itemExpression/ItemExpression.java | 16 ++++++++-------- .../itemExpression/amount/ItemAmountMatcher.java | 7 +++++++ .../amount/ItemDurabilityMatcher.java | 7 +++++++ .../itemExpression/lore/ItemLoreMatcher.java | 7 +++++++ .../material/ItemMaterialMatcher.java | 7 +++++++ .../misc/ItemLeatherArmorColorMatcher.java | 7 +++++++ .../misc/ItemShulkerBoxColorMatcher.java | 7 +++++++ .../itemExpression/misc/ItemSkullMatcher.java | 7 +++++++ .../itemExpression/name/ItemNameMatcher.java | 7 +++++++ 9 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 9a8418bd..cd2186c1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -99,19 +99,19 @@ public ItemExpression(ItemStack item, boolean acceptSimilar) { */ public void parseConfig(ConfigurationSection config) { // material - addMatcher(new ItemMaterialMatcher(parseMaterial(config, "material"))); + addMatcher(ItemMaterialMatcher.construct(parseMaterial(config, "material"))); // amount - addMatcher(new ItemAmountMatcher(parseAmount(config, "amount"))); + addMatcher(ItemAmountMatcher.construct(parseAmount(config, "amount"))); // durability - addMatcher(new ItemDurabilityMatcher(parseAmount(config, "durability"))); + addMatcher(ItemDurabilityMatcher.construct(parseAmount(config, "durability"))); // lore - addMatcher(new ItemLoreMatcher(parseLore(config, "lore"))); + addMatcher(ItemLoreMatcher.construct(parseLore(config, "lore"))); // display name - addMatcher(new ItemNameMatcher(parseName(config, "name"))); + addMatcher(ItemNameMatcher.construct(parseName(config, "name"))); // enchantments (example: eff5 diamond pickaxe) addMatcher(parseEnchantment(config, "enchantmentsAny", ANY, ITEM)); @@ -126,7 +126,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseEnchangmentCount(config, "enchantmentHeldCount", HELD)); // skull - addMatcher(new ItemSkullMatcher(parseSkull(config, "skull"))); + addMatcher(ItemSkullMatcher.construct(parseSkull(config, "skull"))); // item flags (https://hub.spigotmc.org/javadocs/spigot/org/bukkit/inventory/ItemFlag.html) addMatcher(parseFlags(config, "flags")); @@ -139,7 +139,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseInventory(config, "shulkerbox.inventory")); // shulker box color - addMatcher(new ItemShulkerBoxColorMatcher(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); + addMatcher(ItemShulkerBoxColorMatcher.construct(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); // written book addMatcher(parseBook(config, "book")); @@ -161,7 +161,7 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseTropicFishBucket(config, "tropicalFishBucket")); // leather armor color - addMatcher(new ItemLeatherArmorColorMatcher(parseColor(config, "leatherArmorColor"))); + addMatcher(ItemLeatherArmorColorMatcher.construct(parseColor(config, "leatherArmorColor"))); // map addMatcher(parseMap(config, "map")); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java index 01517e50..80260887 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java @@ -13,6 +13,13 @@ public ItemAmountMatcher(AmountMatcher matcher) { this.matcher = matcher; } + public static ItemAmountMatcher construct(AmountMatcher matcher) { + if (matcher == null) + return null; + + return new ItemAmountMatcher(matcher); + } + public AmountMatcher matcher; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java index 1cd6a378..8c13823f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java @@ -12,6 +12,13 @@ public ItemDurabilityMatcher(AmountMatcher matcher) { this.matcher = matcher; } + public static ItemDurabilityMatcher construct(AmountMatcher matcher) { + if (matcher == null) + return null; + + return new ItemDurabilityMatcher(matcher); + } + public AmountMatcher matcher; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java index 7049ea35..a4e5e398 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java @@ -11,6 +11,13 @@ public ItemLoreMatcher(LoreMatcher matcher) { this.matcher = matcher; } + public static ItemLoreMatcher construct(LoreMatcher matcher) { + if (matcher == null) + return null; + + return new ItemLoreMatcher(matcher); + } + public LoreMatcher matcher; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java index 4b2606a5..3ec95bfb 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java @@ -11,6 +11,13 @@ public ItemMaterialMatcher(MaterialMatcher matcher) { this.matcher = matcher; } + public static ItemMaterialMatcher construct(MaterialMatcher matcher) { + if (matcher == null) + return null; + + return new ItemMaterialMatcher(matcher); + } + public MaterialMatcher matcher; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java index f13a9c3f..fdf52f3e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java @@ -14,6 +14,13 @@ public ItemLeatherArmorColorMatcher(ColorMatcher color) { this.color = color; } + public static ItemLeatherArmorColorMatcher construct(ColorMatcher color) { + if (color == null) + return null; + + return new ItemLeatherArmorColorMatcher(color); + } + public ColorMatcher color; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java index 0ebd1303..28ff0086 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java @@ -15,6 +15,13 @@ public ItemShulkerBoxColorMatcher(EnumMatcher color) { this.color = color; } + public static ItemShulkerBoxColorMatcher construct(EnumMatcher color) { + if (color == null) + return null; + + return new ItemShulkerBoxColorMatcher(color); + } + public EnumMatcher color; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java index a40c6b5a..07731717 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java @@ -16,6 +16,13 @@ public ItemSkullMatcher(List ownerMatcher) { this.ownerMatcher = ownerMatcher; } + public static ItemSkullMatcher construct(List ownerMatcher) { + if (ownerMatcher == null || ownerMatcher.isEmpty()) + return null; + + return new ItemSkullMatcher(ownerMatcher); + } + public List ownerMatcher; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java index e5f50416..89af0390 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java @@ -11,6 +11,13 @@ public ItemNameMatcher(NameMatcher matcher) { this.matcher = matcher; } + public static ItemNameMatcher construct(NameMatcher matcher) { + if (matcher == null) + return null; + + return new ItemNameMatcher(matcher); + } + public NameMatcher matcher; @Override From d08517cf1301cc3bc57697bec1cbb5b184b520db Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 13 Mar 2019 00:10:29 -0700 Subject: [PATCH 088/108] Add matching over monster spawners --- .../itemExpression/ItemExpression.java | 53 +++++++++++++++++++ .../ItemMobSpawnerDelayMatcher.java | 24 +++++++++ ...temMobSpawnerMaxNearbyEntitiesMatcher.java | 24 +++++++++ ...mMobSpawnerRequiredPlayerRangeMatcher.java | 24 +++++++++ .../ItemMobSpawnerSpawnCountMatcher.java | 24 +++++++++ .../ItemMobSpawnerSpawnDelayMatcher.java | 35 ++++++++++++ .../ItemMobSpawnerSpawnRadiusMatcher.java | 24 +++++++++ .../ItemMobSpawnerSpawnedMobMatcher.java | 25 +++++++++ .../mobspawner/MobSpawnerUtil.java | 50 +++++++++++++++++ 9 files changed, 283 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index cd2186c1..2d3483a1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -7,6 +7,7 @@ import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.entity.EntityType; import org.bukkit.entity.TropicalFish; import org.bukkit.inventory.*; import org.bukkit.inventory.meta.*; @@ -29,6 +30,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket.ItemTropicFishBBodyColorMatcher; @@ -165,6 +167,9 @@ public void parseConfig(ConfigurationSection config) { // map addMatcher(parseMap(config, "map")); + + // mob spawner + addMatcher(parseMobSpawner(config, "spawner")); } /** @@ -668,6 +673,54 @@ private List parseMap(ConfigurationSection config, String path) { return matchers; } + private List parseMobSpawner(ConfigurationSection config, String path) { + if (!config.isConfigurationSection(path)) + return Collections.emptyList(); + + ArrayList matchers = new ArrayList<>(); + ConfigurationSection spawner = config.getConfigurationSection(path); + + if (spawner.contains("delay.current")) { + // Caution: This is the time until the spawner will spawn its next mob. See minDelay and maxDelay for + // what might be expected. + matchers.add(new ItemMobSpawnerDelayMatcher(parseAmount(spawner, "delay.current"))); + } + + if (spawner.contains("maxNearbyEntities")) { + matchers.add(new ItemMobSpawnerMaxNearbyEntitiesMatcher(parseAmount(spawner, "maxNearbyEntities"))); + } + + if (spawner.contains("requiredPlayerRange")) { + matchers.add(new ItemMobSpawnerRequiredPlayerRangeMatcher(parseAmount(spawner, "requiredPlayerRange"))); + } + + if (spawner.contains("spawnCount")) { + matchers.add(new ItemMobSpawnerSpawnCountMatcher(parseAmount(spawner, "spawnCount"))); + } + + if (spawner.contains("delay.max")) { + matchers.add(new ItemMobSpawnerSpawnDelayMatcher(parseAmount(spawner, "delay.max"), + ItemMobSpawnerSpawnDelayMatcher.MinMax.MAX)); + } + + if (spawner.contains("delay.min")) { + matchers.add(new ItemMobSpawnerSpawnDelayMatcher(parseAmount(spawner, "delay.min"), + ItemMobSpawnerSpawnDelayMatcher.MinMax.MIN)); + } + + if (spawner.contains("mob")) { + matchers.add(new ItemMobSpawnerSpawnedMobMatcher(parseEnumMatcher(spawner, "mob", EntityType.class))); + } else if (spawner.contains("entity")) { + // duplicate of "mob", for completeness + matchers.add(new ItemMobSpawnerSpawnedMobMatcher(parseEnumMatcher(spawner, "entity", EntityType.class))); + } + + if (spawner.contains("radius")) { + matchers.add(new ItemMobSpawnerSpawnRadiusMatcher(parseAmount(spawner, "radius"))); + } + + return matchers; + } /** * Runs this ItemExpression on a given ItemStack. diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java new file mode 100644 index 00000000..ea4fcd0d --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Amelorate + */ +public class ItemMobSpawnerDelayMatcher implements ItemMatcher { + public ItemMobSpawnerDelayMatcher(AmountMatcher delay) { + this.delay = delay; + } + + public AmountMatcher delay; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + return delay.matches(MobSpawnerUtil.getMobSpawnerState(item).getDelay()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java new file mode 100644 index 00000000..866f7019 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemMobSpawnerMaxNearbyEntitiesMatcher implements ItemMatcher { + public ItemMobSpawnerMaxNearbyEntitiesMatcher(AmountMatcher maxNearbyEntities) { + this.maxNearbyEntities = maxNearbyEntities; + } + + public AmountMatcher maxNearbyEntities; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + return maxNearbyEntities.matches(MobSpawnerUtil.getMobSpawnerState(item).getMaxNearbyEntities()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java new file mode 100644 index 00000000..cedb3e59 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemMobSpawnerRequiredPlayerRangeMatcher implements ItemMatcher { + public ItemMobSpawnerRequiredPlayerRangeMatcher(AmountMatcher range) { + this.range = range; + } + + public AmountMatcher range; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + return range.matches(MobSpawnerUtil.getMobSpawnerState(item).getRequiredPlayerRange()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java new file mode 100644 index 00000000..ea6936a7 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemMobSpawnerSpawnCountMatcher implements ItemMatcher { + public ItemMobSpawnerSpawnCountMatcher(AmountMatcher spawnCount) { + this.spawnCount = spawnCount; + } + + public AmountMatcher spawnCount; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + return spawnCount.matches(MobSpawnerUtil.getMobSpawnerState(item).getSpawnCount()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java new file mode 100644 index 00000000..f37b3e38 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java @@ -0,0 +1,35 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.block.CreatureSpawner; +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemMobSpawnerSpawnDelayMatcher implements ItemMatcher { + public ItemMobSpawnerSpawnDelayMatcher(AmountMatcher spawnDelay, MinMax source) { + this.spawnDelay = spawnDelay; + this.source = source; + } + + public AmountMatcher spawnDelay; + public MinMax source; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + int spawnDelay = source == MinMax.MAX ? spawner.getMaxSpawnDelay() : spawner.getMinSpawnDelay(); + + return this.spawnDelay.matches(spawnDelay); + } + + public enum MinMax { + MIN, + MAX, + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java new file mode 100644 index 00000000..37bdee28 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java @@ -0,0 +1,24 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemMobSpawnerSpawnRadiusMatcher implements ItemMatcher { + public ItemMobSpawnerSpawnRadiusMatcher(AmountMatcher spawnRadius) { + this.spawnRadius = spawnRadius; + } + + public AmountMatcher spawnRadius; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + return spawnRadius.matches(MobSpawnerUtil.getMobSpawnerState(item).getSpawnRange()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java new file mode 100644 index 00000000..5ab95952 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; + +/** + * @author Ameliorate + */ +public class ItemMobSpawnerSpawnedMobMatcher implements ItemMatcher { + public ItemMobSpawnerSpawnedMobMatcher(EnumMatcher spawned) { + this.spawned = spawned; + } + + public EnumMatcher spawned; + + @Override + public boolean matches(ItemStack item) { + if (!MobSpawnerUtil.isMobSpawner(item)) + return false; + + return spawned.matches(MobSpawnerUtil.getMobSpawnerState(item).getSpawnedType()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java new file mode 100644 index 00000000..3da6669f --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java @@ -0,0 +1,50 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; + +import org.bukkit.block.CreatureSpawner; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; + +/** + * Utility class for dealing with Creature Spawners. + * + * This is mostly ment for ItemExpressions matching over mob spawners. + * + * @author Ameliorate + */ +public class MobSpawnerUtil { + /** + * Checks if a given item holds a BlockState, and if it does if that BlockState holds a CreatureSpawner. + * + * @param item The item that may or may not hold a CreatureSpawner + * @return true if the item holds a CreatureSpawner, false otherwise + */ + public static boolean isMobSpawner(ItemStack item) { + if (!item.hasItemMeta()) + return false; + + if (!(item.getItemMeta() instanceof BlockStateMeta)) + return false; + + if (!((BlockStateMeta) item.getItemMeta()).hasBlockState()) + return false; + + return ((BlockStateMeta) item.getItemMeta()).getBlockState() instanceof CreatureSpawner; + } + + /** + * Gets a CreatureSpawner from an ItemStack, by getting a stored BlockState from the item's meta, and then + * casting that BlockState to a CreatureSpawner. + * + * @param item The item to get a CreatureSpawner from. + * @return The CreatureSpawner the ItemStack was holding. + * @throws IllegalArgumentException If the item does not hold a CreatureSpawner + */ + public static CreatureSpawner getMobSpawnerState(ItemStack item) { + if (!isMobSpawner(item)) + throw new IllegalArgumentException("item is not a mob spawner"); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + + return (CreatureSpawner) meta.getBlockState(); + } +} From d538eed88fa7760fbe1fccd9fd03e91c956ea4e2 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 13 Mar 2019 00:11:17 -0700 Subject: [PATCH 089/108] Add a null check to ItemExpression.addMatcher(Collection) Now it'll ignore matchers == null, in case it is passed in. --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 2d3483a1..d18a12f4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -967,6 +967,9 @@ public void addMatcher(ItemMatcher matcher) { * item. If this list contains any null elements, those null elements will be ignored. */ public void addMatcher(Collection matchers) { + if (matchers == null) + return; + matchers.forEach(this::addMatcher); } From 6f77cc9a6b4720da680e4e0d99933f195aebcc8f Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 13 Mar 2019 00:13:39 -0700 Subject: [PATCH 090/108] Remove unused import in ExactlyColour --- .../itemHandling/itemExpression/color/ExactlyColor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java index 6efa84fb..8b10e17c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java @@ -3,7 +3,6 @@ import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.DyeColor; -import org.bukkit.inventory.ItemFactory; /** * @author Ameliorate From 7deef0c1fad0e61b490d011fc1f37d0b81c663e4 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 13 Mar 2019 22:18:15 -0700 Subject: [PATCH 091/108] Greately improve ListMatchingMode It now has a function to implement its logic, and functions to get each mode's name as UpperCamelCase or lowerCamelCase. Also adds GenericMatcher, which is implemented for all the *Matcher's. This is used in the implementation of ListMatchingMode.matches(Collection, Collection). --- .../itemExpression/ItemExpression.java | 4 +- .../itemExpression/ItemMatcher.java | 8 +- .../itemExpression/amount/AmountMatcher.java | 9 +- .../itemExpression/book/BookPageMatcher.java | 9 +- .../itemExpression/color/ColorMatcher.java | 8 +- .../enchantment/EnchantmentMatcher.java | 10 +- .../enchantment/ItemEnchantmentsMatcher.java | 25 +---- .../enummatcher/EnumMatcher.java | 9 +- .../itemExpression/lore/LoreMatcher.java | 9 +- .../itemExpression/map/MapViewMatcher.java | 8 +- .../material/MaterialMatcher.java | 8 +- .../itemExpression/misc/GenericMatcher.java | 22 ++++ .../misc/ItemAttributeMatcher.java | 26 ++--- .../itemExpression/misc/ListMatchingMode.java | 100 +++++++++++++++++- .../itemExpression/name/NameMatcher.java | 9 +- .../potion/ItemPotionEffectsMatcher.java | 18 +--- .../potion/PotionEffectMatcher.java | 8 +- .../itemExpression/uuid/UUIDMatcher.java | 9 +- 18 files changed, 223 insertions(+), 76 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index d18a12f4..5d5e69a5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -471,14 +471,14 @@ private List parseAllAttributes(ConfigurationSection confi for (ListMatchingMode mode : ListMatchingMode.values()) { for (EquipmentSlot slot : EquipmentSlot.values()) { - String modeString = mode.toString().toLowerCase(); + String modeString = mode.getLowerCamelCase(); matchers.add(parseAttributes(config, path + "." + slot + "." + modeString, slot, mode)); } } for (ListMatchingMode mode : ListMatchingMode.values()) { - matchers.add(parseAttributes(config, path + ".any." + mode, null, mode)); + matchers.add(parseAttributes(config, path + ".any." + mode.getLowerCamelCase(), null, mode)); } return matchers; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java index 4ca31def..3325e304 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; /** * Represents a single property of an item that should be checked. @@ -9,6 +10,11 @@ * * @author Ameliorate */ -public interface ItemMatcher { +public interface ItemMatcher extends GenericMatcher { boolean matches(ItemStack item); + + @Override + default boolean genericMatches(ItemStack matched) { + return matches(matched); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index 256a2f49..b639b939 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -1,15 +1,22 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + /** * @author Ameliorate * * In addition to the amount of items in an ItemStack, these are also used for the durability of an item, and * the level of an enchantment. */ -public interface AmountMatcher { +public interface AmountMatcher extends GenericMatcher { default boolean matches(int amount) { return matches((double) amount); } boolean matches(double amount); + + @Override + default boolean genericMatches(Double amount) { + return matches(amount); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java index c4715d54..8c425d12 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java @@ -1,15 +1,22 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + import java.util.List; /** * @author Ameliorate */ -public interface BookPageMatcher { +public interface BookPageMatcher extends GenericMatcher> { /** * @param pages A list of multi-line strings that represent the pages of a written book. Colours left intact in the * section character format. * @return If the pages matched. */ boolean matches(List pages); + + @Override + default boolean genericMatches(List matched) { + return matches(matched); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java index 79aeaa45..a679a684 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java @@ -1,10 +1,16 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color; import org.bukkit.Color; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; /** * @author Ameliorate */ -public interface ColorMatcher { +public interface ColorMatcher extends GenericMatcher { boolean matches(Color color); + + @Override + default boolean genericMatches(Color color) { + return matches(color); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java index c7b0599b..2300c307 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java @@ -1,10 +1,18 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; import org.bukkit.enchantments.Enchantment; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + +import java.util.Map; /** * @author Ameliorate */ -public interface EnchantmentMatcher { +public interface EnchantmentMatcher extends GenericMatcher> { boolean matches(Enchantment enchantment, int level); + + @Override + default boolean genericMatches(Map.Entry matched) { + return matches(matched.getKey(), matched.getValue()); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java index 09e9a631..52bbe023 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java @@ -8,8 +8,6 @@ import java.util.List; import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Stream; /** * @author Ameliorate @@ -40,30 +38,9 @@ public boolean matches(ItemStack item) { return matches(((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants()); } throw new AssertionError("not reachable"); - // see the below function for the coy remarks } public boolean matches(Map enchantments) { - Stream enchantmentMatcherStream = enchantmentMatchers.stream(); - Predicate predicate = (enchantmentMatcher) -> enchantments.entrySet().stream().anyMatch((e) -> { - Enchantment enchantment = e.getKey(); - int level = e.getValue(); - return enchantmentMatcher.matches(enchantment, level); - }); - - switch (mode) { - // Normally there'd be a break statement after each of the return's, but java complains because the break's - // are technically unreachable. - case ANY: - return enchantmentMatcherStream.anyMatch(predicate); - case ALL: - return enchantmentMatcherStream.allMatch(predicate); - case NONE: - return enchantmentMatcherStream.noneMatch(predicate); - } - - throw new AssertionError("not reachable"); - // naturally, it complains here because it can't figure out that the switch above always returns, so we don't - // need a return statement here. + return mode.matches(enchantmentMatchers, enchantments.entrySet()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java index c194fcbd..9cabe902 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java @@ -1,5 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + /** * Matches over an Enum in an enum-generic way. * @@ -7,6 +9,11 @@ * * @author Ameliorate */ -public interface EnumMatcher> { +public interface EnumMatcher> extends GenericMatcher { boolean matches(E enumm); + + @Override + default boolean genericMatches(E matched) { + return matches(matched); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java index b6dac746..e93e4621 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java @@ -1,10 +1,17 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + import java.util.List; /** * @author Ameliorate */ -public interface LoreMatcher { +public interface LoreMatcher extends GenericMatcher> { boolean matches(List lore); + + @Override + default boolean genericMatches(List lore) { + return matches(lore); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java index b72fb415..69c7a438 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java @@ -1,10 +1,16 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; import org.bukkit.map.MapView; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; /** * @author Ameliorate */ -public interface MapViewMatcher { +public interface MapViewMatcher extends GenericMatcher { boolean matches(MapView map); + + @Override + default boolean genericMatches(MapView view) { + return matches(view); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java index ab2243ce..d87fb042 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java @@ -1,10 +1,16 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; import org.bukkit.Material; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; /** * @author Ameliorate */ -public interface MaterialMatcher { +public interface MaterialMatcher extends GenericMatcher { boolean matches(Material material); + + @Override + default boolean genericMatches(Material matched) { + return matches(matched); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java new file mode 100644 index 00000000..9f0bffd3 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java @@ -0,0 +1,22 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +/** + * Represents any interface for matching over a class. This is used in the implenation of + * ListMatcherMode.matches() in order to be able to accept any list of matchers and list of things. + * + * @param The thing that is matched over by this matcher. + * + * @author Ameliorate + */ +public interface GenericMatcher { + /** + * Matches over the thing. + * + * In most *Matcher interfaces, this should be defined as a default method that calls the interface's individual + * matches() function. + * + * @param matched The thing that this matcher is matching over. + * @return If this matcher matched the thing. + */ + boolean genericMatches(T matched); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java index abff8acb..1aec6d38 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java @@ -11,6 +11,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.UUIDMatcher; import java.util.List; +import java.util.Map; import java.util.function.Predicate; /** @@ -37,26 +38,10 @@ public boolean matches(ItemStack item) { if (!item.hasItemMeta() || !item.getItemMeta().hasAttributeModifiers()) return false; - return item.getItemMeta().getAttributeModifiers(slot).entries().stream().anyMatch((e) -> { - Attribute attribute = e.getKey(); - AttributeModifier modifier = e.getValue(); - - Predicate matcherMatchesPredicate = (matcher) -> matcher.matches(attribute, modifier); - - switch (mode) { - case ANY: - return matchers.stream().anyMatch(matcherMatchesPredicate); - case ALL: - return matchers.stream().allMatch(matcherMatchesPredicate); - case NONE: - return matchers.stream().noneMatch(matcherMatchesPredicate); - } - - throw new AssertionError("not reachable"); - }); + return mode.matches(matchers, item.getItemMeta().getAttributeModifiers(slot).entries()); } - public static class AttributeMatcher { + public static class AttributeMatcher implements GenericMatcher> { public AttributeMatcher(EnumMatcher attribute, NameMatcher name, EnumMatcher operation, UUIDMatcher uuid, AmountMatcher amount) { @@ -87,5 +72,10 @@ else if (amount != null && !amount.matches(modifier.getAmount())) else return true; } + + @Override + public boolean genericMatches(Map.Entry matched) { + return matches(matched.getKey(), matched.getValue()); + } } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java index 086b1ee2..942e17fd 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java @@ -1,5 +1,13 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import com.google.common.collect.Lists; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Stream; + /** * Represents the different ways of interpreting a list of things when comparing it to another list. * @@ -9,15 +17,101 @@ public enum ListMatchingMode { /** * At least one element in the list must match an element in the other list. */ - ANY, + ANY("Any", "any"), /** * Every one of the elements in the list must match an element in the other list. */ - ALL, + ALL("All", "all"), /** * No element in the list may match an element in the other list. */ - NONE, + NONE("None", "none"), + + /** + * Try to match each element to another element in the other list 1:1, where no element in either list has a + * counterpart in the other list. Returns true when every item in the first list matched an item in the second + * list. + * + * This is like ALL, but in ALL an item in the first list can match multiple items in the second list. In this mode, + * an item in the first list can only match one item in the second list. + */ + ONE_TO_ONE("OneToOne", "oneToOne"); + + ListMatchingMode(String upperCamelCase, String lowerCamelCase) { + this.upperCamelCase = upperCamelCase; + this.lowerCamelCase = lowerCamelCase; + } + + /** + * Returns the name of this mode, in CamelCase starting with an upper case letter. + * + * For example: ONE_TO_ONE becomes OneToOne. + * + * @return The name of the mode, in UpperCammelCase. + */ + public String getUpperCamelCase() { + return upperCamelCase; + } + + /** + * Returns the name of this mode, in CamelCase starting with a lower case letter. + * + * For example: ONE_TO_ONE becomes oneToOne. + * + * @return The name of the mode, in lowerCamelCase. + */ + public String getLowerCamelCase() { + return lowerCamelCase; + } + + private String upperCamelCase; + private String lowerCamelCase; + + /** + * Generic function to exxert this ListMatchingMode in matching a list of things using a list of matchers. + * + * @param matchers The list of matchers that will match over elements of the list of things. + * @param matched The list of things that the list of matchers will match over. + * @param The type of the list of things. + * @param The type of each matcher. + * @return If the list of matchers matched over the list of things, in the order that was defined in this ListMatchingMode. + */ + public > boolean matches(Collection matchers, Collection matched) { + Stream matcherStream = matchers.stream(); + Predicate matchedPredicate = (matcher) -> matched.stream().anyMatch(matcher::genericMatches); + + switch (this) { + case ANY: + return matcherStream.anyMatch(matchedPredicate); + case ALL: + return matcherStream.allMatch(matchedPredicate); + case NONE: + return matcherStream.noneMatch(matchedPredicate); + case ONE_TO_ONE: + List matchersClone = new ArrayList<>(matchers); + List matchedClone = new ArrayList<>(matched); + + for (M matcher : Lists.reverse(matchersClone)) { + boolean hasMatched = false; + + for (T matchedElement : matchedClone) { + if (matcher.genericMatches(matchedElement)) { + matchedClone.remove(matchedElement); + matchersClone.remove(matcher); + hasMatched = true; + break; + } + } + + if (!hasMatched) + return false; + } + + return matchersClone.isEmpty(); + } + + throw new AssertionError("not reachable"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java index 865d3d0e..8fcb48a8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java @@ -1,8 +1,15 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + /** * @author Ameliorate */ -public interface NameMatcher { +public interface NameMatcher extends GenericMatcher { boolean matches(String name); + + @Override + default boolean genericMatches(String matched) { + return matches(matched); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java index 1c6113bf..570b3218 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java @@ -41,22 +41,6 @@ public boolean matches(ItemStack item) { } public boolean matches(List effects) { - Stream enchantmentMatcherStream = potionMatchers.stream(); - Predicate predicate = (potionMatcher) -> effects.stream().anyMatch(potionMatcher::matches); - - switch (mode) { - // Normally there'd be a break statement after each of the return's, but java complains because the break's - // are technically unreachable. - case ANY: - return enchantmentMatcherStream.anyMatch(predicate); - case ALL: - return enchantmentMatcherStream.allMatch(predicate); - case NONE: - return enchantmentMatcherStream.noneMatch(predicate); - } - - throw new AssertionError("not reachable"); - // naturally, it complains here because it can't figure out that the switch above always returns, so we don't - // need a return statement here. + return mode.matches(potionMatchers, effects); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java index 016f4d23..6fc532cf 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java @@ -1,10 +1,16 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; import org.bukkit.potion.PotionEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; /** * @author Ameliorate */ -public interface PotionEffectMatcher { +public interface PotionEffectMatcher extends GenericMatcher { boolean matches(PotionEffect effect); + + @Override + default boolean genericMatches(PotionEffect matched) { + return matches(matched); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java index 2890f5d5..55b4d728 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java @@ -1,5 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; + import java.util.UUID; /** @@ -7,6 +9,11 @@ * * These classes are generally used for matching player heads. */ -public interface UUIDMatcher { +public interface UUIDMatcher extends GenericMatcher { boolean matches(UUID uuid); + + @Override + default boolean genericMatches(UUID matched) { + return matches(matched); + } } From b027455e548a7d6f1f2bbd0027e676518885d01e Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Wed, 13 Mar 2019 23:52:27 -0700 Subject: [PATCH 092/108] Refactor GenericMatcher into a generic class for all matchers Basically a bunch of magic. Now all the *matcher interfaces don't have to say boolean matches(TheThing theThing);. It's automagically infered by the java compiler somehow. It works, and it even is backwards- compatible with almost all the classes. --- .../itemExpression/ItemMatcher.java | 9 +------ .../itemHandling/itemExpression/Matcher.java | 25 +++++++++++++++++++ .../itemExpression/amount/AmountMatcher.java | 11 ++------ .../itemExpression/amount/AnyAmount.java | 2 +- .../itemExpression/amount/ExactlyAmount.java | 2 +- .../itemExpression/amount/RangeAmount.java | 2 +- .../itemExpression/book/BookPageMatcher.java | 15 ++--------- .../itemExpression/color/ColorMatcher.java | 10 ++------ .../enchantment/EnchantmentMatcher.java | 6 ++--- .../enummatcher/EnumMatcher.java | 10 ++------ .../itemExpression/lore/LoreMatcher.java | 10 ++------ .../itemExpression/map/MapViewMatcher.java | 10 ++------ .../material/MaterialMatcher.java | 10 ++------ .../itemExpression/misc/GenericMatcher.java | 22 ---------------- .../misc/ItemAttributeMatcher.java | 6 ++--- .../itemExpression/misc/ListMatchingMode.java | 7 +++--- .../itemExpression/name/NameMatcher.java | 10 ++------ .../potion/PotionEffectMatcher.java | 10 ++------ .../itemExpression/uuid/UUIDMatcher.java | 10 ++------ 19 files changed, 59 insertions(+), 128 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java index 3325e304..6ab6b5e2 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemMatcher.java @@ -1,7 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; import org.bukkit.inventory.ItemStack; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; /** * Represents a single property of an item that should be checked. @@ -10,11 +9,5 @@ * * @author Ameliorate */ -public interface ItemMatcher extends GenericMatcher { - boolean matches(ItemStack item); - - @Override - default boolean genericMatches(ItemStack matched) { - return matches(matched); - } +public interface ItemMatcher extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java new file mode 100644 index 00000000..7bade75a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; + +/** + * Represents any interface for matching over a class. + * + * This is used mainly in the implementation of ListMatcherMode.matches() + * in order to be able to accept any list of matchers and list of things. + * + * However, this is used by all the *Matcher's in order to define the boolean matches(TheThing) function. + * + * @param The thing that is matched over by this matcher. + * + * @author Ameliorate + */ +public interface Matcher { + /** + * Determines if this Matcher matches the thing passed in. + * + * This should not mutate matched in any way. + * + * @param matched The thing that this matcher is matching over. + * @return If this matcher matched the thing. + */ + boolean matches(T matched); +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index b639b939..dbc58626 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -1,6 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * @author Ameliorate @@ -8,15 +8,8 @@ * In addition to the amount of items in an ItemStack, these are also used for the durability of an item, and * the level of an enchantment. */ -public interface AmountMatcher extends GenericMatcher { +public interface AmountMatcher extends Matcher { default boolean matches(int amount) { return matches((double) amount); } - - boolean matches(double amount); - - @Override - default boolean genericMatches(Double amount) { - return matches(amount); - } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java index 795a932f..328129b6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java @@ -7,7 +7,7 @@ */ public class AnyAmount implements AmountMatcher { @Override - public boolean matches(double amount) { + public boolean matches(Double amount) { return true; } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java index 2c8c30d1..00ee71f7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java @@ -13,7 +13,7 @@ public ExactlyAmount(double amount) { public double amount; @Override - public boolean matches(double amount) { + public boolean matches(Double amount) { return this.amount == amount; } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java index 4f68d6ee..c35796d4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java @@ -44,7 +44,7 @@ public double getHigh() { } @Override - public boolean matches(double amount) { + public boolean matches(Double amount) { if (lowInclusive) { if (amount < low) return false; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java index 8c425d12..42491adf 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/BookPageMatcher.java @@ -1,22 +1,11 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import java.util.List; /** * @author Ameliorate */ -public interface BookPageMatcher extends GenericMatcher> { - /** - * @param pages A list of multi-line strings that represent the pages of a written book. Colours left intact in the - * section character format. - * @return If the pages matched. - */ - boolean matches(List pages); - - @Override - default boolean genericMatches(List matched) { - return matches(matched); - } +public interface BookPageMatcher extends Matcher> { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java index a679a684..51b5fba0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ColorMatcher.java @@ -1,16 +1,10 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color; import org.bukkit.Color; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * @author Ameliorate */ -public interface ColorMatcher extends GenericMatcher { - boolean matches(Color color); - - @Override - default boolean genericMatches(Color color) { - return matches(color); - } +public interface ColorMatcher extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java index 2300c307..790ad448 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentMatcher.java @@ -1,18 +1,18 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; import org.bukkit.enchantments.Enchantment; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import java.util.Map; /** * @author Ameliorate */ -public interface EnchantmentMatcher extends GenericMatcher> { +public interface EnchantmentMatcher extends Matcher> { boolean matches(Enchantment enchantment, int level); @Override - default boolean genericMatches(Map.Entry matched) { + default boolean matches(Map.Entry matched) { return matches(matched.getKey(), matched.getValue()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java index 9cabe902..e5d8ec10 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumMatcher.java @@ -1,6 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * Matches over an Enum in an enum-generic way. @@ -9,11 +9,5 @@ * * @author Ameliorate */ -public interface EnumMatcher> extends GenericMatcher { - boolean matches(E enumm); - - @Override - default boolean genericMatches(E matched) { - return matches(matched); - } +public interface EnumMatcher> extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java index e93e4621..34dcb600 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/LoreMatcher.java @@ -1,17 +1,11 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import java.util.List; /** * @author Ameliorate */ -public interface LoreMatcher extends GenericMatcher> { - boolean matches(List lore); - - @Override - default boolean genericMatches(List lore) { - return matches(lore); - } +public interface LoreMatcher extends Matcher> { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java index 69c7a438..d897a9d2 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/MapViewMatcher.java @@ -1,16 +1,10 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; import org.bukkit.map.MapView; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * @author Ameliorate */ -public interface MapViewMatcher extends GenericMatcher { - boolean matches(MapView map); - - @Override - default boolean genericMatches(MapView view) { - return matches(view); - } +public interface MapViewMatcher extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java index d87fb042..0a46efdf 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java @@ -1,16 +1,10 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; import org.bukkit.Material; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * @author Ameliorate */ -public interface MaterialMatcher extends GenericMatcher { - boolean matches(Material material); - - @Override - default boolean genericMatches(Material matched) { - return matches(matched); - } +public interface MaterialMatcher extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java deleted file mode 100644 index 9f0bffd3..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/GenericMatcher.java +++ /dev/null @@ -1,22 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; - -/** - * Represents any interface for matching over a class. This is used in the implenation of - * ListMatcherMode.matches() in order to be able to accept any list of matchers and list of things. - * - * @param The thing that is matched over by this matcher. - * - * @author Ameliorate - */ -public interface GenericMatcher { - /** - * Matches over the thing. - * - * In most *Matcher interfaces, this should be defined as a default method that calls the interface's individual - * matches() function. - * - * @param matched The thing that this matcher is matching over. - * @return If this matcher matched the thing. - */ - boolean genericMatches(T matched); -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java index 1aec6d38..92e07f12 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java @@ -5,6 +5,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; @@ -12,7 +13,6 @@ import java.util.List; import java.util.Map; -import java.util.function.Predicate; /** * Matches over the attributes of an item that apply for a given slot. @@ -41,7 +41,7 @@ public boolean matches(ItemStack item) { return mode.matches(matchers, item.getItemMeta().getAttributeModifiers(slot).entries()); } - public static class AttributeMatcher implements GenericMatcher> { + public static class AttributeMatcher implements Matcher> { public AttributeMatcher(EnumMatcher attribute, NameMatcher name, EnumMatcher operation, UUIDMatcher uuid, AmountMatcher amount) { @@ -74,7 +74,7 @@ else if (amount != null && !amount.matches(modifier.getAmount())) } @Override - public boolean genericMatches(Map.Entry matched) { + public boolean matches(Map.Entry matched) { return matches(matched.getKey(), matched.getValue()); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java index 942e17fd..22035072 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; import com.google.common.collect.Lists; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import java.util.ArrayList; import java.util.Collection; @@ -78,9 +79,9 @@ public String getLowerCamelCase() { * @param The type of each matcher. * @return If the list of matchers matched over the list of things, in the order that was defined in this ListMatchingMode. */ - public > boolean matches(Collection matchers, Collection matched) { + public > boolean matches(Collection matchers, Collection matched) { Stream matcherStream = matchers.stream(); - Predicate matchedPredicate = (matcher) -> matched.stream().anyMatch(matcher::genericMatches); + Predicate matchedPredicate = (matcher) -> matched.stream().anyMatch(matcher::matches); switch (this) { case ANY: @@ -97,7 +98,7 @@ public > boolean matches(Collection matchers, boolean hasMatched = false; for (T matchedElement : matchedClone) { - if (matcher.genericMatches(matchedElement)) { + if (matcher.matches(matchedElement)) { matchedClone.remove(matchedElement); matchersClone.remove(matcher); hasMatched = true; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java index 8fcb48a8..87935352 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/NameMatcher.java @@ -1,15 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * @author Ameliorate */ -public interface NameMatcher extends GenericMatcher { - boolean matches(String name); - - @Override - default boolean genericMatches(String matched) { - return matches(matched); - } +public interface NameMatcher extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java index 6fc532cf..46aab89e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/PotionEffectMatcher.java @@ -1,16 +1,10 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; import org.bukkit.potion.PotionEffect; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; /** * @author Ameliorate */ -public interface PotionEffectMatcher extends GenericMatcher { - boolean matches(PotionEffect effect); - - @Override - default boolean genericMatches(PotionEffect matched) { - return matches(matched); - } +public interface PotionEffectMatcher extends Matcher { } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java index 55b4d728..42cef605 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/UUIDMatcher.java @@ -1,6 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.GenericMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import java.util.UUID; @@ -9,11 +9,5 @@ * * These classes are generally used for matching player heads. */ -public interface UUIDMatcher extends GenericMatcher { - boolean matches(UUID uuid); - - @Override - default boolean genericMatches(UUID matched) { - return matches(matched); - } +public interface UUIDMatcher extends Matcher { } From eed6880d4d5a856ec5ca0cd15fdfbe2a80b20980 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 15 Mar 2019 20:51:22 -0700 Subject: [PATCH 093/108] Add matching fireworks --- .../itemExpression/ItemExpression.java | 82 +++++++++++++++++++ .../firework/ExactlyFireworkEffect.java | 62 ++++++++++++++ .../firework/FireworkEffectMatcher.java | 10 +++ .../ItemFireworkEffectHolderMatcher.java | 32 ++++++++ .../ItemFireworkEffectsCountMatcher.java | 25 ++++++ .../firework/ItemFireworkEffectsMatcher.java | 32 ++++++++ .../firework/ItemFireworkPowerMatcher.java | 25 ++++++ 7 files changed, 268 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/FireworkEffectMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 5d5e69a5..276a1e4e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -2,6 +2,7 @@ import org.bukkit.Color; import org.bukkit.DyeColor; +import org.bukkit.FireworkEffect; import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; @@ -25,6 +26,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumIndexMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.NameEnumMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; @@ -170,6 +172,12 @@ public void parseConfig(ConfigurationSection config) { // mob spawner addMatcher(parseMobSpawner(config, "spawner")); + + // firework holder (example: firework star) + addMatcher(ItemFireworkEffectHolderMatcher.construct(parseFireworkEffect(config, "fireworkEffectHolder"))); + + // firework + addMatcher(parseFirework(config, "firework")); } /** @@ -722,6 +730,80 @@ private List parseMobSpawner(ConfigurationSection config, String pa return matchers; } + private FireworkEffectMatcher parseFireworkEffect(ConfigurationSection config, String path) { + if (!config.isConfigurationSection(path)) + return null; + + ConfigurationSection fireworkEffect = config.getConfigurationSection(path); + + // effect base color + List colors = new ArrayList<>(); + ListMatchingMode colorsMode = ListMatchingMode.valueOf(fireworkEffect.getString("colorsMode", "ANY").toUpperCase()); + + if (fireworkEffect.isList("colors")) { + for (Object color : fireworkEffect.getList("colors")) { + colors.add(parseColor(color)); + } + } + + colors.add(parseColor(fireworkEffect, "color")); + + List fadeColors = new ArrayList<>(); + ListMatchingMode fadeColorsMode = ListMatchingMode.valueOf(fireworkEffect.getString("fadeColorsMode", "ANY").toUpperCase()); + + if (fireworkEffect.isList("fadeColors")) { + for (Object color : fireworkEffect.getList("fadeColors")) { + fadeColors.add(parseColor(color)); + } + } + + fadeColors.add(parseColor(fireworkEffect, "fadeColor")); + + EnumMatcher type = parseEnumMatcher(fireworkEffect, "type", FireworkEffect.Type.class); + + Optional hasFlicker = Optional.empty(); + if (fireworkEffect.isBoolean("hasFlicker")) { + hasFlicker = Optional.of(fireworkEffect.getBoolean("hasFlicker")); + } + + Optional hasTrail = Optional.empty(); + if (fireworkEffect.isBoolean("hasTrail")) { + hasTrail = Optional.of(fireworkEffect.getBoolean("hasTrail")); + } + + return new ExactlyFireworkEffect(type, colors, colorsMode, fadeColors, fadeColorsMode, hasFlicker, hasTrail); + } + + private List parseFirework(ConfigurationSection config, String path) { + if (!config.isConfigurationSection(path)) + return null; + + ConfigurationSection firework = config.getConfigurationSection(path); + ArrayList matchers = new ArrayList<>(); + + for (ListMatchingMode mode : ListMatchingMode.values()) { + ArrayList effectMatchers = new ArrayList<>(); + + for (ConfigurationSection effect : getConfigList(firework, "effects" + mode.getUpperCamelCase())) { + FireworkEffectMatcher matcher = parseFireworkEffect(effect, ""); + effectMatchers.add(matcher); + } + + if (!effectMatchers.isEmpty()) + matchers.add(new ItemFireworkEffectsMatcher(effectMatchers, mode)); + } + + AmountMatcher power = parseAmount(firework, "power"); + if (power != null) + matchers.add(new ItemFireworkPowerMatcher(power)); + + AmountMatcher effectsCount = parseAmount(firework, "effectsCount"); + if (effectsCount != null) + matchers.add(new ItemFireworkEffectsCountMatcher(effectsCount)); + + return matchers; + } + /** * Runs this ItemExpression on a given ItemStack. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java new file mode 100644 index 00000000..267df4fb --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java @@ -0,0 +1,62 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; + +import org.bukkit.FireworkEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ColorMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; + +import java.util.List; +import java.util.Optional; + +/** + * @author Amleiorate + */ +public class ExactlyFireworkEffect implements FireworkEffectMatcher { + public ExactlyFireworkEffect(EnumMatcher type, + List colors, ListMatchingMode colorsMode, + List fadeColors, ListMatchingMode fadeColorsMode, + Optional hasFlicker, Optional hasTrail) { + this.type = type; + this.colors = colors; + this.colorsMode = colorsMode; + this.fadeColors = fadeColors; + this.fadeColorsMode = fadeColorsMode; + this.hasFlicker = hasFlicker; + this.hasTrail = hasTrail; + } + + public EnumMatcher type; + + public List colors; + public ListMatchingMode colorsMode; + + public List fadeColors; + public ListMatchingMode fadeColorsMode; + + public Optional hasFlicker = Optional.empty(); + public Optional hasTrail = Optional.empty(); + + @Override + public boolean matches(FireworkEffect effect) { + if (hasFlicker.isPresent()) { + if (hasFlicker.get() != effect.hasFlicker()) + return false; + } + + if (hasTrail.isPresent()) { + if (hasTrail.get() != effect.hasTrail()) + return false; + } + + if (type != null && !type.matches(effect.getType())) + return false; + + if (!colorsMode.matches(colors, effect.getColors())) + return false; + + if (!fadeColorsMode.matches(fadeColors, effect.getFadeColors())) + return false; + + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/FireworkEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/FireworkEffectMatcher.java new file mode 100644 index 00000000..a57b860a --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/FireworkEffectMatcher.java @@ -0,0 +1,10 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; + +import org.bukkit.FireworkEffect; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; + +/** + * @author Ameliorate + */ +public interface FireworkEffectMatcher extends Matcher { +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java new file mode 100644 index 00000000..f51c4428 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java @@ -0,0 +1,32 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkEffectMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; + +/** + * @author Ameliorate + */ +public class ItemFireworkEffectHolderMatcher implements ItemMatcher { + public ItemFireworkEffectHolderMatcher(FireworkEffectMatcher effect) { + this.effect = effect; + } + + public static ItemFireworkEffectHolderMatcher construct(FireworkEffectMatcher effect) { + if (effect != null) + return null; + + return new ItemFireworkEffectHolderMatcher(effect); + } + + public FireworkEffectMatcher effect; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkEffectMeta) || + !((FireworkEffectMeta) item.getItemMeta()).hasEffect()) + return false; + + return effect.matches(((FireworkEffectMeta) item.getItemMeta()).getEffect()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java new file mode 100644 index 00000000..f073ce26 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemFireworkEffectsCountMatcher implements ItemMatcher { + public ItemFireworkEffectsCountMatcher(AmountMatcher count) { + this.count = count; + } + + public AmountMatcher count; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkMeta)) + return false; + + return count.matches(((FireworkMeta) item.getItemMeta()).getEffectsSize()); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java new file mode 100644 index 00000000..879a3327 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java @@ -0,0 +1,32 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; + +import org.bukkit.FireworkEffect; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; + +import java.util.List; + +/** + * @author Ameliorate + */ +public class ItemFireworkEffectsMatcher implements ItemMatcher { + public ItemFireworkEffectsMatcher(List effects, ListMatchingMode mode) { + this.effects = effects; + this.mode = mode; + } + + public List effects; + public ListMatchingMode mode; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkMeta) || + !((FireworkMeta) item.getItemMeta()).hasEffects()) + return false; + + List effects = ((FireworkMeta) item.getItemMeta()).getEffects(); + return mode.matches(this.effects, effects); + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java new file mode 100644 index 00000000..ede94738 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java @@ -0,0 +1,25 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkMeta; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; + +/** + * @author Ameliorate + */ +public class ItemFireworkPowerMatcher implements ItemMatcher { + public ItemFireworkPowerMatcher(AmountMatcher power) { + this.power = power; + } + + public AmountMatcher power; + + @Override + public boolean matches(ItemStack item) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkMeta)) + return false; + + return power.matches(((FireworkMeta) item.getItemMeta()).getPower()); + } +} From bf9c70c4555c43a36e6bad668d9500a714761311 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Fri, 15 Mar 2019 23:08:36 -0700 Subject: [PATCH 094/108] Refactor all of config parsing to use Optional instead of null This touches basically everything, but also fixes a lot of bugs and edge cases. --- .../itemExpression/ItemExpression.java | 311 ++++++++++-------- .../amount/ItemAmountMatcher.java | 9 +- .../amount/ItemDurabilityMatcher.java | 9 +- .../itemExpression/enummatcher/AnyEnum.java | 13 + .../ItemFireworkEffectHolderMatcher.java | 9 +- .../itemExpression/lore/ItemLoreMatcher.java | 9 +- .../material/ItemMaterialMatcher.java | 9 +- .../ItemExpressionConfigParsingError.java | 9 + .../misc/ItemKnowledgeBookMatcher.java | 6 + .../misc/ItemLeatherArmorColorMatcher.java | 9 +- .../misc/ItemShulkerBoxColorMatcher.java | 9 +- .../itemExpression/name/AnyName.java | 11 + .../itemExpression/name/ItemNameMatcher.java | 9 +- .../ItemTropicFishBBodyColorMatcher.java | 6 + .../ItemTropicFishBPatternColorMatcher.java | 6 + .../ItemTropicFishBPatternMatcher.java | 6 + .../itemExpression/uuid/AnyUUID.java | 13 + 17 files changed, 270 insertions(+), 183 deletions(-) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExpressionConfigParsingError.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 276a1e4e..25e31750 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,9 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; -import org.bukkit.Color; -import org.bukkit.DyeColor; -import org.bukkit.FireworkEffect; -import org.bukkit.Material; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; @@ -22,10 +19,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ExactlyColor; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ListColor; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumFromListMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumIndexMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.NameEnumMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; @@ -152,8 +146,8 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseExactly(config, "exactly")); // knowlege book (creative item that holds recipe unlocks) - addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAny", false)); - addMatcher(parseKnowlegeBook(config, "knowlegebook.recipesAll", true)); + addMatcher(ItemKnowledgeBookMatcher.construct(parseName(config, "knowlegebook.recipesAny"), false)); + addMatcher(ItemKnowledgeBookMatcher.construct(parseName(config, "knowlegebook.recipesAll"), true)); // potion addMatcher(parsePotion(config, "potion")); @@ -184,14 +178,14 @@ public void parseConfig(ConfigurationSection config) { * Gets a ItemExpression from the given path in the config * @param configurationSection The config to get the ItemExpression from * @param path The path to the ItemExpression - * @return The ItemExpression in the config that path points to, or null if there was not an ItemExpression at path. + * @return The ItemExpression in the config that path points to, or empty if there was not an ItemExpression at path. */ - public static ItemExpression getItemExpression(ConfigurationSection configurationSection, String path) { + public static Optional getItemExpression(ConfigurationSection configurationSection, String path) { if (configurationSection == null) - return null; + return Optional.empty(); if (!configurationSection.contains(path)) - return null; - return new ItemExpression(configurationSection.getConfigurationSection(path)); + return Optional.empty(); + return Optional.of(new ItemExpression(configurationSection.getConfigurationSection(path))); } public static List getItemExpressionList(ConfigurationSection config, String path) { @@ -229,66 +223,67 @@ private static List getConfigList(ConfigurationSection con return list; } - private MaterialMatcher parseMaterial(ConfigurationSection config, String path) { + private Optional parseMaterial(ConfigurationSection config, String path) { if (config.contains(path + ".regex")) - return(new RegexMaterial(Pattern.compile(config.getString(path + ".regex")))); + return Optional.of(new RegexMaterial(Pattern.compile(config.getString(path + ".regex")))); else if (config.contains(path)) - return(new ExactlyMaterial(Material.getMaterial(config.getString(path)))); - return null; + return Optional.of(new ExactlyMaterial(Material.getMaterial(config.getString(path)))); + return Optional.empty(); } - private AmountMatcher parseAmount(ConfigurationSection config, String path) { + private Optional parseAmount(ConfigurationSection config, String path) { if (config.contains(path + ".range")) - return(new RangeAmount( + return Optional.of((new RangeAmount( config.getDouble(path + ".range.low", 0), config.getDouble(path + ".range.high"), config.getBoolean(path + ".range.inclusiveLow", true), - config.getBoolean(path + ".range.inclusiveHigh", true))); + config.getBoolean(path + ".range.inclusiveHigh", true)))); else if ("any".equals(config.getString(path))) - return(new AnyAmount()); + return Optional.of(new AnyAmount()); else if (config.contains(path)) - return(new ExactlyAmount(config.getDouble(path))); - return null; + return Optional.of(new ExactlyAmount(config.getDouble(path))); + return Optional.empty(); } - private LoreMatcher parseLore(ConfigurationSection config, String path) { + private Optional parseLore(ConfigurationSection config, String path) { if (config.contains(path + ".regex")) { String patternStr = config.getString(path + ".regex"); boolean multiline = config.getBoolean(path + ".regexMultiline", true); Pattern pattern = Pattern.compile(patternStr, multiline ? Pattern.MULTILINE : 0); - return(new RegexLore(pattern)); + return Optional.of(new RegexLore(pattern)); } else if (config.contains(path)) - return(new ExactlyLore(config.getStringList(path))); - return null; + return Optional.of(new ExactlyLore(config.getStringList(path))); + return Optional.empty(); } - private NameMatcher parseName(ConfigurationSection config, String path, boolean caseSensitive) { + private Optional parseName(ConfigurationSection config, String path, boolean caseSensitive) { if (config.contains(path + ".regex")) - return(new RegexName(Pattern.compile(config.getString(path + ".regex"), + return Optional.of(new RegexName(Pattern.compile(config.getString(path + ".regex"), caseSensitive ? 0 : Pattern.CASE_INSENSITIVE))); else if ("vanilla".equals(config.getString(path))) - return(new VanillaName()); + return Optional.of(new VanillaName()); else if (config.contains(path)) - return(new ExactlyName(config.getString(path), caseSensitive)); - return null; + return Optional.of(new ExactlyName(config.getString(path), caseSensitive)); + return Optional.empty(); } - private NameMatcher parseName(ConfigurationSection config, String path) { + private Optional parseName(ConfigurationSection config, String path) { return parseName(config, path, true); } - private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, String path, + private Optional parseEnchantment(ConfigurationSection config, String path, ListMatchingMode mode, EnchantmentsSource source) { ConfigurationSection enchantments = config.getConfigurationSection(path); if (enchantments == null) - return null; + return Optional.empty(); ArrayList enchantmentMatcher = new ArrayList<>(); for (String enchantName : enchantments.getKeys(false)) { EnchantmentMatcher matcher; - AmountMatcher amountMatcher = parseAmount(config, path + "." + enchantName); + AmountMatcher amountMatcher = parseAmount(config, path + "." + enchantName) + .orElseThrow(AssertionError::new); if (enchantName.equals("any")) { matcher = new AnyEnchantment(amountMatcher); } else { @@ -298,15 +293,16 @@ private ItemEnchantmentsMatcher parseEnchantment(ConfigurationSection config, St enchantmentMatcher.add(matcher); } - return new ItemEnchantmentsMatcher(enchantmentMatcher, mode, source); + return Optional.of(new ItemEnchantmentsMatcher(enchantmentMatcher, mode, source)); } - private ItemEnchantmentCountMatcher parseEnchangmentCount(ConfigurationSection config, String path, + private Optional parseEnchangmentCount(ConfigurationSection config, String path, EnchantmentsSource source) { if (!config.contains(path)) - return null; + return Optional.empty(); - return new ItemEnchantmentCountMatcher(parseAmount(config, path), source); + return Optional.of(new ItemEnchantmentCountMatcher(parseAmount(config, path) + .orElseThrow(ItemExpressionConfigParsingError::new), source)); } private List parseSkull(ConfigurationSection config, String path) { @@ -351,19 +347,19 @@ private List parseFlags(ConfigurationSection config, String pat return matchers; } - private ItemUnbreakableMatcher parseUnbreakable(ConfigurationSection config, String path) { + private Optional parseUnbreakable(ConfigurationSection config, String path) { if (!config.contains(path)) - return null; + return Optional.empty(); boolean unbreakable = config.getBoolean(path); - return new ItemUnbreakableMatcher(unbreakable); + return Optional.of(new ItemUnbreakableMatcher(unbreakable)); } - private ItemExactlyInventoryMatcher parseInventory(ConfigurationSection config, String path) { + private Optional parseInventory(ConfigurationSection config, String path) { List itemExpressions = getItemExpressionList(config, path); if (itemExpressions.isEmpty()) - return null; + return Optional.empty(); - return new ItemExactlyInventoryMatcher(itemExpressions); + return Optional.of(new ItemExactlyInventoryMatcher(itemExpressions)); } private List parseBook(ConfigurationSection config, String path) { @@ -375,15 +371,19 @@ private List parseBook(ConfigurationSection config, String path) { // author if (book.contains("author")) { - matchers.add(new ItemBookAuthorMatcher(parseName(book, "author"))); + matchers.add(new ItemBookAuthorMatcher(parseName(book, "author") + .orElseThrow(ItemExpressionConfigParsingError::new))); } // generation - matchers.add(new ItemBookGenerationMatcher(parseEnumMatcher(config, "generation", BookMeta.Generation.class))); + matchers.add(new ItemBookGenerationMatcher( + parseEnumMatcher(config, "generation", BookMeta.Generation.class) + .orElseThrow(ItemExpressionConfigParsingError::new))); // title if (book.contains("title")) { - matchers.add(new ItemBookTitleMatcher(parseName(book, "title"))); + matchers.add(new ItemBookTitleMatcher(parseName(book, "title") + .orElseThrow(ItemExpressionConfigParsingError::new))); } // pages @@ -399,26 +399,20 @@ private List parseBook(ConfigurationSection config, String path) { // page count if (book.contains("pageCount")) { - matchers.add(new ItemBookPageCountMatcher(parseAmount(book, "pageCount"))); + matchers.add(new ItemBookPageCountMatcher(parseAmount(book, "pageCount") + .orElseThrow(ItemExpressionConfigParsingError::new))); } return matchers; } - private ItemExactlyStackMatcher parseExactly(ConfigurationSection config, String path) { + private Optional parseExactly(ConfigurationSection config, String path) { if (!config.contains(path)) - return null; + return Optional.empty(); boolean acceptBoolean = config.getBoolean(path + ".acceptSimilar"); - return new ItemExactlyStackMatcher(config.getItemStack(path), acceptBoolean); - } - - private ItemKnowledgeBookMatcher parseKnowlegeBook(ConfigurationSection config, String path, boolean requireAll) { - if (!config.contains(path)) - return null; - - return new ItemKnowledgeBookMatcher(parseName(config, path), requireAll); + return Optional.of(new ItemExactlyStackMatcher(config.getItemStack(path), acceptBoolean)); } private List parsePotion(ConfigurationSection config, String path) { @@ -429,9 +423,9 @@ private List parsePotion(ConfigurationSection config, String path) ConfigurationSection potion = config.getConfigurationSection(path); - matchers.add(parsePotionEffects(potion, "customEffectsAny", ANY)); - matchers.add(parsePotionEffects(potion, "customEffectsAll", ALL)); - matchers.add(parsePotionEffects(potion, "customEffectsNone", NONE)); + matchers.add(parsePotionEffects(potion, "customEffectsAny", ANY).orElse(null)); + matchers.add(parsePotionEffects(potion, "customEffectsAll", ALL).orElse(null)); + matchers.add(parsePotionEffects(potion, "customEffectsNone", NONE).orElse(null)); if (potion.isConfigurationSection("base")) { ConfigurationSection base = potion.getConfigurationSection("base"); @@ -441,7 +435,8 @@ private List parsePotion(ConfigurationSection config, String path) EnumMatcher type; if (base.contains("type")) { - type = parseEnumMatcher(base, "type", PotionType.class); + type = parseEnumMatcher(base, "type", PotionType.class) + .orElseThrow(ItemExpressionConfigParsingError::new); } else { type = new EnumFromListMatcher<>(Arrays.asList(PotionType.values())); } @@ -453,16 +448,16 @@ private List parsePotion(ConfigurationSection config, String path) return matchers; } - private ItemPotionEffectsMatcher parsePotionEffects(ConfigurationSection config, String path, ListMatchingMode mode) { + private Optional parsePotionEffects(ConfigurationSection config, String path, ListMatchingMode mode) { if (!config.isList(path)) - return null; + return Optional.empty(); ArrayList matchers = new ArrayList<>(); for (ConfigurationSection effect : getConfigList(config, path)) { String type = effect.getString("type"); - AmountMatcher level = parseAmount(effect, "level"); - AmountMatcher duration = parseAmount(effect, "durationTicks"); + AmountMatcher level = parseAmount(effect, "level").orElse(new AnyAmount()); + AmountMatcher duration = parseAmount(effect, "durationTicks").orElse(new AnyAmount()); PotionEffectMatcher matcher = type.equals("any") ? new AnyPotionEffect(level, duration) : @@ -471,7 +466,7 @@ private ItemPotionEffectsMatcher parsePotionEffects(ConfigurationSection config, matchers.add(matcher); } - return new ItemPotionEffectsMatcher(matchers, mode); + return Optional.of(new ItemPotionEffectsMatcher(matchers, mode)); } private List parseAllAttributes(ConfigurationSection config, String path) { @@ -481,30 +476,35 @@ private List parseAllAttributes(ConfigurationSection confi for (EquipmentSlot slot : EquipmentSlot.values()) { String modeString = mode.getLowerCamelCase(); - matchers.add(parseAttributes(config, path + "." + slot + "." + modeString, slot, mode)); + matchers.add(parseAttributes(config, path + "." + slot + "." + modeString, slot, mode) + .orElse(null)); } } for (ListMatchingMode mode : ListMatchingMode.values()) { - matchers.add(parseAttributes(config, path + ".any." + mode.getLowerCamelCase(), null, mode)); + matchers.add(parseAttributes(config, path + ".any." + mode.getLowerCamelCase(), null, mode) + .orElse(null)); } return matchers; } - private ItemAttributeMatcher parseAttributes(ConfigurationSection config, String path, EquipmentSlot slot, + private Optional parseAttributes(ConfigurationSection config, String path, EquipmentSlot slot, ListMatchingMode mode) { if (!(config.isList(path))) - return null; + return Optional.empty(); List attributeMatchers = new ArrayList<>(); for (ConfigurationSection attribute : getConfigList(config, path)) { - EnumMatcher attributeM = parseEnumMatcher(attribute, "attribute", Attribute.class); - EnumMatcher operation = parseEnumMatcher(attribute, "operation", AttributeModifier.Operation.class); - NameMatcher name = parseName(attribute, "name"); - UUIDMatcher uuid = new ExactlyUUID(UUID.fromString(attribute.getString("uuid"))); - AmountMatcher amount = parseAmount(attribute, "amount"); + EnumMatcher attributeM = parseEnumMatcher(attribute, "attribute", Attribute.class) + .orElse(new AnyEnum<>()); + EnumMatcher operation = parseEnumMatcher(attribute, "operation", AttributeModifier.Operation.class) + .orElse(new AnyEnum<>()); + NameMatcher name = parseName(attribute, "name").orElse(new AnyName()); + UUIDMatcher uuid = attribute.isString("uuid") ? + new ExactlyUUID(UUID.fromString(attribute.getString("uuid"))) : new AnyUUID(); + AmountMatcher amount = parseAmount(attribute, "amount").orElse(new AnyAmount()); ItemAttributeMatcher.AttributeMatcher attributeMatcher = new ItemAttributeMatcher.AttributeMatcher(attributeM, name, operation, uuid, amount); @@ -512,7 +512,7 @@ private ItemAttributeMatcher parseAttributes(ConfigurationSection config, String attributeMatchers.add(attributeMatcher); } - return new ItemAttributeMatcher(attributeMatchers, slot, mode); + return Optional.of(new ItemAttributeMatcher(attributeMatchers, slot, mode)); } private List parseTropicFishBucket(ConfigurationSection config, String path) { @@ -523,17 +523,17 @@ private List parseTropicFishBucket(ConfigurationSection config, Str ConfigurationSection bucket = config.getConfigurationSection(path); - matchers.add(new ItemTropicFishBBodyColorMatcher(parseEnumMatcher(bucket, "bodyColor", DyeColor.class))); - matchers.add(new ItemTropicFishBPatternColorMatcher(parseEnumMatcher(bucket, "patternColor", DyeColor.class))); - matchers.add(new ItemTropicFishBPatternMatcher(parseEnumMatcher(bucket, "pattern", TropicalFish.Pattern.class))); + matchers.add(ItemTropicFishBBodyColorMatcher.construct(parseEnumMatcher(bucket, "bodyColor", DyeColor.class))); + matchers.add(ItemTropicFishBPatternColorMatcher.construct(parseEnumMatcher(bucket, "patternColor", DyeColor.class))); + matchers.add(ItemTropicFishBPatternMatcher.construct(parseEnumMatcher(bucket, "pattern", TropicalFish.Pattern.class))); return matchers; } - private > EnumMatcher parseEnumMatcher(ConfigurationSection config, String path, + private > Optional> parseEnumMatcher(ConfigurationSection config, String path, Class enumClass) { if (!config.contains(path)) - return null; + return Optional.empty(); if (config.isList(path)) { List enumStrings = config.getStringList(path); @@ -548,36 +548,39 @@ private > EnumMatcher parseEnumMatcher(ConfigurationSection .map((name) -> E.valueOf(enumClass, name.toUpperCase())) .collect(Collectors.toList()); - return new EnumFromListMatcher<>(properties, notInList); + return Optional.of(new EnumFromListMatcher<>(properties, notInList)); } if (config.isInt(path + ".index")) { - return new EnumIndexMatcher<>(config.getInt(path + ".index")); + return Optional.of(new EnumIndexMatcher<>(config.getInt(path + ".index"))); } else { - return new NameEnumMatcher<>(parseName(config, path, false)); + return parseName(config, path, false).map(NameEnumMatcher::new); } } - private ColorMatcher parseColor(ConfigurationSection config, String path) { + private Optional parseColor(ConfigurationSection config, String path) { if (!config.contains(path)) - return null; + return Optional.empty(); return parseColor(config.get(path)); } - private ColorMatcher parseColor(Object config) { + private Optional parseColor(Object config) { if (config == null) - return null; + return Optional.empty(); if (config instanceof String) { // vanilla dye name - return new ExactlyColor(ExactlyColor.getColorByVanillaName((String) config)); + return Optional.of(new ExactlyColor(ExactlyColor.getColorByVanillaName((String) config))); } else if (config instanceof Integer) { // rgb color - return new ExactlyColor(Color.fromRGB((Integer) config)); + return Optional.of(new ExactlyColor(Color.fromRGB((Integer) config))); } else if (config instanceof List) { // any of matchers in list - return parseListColor((List) config); + return parseListColor((List) config).map(lc -> lc); // identity map to fix type inferency errors + // By default, java can't cast Option to Option. + // However, it can cast ListColor to ColorMatcher, of course. By having an identity map, we give java the + // chance to make that type inference. } else if (config instanceof Map) { if (((Map) config).containsKey("rgb")) { @@ -586,45 +589,46 @@ private ColorMatcher parseColor(Object config) { if (rgb instanceof Integer) { // rgb int - return new ExactlyColor(Color.fromRGB((Integer) rgb)); + return Optional.of(new ExactlyColor(Color.fromRGB((Integer) rgb))); } else if (rgb instanceof List) { // [r, g, b] int red = (int) ((List) rgb).get(0); int green = (int) ((List) rgb).get(1); int blue = (int) ((List) rgb).get(2); - return new ExactlyColor(Color.fromRGB(red, green, blue)); + return Optional.of(new ExactlyColor(Color.fromRGB(red, green, blue))); } } else if (((Map) config).containsKey("html")) { // html color name String htmlColorName = (String) ((Map) config).get("html"); - return new ExactlyColor(ExactlyColor.getColorByHTMLName(htmlColorName)); + return Optional.of(new ExactlyColor(ExactlyColor.getColorByHTMLName(htmlColorName))); } else if (((Map) config).containsKey("firework")) { // firework vanilla dye name String fireworkDyeColorName = (String) ((Map) config).get("firework"); - return new ExactlyColor(ExactlyColor.getColorByVanillaName(fireworkDyeColorName, true)); + return Optional.of(new ExactlyColor(ExactlyColor.getColorByVanillaName(fireworkDyeColorName, true))); } else if (((Map) config).containsKey("anyOf")) { // any of matchers in list - return parseListColor((List) ((Map) config).get("anyOf")); + return parseListColor((List) ((Map) config).get("anyOf")).map(lc -> lc); } else if (((Map) config).containsKey("noneOf")) { // none of matchers in list - return parseListColor((List) ((Map) config).get("noneOf")); + return parseListColor((List) ((Map) config).get("noneOf")).map(lc -> lc); } } - return null; + return Optional.empty(); } - private ListColor parseListColor(List config) { + private Optional parseListColor(List config) { if (config == null) - return null; + return Optional.empty(); - return new ListColor(((List) config).stream() + return Optional.of(new ListColor(((List) config).stream() .map(this::parseColor) - .collect(Collectors.toList()), false); + .map((option) -> option.orElseThrow(ItemExpressionConfigParsingError::new)) + .collect(Collectors.toList()), false)); } private List parseMap(ConfigurationSection config, String path) { @@ -636,17 +640,18 @@ private List parseMap(ConfigurationSection config, String path) { ConfigurationSection map = config.getConfigurationSection(path); if (map.contains("center.x")) { - matchers.add(new ItemMapViewMatcher(new CenterMapView(parseAmount(map, "center.x"), - CenterMapView.CenterCoordinate.X))); + matchers.add(new ItemMapViewMatcher(new CenterMapView(parseAmount(map, "center.x") + .orElseThrow(AssertionError::new), CenterMapView.CenterCoordinate.X))); } if (map.contains("center.z")) { - matchers.add(new ItemMapViewMatcher(new CenterMapView(parseAmount(map, "center.z"), - CenterMapView.CenterCoordinate.Z))); + matchers.add(new ItemMapViewMatcher(new CenterMapView(parseAmount(map, "center.z") + .orElseThrow(AssertionError::new), CenterMapView.CenterCoordinate.Z))); } if (map.contains("id")) { - matchers.add(new ItemMapViewMatcher(new IDMapView(parseAmount(map, "id")))); + matchers.add(new ItemMapViewMatcher(new IDMapView(parseAmount(map, "id") + .orElseThrow(AssertionError::new)))); } if (map.isBoolean("isUnlimitedTracking")) { @@ -659,15 +664,16 @@ private List parseMap(ConfigurationSection config, String path) { if (map.contains("scale")) { matchers.add(new ItemMapViewMatcher(new ScaleMapView( - parseEnumMatcher(map, "scale", MapView.Scale.class)))); + parseEnumMatcher(map, "scale", MapView.Scale.class).orElseThrow(AssertionError::new)))); } if (map.contains("world")) { - matchers.add(new ItemMapViewMatcher(new WorldMapView(parseName(map, "world")))); + matchers.add(new ItemMapViewMatcher(new WorldMapView(parseName(map, "world").orElseThrow(AssertionError::new)))); } if (map.contains("color")) { - matchers.add(new ItemMapColorMatcher(parseColor(map, "color"))); + matchers.add(new ItemMapColorMatcher(parseColor(map, "color") + .orElseThrow(ItemExpressionConfigParsingError::new))); } if (map.isBoolean("isScaling")) { @@ -675,7 +681,7 @@ private List parseMap(ConfigurationSection config, String path) { } if (map.contains("location")) { - matchers.add(new ItemMapLocationMatcher(parseName(map, "location"))); + matchers.add(new ItemMapLocationMatcher(parseName(map, "location").orElseThrow(AssertionError::new))); } return matchers; @@ -691,48 +697,55 @@ private List parseMobSpawner(ConfigurationSection config, String pa if (spawner.contains("delay.current")) { // Caution: This is the time until the spawner will spawn its next mob. See minDelay and maxDelay for // what might be expected. - matchers.add(new ItemMobSpawnerDelayMatcher(parseAmount(spawner, "delay.current"))); + matchers.add(new ItemMobSpawnerDelayMatcher(parseAmount(spawner, "delay.current") + .orElseThrow(AssertionError::new))); } if (spawner.contains("maxNearbyEntities")) { - matchers.add(new ItemMobSpawnerMaxNearbyEntitiesMatcher(parseAmount(spawner, "maxNearbyEntities"))); + matchers.add(new ItemMobSpawnerMaxNearbyEntitiesMatcher(parseAmount(spawner, "maxNearbyEntities") + .orElseThrow(AssertionError::new))); } if (spawner.contains("requiredPlayerRange")) { - matchers.add(new ItemMobSpawnerRequiredPlayerRangeMatcher(parseAmount(spawner, "requiredPlayerRange"))); + matchers.add(new ItemMobSpawnerRequiredPlayerRangeMatcher(parseAmount(spawner, "requiredPlayerRange") + .orElseThrow(AssertionError::new))); } if (spawner.contains("spawnCount")) { - matchers.add(new ItemMobSpawnerSpawnCountMatcher(parseAmount(spawner, "spawnCount"))); + matchers.add(new ItemMobSpawnerSpawnCountMatcher(parseAmount(spawner, "spawnCount") + .orElseThrow(AssertionError::new))); } if (spawner.contains("delay.max")) { - matchers.add(new ItemMobSpawnerSpawnDelayMatcher(parseAmount(spawner, "delay.max"), - ItemMobSpawnerSpawnDelayMatcher.MinMax.MAX)); + matchers.add(new ItemMobSpawnerSpawnDelayMatcher(parseAmount(spawner, "delay.max") + .orElseThrow(AssertionError::new), ItemMobSpawnerSpawnDelayMatcher.MinMax.MAX)); } if (spawner.contains("delay.min")) { - matchers.add(new ItemMobSpawnerSpawnDelayMatcher(parseAmount(spawner, "delay.min"), - ItemMobSpawnerSpawnDelayMatcher.MinMax.MIN)); + matchers.add(new ItemMobSpawnerSpawnDelayMatcher(parseAmount(spawner, "delay.min") + .orElseThrow(AssertionError::new), ItemMobSpawnerSpawnDelayMatcher.MinMax.MIN)); } if (spawner.contains("mob")) { - matchers.add(new ItemMobSpawnerSpawnedMobMatcher(parseEnumMatcher(spawner, "mob", EntityType.class))); + matchers.add(new ItemMobSpawnerSpawnedMobMatcher(parseEnumMatcher(spawner, "mob", EntityType.class) + .orElseThrow(AssertionError::new))); } else if (spawner.contains("entity")) { // duplicate of "mob", for completeness - matchers.add(new ItemMobSpawnerSpawnedMobMatcher(parseEnumMatcher(spawner, "entity", EntityType.class))); + matchers.add(new ItemMobSpawnerSpawnedMobMatcher(parseEnumMatcher(spawner, "entity", EntityType.class) + .orElseThrow(AssertionError::new))); } if (spawner.contains("radius")) { - matchers.add(new ItemMobSpawnerSpawnRadiusMatcher(parseAmount(spawner, "radius"))); + matchers.add(new ItemMobSpawnerSpawnRadiusMatcher(parseAmount(spawner, "radius") + .orElseThrow(AssertionError::new))); } return matchers; } - private FireworkEffectMatcher parseFireworkEffect(ConfigurationSection config, String path) { + private Optional parseFireworkEffect(ConfigurationSection config, String path) { if (!config.isConfigurationSection(path)) - return null; + return Optional.empty(); ConfigurationSection fireworkEffect = config.getConfigurationSection(path); @@ -742,24 +755,25 @@ private FireworkEffectMatcher parseFireworkEffect(ConfigurationSection config, S if (fireworkEffect.isList("colors")) { for (Object color : fireworkEffect.getList("colors")) { - colors.add(parseColor(color)); + colors.add(parseColor(color).orElseThrow(ItemExpressionConfigParsingError::new)); } } - colors.add(parseColor(fireworkEffect, "color")); + parseColor(fireworkEffect, "color").map(colors::add); List fadeColors = new ArrayList<>(); ListMatchingMode fadeColorsMode = ListMatchingMode.valueOf(fireworkEffect.getString("fadeColorsMode", "ANY").toUpperCase()); if (fireworkEffect.isList("fadeColors")) { for (Object color : fireworkEffect.getList("fadeColors")) { - fadeColors.add(parseColor(color)); + fadeColors.add(parseColor(color).orElseThrow(ItemExpressionConfigParsingError::new)); } } - fadeColors.add(parseColor(fireworkEffect, "fadeColor")); + parseColor(fireworkEffect, "fadeColor").map(fadeColors::add); - EnumMatcher type = parseEnumMatcher(fireworkEffect, "type", FireworkEffect.Type.class); + EnumMatcher type = parseEnumMatcher(fireworkEffect, "type", FireworkEffect.Type.class) + .orElse(new AnyEnum<>()); Optional hasFlicker = Optional.empty(); if (fireworkEffect.isBoolean("hasFlicker")) { @@ -771,12 +785,12 @@ private FireworkEffectMatcher parseFireworkEffect(ConfigurationSection config, S hasTrail = Optional.of(fireworkEffect.getBoolean("hasTrail")); } - return new ExactlyFireworkEffect(type, colors, colorsMode, fadeColors, fadeColorsMode, hasFlicker, hasTrail); + return Optional.of(new ExactlyFireworkEffect(type, colors, colorsMode, fadeColors, fadeColorsMode, hasFlicker, hasTrail)); } private List parseFirework(ConfigurationSection config, String path) { if (!config.isConfigurationSection(path)) - return null; + return Collections.emptyList(); ConfigurationSection firework = config.getConfigurationSection(path); ArrayList matchers = new ArrayList<>(); @@ -785,7 +799,8 @@ private List parseFirework(ConfigurationSection config, String path ArrayList effectMatchers = new ArrayList<>(); for (ConfigurationSection effect : getConfigList(firework, "effects" + mode.getUpperCamelCase())) { - FireworkEffectMatcher matcher = parseFireworkEffect(effect, ""); + FireworkEffectMatcher matcher = parseFireworkEffect(effect, "") + .orElseThrow(ItemExpressionConfigParsingError::new); effectMatchers.add(matcher); } @@ -793,13 +808,11 @@ private List parseFirework(ConfigurationSection config, String path matchers.add(new ItemFireworkEffectsMatcher(effectMatchers, mode)); } - AmountMatcher power = parseAmount(firework, "power"); - if (power != null) - matchers.add(new ItemFireworkPowerMatcher(power)); + Optional power = parseAmount(firework, "power"); + power.ifPresent(aPower -> matchers.add(new ItemFireworkPowerMatcher(aPower))); - AmountMatcher effectsCount = parseAmount(firework, "effectsCount"); - if (effectsCount != null) - matchers.add(new ItemFireworkEffectsCountMatcher(effectsCount)); + Optional effectsCount = parseAmount(firework, "effectsCount"); + effectsCount.ifPresent(aEffectsCount -> matchers.add(new ItemFireworkEffectsCountMatcher(aEffectsCount))); return matchers; } @@ -1055,6 +1068,18 @@ public void addMatcher(Collection matchers) { matchers.forEach(this::addMatcher); } + /** + * Adds the matcher if Optional is not none. + * @param matcher The optional that may contain an ItemMatcher. + * @param The type of ItemMatcher being added. + */ + public void addMatcher(Optional matcher) { + if (!matcher.isPresent()) + return; + + matcher.ifPresent(this::addMatcher); + } + /** * All of the matchers in this set must return true in order for this ItemExpression to match a given item. * diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java index 80260887..bcc2a7b2 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java @@ -5,6 +5,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMapMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -13,11 +15,8 @@ public ItemAmountMatcher(AmountMatcher matcher) { this.matcher = matcher; } - public static ItemAmountMatcher construct(AmountMatcher matcher) { - if (matcher == null) - return null; - - return new ItemAmountMatcher(matcher); + public static ItemAmountMatcher construct(Optional matcher) { + return matcher.map(ItemAmountMatcher::new).orElse(null); } public AmountMatcher matcher; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java index 8c13823f..0c95d470 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java @@ -4,6 +4,8 @@ import org.bukkit.inventory.meta.Damageable; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -12,11 +14,8 @@ public ItemDurabilityMatcher(AmountMatcher matcher) { this.matcher = matcher; } - public static ItemDurabilityMatcher construct(AmountMatcher matcher) { - if (matcher == null) - return null; - - return new ItemDurabilityMatcher(matcher); + public static ItemDurabilityMatcher construct(Optional matcher) { + return matcher.map(ItemDurabilityMatcher::new).orElse(null); } public AmountMatcher matcher; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java new file mode 100644 index 00000000..e2baa640 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java @@ -0,0 +1,13 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher; + +/** + * Accepts any enum. This is intended to be used as a default value in some places, and is not exposed in the config. + * + * @author Ameliorate + */ +public class AnyEnum> implements EnumMatcher { + @Override + public boolean matches(E matched) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java index f51c4428..50017aad 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java @@ -4,6 +4,8 @@ import org.bukkit.inventory.meta.FireworkEffectMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -12,11 +14,8 @@ public ItemFireworkEffectHolderMatcher(FireworkEffectMatcher effect) { this.effect = effect; } - public static ItemFireworkEffectHolderMatcher construct(FireworkEffectMatcher effect) { - if (effect != null) - return null; - - return new ItemFireworkEffectHolderMatcher(effect); + public static ItemFireworkEffectHolderMatcher construct(Optional effect) { + return effect.map(ItemFireworkEffectHolderMatcher::new).orElse(null); } public FireworkEffectMatcher effect; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java index a4e5e398..3cb3e74c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java @@ -3,6 +3,8 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -11,11 +13,8 @@ public ItemLoreMatcher(LoreMatcher matcher) { this.matcher = matcher; } - public static ItemLoreMatcher construct(LoreMatcher matcher) { - if (matcher == null) - return null; - - return new ItemLoreMatcher(matcher); + public static ItemLoreMatcher construct(Optional matcher) { + return matcher.map(ItemLoreMatcher::new).orElse(null); } public LoreMatcher matcher; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java index 3ec95bfb..d295a2a7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java @@ -3,6 +3,8 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -11,11 +13,8 @@ public ItemMaterialMatcher(MaterialMatcher matcher) { this.matcher = matcher; } - public static ItemMaterialMatcher construct(MaterialMatcher matcher) { - if (matcher == null) - return null; - - return new ItemMaterialMatcher(matcher); + public static ItemMaterialMatcher construct(Optional matcher) { + return matcher.map(ItemMaterialMatcher::new).orElse(null); } public MaterialMatcher matcher; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExpressionConfigParsingError.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExpressionConfigParsingError.java new file mode 100644 index 00000000..b0e5ef34 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExpressionConfigParsingError.java @@ -0,0 +1,9 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; + +/** + * When there is some error when parsing an ItemExpression out of the config. + * + * @author Ameliorate + */ +public class ItemExpressionConfigParsingError extends RuntimeException { +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java index 7b22fff2..dd4b9084 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java @@ -7,6 +7,7 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -23,6 +24,11 @@ public ItemKnowledgeBookMatcher(NameMatcher recipeMatcher) { this(recipeMatcher, false); } + public static ItemKnowledgeBookMatcher construct(Optional recipeMatcher, boolean requireAllMatch) { + return recipeMatcher.map((aRecipeMatcher) -> new ItemKnowledgeBookMatcher(aRecipeMatcher, requireAllMatch)) + .orElse(null); + } + public NameMatcher recipeMatcher; public boolean requireAllMatch; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java index fdf52f3e..8545c3f8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java @@ -6,6 +6,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ColorMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -14,11 +16,8 @@ public ItemLeatherArmorColorMatcher(ColorMatcher color) { this.color = color; } - public static ItemLeatherArmorColorMatcher construct(ColorMatcher color) { - if (color == null) - return null; - - return new ItemLeatherArmorColorMatcher(color); + public static ItemLeatherArmorColorMatcher construct(Optional color) { + return color.map(ItemLeatherArmorColorMatcher::new).orElse(null); } public ColorMatcher color; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java index 28ff0086..acc9c7d1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java @@ -7,6 +7,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -15,11 +17,8 @@ public ItemShulkerBoxColorMatcher(EnumMatcher color) { this.color = color; } - public static ItemShulkerBoxColorMatcher construct(EnumMatcher color) { - if (color == null) - return null; - - return new ItemShulkerBoxColorMatcher(color); + public static ItemShulkerBoxColorMatcher construct(Optional> color) { + return color.map(ItemShulkerBoxColorMatcher::new).orElse(null); } public EnumMatcher color; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java new file mode 100644 index 00000000..3a2e30a9 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java @@ -0,0 +1,11 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; + +/** + * @author Ameliorate + */ +public class AnyName implements NameMatcher { + @Override + public boolean matches(String matched) { + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java index 89af0390..ab1451fb 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java @@ -3,6 +3,8 @@ import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -11,11 +13,8 @@ public ItemNameMatcher(NameMatcher matcher) { this.matcher = matcher; } - public static ItemNameMatcher construct(NameMatcher matcher) { - if (matcher == null) - return null; - - return new ItemNameMatcher(matcher); + public static ItemNameMatcher construct(Optional matcher) { + return matcher.map(ItemNameMatcher::new).orElse(null); } public NameMatcher matcher; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java index 0e44a0a4..9c3c7657 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java @@ -6,6 +6,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -14,6 +16,10 @@ public ItemTropicFishBBodyColorMatcher(EnumMatcher color) { this.color = color; } + public static ItemTropicFishBBodyColorMatcher construct(Optional> color) { + return color.map(ItemTropicFishBBodyColorMatcher::new).orElse(null); + } + public EnumMatcher color; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java index 909f63ca..36170194 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java @@ -6,6 +6,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -14,6 +16,10 @@ public ItemTropicFishBPatternColorMatcher(EnumMatcher color) { this.color = color; } + public static ItemTropicFishBPatternColorMatcher construct(Optional> color) { + return color.map(ItemTropicFishBPatternColorMatcher::new).orElse(null); + } + public EnumMatcher color; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java index 9e2ae430..0b092ade 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java @@ -6,6 +6,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; +import java.util.Optional; + /** * @author Ameliorate */ @@ -14,6 +16,10 @@ public ItemTropicFishBPatternMatcher(EnumMatcher pattern) this.pattern = pattern; } + public static ItemTropicFishBPatternMatcher construct(Optional> color) { + return color.map(ItemTropicFishBPatternMatcher::new).orElse(null); + } + public EnumMatcher pattern; @Override diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java new file mode 100644 index 00000000..51f5c303 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java @@ -0,0 +1,13 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid; + +import java.util.UUID; + +/** + * @author Ameliorate + */ +public class AnyUUID implements UUIDMatcher { + @Override + public boolean matches(UUID matched) { + return true; + } +} From 3af21dd7ff3fed040e73f3ce177de52a6d87e15d Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 16 Mar 2019 11:49:31 -0700 Subject: [PATCH 095/108] Add better defaults for range Now it used NEGATIVE_INFINITY and INFINITY, accepting any number. --- .../itemHandling/itemExpression/ItemExpression.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 25e31750..0221a753 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -234,8 +234,8 @@ else if (config.contains(path)) private Optional parseAmount(ConfigurationSection config, String path) { if (config.contains(path + ".range")) return Optional.of((new RangeAmount( - config.getDouble(path + ".range.low", 0), - config.getDouble(path + ".range.high"), + config.getDouble(path + ".range.low", Double.NEGATIVE_INFINITY), + config.getDouble(path + ".range.high", Double.POSITIVE_INFINITY), config.getBoolean(path + ".range.inclusiveLow", true), config.getBoolean(path + ".range.inclusiveHigh", true)))); else if ("any".equals(config.getString(path))) From bd9b777cd8f1017731004451e84c609413768ff3 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 16 Mar 2019 16:57:43 -0700 Subject: [PATCH 096/108] Implement Matcher for ItemExpression --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 0221a753..b84b7e64 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -51,7 +51,7 @@ * * @author Ameliorate */ -public class ItemExpression { +public class ItemExpression implements Matcher { /** * Creates the default ItemExpression. * From 0b8bdaa0ce57f9f733fe5113bdca78a2d6724bcb Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 19 May 2019 10:02:39 -0700 Subject: [PATCH 097/108] Add solving Not yet tested, but oops i accidentally added like 1000 loc for a feature that was supposed to be minor --- .../itemExpression/ItemExpression.java | 43 +++++-- .../itemHandling/itemExpression/Matcher.java | 24 ++++ .../itemExpression/amount/AmountMatcher.java | 4 + .../itemExpression/amount/AnyAmount.java | 5 + .../itemExpression/amount/ExactlyAmount.java | 5 + .../amount/ItemAmountMatcher.java | 6 + .../amount/ItemDurabilityMatcher.java | 15 +++ .../itemExpression/amount/RangeAmount.java | 11 ++ .../itemExpression/book/ExactlyBookPages.java | 5 + .../book/ItemBookAuthorMatcher.java | 16 +++ .../book/ItemBookGenerationMatcher.java | 16 +++ .../book/ItemBookPageCountMatcher.java | 21 ++++ .../book/ItemBookPagesMatcher.java | 19 +++ .../book/ItemBookTitleMatcher.java | 17 +++ .../itemExpression/book/RegexBookPages.java | 5 + .../itemExpression/color/ExactlyColor.java | 5 + .../itemExpression/color/ListColor.java | 54 +++++++++ .../enchantment/AnyEnchantment.java | 9 ++ .../enchantment/EnchantmentsSource.java | 83 ++++++++++++- .../enchantment/ExactlyEnchantment.java | 9 ++ .../ItemEnchantmentCountMatcher.java | 48 ++++++++ .../enchantment/ItemEnchantmentsMatcher.java | 24 +++- .../itemExpression/enummatcher/AnyEnum.java | 17 +++ .../enummatcher/EnumFromListMatcher.java | 5 + .../enummatcher/EnumIndexMatcher.java | 16 ++- .../enummatcher/ExactlyEnumMatcher.java | 5 + .../enummatcher/NameEnumMatcher.java | 11 ++ .../firework/ExactlyFireworkEffect.java | 18 +++ .../ItemFireworkEffectHolderMatcher.java | 12 ++ .../ItemFireworkEffectsCountMatcher.java | 71 ++++++++++++ .../firework/ItemFireworkEffectsMatcher.java | 28 +++++ .../firework/ItemFireworkPowerMatcher.java | 15 +++ .../itemExpression/lore/ExactlyLore.java | 5 + .../itemExpression/lore/ItemLoreMatcher.java | 11 ++ .../itemExpression/lore/RegexLore.java | 5 + .../itemExpression/map/CenterMapView.java | 14 +++ .../itemExpression/map/IDMapView.java | 7 ++ .../map/IsUnlimitedTrackingMapView.java | 7 ++ .../itemExpression/map/IsVirtualMapView.java | 19 +++ .../map/ItemMapColorMatcher.java | 15 +++ .../map/ItemMapIsScalingMatcher.java | 14 +++ .../map/ItemMapLocationMatcher.java | 14 +++ .../map/ItemMapViewMatcher.java | 18 +++ .../itemExpression/map/ScaleMapView.java | 7 ++ .../itemExpression/map/WorldMapView.java | 14 +++ .../material/ExactlyMaterial.java | 5 + .../material/ItemMaterialMatcher.java | 6 + .../material/RegexMaterial.java | 5 + .../misc/ItemAttributeMatcher.java | 43 +++++++ .../misc/ItemExactlyInventoryMatcher.java | 28 +++++ .../misc/ItemExactlyStackMatcher.java | 5 + .../itemExpression/misc/ItemFlagMatcher.java | 15 +++ .../misc/ItemKnowledgeBookMatcher.java | 25 ++++ .../misc/ItemLeatherArmorColorMatcher.java | 15 +++ .../misc/ItemShulkerBoxColorMatcher.java | 42 +++++-- .../itemExpression/misc/ItemSkullMatcher.java | 18 +++ .../misc/ItemUnbreakableMatcher.java | 12 ++ .../itemExpression/misc/ListMatchingMode.java | 109 ++++++++++++++++++ .../ItemMobSpawnerDelayMatcher.java | 16 +++ ...temMobSpawnerMaxNearbyEntitiesMatcher.java | 18 +++ ...mMobSpawnerRequiredPlayerRangeMatcher.java | 18 +++ .../ItemMobSpawnerSpawnCountMatcher.java | 18 +++ .../ItemMobSpawnerSpawnDelayMatcher.java | 25 ++++ .../ItemMobSpawnerSpawnRadiusMatcher.java | 18 +++ .../ItemMobSpawnerSpawnedMobMatcher.java | 16 +++ .../mobspawner/MobSpawnerUtil.java | 8 ++ .../itemExpression/name/AnyName.java | 5 + .../itemExpression/name/ExactlyName.java | 5 + .../itemExpression/name/ItemNameMatcher.java | 15 +++ .../itemExpression/name/RegexName.java | 5 + .../itemExpression/name/VanillaName.java | 5 + .../potion/AnyPotionEffect.java | 6 + .../potion/ExactlyPotionEffect.java | 7 ++ .../potion/ItemPotionBaseEffectMatcher.java | 19 +++ .../potion/ItemPotionEffectsMatcher.java | 20 +++- .../ItemTropicFishBBodyColorMatcher.java | 13 +++ .../ItemTropicFishBPatternColorMatcher.java | 13 +++ .../ItemTropicFishBPatternMatcher.java | 13 +++ .../itemExpression/uuid/AnyUUID.java | 5 + .../itemExpression/uuid/ExactlyUUID.java | 5 + .../uuid/PlayerNameRegexUUID.java | 5 + .../itemExpression/uuid/PlayerNameUUID.java | 11 ++ 82 files changed, 1387 insertions(+), 22 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index b84b7e64..1baba18c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,6 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; -import org.bukkit.*; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; @@ -8,7 +11,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.TropicalFish; import org.bukkit.inventory.*; -import org.bukkit.inventory.meta.*; +import org.bukkit.inventory.meta.BookMeta; import org.bukkit.map.MapView; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; @@ -21,10 +24,15 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.ExactlyLore; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.ItemLoreMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.LoreMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.RegexLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ItemExactlyInventoryMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.*; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ItemMaterialMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; @@ -550,9 +558,10 @@ private > Optional> parseEnumMatcher(Configurat return Optional.of(new EnumFromListMatcher<>(properties, notInList)); } if (config.isInt(path + ".index")) { - return Optional.of(new EnumIndexMatcher<>(config.getInt(path + ".index"))); + return Optional.of(new EnumIndexMatcher<>(config.getInt(path + ".index"), enumClass)); } else { - return parseName(config, path, false).map(NameEnumMatcher::new); + return parseName(config, path, false) + .map(nameMatcher -> new NameEnumMatcher(nameMatcher, enumClass)); } } @@ -828,6 +837,21 @@ public boolean matches(ItemStack item) { return matchers.stream().allMatch((matcher) -> matcher.matches(item)); } + @Override + public ItemStack solve(ItemStack inheritFrom) throws NotSolvableException { + inheritFrom = inheritFrom.clone(); + + for (ItemMatcher matcher : matchers) { + inheritFrom = matcher.solve(inheritFrom); + } + + return inheritFrom; + } + + public ItemStack solve() throws NotSolvableException { + return solve(new ItemStack(Material.AIR, 1)); + } + /** * Returns a lambda with the ItemMap bound into its environment. This is an instance of currying in java. * @@ -849,7 +873,7 @@ public Predicate> getMatchesItemMapPredicate(ItemM // currying in java 2019 return (kv) -> { ItemStack item = kv.getKey(); - //Integer amount = kv.getValue(); + //Integer amount = kv.get(); return matchers.stream().allMatch((matcher) -> { if (matcher instanceof ItemMapMatcher) { return ((ItemMapMatcher) matcher).matches(itemMap, item); @@ -974,11 +998,10 @@ public boolean removeFromInventory(Inventory inventory, boolean random) { } /** - * Abstraction for the algorithm defined in removeFromInventory's javadoc. * @param random To select a random number within amount. This only applies if amount is a range. * @return The amount field of the config format. This is extracted from the structure of this ItemStack, not the config. */ - private int getAmount(boolean random) { + public int getAmount(boolean random) { List amountMatchers = matchers.stream() .filter((m) -> m instanceof ItemAmountMatcher) .map((m) -> (ItemAmountMatcher) m) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java index 7bade75a..6ff34c15 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java @@ -22,4 +22,28 @@ public interface Matcher { * @return If this matcher matched the thing. */ boolean matches(T matched); + + /** + * Mutates the state of defaultValue such that matches(defaultValue) == true. + * + * If a value for startingValue where matches(defaultValue) == true, then NotSolvableException should be thrown. + * @param defaultValue Used as a "base" value for feilds that don't need changed for matches(defaultValue) to be true. + * This may or may not be mutated. + * @return The value that matches this matcher. + * @throws NotSolvableException If a state for defaultValue could not be found that matches. + */ + T solve(T defaultValue) throws NotSolvableException; + + /** + * Thrown if a certain matcher can not be solved. + */ + class NotSolvableException extends Exception { + public NotSolvableException(String message, Throwable cause) { + super(message, cause); + } + + public NotSolvableException(String message) { + super(message); + } + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java index dbc58626..11569c60 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AmountMatcher.java @@ -12,4 +12,8 @@ public interface AmountMatcher extends Matcher { default boolean matches(int amount) { return matches((double) amount); } + + default int solve(int defaultAmount) throws NotSolvableException { + return (int) (double) solve((double) defaultAmount); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java index 328129b6..07c87adb 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/AnyAmount.java @@ -10,4 +10,9 @@ public class AnyAmount implements AmountMatcher { public boolean matches(Double amount) { return true; } + + @Override + public Double solve(Double defaultValue) throws NotSolvableException { + return defaultValue; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java index 00ee71f7..5c80a5e7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ExactlyAmount.java @@ -16,4 +16,9 @@ public ExactlyAmount(double amount) { public boolean matches(Double amount) { return this.amount == amount; } + + @Override + public Double solve(Double defaultValue) throws NotSolvableException { + return amount; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java index bcc2a7b2..5a7d11f6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemAmountMatcher.java @@ -26,6 +26,12 @@ public boolean matches(ItemStack item) { return matcher.matches(item.getAmount()); } + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + item.setAmount(matcher.solve(1)); + return item; + } + @Override public boolean matches(ItemMap itemMap, ItemStack item) { return matcher.matches(itemMap.getAmount(item)); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java index 0c95d470..733de8c2 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java @@ -1,7 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import java.util.Optional; @@ -27,4 +29,17 @@ public boolean matches(ItemStack item) { return matcher.matches(((Damageable) item.getItemMeta()).getDamage()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType()); + + if (!(item instanceof Damageable)) + throw new NotSolvableException("item does not have durability"); + + ((Damageable) meta).setDamage(matcher.solve(1)); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java index c35796d4..31622414 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/RangeAmount.java @@ -62,4 +62,15 @@ public boolean matches(Double amount) { return true; } + + @Override + public Double solve(Double defaultValue) throws NotSolvableException { + if (matches(defaultValue)) + return defaultValue; + + if (low == high && !highInclusive && !lowInclusive) + throw new NotSolvableException("range has equal low and high and is exclusive"); + + return low + (lowInclusive ? 0 : 1); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java index d39703df..06e25687 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ExactlyBookPages.java @@ -16,4 +16,9 @@ public ExactlyBookPages(List pages) { public boolean matches(List pages) { return this.pages.equals(pages); } + + @Override + public List solve(List defaultValue) throws NotSolvableException { + return pages; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java index 5fa3a83a..b8e8a810 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookAuthorMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -24,4 +25,19 @@ public boolean matches(ItemStack item) { return this.author.matches(author); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta) || + !((BookMeta) item.getItemMeta()).hasAuthor()) { + item.setType(Material.WRITTEN_BOOK); + } + + assert item.getItemMeta() instanceof BookMeta; // mostly to get intellij autocomplete for BookMeta + + BookMeta meta = (BookMeta) item.getItemMeta(); + meta.setAuthor(author.solve("Nobody")); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java index 1f0a23f5..1efd5247 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookGenerationMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -23,4 +24,19 @@ public boolean matches(ItemStack item) { return generations.matches(((BookMeta) item.getItemMeta()).getGeneration()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta) || + !((BookMeta) item.getItemMeta()).hasGeneration()) { + item.setType(Material.WRITTEN_BOOK); + } + + assert item.getItemMeta() instanceof BookMeta; // mostly to get intellij autocomplete for BookMeta + + BookMeta meta = (BookMeta) item.getItemMeta(); + meta.setGeneration(generations.solve(BookMeta.Generation.ORIGINAL)); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java index df3b71b1..b196af6f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPageCountMatcher.java @@ -1,10 +1,14 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import java.util.Collections; +import java.util.List; + /** * @author Ameliorate */ @@ -22,4 +26,21 @@ public boolean matches(ItemStack item) { return pageCount.matches(((BookMeta) item.getItemMeta()).getPageCount()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta)) { + item.setType(Material.WRITABLE_BOOK); + } + + assert item.getItemMeta() instanceof BookMeta; + + int count = pageCount.solve(1); + List pages = Collections.nCopies(count, ""); + + BookMeta meta = (BookMeta) item.getItemMeta(); + meta.setPages(pages); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java index fad303c2..e2ed9e96 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookPagesMatcher.java @@ -1,9 +1,11 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,4 +29,21 @@ public boolean matches(ItemStack item) { return matcher.matches(pages); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta)) { + item.setType(Material.WRITABLE_BOOK); + } + + assert item.getItemMeta() instanceof BookMeta; + + List pages = matcher.solve(new ArrayList<>()); + // new arraylist instead of Collections.emptyList() because solve() might mutate the list. + + BookMeta meta = (BookMeta) item.getItemMeta(); + meta.setPages(pages); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java index 65f3a882..693c6870 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/ItemBookTitleMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.book; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -29,4 +30,20 @@ public boolean matches(ItemStack item) { return this.title.matches(title); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BookMeta) || + !((BookMeta) item.getItemMeta()).hasTitle()) { + item.setType(Material.WRITTEN_BOOK); + } + + assert item.getItemMeta() instanceof BookMeta; // mostly to get intellij autocomplete for BookMeta + + String title = this.title.solve("Unnamed Book"); + BookMeta meta = (BookMeta) item.getItemMeta(); + meta.setTitle(title); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java index 2fbb92a6..c3baf723 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/book/RegexBookPages.java @@ -25,4 +25,9 @@ public boolean matches(List pages) { String formattedPages = pageBuilder.toString(); return regex.matcher(formattedPages).find(); } + + @Override + public List solve(List defaultValue) throws NotSolvableException { + throw new NotSolvableException("can't solve regexes"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java index 8b10e17c..8a9a53ce 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ExactlyColor.java @@ -19,6 +19,11 @@ public boolean matches(Color color) { return this.color.equals(color); } + @Override + public Color solve(Color defaultValue) throws NotSolvableException { + return color; + } + /** * Maps between HTML colors and org.bukkit.Color. See https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Color.html * for the full list of colors. diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java index 2d0ca0ab..9e8e74ec 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/color/ListColor.java @@ -2,6 +2,7 @@ import org.bukkit.Color; +import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import java.util.stream.Stream; @@ -29,4 +30,57 @@ public boolean matches(Color color) { return stream.anyMatch(predicate); } } + + @Override + public Color solve(Color defaultValue) throws NotSolvableException { + if (!noneInList) { + List causes = new ArrayList<>(); + + for (ColorMatcher matcher : matchers) { + try { + return matcher.solve(defaultValue); + } catch (NotSolvableException e) { + causes.add(e); + } + } + + NotSolvableException e = new NotSolvableException("couldn't solve list of color matchers"); + causes.forEach(e::addSuppressed); + throw e; + } else { + // just brute force it, starting at defaultValue. + + // A brute force search is okay because you can only match over exactly color or in list color. + // If you were to list every single color, ypu'd exaust memory on nearly every machine. + + Color color = defaultValue; + while (!matches(color)) { + int red = color.getRed(); + int green = color.getGreen(); + int blue = color.getBlue(); + + if (++red > 255) { + red = 0; + green++; + } + if (green > 255) { + green = 0; + blue++; + } + if (blue > 255) { + blue = 0; + } + + // we manually implement overflowing because java doesn't have a unsigned 24 bit type, and unsigned + // bytes aren't easy either. + + color = Color.fromRGB(red, green, blue); + + if (color == defaultValue) + throw new NotSolvableException("exausted entire rgb space searching for matching color"); + } + + return color; + } + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java index 6750130e..56bc98d8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/AnyEnchantment.java @@ -3,6 +3,9 @@ import org.bukkit.enchantments.Enchantment; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import java.util.AbstractMap; +import java.util.Map; + /** * Matches any enchantment type, as long as the level matches the level matcher. * @@ -19,4 +22,10 @@ public AnyEnchantment(AmountMatcher level) { public boolean matches(Enchantment enchantment, int level) { return this.level.matches(level); } + + @Override + public Map.Entry solve(Map.Entry entry) throws NotSolvableException { + int level = this.level.solve(1); + return new AbstractMap.SimpleEntry<>(entry.getKey(), level); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java index 714cebc2..eee5eb1c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java @@ -1,5 +1,13 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; + +import java.util.Collections; +import java.util.Map; + /** * Represents the different holders of enchantments an item can have. * @@ -14,5 +22,78 @@ public enum EnchantmentsSource { /** * For example from the enchantments held inside an enchanted book */ - HELD, + HELD; + + /** + * Gets the enchantments from an item based on the value of this. + * @param item The item to get the enchantments from. + * @return The stored enchantments if this == HELD, or the regular enchantments if this == ITEM. + */ + public Map get(ItemStack item) { + if (!item.hasItemMeta()) + return Collections.emptyMap(); + + if (this == ITEM) + return item.getEnchantments(); + + if (this == HELD) { + if (!(item.getItemMeta() instanceof EnchantmentStorageMeta)) + return Collections.emptyMap(); + return ((EnchantmentStorageMeta) item.getItemMeta()).getStoredEnchants(); + } + + throw new AssertionError("not reachable"); + } + + public void set(ItemStack item, Map enchantments, boolean unsafe) { + if (this == ITEM) { + item.getEnchantments().keySet().forEach(item::removeEnchantment); + if (unsafe) + item.addUnsafeEnchantments(enchantments); + else + item.addEnchantments(enchantments); + } + + if (this == HELD) { + if (!(item.hasItemMeta()) || !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + throw new IllegalArgumentException("item does not store enchantments"); + + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + + meta.getStoredEnchants().keySet().forEach(meta::removeStoredEnchant); + enchantments.forEach((enchantment, level) -> + meta.addStoredEnchant(enchantment, level, unsafe)); + item.setItemMeta(meta); + } + } + + public void add(ItemStack item, Enchantment enchantment, int level, boolean unsafe) { + if (this == ITEM) { + if (unsafe) + item.addUnsafeEnchantment(enchantment, level); + else + item.addEnchantment(enchantment, level); + } + + if (this == HELD) { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + throw new IllegalArgumentException("item does not store enchantments"); + + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + meta.addStoredEnchant(enchantment, level, unsafe); + item.setItemMeta(meta); + } + } + + /** + * @return A material that can reasonably hold enchantments in the slot according to this enum. + */ + public Material getReasonableType() { + if (this == ITEM) + return Material.WOODEN_SWORD; + if (this == HELD) + return Material.ENCHANTED_BOOK; + + throw new AssertionError("not reachable"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java index e4cadf5e..04153ce5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ExactlyEnchantment.java @@ -3,6 +3,9 @@ import org.bukkit.enchantments.Enchantment; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import java.util.AbstractMap; +import java.util.Map; + /** * @author Ameliorate */ @@ -21,4 +24,10 @@ public boolean matches(Enchantment enchantment, int level) { return false; return this.level.matches(level); } + + @Override + public Map.Entry solve(Map.Entry defaultValue) throws NotSolvableException { + int level = this.level.solve(defaultValue.getValue()); + return new AbstractMap.SimpleEntry<>(enchantment, level); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java index b54aac9c..6339d314 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java @@ -1,10 +1,18 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; +import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + /** * @author Ameliorate */ @@ -40,4 +48,44 @@ public boolean matches(ItemStack item) { return enchantmentCount.matches(count); } + + private static List allEnchantments = new ArrayList<>(); + + static { + Class enchantmentClass = Enchantment.class; + List staticFields = Arrays.stream(enchantmentClass.getFields()) + .filter((f) -> Modifier.isStatic(f.getModifiers())) // is static + .filter((f) -> f.getType().isAssignableFrom(Enchantment.class)) // is of type Enchantment + .filter((f) -> Modifier.isPublic(f.getModifiers())) // is public + .collect(Collectors.toList()); // in other words, get all the enchantments declared in Enchangments. + + staticFields.forEach((f) -> { + try { + allEnchantments.add((Enchantment) f.get(Enchantment.PROTECTION_FALL)); + } catch (IllegalAccessException e) { + throw new AssertionError("expected f to be a public member", e); + } + }); + } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + int i = 0; + boolean unsafe = false; + + while (!enchantmentCount.matches(source.get(item).size())) { + source.add(item, allEnchantments.get(i++), 1, unsafe); + + if (i >= allEnchantments.size() && unsafe) + throw new NotSolvableException("not enough enchantments exist to solve for enchantment count on item"); + + if (i >= allEnchantments.size()) { + // if can't get enough enchantments with safe enchantments, add some unsafe enchantments. + unsafe = true; + i = 0; + } + } + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java index 52bbe023..312978c4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java @@ -8,12 +8,15 @@ import java.util.List; import java.util.Map; +import java.util.stream.Collectors; + +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.HELD; +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.ITEM; /** * @author Ameliorate */ public class ItemEnchantmentsMatcher implements ItemMatcher { - public ItemEnchantmentsMatcher(List enchantmentMatchers, ListMatchingMode mode, EnchantmentsSource source) { if (enchantmentMatchers.isEmpty()) throw new IllegalArgumentException("enchanmentMatchers can not be empty. If an empty enchantmentMatchers " + @@ -40,6 +43,25 @@ public boolean matches(ItemStack item) { throw new AssertionError("not reachable"); } + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta()) + item.setType(source.getReasonableType()); + if (source == HELD && !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + item.setType(source.getReasonableType()); + if (source == ITEM && !(item.getItemMeta().hasEnchants())) + item.setType(source.getReasonableType()); + + List> enchantments = + mode.solve(enchantmentMatchers, + new ListMatchingMode.LazyFromListEntrySupplier<>(item.getEnchantments())); + + Map enchantmentMap = + enchantments.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + source.set(item, enchantmentMap, true); + return item; + } + public boolean matches(Map enchantments) { return mode.matches(enchantmentMatchers, enchantments.entrySet()); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java index e2baa640..d9c600d5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/AnyEnum.java @@ -6,8 +6,25 @@ * @author Ameliorate */ public class AnyEnum> implements EnumMatcher { + public AnyEnum() { + } + + public AnyEnum(Class enumClass) { + this.enumClass = enumClass; + } + + public Class enumClass = null; + @Override public boolean matches(E matched) { return true; } + + @Override + public E solve(E defaultValue) throws NotSolvableException { + if (enumClass == null) + throw new NotSolvableException("not able to solve an AnyEnum without a enumClass set"); + + return enumClass.getEnumConstants()[0]; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java index 4d6c6917..493b2752 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumFromListMatcher.java @@ -30,4 +30,9 @@ public boolean matches(E enumm) { return enums.contains(enumm); } } + + @Override + public E solve(E defaultValue) throws NotSolvableException { + return enums.get(0); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java index afb5554b..b344cf71 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/EnumIndexMatcher.java @@ -8,10 +8,24 @@ public EnumIndexMatcher(int index) { this.index = index; } - int index; + public EnumIndexMatcher(int index, Class enumClass) { + this(index); + this.enumClass = enumClass; + } + + public int index; + public Class enumClass = null; @Override public boolean matches(E enumm) { return enumm.ordinal() == index; } + + @Override + public E solve(E defaultValue) throws NotSolvableException { + if (enumClass == null) + throw new NotSolvableException("can't solve an EnumIndex without enumClass set"); + + return enumClass.getEnumConstants()[index]; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java index acb8db20..1392366e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/ExactlyEnumMatcher.java @@ -14,4 +14,9 @@ public ExactlyEnumMatcher(E exactly) { public boolean matches(E enumm) { return exactly.equals(enumm); } + + @Override + public E solve(E defaultValue) throws NotSolvableException { + return exactly; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java index f887dda4..ab14802e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java @@ -10,10 +10,21 @@ public NameEnumMatcher(NameMatcher nameMatcher) { this.nameMatcher = nameMatcher; } + public NameEnumMatcher(NameMatcher nameMatcher, Class enumClass) { + this(nameMatcher); + this.enumClass = enumClass; + } + public NameMatcher nameMatcher; + public Class enumClass = null; @Override public boolean matches(E enumm) { return nameMatcher.matches(enumm.toString()); } + + @Override + public E solve(E defaultValue) throws NotSolvableException { + return null; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java index 267df4fb..b8d5d757 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ExactlyFireworkEffect.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; +import org.bukkit.Color; import org.bukkit.FireworkEffect; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.color.ColorMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; @@ -59,4 +60,21 @@ public boolean matches(FireworkEffect effect) { return true; } + + @Override + public FireworkEffect solve(FireworkEffect effect) throws NotSolvableException { + FireworkEffect.Type type = this.type.solve(effect.getType()); + List colors = colorsMode.solve(this.colors, () -> Color.WHITE); + List fadeColors = fadeColorsMode.solve(this.fadeColors, () -> Color.WHITE); + boolean hasFlicker = this.hasFlicker.orElse(effect.hasFlicker()); + boolean hasTrail = this.hasTrail.orElse(effect.hasTrail()); + + return FireworkEffect.builder() + .with(type) + .withColor(colors) + .withFade(fadeColors) + .flicker(hasFlicker) + .trail(hasTrail) + .build(); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java index 50017aad..024a55c5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectHolderMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.FireworkEffectMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -28,4 +29,15 @@ public boolean matches(ItemStack item) { return effect.matches(((FireworkEffectMeta) item.getItemMeta()).getEffect()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkEffectMeta)) + item.setType(Material.FIREWORK_STAR); + + FireworkEffectMeta meta = (FireworkEffectMeta) item.getItemMeta(); + meta.setEffect(effect.solve(meta.getEffect())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java index f073ce26..9075327c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java @@ -1,10 +1,16 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; +import com.google.common.hash.Hashing; +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.FireworkMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; +import java.util.ArrayList; + /** * @author Ameliorate */ @@ -22,4 +28,69 @@ public boolean matches(ItemStack item) { return count.matches(((FireworkMeta) item.getItemMeta()).getEffectsSize()); } + + public static final int TRAIL_MASK = 0b00000000000000000000000000000001; + public static final int FLICK_MASK = 0b00000000000000000000000000000010; // shift 1 to get as an int + public static final int TYPE_MASK = 0b00000000000000000000000000011100; // shift 2 + public static final int CRED_MASK = 0b00000000000000000000001111100000; // shift 5 or 2 for 8 bit MSB + public static final int CGREE_MASK = 0b00000000000000000111110000000000; // shift 10 or 7 + public static final int CBLUE_MASK = 0b00000000000001111000000000000000; // shift 15 or 11 + public static final int FRED_MASK = 0b00000000111110000000000000000000; // shift 19 or 16 + public static final int FGREE_MASK = 0b00001111000000000000000000000000; // shift 24 or 20 + public static final int FBLUE_MASK = 0b11110000000000000000000000000000; // shift 28 or 24 + + @SuppressWarnings("UnstableApiUsage") + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + int count = this.count.solve(0); + + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkMeta)) + item.setType(Material.FIREWORK_ROCKET); + + assert item.getItemMeta() instanceof FireworkMeta; + + FireworkMeta meta = (FireworkMeta) item.getItemMeta(); + + ArrayList effects = new ArrayList<>(); + for (int i = 0; i < count; i++) { + effects.add(getFireworkEffectWithIndex(i)); + } + + meta.addEffects(effects); + item.setItemMeta(meta); + return item; + } + + @SuppressWarnings("UnstableApiUsage") + public static FireworkEffect getFireworkEffectWithIndex(int i) { + int b = Hashing.md5().hashInt(i).asInt(); // probably overkill, but oh well. I don't have internet right now + boolean trail = (b & TRAIL_MASK) == 1; + boolean flicker = (b & FLICK_MASK) == 2; + int typeIndex = b & TYPE_MASK >>> 2; + int typeIndexOver = 0; + if (typeIndex <= 5) { + typeIndexOver = typeIndex - 4; + typeIndex -= 5; + } + FireworkEffect.Type type = FireworkEffect.Type.values()[typeIndex]; + + byte colorRed = (byte) ((b & CRED_MASK) >>> 2); + byte colorGreen = (byte) ((b & CGREE_MASK) >>> 7); + byte colorBlue = (byte) ((b & CBLUE_MASK) >>> 11); + colorBlue += typeIndexOver << 2; // recover the entropy lost from clipping typeIndex. + Color color = Color.fromRGB(colorRed, colorGreen, colorBlue); + + byte fadeRed = (byte) ((b & FRED_MASK) >>> 16); + byte fadeGreen = (byte) ((b & FGREE_MASK) >>> 20); + byte fadeBlue = (byte) ((b & FBLUE_MASK) >>> 24); + Color fadeColor = Color.fromRGB(fadeRed, fadeGreen, fadeBlue); + + return FireworkEffect.builder() + .flicker(flicker) + .trail(trail) + .withColor(color) + .withFade(fadeColor) + .with(type) + .build(); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java index 879a3327..964e7072 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsMatcher.java @@ -1,12 +1,14 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; import org.bukkit.FireworkEffect; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.FireworkMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; import java.util.List; +import java.util.function.Supplier; /** * @author Ameliorate @@ -29,4 +31,30 @@ public boolean matches(ItemStack item) { List effects = ((FireworkMeta) item.getItemMeta()).getEffects(); return mode.matches(this.effects, effects); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkMeta)) + item.setType(Material.FIREWORK_ROCKET); + + FireworkMeta meta = (FireworkMeta) item.getItemMeta(); + if (mode == ListMatchingMode.NONE) { + meta.clearEffects(); + // we clear effects because there may be in there an effectmatcher that matches an effect in effects + // except, this is pointless because ListMatchingMode can't solve a NONE. + } + + List effects = mode.solve(this.effects, new Supplier() { + public int index = 0; + + @Override + public FireworkEffect get() { + return ItemFireworkEffectsCountMatcher.getFireworkEffectWithIndex(index++); + } + }); // we use the old way of lambdas so we can have the index thing there. + + meta.addEffects(effects); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java index ede94738..f6ff6185 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkPowerMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.firework; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.FireworkMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -22,4 +23,18 @@ public boolean matches(ItemStack item) { return power.matches(((FireworkMeta) item.getItemMeta()).getPower()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof FireworkMeta)) { + item.setType(Material.FIREWORK_ROCKET); + } + + assert item.getItemMeta() instanceof FireworkMeta; + + FireworkMeta meta = (FireworkMeta) item.getItemMeta(); + meta.setPower(power.solve(1)); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java index 508ad8e4..08d44078 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ExactlyLore.java @@ -19,4 +19,9 @@ public ExactlyLore(List lore) { public boolean matches(List lore) { return this.lore.equals(lore); } + + @Override + public List solve(List defaultValue) throws NotSolvableException { + return lore; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java index 3cb3e74c..01e9338e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/ItemLoreMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import java.util.Optional; @@ -26,4 +28,13 @@ public boolean matches(ItemStack item) { return matcher.matches(item.getItemMeta().getLore()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType()); + + meta.setLore(matcher.solve(meta.getLore())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java index b117db1b..d132de56 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/lore/RegexLore.java @@ -17,4 +17,9 @@ public RegexLore(Pattern pattern) { public boolean matches(List lore) { return pattern.matcher(String.join("\n", lore)).find(); } + + @Override + public List solve(List defaultValue) throws NotSolvableException { + throw new NotSolvableException("can't solve a regex"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java index 64a14b8c..9b5f6966 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/CenterMapView.java @@ -22,6 +22,20 @@ public boolean matches(MapView map) { return mapLocation.matches(coordinate); } + @Override + public MapView solve(MapView view) throws NotSolvableException { + switch (centerCoordinate) { + case X: + view.setCenterX(mapLocation.solve(0)); + break; + case Z: + view.setCenterZ(mapLocation.solve(0)); + break; + } + + return view; + } + public enum CenterCoordinate { X, Z, diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java index e2c4e6f7..1152b822 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IDMapView.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.Bukkit; import org.bukkit.map.MapView; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -18,4 +19,10 @@ public boolean matches(MapView map) { int id = map.getId(); return this.id.matches(id); } + + @SuppressWarnings("deprecation") + @Override + public MapView solve(MapView defaultValue) throws NotSolvableException { + return Bukkit.getServer().getMap(id.solve(0)); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java index 4bafda0a..370149ed 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsUnlimitedTrackingMapView.java @@ -16,4 +16,11 @@ public IsUnlimitedTrackingMapView(boolean isUmlimitedTracking) { public boolean matches(MapView map) { return map.isUnlimitedTracking() == isUmlimitedTracking; } + + @Override + public MapView solve(MapView map) throws NotSolvableException { + map.setUnlimitedTracking(isUmlimitedTracking); + + return map; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java index a1c8f3ee..dbf13fd8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/IsVirtualMapView.java @@ -1,5 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.map.MapCanvas; +import org.bukkit.map.MapRenderer; import org.bukkit.map.MapView; /** @@ -16,4 +20,19 @@ public IsVirtualMapView(boolean isVirtual) { public boolean matches(MapView map) { return map.isVirtual() == isVirtual; } + + @Override + public MapView solve(MapView map) throws NotSolvableException { + MapView view = Bukkit.createMap(Bukkit.getWorld("world")); + view.addRenderer(new MapRenderer() { + @Override + public void render(MapView mapView, MapCanvas mapCanvas, Player player) { + // do nothing + } + }); + + assert map.isVirtual(); + + return view; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java index e84e3ad2..93c411a0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapColorMatcher.java @@ -1,5 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.DyeColor; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -23,4 +25,17 @@ public boolean matches(ItemStack item) { return color.matches(((MapMeta) item.getItemMeta()).getColor()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta)) + item.setType(Material.MAP); + + MapMeta meta = (MapMeta) item.getItemMeta(); + meta.setColor(color.solve(DyeColor.WHITE.getColor())); + + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java index 29a4106c..9b1a6235 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapIsScalingMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -21,4 +22,17 @@ public boolean matches(ItemStack item) { return ((MapMeta) item.getItemMeta()).isScaling() == isScaling; } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta)) + item.setType(Material.MAP); + + MapMeta meta = (MapMeta) item.getItemMeta(); + meta.setScaling(isScaling); + + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java index 77619aae..3499ccf0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapLocationMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -24,4 +25,17 @@ public boolean matches(ItemStack item) { String location = ((MapMeta) item.getItemMeta()).getLocationName(); return locationName.matches(location); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta)) + item.setType(Material.MAP); + + MapMeta meta = (MapMeta) item.getItemMeta(); + meta.setLocationName(locationName.solve("")); + + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java index 30069bc1..6ff79c90 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ItemMapViewMatcher.java @@ -1,7 +1,10 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; +import org.bukkit.map.MapView; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; /** @@ -22,4 +25,19 @@ public boolean matches(ItemStack item) { return matcher.matches(((MapMeta) item.getItemMeta()).getMapView()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof MapMeta)) + item.setType(Material.MAP); + + MapView view = Bukkit.createMap(Bukkit.getWorld("world")); + view = matcher.solve(view); + + MapMeta meta = (MapMeta) item.getItemMeta(); + meta.setMapView(view); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java index 9e161794..3893d921 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/ScaleMapView.java @@ -17,4 +17,11 @@ public ScaleMapView(EnumMatcher scale) { public boolean matches(MapView map) { return scale.matches(map.getScale()); } + + @Override + public MapView solve(MapView view) throws NotSolvableException { + view.setScale(scale.solve(MapView.Scale.NORMAL)); + + return view; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java index 1c00092b..a0cc72f5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/map/WorldMapView.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map; +import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.map.MapView; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; @@ -20,4 +21,17 @@ public boolean matches(MapView map) { return this.world.matches(world.getName()); } + + @Override + public MapView solve(MapView view) throws NotSolvableException { + String worldStr = world.solve("world"); + World world = Bukkit.getWorld(worldStr); + + if (world == null) { + throw new NotSolvableException("world matcher does not solve to a valid world name"); + } + + view.setWorld(world); + return view; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java index 5dfc4194..549a8f33 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java @@ -16,4 +16,9 @@ public ExactlyMaterial(Material material) { public boolean matches(Material material) { return this.material == material; } + + @Override + public Material solve(Material defaultValue) throws NotSolvableException { + return material; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java index d295a2a7..4d578a63 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java @@ -23,4 +23,10 @@ public static ItemMaterialMatcher construct(Optional matcher) { public boolean matches(ItemStack item) { return matcher.matches(item.getType()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + item.setType(matcher.solve(item.getType())); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java index 7a1d35b7..cb0e371e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java @@ -18,4 +18,9 @@ public RegexMaterial(Pattern regex) { public boolean matches(Material material) { return regex.matcher(material.toString()).matches(); } + + @Override + public Material solve(Material defaultValue) throws NotSolvableException { + throw new NotSolvableException("can't solve a regex"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java index 92e07f12..3e0c4b74 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemAttributeMatcher.java @@ -1,9 +1,13 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import org.bukkit.Bukkit; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -11,8 +15,10 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.uuid.UUIDMatcher; +import java.util.AbstractMap; import java.util.List; import java.util.Map; +import java.util.UUID; /** * Matches over the attributes of an item that apply for a given slot. @@ -27,6 +33,8 @@ public ItemAttributeMatcher(List matchers, EquipmentSlot slot, this.matchers = matchers; this.slot = slot; this.mode = mode; + + matchers.forEach((m) -> m.slot = slot); } public List matchers; @@ -41,6 +49,25 @@ public boolean matches(ItemStack item) { return mode.matches(matchers, item.getItemMeta().getAttributeModifiers(slot).entries()); } + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType()); + + List> attributes = mode.solve(matchers, + () -> new AbstractMap.SimpleEntry<>(Attribute.GENERIC_ARMOR, + new AttributeModifier("a", 1, AttributeModifier.Operation.ADD_NUMBER))); + + Multimap attributesMap = HashMultimap.create(); + + for (Map.Entry entry : attributes) { + attributesMap.put(entry.getKey(), entry.getValue()); + } + + meta.setAttributeModifiers(attributesMap); + item.setItemMeta(meta); + return item; + } + public static class AttributeMatcher implements Matcher> { public AttributeMatcher(EnumMatcher attribute, NameMatcher name, EnumMatcher operation, @@ -58,6 +85,8 @@ public AttributeMatcher(EnumMatcher attribute, public UUIDMatcher uuid; public AmountMatcher amount; + private EquipmentSlot slot; + public boolean matches(Attribute attribute, AttributeModifier modifier) { if (this.attribute != null && !this.attribute.matches(attribute)) return false; @@ -77,5 +106,19 @@ else if (amount != null && !amount.matches(modifier.getAmount())) public boolean matches(Map.Entry matched) { return matches(matched.getKey(), matched.getValue()); } + + @Override + public Map.Entry solve(Map.Entry entry) throws NotSolvableException { + Attribute attribute = this.attribute.solve(entry.getKey()); + + AttributeModifier defaultModifier = entry.getValue(); + + AttributeModifier.Operation operation = this.operation.solve(defaultModifier.getOperation()); + String name = this.name.solve(defaultModifier.getName()); + UUID uuid = this.uuid.solve(defaultModifier.getUniqueId()); + double amount = this.amount.solve(defaultModifier.getAmount()); + + return new AbstractMap.SimpleEntry<>(attribute, new AttributeModifier(uuid, name, amount, operation, slot)); + } } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java index bccf92df..17ffea26 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyInventoryMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import org.bukkit.Material; import org.bukkit.block.Container; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.ItemMap; @@ -28,6 +30,32 @@ public boolean matches(ItemStack item) { return getItemHeldInventory(item).itemExpressionsMatchItems(itemExpressions); } + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof BlockStateMeta) || + !((BlockStateMeta) item.getItemMeta()).hasBlockState() || + !(((BlockStateMeta) item.getItemMeta()).getBlockState() instanceof Container)) + item.setType(Material.SHULKER_BOX); + + ItemMap map = new ItemMap(); + for (ItemExpression itemExpression : itemExpressions) { + map.addItemAmount(itemExpression.solve(), itemExpression.getAmount(false)); + } + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + Container container = (Container) meta.getBlockState(); + Inventory inventory = container.getInventory(); + + if (!map.fitsIn(inventory)) + throw new NotSolvableException("doesn't fit inside inventory"); + map.getItemStackRepresentation().forEach(inventory::addItem); + + meta.setBlockState(container); + item.setItemMeta(meta); + + return item; + } + /** * @param item The item to get the inventory of. * @return An ItemMap of the item's inventory. diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java index ca1365d9..0263022f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemExactlyStackMatcher.java @@ -23,4 +23,9 @@ public boolean matches(ItemStack item) { else return itemStack.isSimilar(item); } + + @Override + public ItemStack solve(ItemStack defaultValue) throws NotSolvableException { + return itemStack.clone(); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java index b47b305b..d3cb28f4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemFlagMatcher.java @@ -1,7 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; public class ItemFlagMatcher implements ItemMatcher { @@ -25,4 +27,17 @@ public boolean matches(ItemStack item) { return this.setting == setting; } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType()); + + if (setting == true) + meta.addItemFlags(flag); + else + meta.removeItemFlags(flag); + + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java index dd4b9084..36ba003e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemKnowledgeBookMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.KnowledgeBookMeta; @@ -48,4 +49,28 @@ public boolean matches(ItemStack item) { else return recipesStream.anyMatch(recipeMatcher::matches); } + + @SuppressWarnings("deprecation") + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof KnowledgeBookMeta)) + item.setType(Material.KNOWLEDGE_BOOK); + + KnowledgeBookMeta meta = (KnowledgeBookMeta) item.getItemMeta(); + + List recipes = meta.getRecipes(); + if (requireAllMatch) + recipes.clear(); + + String defaultValue = recipes.isEmpty() ? "" : recipes.get(0).toString(); + String[] solved = recipeMatcher.solve(defaultValue).split(":", 2); + String namespace = solved[0]; + String str = solved[1]; + + recipes.add(new NamespacedKey(namespace, str)); + + meta.setRecipes(recipes); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java index 8545c3f8..25214e0b 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemLeatherArmorColorMatcher.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; import org.bukkit.Color; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.LeatherArmorMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -30,4 +31,18 @@ public boolean matches(ItemStack item) { Color leatherColor = ((LeatherArmorMeta) item.getItemMeta()).getColor(); return color.matches(leatherColor); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof LeatherArmorMeta)) + item.setType(Material.LEATHER_CHESTPLATE); + + assert item.getItemMeta() instanceof LeatherArmorMeta; + + LeatherArmorMeta meta = (LeatherArmorMeta) item.getItemMeta(); + + meta.setColor(color.solve(meta.getColor())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java index acc9c7d1..f922a513 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemShulkerBoxColorMatcher.java @@ -1,9 +1,10 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import org.bukkit.DyeColor; -import org.bukkit.block.ShulkerBox; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; @@ -25,13 +26,40 @@ public static ItemShulkerBoxColorMatcher construct(Optional shulkerBoxColors = HashBiMap.create(); + private static BiMap colorsShulkerBox; + + static { + shulkerBoxColors.put(DyeColor.BLACK, Material.BLACK_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.BLUE, Material.BLUE_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.BROWN, Material.BROWN_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.CYAN, Material.CYAN_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.GRAY, Material.GRAY_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.GREEN, Material.GREEN_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.LIGHT_BLUE, Material.LIGHT_BLUE_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.LIGHT_GRAY, Material.LIGHT_GRAY_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.LIME, Material.LIME_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.MAGENTA, Material.MAGENTA_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.ORANGE, Material.ORANGE_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.PINK, Material.PINK_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.PURPLE, Material.PURPLE_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.RED, Material.RED_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.WHITE, Material.WHITE_SHULKER_BOX); + shulkerBoxColors.put(DyeColor.YELLOW, Material.YELLOW_SHULKER_BOX); - return this.color.matches(colour); + colorsShulkerBox = shulkerBoxColors.inverse(); + } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + DyeColor color = this.color.solve(DyeColor.PURPLE); + item.setType(shulkerBoxColors.get(color)); + return item; } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java index 07731717..d3a262ff 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemSkullMatcher.java @@ -1,5 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -37,4 +39,20 @@ public boolean matches(ItemStack item) { owner = meta.getOwningPlayer().getUniqueId(); return ownerMatcher.stream().anyMatch((matcher) -> matcher.matches(owner)); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + UUID uuid = ListMatchingMode.ANY.solve(ownerMatcher, + () -> new UUID(0, 0)) + .get(0); + + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof SkullMeta)) + item.setType(Material.PLAYER_HEAD); + assert item.getItemMeta() instanceof SkullMeta; + + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setOwningPlayer(Bukkit.getOfflinePlayer(uuid)); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java index 366b23a0..1d7361e2 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemUnbreakableMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; /** @@ -21,4 +23,14 @@ public boolean matches(ItemStack item) { isUnbreakable = item.getItemMeta().isUnbreakable(); return isUnbreakable == unbreakable; } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType()); + + meta.setUnbreakable(unbreakable); + + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java index 22035072..a6f608f5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java @@ -6,7 +6,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Stream; /** @@ -115,4 +117,111 @@ public > boolean matches(Collection matchers, Collect throw new AssertionError("not reachable"); } + + public > List solve(Collection matchers, Supplier defaultValue) + throws Matcher.NotSolvableException { + ArrayList result = new ArrayList<>(); + + switch (this) { + case ONE_TO_ONE: + case ALL: + for (M matcher : matchers) { + result.add(matcher.solve(defaultValue.get())); + } + + break; + + case ANY: + List causes = new ArrayList<>(); + boolean hasSolved = false; + for (Matcher matcher : matchers) { + try { + result.add(matcher.solve(defaultValue.get())); + hasSolved = true; + break; + } catch (Matcher.NotSolvableException e) { + causes.add(e); + } + } + + if (!hasSolved) { + Matcher.NotSolvableException e = new Matcher.NotSolvableException("while solving for any matching"); + causes.forEach(e::addSuppressed); + throw e; + } + + break; + + case NONE: + throw new Matcher.NotSolvableException("can't yet do negative solving"); + } + + return result; + } + + // TODO: how to make this class for non-entry: + // use object reflection to optain all fields of defaultValue. use reflection to obtain all fields of returnedValue. + // use Object.== operator to compare reference equality. Consiter an entry taken if any of the feilds between the + // two are equal. + public static class LazyFromListEntrySupplier implements Supplier> { + public LazyFromListEntrySupplier(Supplier>> entriesSupplier) { + this.entriesSupplier = entriesSupplier; + } + + public LazyFromListEntrySupplier(Collection> collection) { + this(() -> new ArrayList<>(collection)); + } + + public LazyFromListEntrySupplier(Map map) { + this(map.entrySet()); + } + + private void regen() { + if (entries == null || entries.isEmpty()) + entries = entriesSupplier.get(); + } + + public Collection> entries; + public Supplier>> entriesSupplier; + + @Override + public Map.Entry get() { + return new Map.Entry() { + private K e; + private V l; + private boolean taken = false; + + private void evaluate() { + if (!taken) { + regen(); + Map.Entry entry = entries.stream().limit(1).findFirst() + .orElseThrow(NullPointerException::new); + entries.remove(entry); + + e = entry.getKey(); + l = entry.getValue(); + + taken = true; + } + } + + @Override + public K getKey() { + evaluate(); + return e; + } + + @Override + public V getValue() { + evaluate(); + return l; + } + + @Override + public V setValue(V value) { + throw new UnsupportedOperationException(); + } + }; + } + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java index ea4fcd0d..7847afbd 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerDelayMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -21,4 +23,18 @@ public boolean matches(ItemStack item) { return delay.matches(MobSpawnerUtil.getMobSpawnerState(item).getDelay()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + spawner.setDelay(delay.solve(0)); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java index 866f7019..0dfe7599 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerMaxNearbyEntitiesMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -14,6 +16,8 @@ public ItemMobSpawnerMaxNearbyEntitiesMatcher(AmountMatcher maxNearbyEntities) { public AmountMatcher maxNearbyEntities; + private final int DEFAULT_MAX_NEARBY_ENTITIES = 6; + @Override public boolean matches(ItemStack item) { if (!MobSpawnerUtil.isMobSpawner(item)) @@ -21,4 +25,18 @@ public boolean matches(ItemStack item) { return maxNearbyEntities.matches(MobSpawnerUtil.getMobSpawnerState(item).getMaxNearbyEntities()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + spawner.setMaxNearbyEntities(maxNearbyEntities.solve(DEFAULT_MAX_NEARBY_ENTITIES)); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java index cedb3e59..200e6aa4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerRequiredPlayerRangeMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -14,6 +16,8 @@ public ItemMobSpawnerRequiredPlayerRangeMatcher(AmountMatcher range) { public AmountMatcher range; + private final int DEFAULT_REQUIRED_PLAYER_RANGE = 16; + @Override public boolean matches(ItemStack item) { if (!MobSpawnerUtil.isMobSpawner(item)) @@ -21,4 +25,18 @@ public boolean matches(ItemStack item) { return range.matches(MobSpawnerUtil.getMobSpawnerState(item).getRequiredPlayerRange()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + spawner.setRequiredPlayerRange(range.solve(DEFAULT_REQUIRED_PLAYER_RANGE)); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java index ea6936a7..8432be16 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnCountMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -14,6 +16,8 @@ public ItemMobSpawnerSpawnCountMatcher(AmountMatcher spawnCount) { public AmountMatcher spawnCount; + private final int DEFAULT_SPAWN_COUNT = 4; + @Override public boolean matches(ItemStack item) { if (!MobSpawnerUtil.isMobSpawner(item)) @@ -21,4 +25,18 @@ public boolean matches(ItemStack item) { return spawnCount.matches(MobSpawnerUtil.getMobSpawnerState(item).getSpawnCount()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + spawner.setSpawnCount(spawnCount.solve(DEFAULT_SPAWN_COUNT)); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java index f37b3e38..59d56ac6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnDelayMatcher.java @@ -2,6 +2,7 @@ import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -17,6 +18,9 @@ public ItemMobSpawnerSpawnDelayMatcher(AmountMatcher spawnDelay, MinMax source) public AmountMatcher spawnDelay; public MinMax source; + private final int DEFAULT_MIN_SPAWN_DELAY = 200; // ticks, 10 seconds + private final int DEFAULT_MAX_SPAWN_DELAY = 799; // ticks, 39.95 seconds + @Override public boolean matches(ItemStack item) { if (!MobSpawnerUtil.isMobSpawner(item)) @@ -28,6 +32,27 @@ public boolean matches(ItemStack item) { return this.spawnDelay.matches(spawnDelay); } + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + switch (source) { + case MIN: + spawner.setMinSpawnDelay(spawnDelay.solve(DEFAULT_MIN_SPAWN_DELAY)); + break; + case MAX: + spawner.setMaxSpawnDelay(spawnDelay.solve(DEFAULT_MAX_SPAWN_DELAY)); + break; + } + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } + public enum MinMax { MIN, MAX, diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java index 37bdee28..cec40a8d 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnRadiusMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; @@ -14,6 +16,8 @@ public ItemMobSpawnerSpawnRadiusMatcher(AmountMatcher spawnRadius) { public AmountMatcher spawnRadius; + private final int DEFAULT_SPAWN_RADIUS = 3; + @Override public boolean matches(ItemStack item) { if (!MobSpawnerUtil.isMobSpawner(item)) @@ -21,4 +25,18 @@ public boolean matches(ItemStack item) { return spawnRadius.matches(MobSpawnerUtil.getMobSpawnerState(item).getSpawnRange()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + spawner.setSpawnRange(spawnRadius.solve(DEFAULT_SPAWN_RADIUS)); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java index 5ab95952..3a1c7fe8 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/ItemMobSpawnerSpawnedMobMatcher.java @@ -1,7 +1,9 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.block.CreatureSpawner; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; @@ -22,4 +24,18 @@ public boolean matches(ItemStack item) { return spawned.matches(MobSpawnerUtil.getMobSpawnerState(item).getSpawnedType()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + MobSpawnerUtil.setToMobSpawner(item); + CreatureSpawner spawner = MobSpawnerUtil.getMobSpawnerState(item); + + spawner.setSpawnedType(spawned.solve(EntityType.PIG)); + + BlockStateMeta meta = (BlockStateMeta) item.getItemMeta(); + meta.setBlockState(spawner); + item.setItemMeta(meta); + + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java index 3da6669f..92782b0e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/mobspawner/MobSpawnerUtil.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner; +import org.bukkit.Material; import org.bukkit.block.CreatureSpawner; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; @@ -47,4 +48,11 @@ public static CreatureSpawner getMobSpawnerState(ItemStack item) { return (CreatureSpawner) meta.getBlockState(); } + + public static void setToMobSpawner(ItemStack item) { + if (isMobSpawner(item)) + return; + + item.setType(Material.SPAWNER); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java index 3a2e30a9..7f774df5 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/AnyName.java @@ -8,4 +8,9 @@ public class AnyName implements NameMatcher { public boolean matches(String matched) { return true; } + + @Override + public String solve(String defaultValue) throws NotSolvableException { + return defaultValue; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java index f0ede991..a60cc6c6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java @@ -23,4 +23,9 @@ public boolean matches(String name) { else return this.name.equals(name.toLowerCase()); } + + @Override + public String solve(String defaultValue) throws NotSolvableException { + return name; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java index ab1451fb..4dfb7f5e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ItemNameMatcher.java @@ -1,6 +1,8 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name; +import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import java.util.Optional; @@ -28,4 +30,17 @@ public boolean matches(ItemStack item) { name = item.getItemMeta().getDisplayName(); return matcher.matches(name); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + ItemMeta meta; + if (!item.hasItemMeta()) + meta = Bukkit.getItemFactory().getItemMeta(item.getType()); + else + meta = item.getItemMeta(); + + meta.setDisplayName(matcher.solve(meta.getDisplayName())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java index f9dc9ada..b0484cef 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/RegexName.java @@ -16,4 +16,9 @@ public RegexName(Pattern regex) { public boolean matches(String name) { return regex.matcher(name).matches(); } + + @Override + public String solve(String defaultValue) throws NotSolvableException { + throw new NotSolvableException("can't solve a regex"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java index 725208fe..af6abbc1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/VanillaName.java @@ -12,4 +12,9 @@ public class VanillaName implements NameMatcher { public boolean matches(String name) { return name.isEmpty(); } + + @Override + public String solve(String defaultValue) throws NotSolvableException { + return ""; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java index e67167ee..bbde69d0 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/AnyPotionEffect.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount.AmountMatcher; /** @@ -21,4 +22,9 @@ public AnyPotionEffect(AmountMatcher level, AmountMatcher duration) { public boolean matches(PotionEffect effect) { return level.matches(effect.getAmplifier()) && duration.matches(effect.getDuration()); } + + @Override + public PotionEffect solve(PotionEffect defaultValue) throws NotSolvableException { + return new PotionEffect(PotionEffectType.HEAL, 0, 0); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java index 6ccf55de..ee7f0b38 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ExactlyPotionEffect.java @@ -24,4 +24,11 @@ public boolean matches(PotionEffect effect) { level.matches(effect.getAmplifier()) && duration.matches(effect.getDuration()); } + + @Override + public PotionEffect solve(PotionEffect defaultValue) throws NotSolvableException { + return new PotionEffect(type, + (int) (double) level.solve(0.0), + (int) (double) duration.solve(0.0)); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java index c2133549..78376fe1 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionBaseEffectMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionData; @@ -54,4 +55,22 @@ public boolean matches(ItemStack item) { return this.type.matches(type); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (item.getType() != Material.POTION && + item.getType() != Material.SPLASH_POTION && + item.getType() != Material.LINGERING_POTION) + item.setType(Material.POTION); + + PotionMeta potionMeta = (PotionMeta) item.getItemMeta(); + + PotionType type = this.type.solve(PotionType.AWKWARD); + boolean isExtended = this.isExtended.orElse(false); + boolean isUpgraded = this.isUpgraded.orElse(false); + + potionMeta.setBasePotionData(new PotionData(type, isExtended, isUpgraded)); + item.setItemMeta(potionMeta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java index 570b3218..f139c5ef 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/potion/ItemPotionEffectsMatcher.java @@ -1,15 +1,15 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.potion; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; import java.util.ArrayList; import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Stream; /** * @author Ameliorate @@ -40,6 +40,22 @@ public boolean matches(ItemStack item) { return matches(effects); } + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (item.getType() != Material.POTION && + item.getType() != Material.SPLASH_POTION && + item.getType() != Material.LINGERING_POTION) + item.setType(Material.POTION); + + List effects = mode.solve(potionMatchers, + () -> new PotionEffect(PotionEffectType.HEAL, 0, 0)); + + PotionMeta meta = (PotionMeta) item.getItemMeta(); + effects.forEach(potionEffect -> meta.addCustomEffect(potionEffect, true)); + item.setItemMeta(meta); + return item; + } + public boolean matches(List effects) { return mode.matches(potionMatchers, effects); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java index 9c3c7657..a9d89c37 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBBodyColorMatcher.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket; import org.bukkit.DyeColor; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.TropicalFishBucketMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -30,4 +31,16 @@ public boolean matches(ItemStack item) { return color.matches(((TropicalFishBucketMeta) item.getItemMeta()).getBodyColor()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof TropicalFishBucketMeta)) + item.setType(Material.TROPICAL_FISH_BUCKET); + + TropicalFishBucketMeta meta = (TropicalFishBucketMeta) item.getItemMeta(); + + meta.setBodyColor(color.solve(meta.getBodyColor())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java index 36170194..e016b5d7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternColorMatcher.java @@ -1,6 +1,7 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket; import org.bukkit.DyeColor; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.TropicalFishBucketMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; @@ -30,4 +31,16 @@ public boolean matches(ItemStack item) { return color.matches(((TropicalFishBucketMeta) item.getItemMeta()).getPatternColor()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof TropicalFishBucketMeta)) + item.setType(Material.TROPICAL_FISH_BUCKET); + + TropicalFishBucketMeta meta = (TropicalFishBucketMeta) item.getItemMeta(); + + meta.setPatternColor(color.solve(meta.getPatternColor())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java index 0b092ade..7a8105be 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/tropicalbucket/ItemTropicFishBPatternMatcher.java @@ -1,5 +1,6 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.tropicalbucket; +import org.bukkit.Material; import org.bukkit.entity.TropicalFish; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.TropicalFishBucketMeta; @@ -30,4 +31,16 @@ public boolean matches(ItemStack item) { return pattern.matches(((TropicalFishBucketMeta) item.getItemMeta()).getPattern()); } + + @Override + public ItemStack solve(ItemStack item) throws NotSolvableException { + if (!item.hasItemMeta() || !(item.getItemMeta() instanceof TropicalFishBucketMeta)) + item.setType(Material.TROPICAL_FISH_BUCKET); + + TropicalFishBucketMeta meta = (TropicalFishBucketMeta) item.getItemMeta(); + + meta.setPattern(pattern.solve(meta.getPattern())); + item.setItemMeta(meta); + return item; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java index 51f5c303..2c6ea755 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/AnyUUID.java @@ -10,4 +10,9 @@ public class AnyUUID implements UUIDMatcher { public boolean matches(UUID matched) { return true; } + + @Override + public UUID solve(UUID defaultValue) throws NotSolvableException { + return defaultValue; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java index 22ed1f36..b5bb6f5e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/ExactlyUUID.java @@ -16,4 +16,9 @@ public ExactlyUUID(UUID uuid) { public boolean matches(UUID uuid) { return this.uuid.equals(uuid); } + + @Override + public UUID solve(UUID defaultValue) throws NotSolvableException { + return uuid; + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java index 87886b66..c697fd2f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameRegexUUID.java @@ -25,4 +25,9 @@ public boolean matches(UUID uuid) { } else return false; } + + @Override + public UUID solve(UUID startingValue) throws NotSolvableException { + throw new NotSolvableException("can't solve a regex"); + } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java index 193e457b..9184191c 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/uuid/PlayerNameUUID.java @@ -23,4 +23,15 @@ public boolean matches(UUID uuid) { else return false; } + + @SuppressWarnings("deprecation") + @Override + public UUID solve(UUID startingValue) throws NotSolvableException { + OfflinePlayer player = Bukkit.getOfflinePlayer(name); + + if (player == null) + throw new NotSolvableException("can't find player with name " + name); + + return player.getUniqueId(); + } } From e5a548b2686d6c8e4d76da464e65e08ce613c68e Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 19 May 2019 10:44:36 -0700 Subject: [PATCH 098/108] Rename some config options Now the any all none stuff is basically the same for everything, although one to one isn't very widely supported. --- .../itemExpression/ItemExpression.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 1baba18c..d7524f49 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -120,16 +120,16 @@ public void parseConfig(ConfigurationSection config) { addMatcher(ItemNameMatcher.construct(parseName(config, "name"))); // enchantments (example: eff5 diamond pickaxe) - addMatcher(parseEnchantment(config, "enchantmentsAny", ANY, ITEM)); - addMatcher(parseEnchantment(config, "enchantmentsAll", ALL, ITEM)); - addMatcher(parseEnchantment(config, "enchantmentsNone", NONE, ITEM)); - addMatcher(parseEnchangmentCount(config, "enchantmentCount", ITEM)); + addMatcher(parseEnchantment(config, "enchantments.any", ANY, ITEM)); + addMatcher(parseEnchantment(config, "enchantments.all", ALL, ITEM)); + addMatcher(parseEnchantment(config, "enchantments.none", NONE, ITEM)); + addMatcher(parseEnchangmentCount(config, "enchantment.count", ITEM)); // held enchantments (example: enchanted book) - addMatcher(parseEnchantment(config, "enchantmentsHeldAny", ANY, HELD)); - addMatcher(parseEnchantment(config, "enchantmentsHeldAll", ALL, HELD)); - addMatcher(parseEnchantment(config, "enchantmentsHeldNone", NONE, HELD)); - addMatcher(parseEnchangmentCount(config, "enchantmentHeldCount", HELD)); + addMatcher(parseEnchantment(config, "enchantments.held.any", ANY, HELD)); + addMatcher(parseEnchantment(config, "enchantments.held.all", ALL, HELD)); + addMatcher(parseEnchantment(config, "enchantments.held.none", NONE, HELD)); + addMatcher(parseEnchangmentCount(config, "enchantment.held.count", HELD)); // skull addMatcher(ItemSkullMatcher.construct(parseSkull(config, "skull"))); @@ -154,8 +154,8 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseExactly(config, "exactly")); // knowlege book (creative item that holds recipe unlocks) - addMatcher(ItemKnowledgeBookMatcher.construct(parseName(config, "knowlegebook.recipesAny"), false)); - addMatcher(ItemKnowledgeBookMatcher.construct(parseName(config, "knowlegebook.recipesAll"), true)); + addMatcher(ItemKnowledgeBookMatcher.construct(parseName(config, "knowlegebook.recipes.any"), false)); + addMatcher(ItemKnowledgeBookMatcher.construct(parseName(config, "knowlegebook.recipes.all"), true)); // potion addMatcher(parsePotion(config, "potion")); @@ -431,9 +431,9 @@ private List parsePotion(ConfigurationSection config, String path) ConfigurationSection potion = config.getConfigurationSection(path); - matchers.add(parsePotionEffects(potion, "customEffectsAny", ANY).orElse(null)); - matchers.add(parsePotionEffects(potion, "customEffectsAll", ALL).orElse(null)); - matchers.add(parsePotionEffects(potion, "customEffectsNone", NONE).orElse(null)); + matchers.add(parsePotionEffects(potion, "customEffects.any", ANY).orElse(null)); + matchers.add(parsePotionEffects(potion, "customEffects.all", ALL).orElse(null)); + matchers.add(parsePotionEffects(potion, "customEffects.none", NONE).orElse(null)); if (potion.isConfigurationSection("base")) { ConfigurationSection base = potion.getConfigurationSection("base"); From 029433ab1796a25647a9ad10305d693c67a89dc9 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 19 May 2019 18:19:00 -0700 Subject: [PATCH 099/108] Document a few of the solve methods --- .../itemExpression/ItemExpression.java | 20 +++++++++++++++++++ .../itemHandling/itemExpression/Matcher.java | 3 +++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index d7524f49..b6ad284f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -196,6 +196,12 @@ public static Optional getItemExpression(ConfigurationSection co return Optional.of(new ItemExpression(configurationSection.getConfigurationSection(path))); } + /** + * Parses out a list of ItemExpressions from a config. + * @param config The config to parse + * @param path The path to the list of ItemExpressions + * @return A list of ItemExpressions parsed from the config. + */ public static List getItemExpressionList(ConfigurationSection config, String path) { if (!config.contains(path)) return Collections.emptyList(); @@ -837,6 +843,14 @@ public boolean matches(ItemStack item) { return matchers.stream().allMatch((matcher) -> matcher.matches(item)); } + /** + * Solves this ItemExpression for an ItemStack that matches, taking base attributes from the passed ItemStack. + * @param inheritFrom The itemstack whose attributes and nbt data will be inherited from if this ItemExpression + * doesn't mutate them while solving. + * @return An ItemStack that satisfies the conditions of this piticular ItemStack such that matches(item) == true. + * @throws NotSolvableException If this ItemExpression uses elements such as Regular Expression matching that can + * not be solved in reasonable time. + */ @Override public ItemStack solve(ItemStack inheritFrom) throws NotSolvableException { inheritFrom = inheritFrom.clone(); @@ -848,6 +862,12 @@ public ItemStack solve(ItemStack inheritFrom) throws NotSolvableException { return inheritFrom; } + /** + * Solves this ItemExpression for an ItemStack item where matches(item) == true. + * @return An ItemStack that satisfies the conditions of this piticular ItemStack such that matches(item) == true. + * @throws NotSolvableException If this ItemExpression uses elements such as Regular Expression matching that can + * not be solved in reasonable time. + */ public ItemStack solve() throws NotSolvableException { return solve(new ItemStack(Material.AIR, 1)); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java index 6ff34c15..0f8ea994 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/Matcher.java @@ -36,6 +36,9 @@ public interface Matcher { /** * Thrown if a certain matcher can not be solved. + * + * This might be thrown if the matcher is based on Regular Expressions, as most regular expressions can not be + * solved in reasonable time. */ class NotSolvableException extends Exception { public NotSolvableException(String message, Throwable cause) { From f82efa48e088b656d91a118bb23279278648ea93 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 19 May 2019 18:23:03 -0700 Subject: [PATCH 100/108] Replace the MaterialMatcher stuff with EnumMatcher --- .../itemExpression/ItemExpression.java | 14 +--------- .../material/ExactlyMaterial.java | 24 ----------------- .../material/MaterialMatcher.java | 10 ------- .../material/RegexMaterial.java | 26 ------------------- .../ItemMaterialMatcher.java | 10 ++++--- 5 files changed, 7 insertions(+), 77 deletions(-) delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java delete mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java rename src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/{material => misc}/ItemMaterialMatcher.java (61%) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index b6ad284f..5411fa4e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -29,10 +29,6 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.LoreMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.lore.RegexLore; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.map.*; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ExactlyMaterial; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.ItemMaterialMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.MaterialMatcher; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material.RegexMaterial; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.mobspawner.*; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.*; @@ -105,7 +101,7 @@ public ItemExpression(ItemStack item, boolean acceptSimilar) { */ public void parseConfig(ConfigurationSection config) { // material - addMatcher(ItemMaterialMatcher.construct(parseMaterial(config, "material"))); + addMatcher(ItemMaterialMatcher.construct(parseEnumMatcher(config, "material", Material.class))); // amount addMatcher(ItemAmountMatcher.construct(parseAmount(config, "amount"))); @@ -237,14 +233,6 @@ private static List getConfigList(ConfigurationSection con return list; } - private Optional parseMaterial(ConfigurationSection config, String path) { - if (config.contains(path + ".regex")) - return Optional.of(new RegexMaterial(Pattern.compile(config.getString(path + ".regex")))); - else if (config.contains(path)) - return Optional.of(new ExactlyMaterial(Material.getMaterial(config.getString(path)))); - return Optional.empty(); - } - private Optional parseAmount(ConfigurationSection config, String path) { if (config.contains(path + ".range")) return Optional.of((new RangeAmount( diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java deleted file mode 100644 index 549a8f33..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ExactlyMaterial.java +++ /dev/null @@ -1,24 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; - -import org.bukkit.Material; - -/** - * @author Ameliorate - */ -public class ExactlyMaterial implements MaterialMatcher { - public ExactlyMaterial(Material material) { - this.material = material; - } - - public Material material; - - @Override - public boolean matches(Material material) { - return this.material == material; - } - - @Override - public Material solve(Material defaultValue) throws NotSolvableException { - return material; - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java deleted file mode 100644 index 0a46efdf..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/MaterialMatcher.java +++ /dev/null @@ -1,10 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; - -import org.bukkit.Material; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; - -/** - * @author Ameliorate - */ -public interface MaterialMatcher extends Matcher { -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java deleted file mode 100644 index cb0e371e..00000000 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/RegexMaterial.java +++ /dev/null @@ -1,26 +0,0 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; - -import org.bukkit.Material; - -import java.util.regex.Pattern; - -/** - * @author Ameliorate - */ -public class RegexMaterial implements MaterialMatcher { - public RegexMaterial(Pattern regex) { - this.regex = regex; - } - - public Pattern regex; - - @Override - public boolean matches(Material material) { - return regex.matcher(material.toString()).matches(); - } - - @Override - public Material solve(Material defaultValue) throws NotSolvableException { - throw new NotSolvableException("can't solve a regex"); - } -} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMaterialMatcher.java similarity index 61% rename from src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java rename to src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMaterialMatcher.java index 4d578a63..5f4b1ad4 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/material/ItemMaterialMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ItemMaterialMatcher.java @@ -1,7 +1,9 @@ -package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.material; +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enummatcher.EnumMatcher; import java.util.Optional; @@ -9,15 +11,15 @@ * @author Ameliorate */ public class ItemMaterialMatcher implements ItemMatcher { - public ItemMaterialMatcher(MaterialMatcher matcher) { + public ItemMaterialMatcher(EnumMatcher matcher) { this.matcher = matcher; } - public static ItemMaterialMatcher construct(Optional matcher) { + public static ItemMaterialMatcher construct(Optional> matcher) { return matcher.map(ItemMaterialMatcher::new).orElse(null); } - public MaterialMatcher matcher; + public EnumMatcher matcher; @Override public boolean matches(ItemStack item) { From 7fc6963adcfd27bf083a609775d8959ea84eea3c Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 19 May 2019 18:55:14 -0700 Subject: [PATCH 101/108] Add a utility function to parse a map of ItemExpressions from a config --- .../itemHandling/itemExpression/ItemExpression.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 5411fa4e..555fff13 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -233,6 +233,19 @@ private static List getConfigList(ConfigurationSection con return list; } + public static Map getItemExpressionMap(ConfigurationSection config, String path) { + if (!config.isConfigurationSection(path)) + return Collections.emptyMap(); + + HashMap result = new HashMap<>(); + ConfigurationSection ieConfig = config.getConfigurationSection(path); + for (String section : ieConfig.getKeys(false)) { + result.put(section, getItemExpression(ieConfig, section).orElseThrow(AssertionError::new)); + } + + return result; + } + private Optional parseAmount(ConfigurationSection config, String path) { if (config.contains(path + ".range")) return Optional.of((new RangeAmount( From 21b1dde200d1511925a06af1f3e41e487dffe09e Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sun, 19 May 2019 19:45:15 -0700 Subject: [PATCH 102/108] Use crc32 instead of md5 in getFireworkEffectWithIndex Should be slightly more efficent now, although it barely matters. --- .../firework/ItemFireworkEffectsCountMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java index 9075327c..2a5d1c20 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/firework/ItemFireworkEffectsCountMatcher.java @@ -63,7 +63,7 @@ public ItemStack solve(ItemStack item) throws NotSolvableException { @SuppressWarnings("UnstableApiUsage") public static FireworkEffect getFireworkEffectWithIndex(int i) { - int b = Hashing.md5().hashInt(i).asInt(); // probably overkill, but oh well. I don't have internet right now + int b = Hashing.crc32().hashInt(i).asInt(); boolean trail = (b & TRAIL_MASK) == 1; boolean flicker = (b & FLICK_MASK) == 2; int typeIndex = b & TYPE_MASK >>> 2; From 234c211990eb6cf0da60373c0df53abfafdf0ce2 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Tue, 21 May 2019 18:30:34 -0700 Subject: [PATCH 103/108] Add some commands to debug ItemExpressions because testing spigot plugins is aparently a hard problem --- .../mc/civmodcore/CivModCorePlugin.java | 11 +++++ .../TestItemSolvingCommand.java | 44 +++++++++++++++++++ .../itemExpression/TestMatchingCommand.java | 43 ++++++++++++++++++ src/main/resources/plugin.yml | 16 +++++++ 4 files changed, 114 insertions(+) create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java create mode 100644 src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java diff --git a/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java b/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java index 220a9383..8490d511 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java @@ -1,5 +1,11 @@ package vg.civcraft.mc.civmodcore; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemExpression; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.TestItemSolvingCommand; +import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.TestMatchingCommand; + +import java.util.Map; + /** * The sole purpose of this class is to make Spigot recognize this library as a plugin and automatically load the * classes onto the classpath for us. @@ -15,6 +21,11 @@ public void onEnable() { super.onEnable(); // needed for some of the apis instance = this; + + Map itemExpressions = ItemExpression.getItemExpressionMap(getConfig(), "itemExpressions"); + + getCommand("testitemsolving").setExecutor(new TestItemSolvingCommand(itemExpressions)); + getCommand("testitemmatching").setExecutor(new TestMatchingCommand(itemExpressions)); } public static CivModCorePlugin getInstance() { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java new file mode 100644 index 00000000..076e83fb --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java @@ -0,0 +1,44 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class TestItemSolvingCommand implements CommandExecutor { + public TestItemSolvingCommand(Map itemExpressions) { + this.itemExpressions = itemExpressions; + } + + Map itemExpressions; + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String name, String[] args) { + if (args.length != 1) + return false; + + if (!(commandSender instanceof Player)) { + commandSender.sendMessage(ChatColor.RED + "This command can only be used by players."); + return true; + } + + Player player = (Player) commandSender; + + System.out.println(itemExpressions); + String ieName = args[0]; + ItemExpression expression = itemExpressions.get(ieName); + + try { + player.getLocation().getWorld().dropItem(player.getLocation(), expression.solve()); + } catch (Matcher.NotSolvableException e) { + e.printStackTrace(); + commandSender.sendMessage(ChatColor.RED + "Could not solve item expression: " + e.getLocalizedMessage() + + ". Please check the server log for more details."); + } + + return true; + } +} diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java new file mode 100644 index 00000000..5e62eeb0 --- /dev/null +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java @@ -0,0 +1,43 @@ +package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.Map; + +public class TestMatchingCommand implements CommandExecutor { + public TestMatchingCommand(Map itemExpressions) { + this.itemExpressions = itemExpressions; + } + + Map itemExpressions; + + @Override + public boolean onCommand(CommandSender commandSender, Command command, String name, String[] args) { + if (args.length != 1) + return false; + + if (!(commandSender instanceof Player)) { + commandSender.sendMessage(ChatColor.RED + "This command can only be used by players."); + return true; + } + + Player player = (Player) commandSender; + + String ieName = args[0]; + ItemExpression expression = itemExpressions.get(ieName); + ItemStack item = player.getInventory().getItemInMainHand(); + + if (expression.matches(item)) { + commandSender.sendMessage("Matches!"); + } else { + commandSender.sendMessage("Does not match."); + } + + return true; + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b9774e4d..d8149df5 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,3 +4,19 @@ authors: [valadian, rourke750, ProgrammerDan, Maxopoly, DeadBeef] main: ${groupId}.${name}Plugin api-version: 1.13 dev-url: null + +commands: + testitemsolving: + description: Test item solving using an ItemExpression in the CivModCore config. This will give you an item that matches the ItemExpression. + usage: /testitemsolving [name] + permission: civmodcore.test + testitemmatching: + description: Test item matching using an ItemExpression in the CivModCore config. This will tell you if the item in your hand matches an ItemExpression. + usage: /testitemmatches [name] + permission: civmodcore.test + +permissions: + civmodcore.test: + description: Allows testing internal APIs of CivModCore. Note that this permission unlocks commands that can be used to give/dupe items. + default: op + From 7c71ec6fc373ae47405dbcabe9c352629a67d32b Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 25 May 2019 10:27:18 -0700 Subject: [PATCH 104/108] Fix a bunch of bugs Most were regarding ItemExpression solving --- .../itemExpression/ItemExpression.java | 37 +++++++++++++------ ...ityMatcher.java => ItemDamageMatcher.java} | 13 +++---- .../enchantment/EnchantmentsSource.java | 2 +- .../ItemEnchantmentCountMatcher.java | 8 +++- .../enchantment/ItemEnchantmentsMatcher.java | 17 +++++---- .../enummatcher/NameEnumMatcher.java | 11 +++++- .../itemExpression/misc/ListMatchingMode.java | 13 ++++--- .../itemExpression/name/ExactlyName.java | 2 +- 8 files changed, 67 insertions(+), 36 deletions(-) rename src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/{ItemDurabilityMatcher.java => ItemDamageMatcher.java} (66%) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 555fff13..1feaddc6 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -1,13 +1,11 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression; -import org.bukkit.Color; -import org.bukkit.DyeColor; -import org.bukkit.FireworkEffect; -import org.bukkit.Material; +import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.entity.TropicalFish; import org.bukkit.inventory.*; @@ -106,8 +104,8 @@ public void parseConfig(ConfigurationSection config) { // amount addMatcher(ItemAmountMatcher.construct(parseAmount(config, "amount"))); - // durability - addMatcher(ItemDurabilityMatcher.construct(parseAmount(config, "durability"))); + // damage + addMatcher(ItemDamageMatcher.construct(parseAmount(config, "damage"))); // lore addMatcher(ItemLoreMatcher.construct(parseLore(config, "lore"))); @@ -119,13 +117,13 @@ public void parseConfig(ConfigurationSection config) { addMatcher(parseEnchantment(config, "enchantments.any", ANY, ITEM)); addMatcher(parseEnchantment(config, "enchantments.all", ALL, ITEM)); addMatcher(parseEnchantment(config, "enchantments.none", NONE, ITEM)); - addMatcher(parseEnchangmentCount(config, "enchantment.count", ITEM)); + addMatcher(parseEnchangmentCount(config, "enchantments.count", ITEM)); // held enchantments (example: enchanted book) addMatcher(parseEnchantment(config, "enchantments.held.any", ANY, HELD)); addMatcher(parseEnchantment(config, "enchantments.held.all", ALL, HELD)); addMatcher(parseEnchantment(config, "enchantments.held.none", NONE, HELD)); - addMatcher(parseEnchangmentCount(config, "enchantment.held.count", HELD)); + addMatcher(parseEnchangmentCount(config, "enchantments.held.count", HELD)); // skull addMatcher(ItemSkullMatcher.construct(parseSkull(config, "skull"))); @@ -302,7 +300,8 @@ private Optional parseEnchantment(ConfigurationSection if (enchantName.equals("any")) { matcher = new AnyEnchantment(amountMatcher); } else { - matcher = new AnyEnchantment(amountMatcher); + matcher = new ExactlyEnchantment(Enchantment.getByKey(NamespacedKey.minecraft(enchantName)), + amountMatcher); } enchantmentMatcher.add(matcher); @@ -566,6 +565,12 @@ private > Optional> parseEnumMatcher(Configurat return Optional.of(new EnumFromListMatcher<>(properties, notInList)); } if (config.isInt(path + ".index")) { return Optional.of(new EnumIndexMatcher<>(config.getInt(path + ".index"), enumClass)); + } if (config.isString(path)) { + E en = Arrays.stream(enumClass.getEnumConstants()) + .filter((e) -> e.name().equals(config.getString(path))) + .findFirst() + .orElseThrow(() -> new Error("could not find enum constant " + config.getString(path))); + return Optional.of(new ExactlyEnumMatcher<>(en)); } else { return parseName(config, path, false) .map(nameMatcher -> new NameEnumMatcher(nameMatcher, enumClass)); @@ -841,6 +846,10 @@ private List parseFirework(ConfigurationSection config, String path * @return If the given item matches. */ public boolean matches(ItemStack item) { + //System.out.println("These match:"); + //matchers.stream().filter((matcher) -> matcher.matches(item)).forEach(System.out::println); + //System.out.println("These do not match:"); + //matchers.stream().filter((matcher) -> !matcher.matches(item)).forEach(System.out::println); return matchers.stream().allMatch((matcher) -> matcher.matches(item)); } @@ -857,6 +866,12 @@ public ItemStack solve(ItemStack inheritFrom) throws NotSolvableException { inheritFrom = inheritFrom.clone(); for (ItemMatcher matcher : matchers) { + if (!inheritFrom.hasItemMeta()) { + inheritFrom.setItemMeta(Bukkit.getItemFactory().getItemMeta(inheritFrom.getType())); + // so many matchers require meta that setting it here fixes a lot of bugs + // although it also creates a lot of dead code + } + inheritFrom = matcher.solve(inheritFrom); } @@ -870,7 +885,7 @@ public ItemStack solve(ItemStack inheritFrom) throws NotSolvableException { * not be solved in reasonable time. */ public ItemStack solve() throws NotSolvableException { - return solve(new ItemStack(Material.AIR, 1)); + return solve(new ItemStack(Material.STONE, 1)); } /** @@ -1129,5 +1144,5 @@ public void addMatcher(Optional matcher) { * * This is the only data structure holding ItemMatchers in this ItemExpression, so it is fine to mutate this field. */ - public HashSet matchers = new HashSet<>(); + public ArrayList matchers = new ArrayList<>(); } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDamageMatcher.java similarity index 66% rename from src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java rename to src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDamageMatcher.java index 733de8c2..b33f7361 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDurabilityMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/amount/ItemDamageMatcher.java @@ -1,6 +1,5 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.amount; -import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; @@ -11,13 +10,13 @@ /** * @author Ameliorate */ -public class ItemDurabilityMatcher implements ItemMatcher { - public ItemDurabilityMatcher(AmountMatcher matcher) { +public class ItemDamageMatcher implements ItemMatcher { + public ItemDamageMatcher(AmountMatcher matcher) { this.matcher = matcher; } - public static ItemDurabilityMatcher construct(Optional matcher) { - return matcher.map(ItemDurabilityMatcher::new).orElse(null); + public static ItemDamageMatcher construct(Optional matcher) { + return matcher.map(ItemDamageMatcher::new).orElse(null); } public AmountMatcher matcher; @@ -32,9 +31,9 @@ public boolean matches(ItemStack item) { @Override public ItemStack solve(ItemStack item) throws NotSolvableException { - ItemMeta meta = item.hasItemMeta() ? item.getItemMeta() : Bukkit.getItemFactory().getItemMeta(item.getType()); + ItemMeta meta = item.getItemMeta(); - if (!(item instanceof Damageable)) + if (!(meta instanceof Damageable)) throw new NotSolvableException("item does not have durability"); ((Damageable) meta).setDamage(matcher.solve(1)); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java index eee5eb1c..a2b10e18 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/EnchantmentsSource.java @@ -55,7 +55,7 @@ public void set(ItemStack item, Map enchantments, boolean } if (this == HELD) { - if (!(item.hasItemMeta()) || !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + if (!(item.getItemMeta() instanceof EnchantmentStorageMeta)) throw new IllegalArgumentException("item does not store enchantments"); EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java index 6339d314..ed466c4e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentCountMatcher.java @@ -13,6 +13,8 @@ import java.util.List; import java.util.stream.Collectors; +import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.HELD; + /** * @author Ameliorate */ @@ -33,7 +35,7 @@ public ItemEnchantmentCountMatcher(AmountMatcher enchantmentCount) { public boolean matches(ItemStack item) { if (!item.hasItemMeta()) return false; - if (source == EnchantmentsSource.HELD && !(item.getItemMeta() instanceof EnchantmentStorageMeta)) + if (source == HELD && !(item.getItemMeta() instanceof EnchantmentStorageMeta)) return false; int count = 0; @@ -74,7 +76,9 @@ public ItemStack solve(ItemStack item) throws NotSolvableException { boolean unsafe = false; while (!enchantmentCount.matches(source.get(item).size())) { - source.add(item, allEnchantments.get(i++), 1, unsafe); + if (unsafe || source == HELD || allEnchantments.get(i).canEnchantItem(item)) + source.add(item, allEnchantments.get(i), 1, unsafe); + i++; if (i >= allEnchantments.size() && unsafe) throw new NotSolvableException("not enough enchantments exist to solve for enchantment count on item"); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java index 312978c4..6fbcdf6f 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enchantment/ItemEnchantmentsMatcher.java @@ -1,17 +1,18 @@ package vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment; +import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemMatcher; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.misc.ListMatchingMode; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.HELD; -import static vg.civcraft.mc.civmodcore.itemHandling.itemExpression.enchantment.EnchantmentsSource.ITEM; /** * @author Ameliorate @@ -45,16 +46,18 @@ public boolean matches(ItemStack item) { @Override public ItemStack solve(ItemStack item) throws NotSolvableException { - if (!item.hasItemMeta()) - item.setType(source.getReasonableType()); if (source == HELD && !(item.getItemMeta() instanceof EnchantmentStorageMeta)) - item.setType(source.getReasonableType()); - if (source == ITEM && !(item.getItemMeta().hasEnchants())) - item.setType(source.getReasonableType()); + item.setType(Material.ENCHANTED_BOOK); + + Map defaultEnchantments = item.getEnchantments(); + if (defaultEnchantments.isEmpty()) { + defaultEnchantments = new HashMap<>(defaultEnchantments); // spigot returns a immutable hashmap + defaultEnchantments.put(Enchantment.DAMAGE_ALL, 1); + } List> enchantments = mode.solve(enchantmentMatchers, - new ListMatchingMode.LazyFromListEntrySupplier<>(item.getEnchantments())); + new ListMatchingMode.LazyFromListEntrySupplier<>(defaultEnchantments)); Map enchantmentMap = enchantments.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java index ab14802e..4f828544 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/enummatcher/NameEnumMatcher.java @@ -2,6 +2,8 @@ import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.name.NameMatcher; +import java.util.Arrays; + /** * @author Ameliorate */ @@ -20,11 +22,16 @@ public NameEnumMatcher(NameMatcher nameMatcher, Class enumClass) { @Override public boolean matches(E enumm) { - return nameMatcher.matches(enumm.toString()); + return nameMatcher.matches(enumm.name()); } @Override public E solve(E defaultValue) throws NotSolvableException { - return null; + String name = nameMatcher.solve(defaultValue.name()); + return Arrays.stream(enumClass.getEnumConstants()) + .filter((e) -> name.equals(e.name())) + .findFirst() + .orElseThrow(() -> new NotSolvableException( + "name of enum " + name + " does not match any variants of enum "+ enumClass.getName())); } } diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java index a6f608f5..f676e35e 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/misc/ListMatchingMode.java @@ -3,10 +3,7 @@ import com.google.common.collect.Lists; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.Matcher; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; @@ -170,15 +167,21 @@ public LazyFromListEntrySupplier(Supplier>> entriesSu public LazyFromListEntrySupplier(Collection> collection) { this(() -> new ArrayList<>(collection)); + if (collection.isEmpty()) + throw new AssertionError("collection can not be empty"); } public LazyFromListEntrySupplier(Map map) { - this(map.entrySet()); + this(new HashMap<>(map).entrySet()); + if (map.isEmpty()) + throw new AssertionError("map can not be empty"); } private void regen() { if (entries == null || entries.isEmpty()) entries = entriesSupplier.get(); + if (entries.isEmpty()) + throw new AssertionError("entries can not be empty"); } public Collection> entries; diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java index a60cc6c6..843ffeb7 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/name/ExactlyName.java @@ -9,7 +9,7 @@ public ExactlyName(String name) { } public ExactlyName(String name, boolean caseSensitive) { - this.name = name.toLowerCase(); + this.name = name; this.caseSensitive = caseSensitive; } From 79a48246ffef1b2a2b9b7f987e8c0cc843968fc8 Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 25 May 2019 10:31:42 -0700 Subject: [PATCH 105/108] Improve the TestItemSolving and TestItemMatching commands Now they reload from the config each time they're used. --- .../vg/civcraft/mc/civmodcore/CivModCorePlugin.java | 9 ++------- .../itemExpression/TestItemSolvingCommand.java | 13 +++++-------- .../itemExpression/TestMatchingCommand.java | 10 ++++------ 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java b/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java index 8490d511..1dd06c13 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/CivModCorePlugin.java @@ -1,11 +1,8 @@ package vg.civcraft.mc.civmodcore; -import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.ItemExpression; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.TestItemSolvingCommand; import vg.civcraft.mc.civmodcore.itemHandling.itemExpression.TestMatchingCommand; -import java.util.Map; - /** * The sole purpose of this class is to make Spigot recognize this library as a plugin and automatically load the * classes onto the classpath for us. @@ -22,10 +19,8 @@ public void onEnable() { // needed for some of the apis instance = this; - Map itemExpressions = ItemExpression.getItemExpressionMap(getConfig(), "itemExpressions"); - - getCommand("testitemsolving").setExecutor(new TestItemSolvingCommand(itemExpressions)); - getCommand("testitemmatching").setExecutor(new TestMatchingCommand(itemExpressions)); + getCommand("testitemsolving").setExecutor(new TestItemSolvingCommand()); + getCommand("testitemmatching").setExecutor(new TestMatchingCommand()); } public static CivModCorePlugin getInstance() { diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java index 076e83fb..36569238 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java @@ -5,16 +5,11 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import vg.civcraft.mc.civmodcore.CivModCorePlugin; import java.util.Map; public class TestItemSolvingCommand implements CommandExecutor { - public TestItemSolvingCommand(Map itemExpressions) { - this.itemExpressions = itemExpressions; - } - - Map itemExpressions; - @Override public boolean onCommand(CommandSender commandSender, Command command, String name, String[] args) { if (args.length != 1) @@ -25,14 +20,16 @@ public boolean onCommand(CommandSender commandSender, Command command, String na return true; } + Map itemExpressions = ItemExpression.getItemExpressionMap( + CivModCorePlugin.getInstance().getConfig(), "itemExpressions"); + Player player = (Player) commandSender; - System.out.println(itemExpressions); String ieName = args[0]; ItemExpression expression = itemExpressions.get(ieName); try { - player.getLocation().getWorld().dropItem(player.getLocation(), expression.solve()); + player.getInventory().addItem(expression.solve()); } catch (Matcher.NotSolvableException e) { e.printStackTrace(); commandSender.sendMessage(ChatColor.RED + "Could not solve item expression: " + e.getLocalizedMessage() + diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java index 5e62eeb0..444be2f3 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java @@ -6,16 +6,11 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import vg.civcraft.mc.civmodcore.CivModCorePlugin; import java.util.Map; public class TestMatchingCommand implements CommandExecutor { - public TestMatchingCommand(Map itemExpressions) { - this.itemExpressions = itemExpressions; - } - - Map itemExpressions; - @Override public boolean onCommand(CommandSender commandSender, Command command, String name, String[] args) { if (args.length != 1) @@ -26,6 +21,9 @@ public boolean onCommand(CommandSender commandSender, Command command, String na return true; } + Map itemExpressions = ItemExpression.getItemExpressionMap( + CivModCorePlugin.getInstance().getConfig(), "itemExpressions"); + Player player = (Player) commandSender; String ieName = args[0]; From 89ad1cae7a005ed72c7c55c8a2232ebbf1b7c6cf Mon Sep 17 00:00:00 2001 From: Ameliorate Date: Sat, 25 May 2019 10:33:34 -0700 Subject: [PATCH 106/108] Actually reload the config --- pom.xml | 18 ------------------ .../itemExpression/TestItemSolvingCommand.java | 1 + .../itemExpression/TestMatchingCommand.java | 1 + 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index e7647401..b53c2d66 100644 --- a/pom.xml +++ b/pom.xml @@ -72,24 +72,6 @@ - - org.apache.maven.plugins - maven-checkstyle-plugin - 2.17 - - https://build.devotedmc.com/job/Style-guide-master/lastSuccessfulBuild/artifact/src/main/resources/devoted_checks.xml - true - - - - checkstyle - - checkstyle - - prepare-package - - - diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java index 36569238..4e81cae9 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestItemSolvingCommand.java @@ -20,6 +20,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String na return true; } + CivModCorePlugin.getInstance().reloadConfig(); Map itemExpressions = ItemExpression.getItemExpressionMap( CivModCorePlugin.getInstance().getConfig(), "itemExpressions"); diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java index 444be2f3..121f51ea 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/TestMatchingCommand.java @@ -21,6 +21,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String na return true; } + CivModCorePlugin.getInstance().reloadConfig(); Map itemExpressions = ItemExpression.getItemExpressionMap( CivModCorePlugin.getInstance().getConfig(), "itemExpressions"); From 3625d55df89ad8c2479d8771c064cb7ca7e6d53a Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sun, 11 Aug 2019 15:40:19 -0700 Subject: [PATCH 107/108] Remove shulkerbox.inventory. I didn't want to document the fact that shulkerbox.inventory also works for a +NBT inventory chest. --- .../civmodcore/itemHandling/itemExpression/ItemExpression.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index 1feaddc6..df819926 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -136,7 +136,6 @@ public void parseConfig(ConfigurationSection config) { // held inventory (example: shulker box) addMatcher(parseInventory(config, "inventory")); - addMatcher(parseInventory(config, "shulkerbox.inventory")); // shulker box color addMatcher(ItemShulkerBoxColorMatcher.construct(parseEnumMatcher(config, "shulkerbox.color", DyeColor.class))); From 77f4b65f262f21b7e472a1a5bb2edab11e02a562 Mon Sep 17 00:00:00 2001 From: Amelorate Date: Sun, 11 Aug 2019 17:58:51 -0700 Subject: [PATCH 108/108] Add a base check to solve that checks if the generated item matches Some bugs might generate items that don't match, but it is also possible to create ItemExpressions that when solved don't produce an item that matches. --- .../itemHandling/itemExpression/ItemExpression.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java index df819926..72a97335 100644 --- a/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java +++ b/src/main/java/vg/civcraft/mc/civmodcore/itemHandling/itemExpression/ItemExpression.java @@ -874,6 +874,10 @@ public ItemStack solve(ItemStack inheritFrom) throws NotSolvableException { inheritFrom = matcher.solve(inheritFrom); } + if (!matches(inheritFrom)) { + throw new NotSolvableException("not solvable: generated item " + inheritFrom + " does not match"); + } + return inheritFrom; }