Skip to content

Commit

Permalink
Make item matching ignore modifier uuids (#1426)
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Herrera <[email protected]>
  • Loading branch information
Pablete1234 authored Nov 6, 2024
1 parent 9cabbe2 commit 144ca2d
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 16 deletions.
18 changes: 6 additions & 12 deletions core/src/main/java/tc/oc/pgm/shops/ShopModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import tc.oc.pgm.shops.menu.Icon;
import tc.oc.pgm.shops.menu.Payment;
import tc.oc.pgm.util.xml.InvalidXMLException;
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.util.xml.XMLFluentParser;
import tc.oc.pgm.util.xml.XMLUtils;

Expand Down Expand Up @@ -184,20 +183,15 @@ public static List<Payment> parsePayments(Element parent, XMLFluentParser parser
return payments;
}

public static Payment parsePayment(Element element, XMLFluentParser parser)
public static Payment parsePayment(Element el, XMLFluentParser parser)
throws InvalidXMLException {
Node priceAttr = Node.fromAttr(element, "price");
Node currencyAttr = Node.fromAttr(element, "currency");
Node colorAttr = Node.fromAttr(element, "color");
Integer price = parser.parseInt(el, "price").optional(0);
Material currency = price <= 0 ? null : parser.material(el, "currency").orNull();
ChatColor color = parser.parseEnum(ChatColor.class, el, "color").optional(ChatColor.GOLD);

Integer price = XMLUtils.parseNumber(priceAttr, Integer.class, 0);
Material currency =
price <= 0 || currencyAttr == null ? null : XMLUtils.parseMaterial(currencyAttr);
ChatColor color = XMLUtils.parseChatColor(colorAttr, ChatColor.GOLD);

ItemStack item = parser.item(element, "item").child().orNull();
ItemStack item = parser.item(el, "item").child().orNull();
if (currency == null && item == null && price > 0) {
throw new InvalidXMLException("A 'currency' attribute or child <item> is required", element);
throw new InvalidXMLException("A 'currency' attribute or child <item> is required", el);
}

return new Payment(currency, price, color, item);
Expand Down
10 changes: 8 additions & 2 deletions core/src/main/java/tc/oc/pgm/shops/menu/Payment.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,14 @@ public ChatColor getColor() {
}

public boolean hasPayment(PlayerInventory inventory) {
return price <= 0
|| (item != null ? inventory.contains(item, price) : inventory.contains(currency, price));
if (price <= 0) return true;

int remaining = price;
for (ItemStack item : inventory.getContents()) {
if (item == null || !matches(item)) continue;
if ((remaining -= item.getAmount()) <= 0) return true;
}
return false;
}

public boolean matches(ItemStack item) {
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/tc/oc/pgm/util/xml/XMLFluentParser.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tc.oc.pgm.util.xml;

import java.time.Duration;
import org.bukkit.Material;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import org.jdom2.Element;
Expand Down Expand Up @@ -93,6 +94,15 @@ public <T extends Number> NumberBuilder<T> number(Class<T> cls, Element el, Stri
return new NumberBuilder<>(cls, el, prop);
}

public Builder.Generic<Material> material(Element el, String... prop) {
return new Builder.Generic<>(el, prop) {
@Override
protected Material parse(Node node) throws InvalidXMLException {
return XMLUtils.parseMaterial(node);
}
};
}

public Builder.Generic<Vector> vector(Element el, String... prop) {
return new Builder.Generic<>(el, prop) {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,29 @@ public void applyAttributeModifiers(
}
}

@Override
public boolean attributesEqual(ItemMeta meta1, ItemMeta meta2) {
var attributes1 = meta1.getAttributeModifiers();
var attributes2 = meta2.getAttributeModifiers();
if (attributes1 == null || attributes2 == null) return false;

if (!attributes1.keySet().equals(attributes2.keySet())) return false;

for (Attribute attr : attributes1.keySet()) {
if (modifiersDiffer(attributes1.get(attr), attributes2.get(attr))) return false;
}
return true;
}

@Override
public void stripAttributes(ItemMeta meta) {
var attributes = meta.getAttributeModifiers();

if (attributes != null && !attributes.isEmpty()) {
attributes.keySet().forEach(meta::removeAttributeModifier);
}
}

@Override
public EquipmentSlot getUsedHand(PlayerEvent event) {
return switch (event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ public void applyAttributeModifiers(
}
}

@Override
public boolean attributesEqual(ItemMeta meta1, ItemMeta meta2) {
var attributes = meta1.getModifiedAttributes();
if (!attributes.equals(meta2.getModifiedAttributes())) return false;

for (String attr : attributes) {
if (modifiersDiffer(meta1.getAttributeModifiers(attr), meta2.getAttributeModifiers(attr)))
return false;
}
return true;
}

@Override
public void stripAttributes(ItemMeta meta) {
for (String attr : meta.getModifiedAttributes()) {
meta.getAttributeModifiers(attr).clear();
}
}

@Override
public EquipmentSlot getUsedHand(PlayerEvent event) {
return EquipmentSlot.HAND;
Expand Down
35 changes: 35 additions & 0 deletions util/src/main/java/tc/oc/pgm/util/inventory/InventoryUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import tc.oc.pgm.util.bukkit.BukkitUtils;
import tc.oc.pgm.util.platform.Platform;
Expand Down Expand Up @@ -188,6 +189,40 @@ default void setUnbreakable(ItemStack item, boolean unbreakable) {
void applyAttributeModifiers(
SetMultimap<Attribute, AttributeModifier> modifiers, ItemMeta meta);

boolean attributesEqual(ItemMeta meta1, ItemMeta meta2);

default boolean modifiersDiffer(
Collection<AttributeModifier> a, Collection<AttributeModifier> b) {
if (a.size() != b.size()) return true;
if (a.isEmpty()) return false;
// Fast case for single modifier
if (a.size() == 1) {
var modA = a.iterator().next();
var modB = b.iterator().next();
return modA.getOperation() != modB.getOperation() || modA.getAmount() != modB.getAmount();
}

record SimpleModifier(double amount, AttributeModifier.Operation operation)
implements Comparable<SimpleModifier> {
public SimpleModifier(AttributeModifier modifier) {
this(modifier.getAmount(), modifier.getOperation());
}

@Override
public int compareTo(@NotNull SimpleModifier o) {
int res = operation.ordinal() - o.operation.ordinal();
if (res != 0) return res;
return Double.compare(amount, o.amount);
}
}

var listA = a.stream().map(SimpleModifier::new).sorted().toList();
var listB = b.stream().map(SimpleModifier::new).sorted().toList();
return !listA.equals(listB);
}

void stripAttributes(ItemMeta meta);

EquipmentSlot getUsedHand(PlayerEvent event);

void setCanDestroy(ItemMeta itemMeta, Set<Material> materials);
Expand Down
18 changes: 16 additions & 2 deletions util/src/main/java/tc/oc/pgm/util/material/Materials.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tc.oc.pgm.util.material;

import static org.bukkit.Material.*;
import static tc.oc.pgm.util.inventory.InventoryUtils.INVENTORY_UTILS;

import org.bukkit.Bukkit;
import org.bukkit.Location;
Expand Down Expand Up @@ -108,8 +109,21 @@ static boolean itemsSimilar(ItemStack first, ItemStack second, boolean skipDur)
final boolean hasMeta2 = second.hasItemMeta();
if (!hasMeta1 && !hasMeta2) return true;

final ItemMeta meta1 = hasMeta1 ? first.getItemMeta() : null;
final ItemMeta meta2 = hasMeta2 ? second.getItemMeta() : null;
ItemMeta meta1 = hasMeta1 ? first.getItemMeta() : null;
ItemMeta meta2 = hasMeta2 ? second.getItemMeta() : null;

if (hasMeta1 && hasMeta2 && meta1.hasAttributeModifiers() && meta2.hasAttributeModifiers()) {
if (INVENTORY_UTILS.attributesEqual(meta1, meta2)) {
// If attributes match, strip them not to affect the comparison.
// This is done because attributes have a random UUID in t hem that make them never equal
meta1 = meta1.clone();
meta2 = meta2.clone();
INVENTORY_UTILS.stripAttributes(meta1);
INVENTORY_UTILS.stripAttributes(meta2);
} else {
return false;
}
}

return Bukkit.getItemFactory().equals(meta1, meta2);
}
Expand Down

0 comments on commit 144ca2d

Please sign in to comment.