package com.infinityraider.agricraft.utility; import com.agricraft.agricore.core.AgriCore; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.JsonToNBT; import net.minecraft.nbt.NBTException; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.registry.ForgeRegistries; import net.minecraftforge.oredict.OreDictionary; public final class OreDictUtil { public static final String PREFIX_OREDICT = "oredict"; /** * Determines if the given string represents a valid oredict resource entry. * * @param element the string representation of the oredict entry, should start with {@link PREFIX_OREDICT}. * @return {@literal true} if and only if the given string represents a valid oredict entry, {@literal false} otherwise. */ public static final boolean isValidOre(@Nullable String element) { // If null or empty return nothing. if (element == null || element.isEmpty()) { return false; } // Split the element. final String[] parts = element.split(":"); // If only 1 part, then assume is suffix. if (parts.length == 1) { return false; } else if (parts.length == 2) { return isValidOre(parts[0], parts[1]); } else if (parts.length > 2) { AgriCore.getLogger("agricraft").warn("Invalid stack identifier detected!\n\tGiven: \"{0}\"\n\tAssuming: \"{1}:{2}\"", element, parts[0], parts[1]); return isValidOre(parts[0], parts[1]); } else { throw new AssertionError("String.split() method worked incorrectly. This should be an impossible error."); } } /** * Determines if the given string represents a valid oredict resource entry. * * @param prefix * @param suffix * @return {@literal true} if and only if the given string represents a valid oredict entry, {@literal false} otherwise. */ public static final boolean isValidOre(@Nonnull String prefix, @Nonnull String suffix) { // Validate Preconditions.checkNotNull(prefix, "A stack identifier must have a non-null prefix!"); Preconditions.checkNotNull(suffix, "A stack identifier must have a non-null suffix!"); // Check that prefix is correct. if (!PREFIX_OREDICT.equals(prefix)) { return false; } // Check that the oredictionary contains the given object. if (!OreDictionary.doesOreNameExist(suffix)) { AgriCore.getLogger("agricraft").error("Unable to resolve Ore Dictionary Entry: \"{0}:{1}\".", prefix, suffix); return false; } else { return true; } } /** * Finds the first ItemStack in the OreDictionary with matching ore name. * * @param oreName the name of the ore type. * @return an optional containing a matching ItemStack, or the empty * optional. */ @Nonnull public static Optional<ItemStack> getFirstOre(@Nonnull String oreName) { return OreDictionary.getOres(oreName).stream() .findFirst(); } /** * Creates an ItemStack with the given attributes, if possible. * * Unlike {@link OreDictionary#makeItemStack()} this method will not throw a * runtime exception if the JSON NBT string is invalid. * * This method allows for the optional support of PREFIX_OREDICT as a modid * prefix, in which case the first matching ore is returned as the item * stack. * * @param element the registry name of the item. * @param meta the metadata value associated with the item. * @param amount the amount of the item to be in the stack. * @param tags a json string representation of the tags to be associated * with the item. * @return an optional containing a matching ItemStack, or the empty * optional. */ @Nonnull public static final Optional<ItemStack> makeItemStack(@Nullable String element, int meta, int amount, @Nullable String tags) { // If null or empty return nothing. if (element == null || element.isEmpty()) { return Optional.empty(); } // Split the element. final String[] parts = element.split(":"); // If only 1 part, then assume is suffix. if (parts.length == 1) { return makeItemStack("minecraft", parts[0], meta, amount, tags); } else if (parts.length == 2) { return makeItemStack(parts[0], parts[1], meta, amount, tags); } else if (parts.length > 2) { AgriCore.getLogger("agricraft").warn("Invalid stack identifier detected!\n\tGiven: \"{0}\"\n\tAssuming: \"{1}:{2}\"", element, parts[0], parts[1]); return makeItemStack(parts[0], parts[1], meta, amount, tags); } else { throw new AssertionError("String.split() method worked incorrectly. This should be an impossible error."); } } /** * Creates an ItemStack with the given attributes, if possible. * * Unlike {@link OreDictionary#makeItemStack()} this method will not throw a * runtime exception if the JSON NBT string is invalid. * * This method allows for the optional support of PREFIX_OREDICT as a modid * prefix, in which case the first matching ore is returned as the item * stack. * * @param prefix the registry domain of the item. * @param suffix the registry path of the item. * @param meta the metadata value associated with the item. * @param amount the amount of the item to be in the stack. * @param tags a json string representation of the tags to be associated * with the item. * @return an optional containing a matching ItemStack, or the empty * optional. */ @Nonnull public static final Optional<ItemStack> makeItemStack(@Nonnull String prefix, @Nonnull String suffix, int meta, int amount, @Nullable String tags) { // Validate Preconditions.checkNotNull(prefix, "A stack identifier must have a non-null prefix!"); Preconditions.checkNotNull(suffix, "A stack identifier must have a non-null suffix!"); // Test if the prefix is the special oredict prefix. if (PREFIX_OREDICT.equals(prefix)) { return makeItemStackOreDict(prefix, suffix, meta, amount, tags); } else { return makeItemStackNormal(prefix, suffix, meta, amount, tags); } } @Nonnull private static Optional<ItemStack> makeItemStackNormal(@Nonnull String prefix, @Nonnull String suffix, int meta, int amount, String tags) { // Step 0. Fetch the item. final Item item = ForgeRegistries.ITEMS.getValue(new ResourceLocation(prefix, suffix)); // Step 1. Check that item is not null. if (item == null) { AgriCore.getLogger("agricraft").error("Unable to resolve item: {0}:{1}.", prefix, suffix); return Optional.empty(); } // Step 2. Create the itemstack. final ItemStack stack = new ItemStack(item, amount, meta); // Step 3. Add NBT data. return addNbtData(stack, tags); } @Nonnull private static Optional<ItemStack> makeItemStackOreDict(@Nonnull String prefix, @Nonnull String suffix, int meta, int amount, String tags) { // Do the thing. return getFirstOre(suffix) .map((s) -> { s = s.copy(); s.setCount(amount); return s; }) .flatMap(s -> addNbtData(s, tags)); } @Nonnull private static Optional<ItemStack> addNbtData(@Nonnull ItemStack stack, @Nullable String tags) { // Step 0. Validate. Preconditions.checkNotNull(stack, "The itemstack to add NBT data to may not be null"); // Step 1. Abort if tags are null. if (Strings.isNullOrEmpty(tags)) { return Optional.of(stack); } // Step 2. Get the tag instance. final NBTTagCompound tag = StackHelper.getTag(stack); // Step 3. Parse the tags. try { final NBTTagCompound added = JsonToNBT.getTagFromJson(tags); tag.merge(added); stack.setTagCompound(tag); return Optional.of(stack); } catch (NBTException e) { AgriCore.getLogger("agricraft").error("Unable to parse NBT Data: \"{0}\".\nCause: {1}", tags, e); return Optional.empty(); } } /** * Dummy constructor to prevent instantiation of utility class. */ private OreDictUtil() { // Nothing to see here @TehNut! } }