mirror of
https://github.com/StarWishsama/Slimefun4.git
synced 2024-09-19 19:25:48 +00:00
DistinctiveItem/isSimilar + Backpack canStack (#3417)
Co-authored-by: Daniel Walsh <walshydev@gmail.com> Co-authored-by: poma123 <25465545+poma123@users.noreply.github.com>
This commit is contained in:
parent
1beeb8fd8e
commit
934ab822a6
@ -0,0 +1,33 @@
|
||||
package io.github.thebusybiscuit.slimefun4.core.attributes;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Implement this interface for any {@link SlimefunItem} to prevent
|
||||
* cargo using only its ID when comparing. #canStack is used when
|
||||
* comparing stacks
|
||||
*
|
||||
* @author Sefiraat
|
||||
*/
|
||||
public interface DistinctiveItem extends ItemAttribute {
|
||||
|
||||
/**
|
||||
* This method is called by {@link SlimefunUtils#isItemSimilar} when two {@link SlimefunItemStack}
|
||||
* IDs match on a DistinctiveItem and should return if the two items can stack
|
||||
* with one another.
|
||||
*
|
||||
* @param itemMetaOne
|
||||
* The {@link ItemMeta} of the first stack being compared.
|
||||
* @param itemMetaTwo
|
||||
* The {@link ItemMeta} of the second stack being compared.
|
||||
*
|
||||
* @return Whether the two {@link ItemMeta}s are stackable
|
||||
*/
|
||||
boolean canStack(@Nonnull ItemMeta itemMetaOne, @Nonnull ItemMeta itemMetaTwo);
|
||||
}
|
@ -6,16 +6,19 @@ import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
|
||||
import io.github.thebusybiscuit.slimefun4.api.player.PlayerBackpack;
|
||||
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.DistinctiveItem;
|
||||
import io.github.thebusybiscuit.slimefun4.core.handlers.ItemUseHandler;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
|
||||
import io.github.thebusybiscuit.slimefun4.implementation.listeners.BackpackListener;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
|
||||
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
|
||||
|
||||
/**
|
||||
@ -28,7 +31,7 @@ import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
|
||||
* @see PlayerBackpack
|
||||
*
|
||||
*/
|
||||
public class SlimefunBackpack extends SimpleSlimefunItem<ItemUseHandler> {
|
||||
public class SlimefunBackpack extends SimpleSlimefunItem<ItemUseHandler> implements DistinctiveItem {
|
||||
|
||||
private final int size;
|
||||
|
||||
@ -82,4 +85,14 @@ public class SlimefunBackpack extends SimpleSlimefunItem<ItemUseHandler> {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStack(@Nonnull ItemMeta itemMetaOne, @Nonnull ItemMeta itemMetaTwo) {
|
||||
boolean hasLoreItem = itemMetaTwo.hasLore();
|
||||
boolean hasLoreSfItem = itemMetaOne.hasLore();
|
||||
|
||||
if (hasLoreItem && hasLoreSfItem && SlimefunUtils.equalsLore(itemMetaTwo.getLore(), itemMetaOne.getLore())) {
|
||||
return true;
|
||||
}
|
||||
return !hasLoreItem && !hasLoreSfItem;
|
||||
}
|
||||
}
|
||||
|
@ -90,9 +90,9 @@ public class EnhancedCraftingTable extends AbstractCraftingTable {
|
||||
|
||||
private boolean isCraftable(Inventory inv, ItemStack[] recipe) {
|
||||
for (int j = 0; j < inv.getContents().length; j++) {
|
||||
if (!SlimefunUtils.isItemSimilar(inv.getContents()[j], recipe[j], true)) {
|
||||
if (!SlimefunUtils.isItemSimilar(inv.getContents()[j], recipe[j], true, true, false)) {
|
||||
if (SlimefunItem.getByItem(recipe[j]) instanceof SlimefunBackpack) {
|
||||
if (!SlimefunUtils.isItemSimilar(inv.getContents()[j], recipe[j], false)) {
|
||||
if (!SlimefunUtils.isItemSimilar(inv.getContents()[j], recipe[j], false, true, false)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -37,6 +37,7 @@ import io.github.thebusybiscuit.slimefun4.api.exceptions.PrematureCodeException;
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.ItemSpawnReason;
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.DistinctiveItem;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive;
|
||||
import io.github.thebusybiscuit.slimefun4.core.attributes.Soulbound;
|
||||
import io.github.thebusybiscuit.slimefun4.core.debug.Debug;
|
||||
@ -260,7 +261,7 @@ public final class SlimefunUtils {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isItemSimilar(stack, item, checkLore, false)) {
|
||||
if (isItemSimilar(stack, item, checkLore, false, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -268,11 +269,69 @@ public final class SlimefunUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two {@link ItemStack}s and returns if they are similar or not.
|
||||
* Takes into account some shortcut checks specific to {@link SlimefunItem}s
|
||||
* for performance.
|
||||
* Will check for distintion of items by default and will also confirm the amount
|
||||
* is the same.
|
||||
* @see DistinctiveItem
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} being tested.
|
||||
* @param sfitem
|
||||
* The {@link ItemStack} that {@param item} is being compared against.
|
||||
* @param checkLore
|
||||
* Whether to include the current lore of either item in the comparison
|
||||
*
|
||||
* @return True if the given {@link ItemStack}s are similar under the given constraints
|
||||
*/
|
||||
public static boolean isItemSimilar(@Nullable ItemStack item, @Nullable ItemStack sfitem, boolean checkLore) {
|
||||
return isItemSimilar(item, sfitem, checkLore, true);
|
||||
return isItemSimilar(item, sfitem, checkLore, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two {@link ItemStack}s and returns if they are similar or not.
|
||||
* Takes into account some shortcut checks specific to {@link SlimefunItem}s
|
||||
* for performance.
|
||||
* Will check for distintion of items by default
|
||||
* @see DistinctiveItem
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} being tested.
|
||||
* @param sfitem
|
||||
* The {@link ItemStack} that {@param item} is being compared against.
|
||||
* @param checkLore
|
||||
* Whether to include the current lore of either item in the comparison
|
||||
* @param checkAmount
|
||||
* Whether to include the item's amount(s) in the comparison
|
||||
*
|
||||
* @return True if the given {@link ItemStack}s are similar under the given constraints
|
||||
*/
|
||||
public static boolean isItemSimilar(@Nullable ItemStack item, @Nullable ItemStack sfitem, boolean checkLore, boolean checkAmount) {
|
||||
return isItemSimilar(item, sfitem, checkLore, checkAmount, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two {@link ItemStack}s and returns if they are similar or not.
|
||||
* Takes into account some shortcut checks specific to {@link SlimefunItem}s
|
||||
* for performance.
|
||||
*
|
||||
* @param item
|
||||
* The {@link ItemStack} being tested.
|
||||
* @param sfitem
|
||||
* The {@link ItemStack} that {@param item} is being compared against.
|
||||
* @param checkLore
|
||||
* Whether to include the current lore of either item in the comparison
|
||||
* @param checkAmount
|
||||
* Whether to include the item's amount(s) in the comparison
|
||||
* @param checkDistinction
|
||||
* Whether to check for special distinctive properties of the items.
|
||||
* @see DistinctiveItem
|
||||
*
|
||||
* @return True if the given {@link ItemStack}s are similar under the given constraints
|
||||
*/
|
||||
public static boolean isItemSimilar(@Nullable ItemStack item, @Nullable ItemStack sfitem, boolean checkLore, boolean checkAmount, boolean checkDistinction) {
|
||||
if (item == null) {
|
||||
return sfitem == null;
|
||||
} else if (sfitem == null) {
|
||||
@ -281,17 +340,42 @@ public final class SlimefunUtils {
|
||||
return false;
|
||||
} else if (checkAmount && item.getAmount() < sfitem.getAmount()) {
|
||||
return false;
|
||||
} else if (sfitem instanceof SlimefunItemStack && item instanceof SlimefunItemStack) {
|
||||
return ((SlimefunItemStack) item).getItemId().equals(((SlimefunItemStack) sfitem).getItemId());
|
||||
} else if (sfitem instanceof SlimefunItemStack stackOne && item instanceof SlimefunItemStack stackTwo) {
|
||||
if (stackOne.getItemId().equals(stackTwo.getItemId())) {
|
||||
/*
|
||||
* PR #3417
|
||||
*
|
||||
* Some items can't rely on just IDs matching and will implement {@link DistinctiveItem}
|
||||
* in which case we want to use the method provided to compare
|
||||
*/
|
||||
if (checkDistinction && stackOne instanceof DistinctiveItem distinctive && stackTwo instanceof DistinctiveItem) {
|
||||
return distinctive.canStack(stackOne.getItemMeta(), stackTwo.getItemMeta());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (item.hasItemMeta()) {
|
||||
Debug.log(TestCase.CARGO_INPUT_TESTING, "SlimefunUtils#isItemSimilar - item.hasItemMeta()");
|
||||
ItemMeta itemMeta = item.getItemMeta();
|
||||
|
||||
if (sfitem instanceof SlimefunItemStack) {
|
||||
Optional<String> id = Slimefun.getItemDataService().getItemData(itemMeta);
|
||||
String id = Slimefun.getItemDataService().getItemData(itemMeta).orElse(null);
|
||||
|
||||
if (id.isPresent()) {
|
||||
return id.get().equals(((SlimefunItemStack) sfitem).getItemId());
|
||||
if (id != null) {
|
||||
if (checkDistinction) {
|
||||
/*
|
||||
* PR #3417
|
||||
*
|
||||
* Some items can't rely on just IDs matching and will implement {@link DistinctiveItem}
|
||||
* in which case we want to use the method provided to compare
|
||||
*/
|
||||
Optional<DistinctiveItem> optionalDistinctive = getDistinctiveItem(id);
|
||||
if (optionalDistinctive.isPresent()) {
|
||||
ItemMeta sfItemMeta = sfitem.getItemMeta();
|
||||
return optionalDistinctive.get().canStack(sfItemMeta, itemMeta);
|
||||
}
|
||||
}
|
||||
return id.equals(((SlimefunItemStack) sfitem).getItemId());
|
||||
}
|
||||
|
||||
ItemMetaSnapshot meta = ((SlimefunItemStack) sfitem).getItemMetaSnapshot();
|
||||
@ -304,12 +388,25 @@ public final class SlimefunUtils {
|
||||
* Slimefun items may be ItemStackWrapper's in the context of cargo
|
||||
* so let's try to do an ID comparison before meta comparison
|
||||
*/
|
||||
ItemMeta possibleSfItemMeta = sfitem.getItemMeta();
|
||||
Debug.log(TestCase.CARGO_INPUT_TESTING, " sfitem is ItemStackWrapper - possible SF Item: {}", sfitem);
|
||||
|
||||
ItemMeta possibleSfItemMeta = sfitem.getItemMeta();
|
||||
String id = Slimefun.getItemDataService().getItemData(itemMeta).orElse(null);
|
||||
String possibleItemId = Slimefun.getItemDataService().getItemData(possibleSfItemMeta).orElse(null);
|
||||
// Prioritize SlimefunItem id comparison over ItemMeta comparison
|
||||
if (Slimefun.getItemDataService().hasEqualItemData(possibleSfItemMeta, itemMeta)) {
|
||||
if (id != null && id.equals(possibleItemId)) {
|
||||
Debug.log(TestCase.CARGO_INPUT_TESTING, " Item IDs matched!");
|
||||
|
||||
/*
|
||||
* PR #3417
|
||||
*
|
||||
* Some items can't rely on just IDs matching and will implement {@link DistinctiveItem}
|
||||
* in which case we want to use the method provided to compare
|
||||
*/
|
||||
Optional<DistinctiveItem> optionalDistinctive = getDistinctiveItem(id);
|
||||
if (optionalDistinctive.isPresent()) {
|
||||
return optionalDistinctive.get().canStack(possibleSfItemMeta, itemMeta);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
Debug.log(TestCase.CARGO_INPUT_TESTING, " Item IDs don't match, checking meta {} == {} (lore: {})", itemMeta, possibleSfItemMeta, checkLore);
|
||||
@ -327,6 +424,14 @@ public final class SlimefunUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nonnull Optional<DistinctiveItem> getDistinctiveItem(@Nonnull String id) {
|
||||
SlimefunItem slimefunItem = SlimefunItem.getById(id);
|
||||
if (slimefunItem instanceof DistinctiveItem distinctive) {
|
||||
return Optional.of(distinctive);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static boolean equalsItemMeta(@Nonnull ItemMeta itemMeta, @Nonnull ItemMetaSnapshot itemMetaSnapshot, boolean checkLore) {
|
||||
Optional<String> displayName = itemMetaSnapshot.getDisplayName();
|
||||
|
||||
@ -523,4 +628,27 @@ public final class SlimefunUtils {
|
||||
public static @Nullable Item spawnItem(Location loc, ItemStack item, ItemSpawnReason reason) {
|
||||
return spawnItem(loc, item, reason, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if an Inventory is empty (has no items in "storage").
|
||||
* If the MC version is 1.16 or above
|
||||
* this will call {@link Inventory#isEmpty()} (Which calls MC code resulting in a faster method).
|
||||
*
|
||||
* @param inventory
|
||||
* The {@link Inventory} to check.
|
||||
*
|
||||
* @return True if the inventory is empty and false otherwise
|
||||
*/
|
||||
public static boolean isInventoryEmpty(@Nonnull Inventory inventory) {
|
||||
if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_16)) {
|
||||
return inventory.isEmpty();
|
||||
} else {
|
||||
for (ItemStack is : inventory.getStorageContents()) {
|
||||
if (is != null && !is.getType().isAir()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user