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

Add basic item matching support #1685

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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 @@ -22,7 +22,9 @@
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.nbt.BinaryTag;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.util.nbt.NbtUtils;
import com.sk89q.worldedit.util.nbt.TagStringIO;
import com.sk89q.worldedit.world.NbtValued;
import com.sk89q.worldedit.world.item.ItemType;
Expand Down Expand Up @@ -106,6 +108,26 @@ public void setNbtReference(@Nullable LazyReference<CompoundBinaryTag> nbtData)
this.nbtData = nbtData;
}

/**
* Gets whether the current item matches the given mask.
*
* <p>
* See {@link NbtUtils#matches(BinaryTag, BinaryTag)} for specifics of NBT behavior.
* </p>
*
* @param mask The mask to test against
* @return if it matches the mask
*/
public boolean matches(BaseItem mask) {
checkNotNull(mask);

if (!mask.getType().equals(getType())) {
return false;
}

return NbtUtils.matches(mask.getNbt(), getNbt());
}

@Override
public String toString() {
String nbtString = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,96 @@ public static <T extends BinaryTag> T getChildTag(CompoundBinaryTag tag, String
return childTagCast;
}

/**
* Tests a {@link BinaryTag} against a "mask" {@link BinaryTag}.
*
* <p>
* This method true if "test" contains all values from "mask". It does not
* matter if it contains more, as long as the mask values are present.
*
* For list tags, compound lists are treated as unordered sets, whereas
* non-compound lists are treated as ordered. This matches the way Minecraft
* treats NBT in items.
* </p>
*
* @param mask The mask tag
* @param test The tested tag
* @return If the test tag contains the values from the mask
*/
public static boolean matches(BinaryTag mask, BinaryTag test) {
if (mask == null) {
// If our mask is null, all match
return true;
}
if (test == null) {
// If our mask is not null but our test is, never match
return false;
}

if (mask.type() != test.type()) {
// If the types differ, they do not match
return false;
}

if (mask.type() == BinaryTagTypes.COMPOUND) {
// For compounds, we ensure that all the keys are available and values match
CompoundBinaryTag maskCompound = (CompoundBinaryTag) mask;
CompoundBinaryTag testCompound = (CompoundBinaryTag) test;

for (String binaryKey : maskCompound.keySet()) {
if (!matches(maskCompound.get(binaryKey), testCompound.get(binaryKey))) {
return false;
}
}

return true;
} else if (mask.type() == BinaryTagTypes.LIST) {
// For lists, we ensure that all the values match
ListBinaryTag maskList = (ListBinaryTag) mask;
ListBinaryTag testList = (ListBinaryTag) test;

if (!maskList.elementType().equals(testList.elementType())) {
// These lists are of different types
return false;
}

if (maskList.elementType() == BinaryTagTypes.COMPOUND) {
// Treat compound lists like a set, due to how MC handle them
for (BinaryTag binaryTag : maskList) {
boolean found = false;
for (BinaryTag testTag : testList) {
if (matches(binaryTag, testTag)) {
found = true;
break;
}
}
if (!found) {
return false;
}
}
} else {
int startIndex = 0;
for (BinaryTag binaryTag : maskList) {
boolean found = false;
for (int i = startIndex; i < testList.size(); i++) {
BinaryTag testTag = testList.get(i);
if (matches(binaryTag, testTag)) {
found = true;
startIndex = i + 1;
break;
}
}
if (!found) {
return false;
}
}
}

return true;
} else {
// For types that are just a value, we can do direct equality.
return mask.equals(test);
}
}

}