diff --git a/src/main/java/mezz/jei/JeiHelpers.java b/src/main/java/mezz/jei/JeiHelpers.java index 393a32510..d5b9b1844 100644 --- a/src/main/java/mezz/jei/JeiHelpers.java +++ b/src/main/java/mezz/jei/JeiHelpers.java @@ -3,6 +3,7 @@ import javax.annotation.Nonnull; import mezz.jei.api.IJeiHelpers; +import mezz.jei.api.INbtRegistry; import mezz.jei.gui.GuiHelper; import mezz.jei.transfer.RecipeTransferHandlerHelper; import mezz.jei.util.StackHelper; @@ -12,6 +13,7 @@ public class JeiHelpers implements IJeiHelpers { private final StackHelper stackHelper; private final ItemBlacklist itemBlacklist; private final NbtIgnoreList nbtIgnoreList; + private final NbtRegistry nbtRegistry; private final RecipeTransferHandlerHelper recipeTransferHandlerHelper; public JeiHelpers() { @@ -19,6 +21,7 @@ public JeiHelpers() { this.stackHelper = new StackHelper(); this.itemBlacklist = new ItemBlacklist(); this.nbtIgnoreList = new NbtIgnoreList(); + this.nbtRegistry = new NbtRegistry(); this.recipeTransferHandlerHelper = new RecipeTransferHandlerHelper(); } @@ -42,10 +45,16 @@ public ItemBlacklist getItemBlacklist() { @Nonnull @Override + @Deprecated public NbtIgnoreList getNbtIgnoreList() { return nbtIgnoreList; } + @Override + public INbtRegistry getNbtRegistry() { + return nbtRegistry; + } + @Nonnull @Override public RecipeTransferHandlerHelper recipeTransferHandlerHelper() { diff --git a/src/main/java/mezz/jei/NbtIgnoreList.java b/src/main/java/mezz/jei/NbtIgnoreList.java index 8bb514913..106c98b31 100644 --- a/src/main/java/mezz/jei/NbtIgnoreList.java +++ b/src/main/java/mezz/jei/NbtIgnoreList.java @@ -14,6 +14,7 @@ import java.util.HashSet; import java.util.Set; +@Deprecated public class NbtIgnoreList implements INbtIgnoreList { private final Set nbtTagNameBlacklist = new HashSet<>(); private final HashMultimap itemNbtTagNameBlacklist = HashMultimap.create(); diff --git a/src/main/java/mezz/jei/NbtRegistry.java b/src/main/java/mezz/jei/NbtRegistry.java new file mode 100644 index 000000000..dd595d760 --- /dev/null +++ b/src/main/java/mezz/jei/NbtRegistry.java @@ -0,0 +1,81 @@ +package mezz.jei; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +import mezz.jei.api.INbtRegistry; +import mezz.jei.util.Log; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class NbtRegistry implements INbtRegistry { + private final Map nbtInterpreters = new HashMap<>(); + + @Override + public void useNbtForSubtypes(@Nonnull Item... items) { + for (Item item : items) { + registerNbtInterpreter(item, AllNbt.INSTANCE); + } + } + + @Override + public void registerNbtInterpreter(@Nullable Item item, @Nullable INbtInterpreter nbtInterpreter) { + if (item == null) { + Log.error("Null item", new NullPointerException()); + return; + } + if (nbtInterpreter == null) { + Log.error("Null nbtInterpreter", new NullPointerException()); + return; + } + + if (nbtInterpreters.containsKey(item)) { + Log.error("An nbtInterpreter is already registered for this item: {}", item, new IllegalArgumentException()); + return; + } + + nbtInterpreters.put(item, nbtInterpreter); + } + + @Nullable + @Override + public String getSubtypeInfoFromNbt(@Nullable ItemStack itemStack) { + if (itemStack == null) { + Log.error("Null itemStack", new NullPointerException()); + return null; + } + + NBTTagCompound tagCompound = itemStack.getTagCompound(); + if (tagCompound == null) { + return null; + } + + Item item = itemStack.getItem(); + if (item == null) { + Log.error("Null item", new NullPointerException()); + return null; + } + + INbtRegistry.INbtInterpreter nbtInterpreter = nbtInterpreters.get(item); + if (nbtInterpreter == null) { + return null; + } + + return nbtInterpreter.getSubtypeInfoFromNbt(tagCompound); + } + + private static class AllNbt implements INbtInterpreter { + public static final AllNbt INSTANCE = new AllNbt(); + + private AllNbt() { } + + @Nullable + @Override + public String getSubtypeInfoFromNbt(@Nonnull NBTTagCompound nbtTagCompound) { + return nbtTagCompound.toString(); + } + } +} diff --git a/src/main/java/mezz/jei/api/IJeiHelpers.java b/src/main/java/mezz/jei/api/IJeiHelpers.java index bac74536b..bc09ffece 100644 --- a/src/main/java/mezz/jei/api/IJeiHelpers.java +++ b/src/main/java/mezz/jei/api/IJeiHelpers.java @@ -30,10 +30,17 @@ public interface IJeiHelpers { /** * Used to tell JEI to ignore NBT tags when comparing items for recipes. + * @deprecated all nbt is now ignored by default. If you have nbt that is used to identify your item's subtype, see {@link #getNbtRegistry()}. */ @Nonnull + @Deprecated INbtIgnoreList getNbtIgnoreList(); + /** + * If your item has subtypes that depend on NBT, use this to help JEI identify those subtypes correctly. + */ + INbtRegistry getNbtRegistry(); + /** * Helps with the implementation of Recipe Transfer Handlers */ diff --git a/src/main/java/mezz/jei/api/INbtIgnoreList.java b/src/main/java/mezz/jei/api/INbtIgnoreList.java index 9a90d3d95..bf5fd932e 100644 --- a/src/main/java/mezz/jei/api/INbtIgnoreList.java +++ b/src/main/java/mezz/jei/api/INbtIgnoreList.java @@ -7,24 +7,34 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +/** + * @deprecated since 3.6.0. all nbt is now ignored by default. See {@link INbtRegistry}. + */ +@Deprecated public interface INbtIgnoreList { /** * Tell JEI to ignore NBT tags on a specific item when comparing items for recipes. * @since JEI 2.22.0, NBT is automatically ignored on items that don't have subtypes. + * @deprecated since 3.6.0. all nbt is now ignored by default. See {@link INbtRegistry}. */ + @Deprecated void ignoreNbtTagNames(@Nonnull Item item, String... nbtTagNames); /** * Tell JEI to ignore NBT tags when comparing items for recipes. * To avoid nbt conflicts with other mods, use the item-specific version. + * @deprecated since 3.6.0. all nbt is now ignored by default. See {@link INbtRegistry}. */ + @Deprecated void ignoreNbtTagNames(String... nbtTagNames); /** * Get NBT from an itemStack, minus the NBT that is being ignored. * Returns null if the itemStack has no NBT or the resulting NBT would be empty. * @since JEI 2.16.0 + * @deprecated since 3.6.0. all nbt is now ignored by default. See {@link INbtRegistry}. */ + @Deprecated @Nullable NBTTagCompound getNbt(@Nonnull ItemStack itemStack); } diff --git a/src/main/java/mezz/jei/api/INbtRegistry.java b/src/main/java/mezz/jei/api/INbtRegistry.java new file mode 100644 index 000000000..f9d037375 --- /dev/null +++ b/src/main/java/mezz/jei/api/INbtRegistry.java @@ -0,0 +1,50 @@ +package mezz.jei.api; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +/** + * Tell JEI how to interpret NBT tags are used when comparing and looking up items. + * + * Some items have subtypes, most of them use meta values for this. + * If your item has subtypes that depend on NBT, use this interface so JEI can tell those subtypes apart. + * + * Most items do not use nbt to differentiate subtypes, so this interface is being used instead of a blacklist. + * Replaces {@link INbtIgnoreList}. + * + * @since 3.6.0 + */ +public interface INbtRegistry { + /** + * Tells JEI to treat all NBT as relevant to these items' subtypes. + */ + void useNbtForSubtypes(@Nonnull Item... items); + + /** + * Add an nbt interpreter to turn nbt into data that can be used to compare item subtypes. + * + * @param item the item that uses nbt to tell subtypes apart. + * @param nbtInterpreter the nbt interpreter for the item. + */ + void registerNbtInterpreter(@Nonnull Item item, @Nonnull INbtInterpreter nbtInterpreter); + + /** + * Get the data from an itemStack that is relevant to comparing and telling subtypes apart. + * Returns null if the itemStack has no NBT or the NBT is not used for subtypes. + */ + @Nullable + String getSubtypeInfoFromNbt(@Nonnull ItemStack itemStack); + + interface INbtInterpreter { + /** + * Get the data from an itemStack that is relevant to telling subtypes apart. + * Returns null if the NBT has no data used for subtypes. + */ + @Nullable + String getSubtypeInfoFromNbt(@Nonnull NBTTagCompound nbtTagCompound); + } +} diff --git a/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java b/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java index 38eb18365..6bc17be35 100644 --- a/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java +++ b/src/main/java/mezz/jei/plugins/vanilla/VanillaPlugin.java @@ -5,6 +5,7 @@ import mezz.jei.api.IItemRegistry; import mezz.jei.api.IJeiHelpers; import mezz.jei.api.IModRegistry; +import mezz.jei.api.INbtRegistry; import mezz.jei.api.JEIPlugin; import mezz.jei.api.recipe.VanillaRecipeCategoryUid; import mezz.jei.api.recipe.transfer.IRecipeTransferRegistry; @@ -34,8 +35,13 @@ import net.minecraft.inventory.ContainerWorkbench; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.ForgeModContainer; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.UniversalBucket; import javax.annotation.Nonnull; +import javax.annotation.Nullable; @JEIPlugin public class VanillaPlugin extends BlankModPlugin { @@ -56,6 +62,21 @@ public void register(@Nonnull IModRegistry registry) { "Unbreakable" ); + INbtRegistry nbtRegistry = jeiHelpers.getNbtRegistry(); + nbtRegistry.useNbtForSubtypes( + Items.BANNER, + Items.SPAWN_EGG, + Items.TIPPED_ARROW, + Items.ENCHANTED_BOOK, + Items.POTIONITEM, + Items.SPLASH_POTION, + Items.LINGERING_POTION + ); + + if (FluidRegistry.isUniversalBucketEnabled()) { + nbtRegistry.useNbtForSubtypes(ForgeModContainer.getInstance().universalBucket); + } + IGuiHelper guiHelper = jeiHelpers.getGuiHelper(); registry.addRecipeCategories( new CraftingRecipeCategory(guiHelper), diff --git a/src/main/java/mezz/jei/util/StackHelper.java b/src/main/java/mezz/jei/util/StackHelper.java index 7ce9ec42e..99a487318 100644 --- a/src/main/java/mezz/jei/util/StackHelper.java +++ b/src/main/java/mezz/jei/util/StackHelper.java @@ -360,14 +360,24 @@ public String getUniqueIdentifierForStack(@Nonnull ItemStack stack, @Nonnull Uid if (mode == UidMode.FULL || stack.getHasSubtypes()) { itemKey.append(':').append(metadata); if (stack.hasTagCompound()) { - NBTTagCompound nbtTagCompound; if (mode == UidMode.FULL) { - nbtTagCompound = stack.getTagCompound(); + NBTTagCompound nbtTagCompound = stack.getTagCompound(); + if (nbtTagCompound != null && !nbtTagCompound.hasNoTags()) { + itemKey.append(':').append(nbtTagCompound); + } } else { - nbtTagCompound = Internal.getHelpers().getNbtIgnoreList().getNbt(stack); - } - if (nbtTagCompound != null && !nbtTagCompound.hasNoTags()) { - itemKey.append(':').append(nbtTagCompound); + NBTTagCompound nbtTagCompound = Internal.getHelpers().getNbtIgnoreList().getNbt(stack); + + if (stack.getTagCompound() != nbtTagCompound) { // legacy handling for mods using nbtIgnoreList + if (nbtTagCompound != null && !nbtTagCompound.hasNoTags()) { + itemKey.append(':').append(nbtTagCompound); + } + } else { // nbtIgnoreList was not used + String subtypeInfo = Internal.getHelpers().getNbtRegistry().getSubtypeInfoFromNbt(stack); + if (subtypeInfo != null) { + itemKey.append(':').append(subtypeInfo); + } + } } } }