Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement item matchers #1055

Merged
merged 1 commit into from
Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public ModuleLoadException(Class<? extends Module> key, String message, Throwabl
return key;
}

public String getFullMessage() {
return getMessage() + (key != null ? " @ " + key.getSimpleName() : "");
}

public ModuleLoadException(Class<? extends Module> key, String message) {
this(key, message, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.kits.ApplyKitEvent;
import tc.oc.pgm.util.event.PlayerItemTransferEvent;
import tc.oc.pgm.util.inventory.ItemMatcher;

public class CarryingItemFilter extends ParticipantItemFilter {
public CarryingItemFilter(ItemStack base) {
super(base);
public CarryingItemFilter(ItemMatcher matcher) {
super(matcher);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.kits.ApplyKitEvent;
import tc.oc.pgm.util.event.PlayerItemTransferEvent;
import tc.oc.pgm.util.inventory.ItemMatcher;

public class HoldingItemFilter extends ParticipantItemFilter {
public HoldingItemFilter(ItemStack base) {
super(base);
public HoldingItemFilter(ItemMatcher matcher) {
super(matcher);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import org.bukkit.inventory.ItemStack;
import tc.oc.pgm.api.filter.query.PlayerQuery;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.util.inventory.ItemMatcher;

public abstract class ParticipantItemFilter extends ParticipantFilter {
protected final ItemStack base;
protected final ItemMatcher matcher;

public ParticipantItemFilter(ItemStack base) {
this.base = Preconditions.checkNotNull(base, "item").clone();
this.base.setDurability((short) 0); // Filter ignores durability
public ParticipantItemFilter(ItemMatcher matcher) {
this.matcher = Preconditions.checkNotNull(matcher, "item");
}

protected abstract ItemStack[] getItems(MatchPlayer player);
Expand All @@ -19,16 +19,8 @@ public ParticipantItemFilter(ItemStack base) {
public boolean matches(PlayerQuery query, MatchPlayer player) {
for (ItemStack item : getItems(player)) {
if (item == null) continue;

item = item.clone();
item.setDurability((short) 0);
if (this.base.isSimilar(item) && item.getAmount() >= base.getAmount()) {
// Match if items stack (ignoring durability) and player's stack is
// at least as big as the filter's.
return true;
}
if (matcher.matches(item)) return true;
}

return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import org.bukkit.inventory.ItemStack;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.kits.ApplyKitEvent;
import tc.oc.pgm.util.inventory.ItemMatcher;

public class WearingItemFilter extends ParticipantItemFilter {
public WearingItemFilter(ItemStack base) {
super(base);
public WearingItemFilter(ItemMatcher matcher) {
super(matcher);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,17 +458,17 @@ public RelationFilter parseRelation(Element el) throws InvalidXMLException {

@MethodParser("carrying")
public CarryingItemFilter parseHasItem(Element el) throws InvalidXMLException {
return new CarryingItemFilter(factory.getKits().parseRequiredItem(el));
return new CarryingItemFilter(factory.getKits().parseItemMatcher(el));
}

@MethodParser("holding")
public HoldingItemFilter parseHolding(Element el) throws InvalidXMLException {
return new HoldingItemFilter(factory.getKits().parseRequiredItem(el));
return new HoldingItemFilter(factory.getKits().parseItemMatcher(el));
}

@MethodParser("wearing")
public WearingItemFilter parseWearingItem(Element el) throws InvalidXMLException {
return new WearingItemFilter(factory.getKits().parseRequiredItem(el));
return new WearingItemFilter(factory.getKits().parseItemMatcher(el));
}

@MethodParser("effect")
Expand Down
28 changes: 24 additions & 4 deletions core/src/main/java/tc/oc/pgm/kits/KitParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import tc.oc.pgm.teams.Teams;
import tc.oc.pgm.util.attribute.AttributeModifier;
import tc.oc.pgm.util.bukkit.BukkitUtils;
import tc.oc.pgm.util.inventory.ItemMatcher;
import tc.oc.pgm.util.material.Materials;
import tc.oc.pgm.util.nms.NMSHacks;
import tc.oc.pgm.util.xml.InvalidXMLException;
Expand Down Expand Up @@ -396,12 +397,31 @@ public ItemStack parseHead(Element el) throws InvalidXMLException {
return itemStack;
}

public ItemStack parseRequiredItem(Element parent) throws InvalidXMLException {
public ItemMatcher parseItemMatcher(Element parent) throws InvalidXMLException {
ItemStack stack = parseItem(parent.getChild("item"), false);
if (stack == null) {
throw new InvalidXMLException("Item expected", parent);
if (stack == null) throw new InvalidXMLException("Item expected", parent);

Range<Integer> amount =
XMLUtils.parseNumericRange(Node.fromAttr(parent, "amount"), Integer.class, null);
if (amount == null) amount = Range.atLeast(stack.getAmount());
else if (stack.getAmount() != 1)
throw new InvalidXMLException("Cannot combine amount range with an item amount", parent);

boolean ignoreDurability =
XMLUtils.parseBoolean(Node.fromAttr(parent, "ignore-durability"), true);
boolean ignoreMetadata = XMLUtils.parseBoolean(Node.fromAttr(parent, "ignore-metadata"), false);
boolean ignoreName =
XMLUtils.parseBoolean(Node.fromAttr(parent, "ignore-name"), ignoreMetadata);
boolean ignoreEnchantments =
XMLUtils.parseBoolean(Node.fromAttr(parent, "ignore-enchantments"), ignoreMetadata);

if (ignoreMetadata && (!ignoreName || !ignoreEnchantments)) {
throw new InvalidXMLException(
"Cannot ignore metadata but respect name or enchantments", parent);
}
return stack;

return new ItemMatcher(
stack, amount, ignoreDurability, ignoreMetadata, ignoreName, ignoreEnchantments);
}

public ItemStack parseItem(Element el, boolean allowAir) throws InvalidXMLException {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/tc/oc/pgm/map/MapFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,10 @@ public MapContext load() throws MapException {
throw e;
} catch (IOException e) {
throw new MapException(source, info, "Unable to read map document", e);
} catch (ModuleLoadException | InvalidXMLException e) {
} catch (InvalidXMLException e) {
throw new MapException(source, info, e.getMessage(), e);
} catch (ModuleLoadException e) {
throw new MapException(source, info, e.getFullMessage(), e);
} catch (JDOMParseException e) {
final InvalidXMLException cause = InvalidXMLException.fromJDOM(e, source.getId());
throw new MapException(source, info, cause.getMessage(), cause);
Expand Down
54 changes: 54 additions & 0 deletions util/src/main/java/tc/oc/pgm/util/inventory/ItemMatcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package tc.oc.pgm.util.inventory;

import com.google.common.collect.Range;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;

public class ItemMatcher {

private final ItemStack base;
private final Range<Integer> amount;

private final boolean ignoreDurability;
private final boolean ignoreMetadata;
private final boolean ignoreName;
private final boolean ignoreEnchantments;

public ItemMatcher(
ItemStack base,
Range<Integer> amount,
boolean ignoreDurability,
boolean ignoreMetadata,
boolean ignoreName,
boolean ignoreEnchantments) {
if (ignoreMetadata && (!ignoreName || !ignoreEnchantments))
throw new UnsupportedOperationException(
"Cannot ignore metadata but respect name or enchantments");

this.ignoreDurability = ignoreDurability;

this.ignoreMetadata = ignoreMetadata;
this.ignoreName = ignoreName;
this.ignoreEnchantments = ignoreEnchantments;

this.amount = amount;
this.base = stripMeta(base);
}

private ItemStack stripMeta(ItemStack item) {
ItemMeta meta = item.getItemMeta();
if (meta == null || (!ignoreMetadata && !(ignoreEnchantments && meta.hasEnchants())))
return item;

item = item.clone();
if (ignoreMetadata) item.setItemMeta(null);
else item.getEnchantments().keySet().forEach(item::removeEnchantment);

return item;
}

public boolean matches(ItemStack query) {
return base.isSimilar(stripMeta(query), ignoreDurability, ignoreName)
&& amount.contains(query.getAmount());
}
}
9 changes: 8 additions & 1 deletion util/src/main/java/tc/oc/pgm/util/xml/XMLUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.bukkit.util.Vector;
import org.jdom2.Attribute;
import org.jdom2.Element;
import org.jetbrains.annotations.NotNull;
import tc.oc.pgm.util.TimeUtils;
import tc.oc.pgm.util.Version;
import tc.oc.pgm.util.attribute.AttributeModifier;
Expand Down Expand Up @@ -384,6 +385,12 @@ public static <T extends Number & Comparable<T>> T parseNumberInRange(
private static final Pattern RANGE_RE =
Pattern.compile("\\s*(\\(|\\[)\\s*([^,]+)\\s*,\\s*([^\\)\\]]+)\\s*(\\)|\\])\\s*");

public static <T extends Number & Comparable<T>> Range<T> parseNumericRange(
@Nullable Node node, Class<T> type, @Nullable Range<T> fallback) throws InvalidXMLException {
if (node == null) return fallback;
return parseNumericRange(node, type);
}

/**
* Parse a range in the standard mathematical format e.g.
*
Expand All @@ -394,7 +401,7 @@ public static <T extends Number & Comparable<T>> T parseNumberInRange(
* <p>Also supports singleton ranges derived from providing a number with no delimiter
*/
public static <T extends Number & Comparable<T>> Range<T> parseNumericRange(
Node node, Class<T> type) throws InvalidXMLException {
@NotNull Node node, Class<T> type) throws InvalidXMLException {
Matcher matcher = RANGE_RE.matcher(node.getValue());
if (!matcher.matches()) {
T value = parseNumber(node, node.getValue(), type, true);
Expand Down